I'm trying to interface with a BNO055 absolute orientation sensor. I'm new to both I2C and Lua, but I've tried to combine the Lua examples for reading from similar sensors and this python code from Adafruit which lists the addresses of the various sensors and protocol for setting modes. However, I'm getting zeroes when I try to read from the device. Any suggestions for where I'm going wrong?
function convert_16_bit(lsb,msb)
res = 0
if msb >= 128 then
res = (-0x7FFF+((msb-128)*256+lsb))
else
res = (msb*256+lsb)
end
return res
end
boardAddr = 0x28 -- address of the board (as found by https://labjack.com/support/software/examples/lua-scripting/i2c/i2c-tuto...)
--SDA is connected to EIO0
sdaPin = 8
--SCL is connected to EIO1
sclPin = 9
--pin num map: FIO0:7 = 0:7, EIO0:7 = 8:15, CIO0:7 = 16:23
throttleVal = 0 --0=fastest; 65535=fastest; 65534, 65533, etc. gets slower.
I2C.config(sdaPin, sclPin, throttleVal, 0, boardAddr, 0) --configure the I2C Bus
--init board slave
MB.W(5104, 0, boardAddr)--change target to board
-- Set to normal power mode.
BNO055_PWR_MODE_ADDR = 0x3E
POWER_MODE_NORMAL = 0x00
I2C.write({BNO055_PWR_MODE_ADDR, POWER_MODE_NORMAL})
-- Enable ndof mode
BNO055_OPR_MODE_ADDR = 0x3D
OPERATION_MODE_NDOF = 0x0C
I2C.write({BNO055_OPR_MODE_ADDR, OPERATION_MODE_NDOF})
-- Quaternion data registers
BNO055_QUATERNION_DATA_W_LSB_ADDR = 0x20
BNO055_QUATERNION_DATA_W_MSB_ADDR = 0x21
BNO055_QUATERNION_DATA_x_LSB_ADDR = 0x22
BNO055_QUATERNION_DATA_x_MSB_ADDR = 0x23
BNO055_QUATERNION_DATA_Y_LSB_ADDR = 0x24
BNO055_QUATERNION_DATA_Y_MSB_ADDR = 0x25
BNO055_QUATERNION_DATA_Z_LSB_ADDR = 0x26
BNO055_QUATERNION_DATA_Z_MSB_ADDR = 0x27
--Begin loop
LJ.IntervalConfig(0, 100)
while true do
if LJ.CheckInterval(0) then
-- loop over data registers
dataQuatRaw = {}
for i=0, 7 do
I2C.write({BNO055_QUATERNION_DATA_W_LSB_ADDR+i}) -- points to the desired address
dataIn = I2C.read(1) -- reads from that address
table.insert(dataQuatRaw, dataIn[1])
end
dataQuat = {}
-- convert from lsb/msb to values
table.insert(dataQuat, convert_16_bit(dataQuatRaw[1], dataQuatRaw[2]))
table.insert(dataQuat, convert_16_bit(dataQuatRaw[3], dataQuatRaw[4]))
table.insert(dataQuat, convert_16_bit(dataQuatRaw[5], dataQuatRaw[6]))
table.insert(dataQuat, convert_16_bit(dataQuatRaw[7], dataQuatRaw[8]))
-- this always prints zeroes for some reason
print("W: "..dataQuat[1].."X: "..dataQuat[2].."Y: "..dataQuat[3].."Z: "..dataQuat[4])
--Report results to print() and User RAM--
--MB.W(46000, 3, dataQuat[1])
--MB.W(46002, 3, dataQuat[2])
--MB.W(46004, 3, dataQuat[3])
--MB.W(46006, 3, dataQuat[4])
end
end
print("Done.")
MB.W(6000, 1, 0)
I think we should start by ckecking for acknowledgements. After running an I2C operation read from the I2C_ACK register discussed in section 6 here: https://labjack.com/support/datasheets/t-series/digital-io/i2c
Normally in these situations the slave device isn't even acknowleding the address.
Also, our I2C app-note covers many common issues: https://labjack.com/support/app-notes/i2c
To check for acknowlegements, am I correct in my understanding that I simply can do something like:
I2C.write({BNO055_PWR_MODE_ADDR, POWER_MODE_NORMAL})
print(MB.R(5114, 0))
f so, I'm getting two zeroes as output.
Lua supports multi-return functions. MB.R returns both the requested value and an error code. So, 0 0 means that there were no ACKs and no errors. That means either the hardware setup isn't right, the slave device is bad, or we have the wrong address.
We might be able to narrow things down using the search function in the I2C examples. If that function finds the slave then we know the hardware setup is good.
A logic analyzer or oscilloscope can make debugging a lot easier.
Some things to look into:
I ran the search script and it does indeed report finding the device at the address I've been using (0x28).
We ordered a BNO055 and will get an example made for you ASAP.
Wow, thanks!
The part came in and we got a quick example made. It is reading numbers that seem to change based on the board's orientation.
The attached example will not be the official example, but hopefully it will get you running.
Back at this after a delay, but looks like it's working perfectly. Thanks again for working this out! Now, any chance there's a way to achieve the same interaction via the python interface? I have a lot of other sensors & devices that I'm already coordinating via python, and it would be great to have it all in one place.
We have a Python example demonstrating I2C usage with the LJM library in the LJM Python download to get you started:
https://labjack.com/support/software/examples/ljm/python
There is no I2C library like in LUA and you will be using the I2C Modbus registers/names. Those are documented here:
https://labjack.com/support/datasheets/t-series/digital-io/i2c
Beaut, thanks!
Got it working in python. Code is attached, but when I add some timers I find that the ljm.eWriteName(jack, "I2C_GO", 1) line inside the final for loop takes about 30ms to return each time, which might be a deal-breaker for my application. Am I missing any optimizations I could be making?
Oh, fixed it; simply set I2C_SPEED_THROTTLE to 0 and I2C_GO now only takes 1ms