Hi, I was wondering if anyone has had any luck getting the Adafruit BNO055 IMU working with Dot Net wrapper? I got other I2C devices working on the U3 but this device doesn't seem to respond to any of my write commands.
I saw in the T9 forum that someone got this device working with Lua script and Python and was hoping for some tips.
Thanks.
The first thing to do is to check the acknowledgements using LJ_chI2C_GET_ACKS. That will tell you whether or not the slave device is responding to it's address. If it is not sending an acknowledgement then we either have a hardware issue, or an incorrect address.
Verify the address: U-Series LabJack devices expect the address to be in the upper 7 bits. So, the address should be 0x52, 0x50 or 0x80 depending on the address configuration from table 4-7 in the BNO055 datasheet.
Our I2C appnote is a good place to start. It covers a lot of common pitfalls: https://labjack.com/support/app-notes/i2c
Thanks for the reply. Yes, I'm actually able to get the unit to acknowledge itself with ACKS. Where I'm running into issues is trying to read the accelerometer data. The code makes it to the end, so my write functions are producing the correct ACKS, but my reads are all 0. I'm not sure if there needs to be some initialization done.
Here is my current code. I'm not sure what I'm missing, but any help or insight would be greatly appreciated.
'Reset everything
LJUD.ePut(u3.ljhandle, LJUD.IO.PIN_CONFIGURATION_RESET, 0, 0, 0)
'Configure the I2C communication.
'The address of the accelerometer is &h29, left shifted by 1 bit to produce &h50
LJUD.AddRequest(u3.ljhandle, LJUD.IO.PUT_CONFIG, LJUD.CHANNEL.I2C_ADDRESS_BYTE, &H50, 0, 0)
'SCL is FIO4
LJUD.AddRequest(u3.ljhandle, LJUD.IO.PUT_CONFIG, LJUD.CHANNEL.I2C_SCL_PIN_NUM, 4, 0, 0)
'SDA is FIO5
LJUD.AddRequest(u3.ljhandle, LJUD.IO.PUT_CONFIG, LJUD.CHANNEL.I2C_SDA_PIN_NUM, 5, 0, 0)
'Enable clock stretching
LJUD.AddRequest(u3.ljhandle, LJUD.IO.PUT_CONFIG, LJUD.CHANNEL.I2C_OPTIONS, 8, 0, 0)
'Set a max speed of about 130 kHz.
LJUD.AddRequest(u3.ljhandle, LJUD.IO.PUT_CONFIG, LJUD.CHANNEL.I2C_SPEED_ADJUST, 0, 0, 0)
'Execute the requests on a single LabJack.
LJUD.GoOne(u3.ljhandle)
'Set to normal power mode
If write_2bytes(&H0, &H3E) = False Then Return
'Enable ndof mode
If write_2bytes(&HC, &H3D) = False Then Return
For i = 0 To 7
numI2CBytesToWrite = 1
writeArray(0) = &H20 + i
LJUD.AddRequest(u3.ljhandle, LJUD.IO.I2C_COMMUNICATION, LJUD.CHANNEL.I2C_WRITE, numI2CBytesToWrite, writeArray, 0)
LJUD.AddRequest(u3.ljhandle, LJUD.IO.I2C_COMMUNICATION, LJUD.CHANNEL.I2C_GET_ACKS, 0, 0, 0)
numI2CBytesToRead = 1
LJUD.AddRequest(u3.ljhandle, LJUD.IO.I2C_COMMUNICATION, LJUD.CHANNEL.I2C_READ, numI2CBytesToRead, readArray, 0)
'Execute the requests.
LJUD.GoOne(u3.ljhandle)
'Get the result of the write just to check for an error.
LJUD.GetResult(u3.ljhandle, LJUD.IO.I2C_COMMUNICATION, LJUD.CHANNEL.I2C_WRITE, 0)
'Get the write ACKs and compare to the expected value. We expect bit 0 to be
'the ACK of the last data byte progressing up to the ACK of the address
'byte (data bytes only for Control firmware 1.43 and less). So if n is the
'number of data bytes, the ACKs value should be (2^(n+1))-1.
LJUD.GetResult(u3.ljhandle, LJUD.IO.I2C_COMMUNICATION, LJUD.CHANNEL.I2C_GET_ACKS, writeACKS)
expectedACKS = Math.Pow(2, numI2CBytesToWrite + 1) - 1
If (writeACKS <> expectedACKS) Then
Return
End If
'need to store read data here, readarray(0), but value is always 0
Next
The address seems to be respondsing correctly, because I'm getting the proper aknowledgements. However each time I loop through and do the read for the accelerometer values, all I get are 0s. The accelerometer works when I connect it to an Arduino and use the supplied code so I don't think it's hardware.
I'm wondering if there's some initialization code that I'm missing? Here is my code, any suggestions would be greatly appreciated:
'Variable to store the read data
Dim outputStr As String = ""
'Reset labjack pins
LJUD.ePut(u3.ljhandle, LJUD.IO.PIN_CONFIGURATION_RESET, 0, 0, 0)
'Configure the I2C communication.
'The address of the accelerometer is &h29, left shifted by 1 bit to produce &h50
LJUD.AddRequest(u3.ljhandle, LJUD.IO.PUT_CONFIG, LJUD.CHANNEL.I2C_ADDRESS_BYTE, &H50, 0, 0)
'SCL is FIO4
LJUD.AddRequest(u3.ljhandle, LJUD.IO.PUT_CONFIG, LJUD.CHANNEL.I2C_SCL_PIN_NUM, 4, 0, 0)
'SDA is FIO5
LJUD.AddRequest(u3.ljhandle, LJUD.IO.PUT_CONFIG, LJUD.CHANNEL.I2C_SDA_PIN_NUM, 5, 0, 0)
'Enable Clock Stretching
LJUD.AddRequest(u3.ljhandle, LJUD.IO.PUT_CONFIG, LJUD.CHANNEL.I2C_OPTIONS, 8, 0, 0)
'Set speed of 130 kHz.
LJUD.AddRequest(u3.ljhandle, LJUD.IO.PUT_CONFIG, LJUD.CHANNEL.I2C_SPEED_ADJUST, 0, 0, 0)
'Execute the requests on a single LabJack.
LJUD.GoOne(u3.ljhandle)
'Set to normal power mode. If no acknowledgment, exit the function
If write_2bytes(&H0, &H3E) = False Then Return
'Enable ndof mode. If no acknowledgment, exit the function
If write_2bytes(&HC, &H3D) = False Then Return
For i = 0 To 7
numI2CBytesToWrite = 1
writeArray(0) = &H20 + i
LJUD.AddRequest(u3.ljhandle, LJUD.IO.I2C_COMMUNICATION, LJUD.CHANNEL.I2C_WRITE, numI2CBytesToWrite, writeArray, 0)
LJUD.AddRequest(u3.ljhandle, LJUD.IO.I2C_COMMUNICATION, LJUD.CHANNEL.I2C_GET_ACKS, 0, 0, 0)
numI2CBytesToRead = 1
LJUD.AddRequest(u3.ljhandle, LJUD.IO.I2C_COMMUNICATION, LJUD.CHANNEL.I2C_READ, numI2CBytesToRead, readArray, 0)
'Execute the requests.
LJUD.GoOne(u3.ljhandle)
'Get the result of the write just to check for an error.
LJUD.GetResult(u3.ljhandle, LJUD.IO.I2C_COMMUNICATION, LJUD.CHANNEL.I2C_WRITE, 0)
'If no acknowledgment, exit the function
LJUD.GetResult(u3.ljhandle, LJUD.IO.I2C_COMMUNICATION, LJUD.CHANNEL.I2C_GET_ACKS, writeACKS)
expectedACKS = Math.Pow(2, numI2CBytesToWrite + 1) - 1
If (writeACKS <> expectedACKS) Then
Return
End If
LJUD.GetResult(u3.ljhandle, LJUD.IO.I2C_COMMUNICATION, LJUD.CHANNEL.I2C_READ, 0)
'Build the output string
outputStr = outputStr & readArray(0) & " "
Next
But I thought writing &HC to address &H3D was supposed to put the unit into NDOF mode?
Does this function "write_2bytes(&HC, &H3D) " actually write the bytes from right to left?
I finally got everything to work. The key was writing to the registers in config mode first and then switching over to ndof mode.
After that, it's a matter of sending a write and read request. Here's my code reading tempearture and the absolute roll, pitch and yaw degrees, in case anyone wants to reference it in the future. Thanks for your help!
Dim numI2CBytesToWrite As Integer
Dim numI2CBytesToRead As Integer
Dim writeArray(128) As Byte
Dim readArray(128) As Byte
Dim Iyaw, Iroll, Ipitch As Integer
LJUD.ePut(lngHandle, LJUD.IO.PIN_CONFIGURATION_RESET, 0, 0, 0)
LJUD.AddRequest(lngHandle, LJUD.IO.PUT_CONFIG, LJUD.CHANNEL.I2C_ADDRESS_BYTE, &H50, 0, 0)
'SCL is FIO4
LJUD.AddRequest(lngHandle, LJUD.IO.PUT_CONFIG, LJUD.CHANNEL.I2C_SCL_PIN_NUM, ACC_SCL, 0, 0)
'SDA is FIO5
LJUD.AddRequest(lngHandle, LJUD.IO.PUT_CONFIG, LJUD.CHANNEL.I2C_SDA_PIN_NUM, ACC_SDA, 0, 0)
'8 = clock stretching, 4 = no stop when restarting, 2 = reset at start
LJUD.AddRequest(lngHandle, LJUD.IO.PUT_CONFIG, LJUD.CHANNEL.I2C_OPTIONS, 12, 0, 0)
'See description of low-level I2C function. 0 is max speed of about 130 kHz.
LJUD.AddRequest(lngHandle, LJUD.IO.PUT_CONFIG, LJUD.CHANNEL.I2C_SPEED_ADJUST, 0, 0, 0)
'Execute the requests on a single LabJack.
LJUD.GoOne(lngHandle)
'**************************************************************************************************************************************
'code to get the temperature
numI2CBytesToWrite = 1
numI2CBytesToRead = 1
writeArray(0) = &H34
LJUD.AddRequest(lngHandle, LJUD.IO.I2C_COMMUNICATION, LJUD.CHANNEL.I2C_WRITE, numI2CBytesToWrite, writeArray, 0)
LJUD.AddRequest(lngHandle, LJUD.IO.I2C_COMMUNICATION, LJUD.CHANNEL.I2C_READ, numI2CBytesToRead, readArray, 0)
LJUD.Go()
'**************************************************************************************************************************************
'yaw msb
numI2CBytesToWrite = 1
numI2CBytesToRead = 1
writeArray(0) = &H1B
LJUD.AddRequest(lngHandle, LJUD.IO.I2C_COMMUNICATION, LJUD.CHANNEL.I2C_WRITE, numI2CBytesToWrite, writeArray, 0)
LJUD.AddRequest(lngHandle, LJUD.IO.I2C_COMMUNICATION, LJUD.CHANNEL.I2C_READ, numI2CBytesToRead, readArray, 0)
LJUD.Go()
Iyaw = Convert.ToInt16(readArray(0)) << 8
'**************************************************************************************************************************************
'yaw lsb. 1 degree = 16 lsb
numI2CBytesToWrite = 1
numI2CBytesToRead = 1
writeArray(0) = &H1A
LJUD.AddRequest(lngHandle, LJUD.IO.I2C_COMMUNICATION, LJUD.CHANNEL.I2C_WRITE, numI2CBytesToWrite, writeArray, 0)
LJUD.AddRequest(lngHandle, LJUD.IO.I2C_COMMUNICATION, LJUD.CHANNEL.I2C_READ, numI2CBytesToRead, readArray, 0)
LJUD.Go()
Iyaw = Iyaw + readArray(0)
Iyaw /= 16
'**************************************************************************************************************************************
'roll msb
numI2CBytesToWrite = 1
numI2CBytesToRead = 1
writeArray(0) = &H1D
LJUD.AddRequest(lngHandle, LJUD.IO.I2C_COMMUNICATION, LJUD.CHANNEL.I2C_WRITE, numI2CBytesToWrite, writeArray, 0)
LJUD.AddRequest(lngHandle, LJUD.IO.I2C_COMMUNICATION, LJUD.CHANNEL.I2C_READ, numI2CBytesToRead, readArray, 0)
LJUD.Go()
Iroll = Convert.ToInt16(readArray(0)) << 8
'**************************************************************************************************************************************
'roll lsb. 1 degree = 16 lsb
numI2CBytesToWrite = 1
numI2CBytesToRead = 1
writeArray(0) = &H1C
LJUD.AddRequest(lngHandle, LJUD.IO.I2C_COMMUNICATION, LJUD.CHANNEL.I2C_WRITE, numI2CBytesToWrite, writeArray, 0)
LJUD.AddRequest(lngHandle, LJUD.IO.I2C_COMMUNICATION, LJUD.CHANNEL.I2C_READ, numI2CBytesToRead, readArray, 0)
LJUD.Go()
Iroll = Iroll + readArray(0)
Iroll /= 16
'**************************************************************************************************************************************
'pitch msb
numI2CBytesToWrite = 1
numI2CBytesToRead = 1
writeArray(0) = &H1F
LJUD.AddRequest(lngHandle, LJUD.IO.I2C_COMMUNICATION, LJUD.CHANNEL.I2C_WRITE, numI2CBytesToWrite, writeArray, 0)
LJUD.AddRequest(lngHandle, LJUD.IO.I2C_COMMUNICATION, LJUD.CHANNEL.I2C_READ, numI2CBytesToRead, readArray, 0)
LJUD.Go()
Ipitch = Convert.ToInt16(readArray(0)) << 8
'**************************************************************************************************************************************
'pitch lsb. 1 degree = 16 lsb
numI2CBytesToWrite = 1
numI2CBytesToRead = 1
writeArray(0) = &H1E
LJUD.AddRequest(lngHandle, LJUD.IO.I2C_COMMUNICATION, LJUD.CHANNEL.I2C_WRITE, numI2CBytesToWrite, writeArray, 0)
LJUD.AddRequest(lngHandle, LJUD.IO.I2C_COMMUNICATION, LJUD.CHANNEL.I2C_READ, numI2CBytesToRead, readArray, 0)
LJUD.Go()
Ipitch = Ipitch + readArray(0)
Ipitch /= 16
Hi, we've been getting random system access violation errors with this code. Sometimes the code runs fine for a few days, other times it stops after a few hours.
Do you know if there are any issues running i2c code this way or with the Dot net wrapper in general?
For all your AddRequest calls that write or read the arrays, change them to use the AddRequestPtr function and that will likely solve the access violation errors. AddRequest is a bit of an old function and is not 64-bit application safe when passing arrays/pointers to the x1 parameter. It is based on 32-bit pointer addresses, and will cut off the upper 32-bits of an address that can lead to memory related errors. Likely when the array's address is above a 32-bit value you see the crash, AddRequestPtr, and other Ptr related functions, are both 32-bit and 64-bit pointer address safe.
Otherwise, your write/read arrays look large enough and shouldn't cause an issue.
thanks for the suggestion, i will give it a try. do you know if i also need to put a sleep in the thread to delay things a bit between each go request?
Additional software delays between Go operations are not needed for U3 operations. Once the Go finishes and you retrieve your results/data, you are ready for the next Go requests.