Nodemcu-firmware: LUA module bme280 not work.

Created on 6 Dec 2020  ·  11Comments  ·  Source: nodemcu/nodemcu-firmware

Expected behavior

Operation of the bme280 sensor using the "LUA module bme280". If I use "C module bme280" the sensor is working fine. However, according to the information "Warning, deprecated API! bme280. It will be removed soon. Use bme280math and bme280 Lua module instead" this version of the module is deprecated and will be retired soon. That's why I want to use the new LUA module in my application. Of course, in the case of "C module" I use firmware that has the bme280 module and the bme280_math module built in. In the case of "LUA module bme280", only the bme280_math module is compiled in the firmware and the device has the bme280.lua file downloaded from https://github.com/nodemcu/nodemcu-firmware/tree/dev/lua_modules/bme280/bme280.lua. Both firmware are built using the website https://nodemcu-build.com/

Actual behavior

The program reports errors and the NodeMcu device resets.

dofile("test280.lua")
test280.lua:8: attempt to index global 's' (a nil value)
stack traceback:
test280.lua:8: in function
test280.lua:8: attempt to index global 's' (a nil value)
stack traceback:
test280.lua:8: in function
test280.lua:8: attempt to index global 's' (a nil value)
stack traceback:
test280.lua:8: in function
test280.lua:8: attempt to index global 's' (a nil value)
stack traceback:
test280.lua:8: in function
test280.lua:8: attempt to index global 's' (a nil value)
stack traceback:
test280.lua:8: in function
ets Jan 8 2013,rst cause:2, boot mode:(3,6)
load 0x40100000, len 27444, room 16
tail 4
chksum 0x9e
load 0x3ffe8000, len 2576, room 4
tail 12
chksum 0x2a
ho 0 tail 12 room 4
load 0x3ffe8a10, len 8, room 12
tail 8
chksum 0x75
csum 0x75
�2r���o���

Test code

alt=36 -- altitude of the measurement place

sda, scl = 2, 1
i2c.setup(0, sda, scl, i2c.SLOW)
s = require('bme280').setup(0)

tmr.create():alarm(500, tmr.ALARM_AUTO, function()
    local T, P, H, QNH = s:read(alt)
    local D = s:dewpoint(H, T)
    print(("T=%.2f, QFE=%.3f, QNH=%.3f, humidity=%.3f, dewpoint=%.2f"):format(T, P, QNH, H, D))
end)

The above code is an example taken from the LUA module bme280 NodeMCU documentation. In my example it is called "test.280.lua"

NodeMCU startup banner

NodeMCU 3.0.0.0 built on nodemcu-build.com provided by frightanic.com
branch: release
commit: 4f6792773f93f36a7255cfd28dca7aa6c4aa9552
release: 3.0-release_20201107
release DTS: 202011071523
SSL: false
build type: float
LFS: 0x0 bytes total capacity
modules: bme280_math,file,gpio,i2c,net,node,tmr,uart,wifi
build 2020-12-05 11:51 powered by Lua 5.1.4 on SDK 3.0.1-dev(fce080e)

Hardware

Amica NodeMcu v.2 and CJMCU BME280 sensor.

Most helpful comment

The documentation for the BME280 LUA module says: "Note: the module works only with the bme280_math module.". That's why I compiled the module bme280_math into the firmware. If, as you write, it is not needed and it can cause problems, the documentation should be corrected.

Is the sensor connected to GPIO5 (sda) and GPIO4 (scl)?

Yes. The same connection worked without problems with the C modules. From the point of view of hardware and connections, everything is rather correct.

I will build the firmware without the bme_math module and try if it works properly. I will also modify the lua code, according to your directions, do some tests and let you know the result.

All 11 comments

Hi. I'm sorry for this issue. It's wise to use the new bme280_math module together with the bme280 Lua module.

It is useless to have both bme280 module and the bme280_math module together. The bme280 module includes all the math that is in the bme280_math module. If you use bme280 Lua module (to be used with bme280_math) then you can have conflicts between the Lua and the C module. But apparently this is not the issue here.

When setup returns nil it means that it could not initialize the BME280 sensor. So before calling s' methods you should test it for nil. This is omitted in the simple example. Is the sensor connected to GPIO5 (sda) and GPIO4 (scl)?

You can also try to enable debug in bme280 module. You would need to uncomment this part:

local print, node_heap = print, node.heap
local function debug (fmt, ...) -- upval: cnt (, print, node_heap)
  if not bme280.debug then return end
  if (...) then fmt = fmt:format(...) end
  print("[bme280]", node_heap(), fmt)
end

and then uncomment every occurrence of debug.

Your test code will then need to look like something like this:

alt=36 -- altitude of the measurement place

sda, scl = 2, 1
i2c.setup(0, sda, scl, i2c.SLOW)
sr = require('bme280')
sr.debug = true
s = sr.setup(0)

tmr.create():alarm(500, tmr.ALARM_AUTO, function()
    local T, P, H, QNH = s:read(alt)
    local D = s:dewpoint(H, T)
    print(("T=%.2f, QFE=%.3f, QNH=%.3f, humidity=%.3f, dewpoint=%.2f"):format(T, P, QNH, H, D))
end)

The documentation for the BME280 LUA module says: "Note: the module works only with the bme280_math module.". That's why I compiled the module bme280_math into the firmware. If, as you write, it is not needed and it can cause problems, the documentation should be corrected.

Is the sensor connected to GPIO5 (sda) and GPIO4 (scl)?

Yes. The same connection worked without problems with the C modules. From the point of view of hardware and connections, everything is rather correct.

I will build the firmware without the bme_math module and try if it works properly. I will also modify the lua code, according to your directions, do some tests and let you know the result.

I loaded the firmware:

NodeMCU 3.0.0.0 built on nodemcu-build.com provided by frightanic.com
branch: release
commit: 4f6792773f93f36a7255cfd28dca7aa6c4aa9552
release: 3.0-release_20201107
release DTS: 202011071523
SSL: false
build type: float
LFS: 0x0 bytes total capacity
modules: file,gpio,i2c,mdns,mqtt,net,node,tmr,uart,wifi
build 2020-12-09 08:18 powered by Lua 5.1.4 on SDK 3.0.1-dev(fce080e)

I uncomment this part in bme280.lua file:

local print, node_heap = print, node.heap
local function debug (fmt, ...) -- upval: cnt (, print, node_heap)
if not bme280.debug then return end
if (...) then fmt = fmt:format(...) end
print("[bme280]", node_heap(), fmt)
end

The bme280.lua file was uploaded to the nodemcu device.
And if I run code (test280-2.lua):

alt=36 -- altitude of the measurement place

sda, scl = 2, 1
i2c.setup(0, sda, scl, i2c.SLOW)
sr = require('bme280')
sr.debug = true
s = sr.setup(0)

tmr.create():alarm(500, tmr.ALARM_AUTO, function()
local T, P, H, QNH = s:read(alt)
local D = s:dewpoint(H, T)
print(("T=%.2f, QFE=%.3f, QNH=%.3f, humidity=%.3f, dewpoint=%.2f"):format(T, P, QNH, H, D))
end)

I get this message:

dofile('test280-2.lua')
Lua error: bme280.lua:22: attempt to index global 'bme280_math' (a nil value)
stack traceback:
bme280.lua:22: in main chunk
[C]: in function 'require'
test280-2.lua:5: in main chunk
[C]: in function 'dofile'
stdin:1: in main chunk
[C]: ?
[C]: ?

I don't understand whether the bme280_math C module has to be compiled into the firmware or not. However, in both cases, the code does not work :-(

Sorry if I was not clear. For the new bme280 Lua module you need to include bme280_math.

You can see it from this error message:

Lua error: bme280.lua:22: attempt to index global 'bme280_math' (a nil value)

Firmware:
NodeMCU 3.0.0.0 built on nodemcu-build.com provided by frightanic.com
branch: release
commit: 4f6792773f93f36a7255cfd28dca7aa6c4aa9552
release: 3.0-release_20201107
release DTS: 202011071523
SSL: false
build type: float
LFS: 0x0 bytes total capacity
modules: bme280_math,file,gpio,i2c,net,node,tmr,uart,wifi
build 2020-12-05 11:51 powered by Lua 5.1.4 on SDK 3.0.1-dev(fce080e)

It still does not work:

dofile("test280-2.lua")
test280-2.lua:10: attempt to index global 's' (a nil value)
stack traceback:
test280-2.lua:10: in function
test280-2.lua:10: attempt to index global 's' (a nil value)
stack traceback:
test280-2.lua:10: in function
test280-2.lua:10: attempt to index global 's' (a nil value)
stack traceback:
test280-2.lua:10: in function
test280-2.lua:10: attempt to index global 's' (a nil value)
stack traceback:
test280-2.lua:10: in function
test280-2.lua:10: attempt to index global 's' (a nil value)
stack traceback:
test280-2.lua:10: in function
ets Jan 8 2013,rst cause:2, boot mode:(3,7)
load 0x40100000, len 27444, room 16
tail 4
chksum 0x9e
load 0x3ffe8000, len 2576, room 4
tail 12
chksum 0x2a
ho 0 tail 12 room 4
load 0x3ffe8a10, len 8, room 12
tail 8
chksum 0x75
csum 0x75
�2r���N��$���

I don't see any debug output if the debug output was enabled. Could you try again with enabled debug output?

bme280.lua is uploaded to nodemcu and it looks like this:

--[[
 BME280 Lua module
 Requires i2c and bme280_math module
 Written by Lukas Voborsky, @voborsky
]]

local bme280 = {}

-- bme280.setup()
-- bme280:setup()
-- bme280:read()
-- bme280:altitude()
-- bme280:dewpoint()
-- bme280:qfe2qnh()
-- bme280:startreadout()

local type, assert = type, assert
local table_concat, math_floor = table.concat, math.floor
local i2c_start, i2c_stop, i2c_address, i2c_read, i2c_write, i2c_TRANSMITTER, i2c_RECEIVER =
  i2c.start, i2c.stop, i2c.address, i2c.read, i2c.write, i2c.TRANSMITTER, i2c.RECEIVER
local bme280_math_setup, bme280_math_read, bme280_math_qfe2qnh, bme280_math_altitude, bme280_math_dewpoint =
  bme280_math.setup, bme280_math.read, bme280_math.qfe2qnh, bme280_math.altitude, bme280_math.dewpoint
local tmr_create, tmr_ALARM_SINGLE = tmr.create, tmr.ALARM_SINGLE


local BME280_I2C_ADDRESS1 = 0x76
local BME280_I2C_ADDRESS2 = 0x77

local BME280_REGISTER_CONTROL = 0xF4
local BME280_REGISTER_CONTROL_HUM = 0xF2
local BME280_REGISTER_CONFIG= 0xF5
local BME280_REGISTER_CHIPID = 0xD0

local BME280_REGISTER_DIG_T = 0x88  -- 0x88-0x8D ( 6)
local BME280_REGISTER_DIG_P = 0x8E  -- 0x8E-0x9F (18)
local BME280_REGISTER_DIG_H1 = 0xA1  -- 0xA1      ( 1)
local BME280_REGISTER_DIG_H2 = 0xE1  -- 0xE1-0xE7 ( 7)
local BME280_REGISTER_PRESS = 0xF7   -- 0xF7-0xF9

-- local BME280_FORCED_MODE = 0x01

-- maximum measurement time in ms for maximum oversampling for all measures
-- 113 > 1.25 + 2.3*16 + 2.3*16 + 0.575 + 2.3*16 + 0.575 ms
local BME280_SAMPLING_DELAY =113

-- Local functions
local read_reg
local write_reg
local bme280_setup
local bme280_read
local bme280_startreadout

-- -- Note that the space between debug and the arglist is there for a reason
-- -- so that a simple global edit "   debug(" -> "-- debug(" or v.v. to
-- -- toggle debug compiled into the module.
local print, node_heap = print, node.heap
local function debug (fmt, ...) -- upval: cnt (, print, node_heap)
  if not bme280.debug then return end
  if (...) then fmt = fmt:format(...) end
  print("[bme280]", node_heap(), fmt)
end

--------------------------- Set up the bme280 object ----------------------------
--       bme280 has method setup to create the sensor object and setup the sensor
--       object created by bme280.setup() has methods: read, qfe2qnh, altitude, dewpoint
---------------------------------------------------------------------------------

function bme280.setup(id, addr, temp_oss, press_oss, humi_oss, power_mode, inactive_duration, IIR_filter, full_init)
  return bme280_setup(nil, id,
    addr, temp_oss, press_oss, humi_oss, power_mode, inactive_duration, IIR_filter, full_init)
end

------------------------------------------------------------------------------
function bme280_setup(self, id, addr,
  temp_oss, press_oss, humi_oss, power_mode, inactive_duration, IIR_filter, full_init)

  addr = (addr==2) and BME280_I2C_ADDRESS2 or BME280_I2C_ADDRESS1
  full_init = full_init or true

  -- debug("%d %x %d", id, addr, BME280_REGISTER_CHIPID)
  local chipid = read_reg(id, addr, BME280_REGISTER_CHIPID, 1)
  if not chipid then
    return nil
  end
  -- debug("chip_id: %x", chipid:byte(1))
  local isbme = (chipid:byte(1) == 0x60)

  local buf = {}
  buf[1] = read_reg(id, addr, BME280_REGISTER_DIG_T, 6)
  buf[2] = read_reg(id, addr, BME280_REGISTER_DIG_P, 18)
  if (isbme) then
    buf[3] = read_reg(id, addr, BME280_REGISTER_DIG_H1, 1)
    buf[4] = read_reg(id, addr, BME280_REGISTER_DIG_H2, 7)
  end

  local sensor, config = bme280_math_setup(table_concat(buf),
    temp_oss, press_oss, humi_oss, power_mode, inactive_duration, IIR_filter)
  self = self  or {
    setup = bme280_setup,
    read = bme280_read,
    startreadout = bme280_startreadout,
    qfe2qnh = bme280_math_qfe2qnh,
    altitude = bme280_math_altitude,
    dewpoint = bme280_math_dewpoint
  }
  self.id, self.addr = id, addr
  self._sensor, self._config, self._isbme = sensor, config, isbme

  if (full_init) then
    write_reg(id, addr, BME280_REGISTER_CONFIG, config[1])
    if (isbme) then write_reg(id, addr, BME280_REGISTER_CONTROL_HUM, config[2]) end
    write_reg(id, addr, BME280_REGISTER_CONTROL, config[3])
  end

  return self
end

function bme280_read(self, alt)
  local buf = read_reg(self.id, self.addr, BME280_REGISTER_PRESS, 8) -- registers are P[3], T[3], H[2]
  if buf then
    return bme280_math_read(self._sensor, buf, alt)
  else
    return nil
  end
end

function bme280_startreadout(self, callback, delay, alt)
  assert(type(callback) == "function", "invalid callback parameter")

  delay = delay or BME280_SAMPLING_DELAY

  if self._isbme then write_reg(self.id, self.addr, BME280_REGISTER_CONTROL_HUM, self._config[2]) end
  write_reg(self.id, self.addr, BME280_REGISTER_CONTROL, 4*math_floor(self._config[3]:byte(1)/4)+ 1) -- LUA51
    -- 4*math_floor(self._config[3]:byte(1)/4)+ 1
    --   an awful way to avoid bit operations but calculate (config[3] & 0xFC) | BME280_FORCED_MODE
    -- Lua 5.3: write_reg(self.id, self.addr, BME280_REGISTER_CONTROL, (self._config[3]:byte(1) & 0xFC) | 1)

  tmr_create():alarm(delay, tmr_ALARM_SINGLE,
    function()
      callback(bme280_read(self, alt))
    end
  )
end

function write_reg(id, dev_addr, reg_addr, data)
  i2c_start(id)
  if not i2c_address(id, dev_addr, i2c_TRANSMITTER) then
    -- debug("No ACK on address: %x", dev_addr)
    return nil
  end
  i2c_write(id, reg_addr)
  local c = i2c_write(id, data)
  i2c_stop(id)
  return c
end

function read_reg(id, dev_addr, reg_addr, n)
  i2c_start(id)
  if not i2c_address(id, dev_addr, i2c_TRANSMITTER) then
    -- debug("No ACK on address: %x", dev_addr)
    return nil
  end
  i2c_write(id, reg_addr)
  i2c_stop(id)
  i2c_start(id)
  i2c_address(id, dev_addr, i2c_RECEIVER)
  local c = i2c_read(id, n)
  i2c_stop(id)
  return c
end

------------------------------------------------ -----------------------------
return bme280

Firmware:

NodeMCU 3.0.0.0 built on nodemcu-build.com provided by frightanic.com
    branch: release
    commit: 4f6792773f93f36a7255cfd28dca7aa6c4aa9552
    release: 3.0-release_20201107
    release DTS: 202011071523
    SSL: false
    build type: float
    LFS: 0x0 bytes total capacity
    modules: bme280_math,file,gpio,i2c,net,node,tmr,uart,wifi
 build 2020-12-05 11:51 powered by Lua 5.1.4 on SDK 3.0.1-dev(fce080e)
cannot open init.lua: 

I run this code (test280-2.lua):

alt=36 -- altitude of the measurement place

sda, scl = 2, 1
i2c.setup(0, sda, scl, i2c.SLOW)
sr = require('bme280')
sr.debug = true
s = sr.setup(0)

tmr.create():alarm(500, tmr.ALARM_AUTO, function()
    local T, P, H, QNH = s:read(alt)
    local D = s:dewpoint(H, T)
    print(("T=%.2f, QFE=%.3f, QNH=%.3f, humidity=%.3f, dewpoint=%.2f"):format(T, P, QNH, H, D))
end)

Below is the result:

dofile("test280-2.lua")
> test280-2.lua:10: attempt to index global 's' (a nil value)
stack traceback:
    test280-2.lua:10: in function <test280-2.lua:9>
test280-2.lua:10: attempt to index global 's' (a nil value)
stack traceback:
    test280-2.lua:10: in function <test280-2.lua:9>
test280-2.lua:10: attempt to index global 's' (a nil value)
stack traceback:
    test280-2.lua:10: in function <test280-2.lua:9>
test280-2.lua:10: attempt to index global 's' (a nil value)
stack traceback:
    test280-2.lua:10: in function <test280-2.lua:9>
test280-2.lua:10: attempt to index global 's' (a nil value)
stack traceback:
    test280-2.lua:10: in function <test280-2.lua:9>

 ets Jan  8 2013,rst cause:2, boot mode:(3,7)

load 0x40100000, len 27444, room 16 
tail 4
chksum 0x9e
load 0x3ffe8000, len 2576, room 4 
tail 12
chksum 0x2a
ho 0 tail 12 room 4
load 0x3ffe8a10, len 8, room 12 
tail 8
chksum 0x75
csum 0x75
�r�ےN��l���

Yes, you still need to uncomment the lines -- debug(... and add sr.debug = true line into your test file.

The line sr.debug = true was added all the time, but the -- debug(... lines were commented out.
The result:

> dofile("test280-2.lua")
[bme280]    33432   0 76 208
[bme280]    33424   No ACK on address: 76
> test280-2.lua:10: attempt to index global 's' (a nil value)
stack traceback:
    test280-2.lua:10: in function <test280-2.lua:9>
test280-2.lua:10: attempt to index global 's' (a nil value)
stack traceback:
    test280-2.lua:10: in function <test280-2.lua:9>
test280-2.lua:10: attempt to index global 's' (a nil value)
stack traceback:
    test280-2.lua:10: in function <test280-2.lua:9>
test280-2.lua:10: attempt to index global 's' (a nil value)
stack traceback:
    test280-2.lua:10: in function <test280-2.lua:9>
test280-2.lua:10: attempt to index global 's' (a nil value)
stack traceback:
    test280-2.lua:10: in function <test280-2.lua:9>

 ets Jan  8 2013,rst cause:2, boot mode:(3,7)

load 0x40100000, len 27444, room 16 
tail 4
chksum 0x9e
load 0x3ffe8000, len 2576, room 4 
tail 12
chksum 0x2a
ho 0 tail 12 room 4
load 0x3ffe8a10, len 8, room 12 
tail 8
chksum 0x75
csum 0x75
�2r���o��l���

The error occurs only when I have the sensor address set to 0x77, after changing to 0x76 the sensor works fine!
Hope we're getting closer to solving the problem :)

Ok, so when your sensor is sitting on the addres 0x77 you need to initialize with:

s = sr.setup(0, 2)

I quote part of the documentation:

Syntax

bme280.setup(id, [address, temp_oss, press_oss, humi_oss, power_mode, inactive_duration, IIR_filter])

Parameters

  • id - I2C bus number
  • (optional)address - BME280 sensor address. 1 for BME280_I2C_ADDRESS1 = 0x76, 2 for BME280_I2C_ADDRESS2 = 0x77. Default sensor address is BME280_I2C_ADDRESS1.

Wow, you are right i got lost with it. Now it works very well. It seemed to me that I was doing everything right, I checked several times. I need to read the documentation more carefully. Thank you for your help and your time.
Thanks!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sivix picture sivix  ·  4Comments

v1993 picture v1993  ·  5Comments

fsch2 picture fsch2  ·  7Comments

liuyang77886 picture liuyang77886  ·  5Comments

marcelstoer picture marcelstoer  ·  4Comments