Interfacing with BNO055 over I2C | LabJack
 

Interfacing with BNO055 over I2C

13 posts / 0 new
Last post
mikelwrnc
mikelwrnc's picture
Interfacing with BNO055 over I2C

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)

LabJack Support
labjack support's picture
I think we should start by

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

mikelwrnc
mikelwrnc's picture
To check for acknowlegements,

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.

LabJack Support
labjack support's picture
Lua supports multi-return

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:

  • Pull up resistors.
  • Reduce the clock speed. Max possible clock speed is controlled source impedance, total capacitance and resistor size. It's always best to start slow (10 kHz or so).
  • Verify all connections
  • Change out the slave part
  • Use a scope to ensure that the lines are getting above and below the logic thresholds.

 

mikelwrnc
mikelwrnc's picture
I ran the search script and

I ran the search script and it does indeed report finding the device at the address I've been using (0x28).

LabJack Support
labjack support's picture
We ordered a BNO055 and will

We ordered a BNO055 and will get an example made for you ASAP.

mikelwrnc
mikelwrnc's picture
Wow, thanks!

Wow, thanks!

LabJack Support
labjack support's picture
The part came in and we got a

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.

File Attachment: 
mikelwrnc
mikelwrnc's picture
Back at this after a delay,

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.

LabJack Support
labjack support's picture
We have a Python example

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

mikelwrnc
mikelwrnc's picture
Beaut, thanks!

Beaut, thanks!

mikelwrnc
mikelwrnc's picture
Got it working in python.

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?

File Attachment: 
mikelwrnc
mikelwrnc's picture
Oh, fixed it; simply set I2C

Oh, fixed it; simply set I2C_SPEED_THROTTLE to 0 and I2C_GO now only takes 1ms