I²C reads on broken out bus #1 always return 0

Hi,

two weeks ago I received my BeagleBone Blue.

So far, I’ve managed to get

  • an OrangeRX DSMX receiver
  • a GP-735T GPS receiver
  • a Servo
  • and a 2S LiPo Akku

going, more or less without any problems.

However, all the I²C devices I connected to the available I²C bus #1 so far only work “one-way”. I.e., I can send data to the devices and they do what they are supposed to, but I can’t seem to get any data from a device to the BBBlue.

E.g., I’ve got a I²C DC motor controller (with more juice than the builtin one).
I can set my motors spinning, braking, reversing, … using this controller, but I can’t get any status information back from the device.

I already swapped all cables (and measured them) - they seem to be okay.

Can it have something to do with the I²C-settings in the dtb? How does u-boot select the right dtb anyway?

Thanks in advance,
Torsten

If you are successfully sending I2C commands, then everything is hooked up correctly, and the device tree is properly configured.

I2C is a bi-directional bus. If it works in one direction, then it has to work in the other direction down at the hardware level.

How are you “reading” the I2C devices?

What app or tool? or what program in what language?

— Graham

So, you have to be doing something wrong. A beaglebone wont function unless
I2C is working. Show us what you're doing, that is not working. The
command, and the output. If you're using your own source, we need to see
that too. Keep in mind that I do also have hands on experience with writing
applications that use I2C in C, and most recent just a week ago. But no
personal hands on with the beaglebone blue. The hardware in this case
however should be exactly the same.

Hi Graham + William,

thank you for getting back to me so quickly.

The device I’m trying to communicate with is this motor controller:

https://www.piborg.org/picoborgrev/specs

It’s made for the Raspberry PI, but I don’t see any reason for it not to work with the Beaglebone Blue.
With the help of an RPi I’ve been able to confirm that the device is in full working condition.

Now, let’s have some fun:

tkurbad@beaglebone:~$ i2cdetect -y -r 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: – -- – -- – -- – -- – -- – -- –
10: – -- – -- – -- – -- – -- – -- – -- – --
20: – -- – -- – -- – -- – -- – -- – -- – --
30: – -- – -- – -- – -- – -- – -- – -- – --
40: – -- – -- 44 – -- – -- – -- – -- – -- –
50: – -- – -- – -- – -- – -- – -- – -- – --
60: – -- – -- – -- – -- – -- – -- – -- – --
70: – -- – -- – -- – --

0x44 is the correct default address for the PicoBorgRev.
(Just to have that out of the way: User tkurbad is a member of the ‘i2c’ group.)

Now, let’s try to read the board ID, i.e. version:

tkurbad@beaglebone:~$ i2cget -y 1 0x44 0x99
0x00

This should return 0x15 instead.

Set motor A spinning forward:

tkurbad@beaglebone:~$ i2cset -y 1 0x44 6 255

Motor is spinning full throttle now.

Read motor PWM setting:

tkurbad@beaglebone:~$ i2cget -y 1 0x44 8

0x00

Should return 0xff now.

Turn off motor A:

tkurbad@beaglebone:~$ i2cset -y 1 0x44 6 0

Motor shuts off.

i2cdump behaves the same as all other read operations. At least some of the values should be != 0x00:

tkurbad@beaglebone:~$ i2cdump -y 1 0x44
No size specified (using byte-data access)
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …

I’ve also got some Python3 code that behaves exactly the same (writes to the device work flawlessly, while reading always returns 0x00):

https://github.com/tkurbad/mipSIE/blob/master/python3/MPU-9250_test.py

Any ideas what I may be doing wrong here?

Best,
Torsten

Update: I lowered the clock frequency of i2c1 to 100kHz via the dtb. That also doesn’t change the behaviour.

It looks like the MPU9250 has a non standard (to my way of thinking) I2C read sequence that requires you to resend the register address as part of a consolidated write/read sequence. The default tool i2cget does not deal with this, and only deals with simple (standard to my way of thinking) read sequences.

Since you can write to the device, and a write requires an acknowledgement from the device, there is nothing wrong down at the hardware and low-level driver level.

If you get a driver specific to the MPU9250 running, that understands the required byte control sequence, I would expect it to work.

If you are using Python, I would suggest using Python 2.7 rather than Python 3. At least to get started, until you are in control.

The last time I did Python control of I2C, you needed to load python-smbus, and it had not yet been updated for Python 3 compatibility.

It may have been updated and re-released in the last six months.

I did find instructions on the web about how to manually recompile python-smbus for Python 3, so it is possible.

— Graham

Hi Graham,

It looks like the MPU9250 has a non standard (to my way of thinking) I2C read sequence that requires you to resend the register address as part of a consolidated write/read sequence. The default tool i2cget does not deal with this, and only deals with simple (standard to my way of thinking) read sequences.

It’s not the MPU9250 that’s causing the problem. This is the IMU built into the Beaglebone Blue and connect to I²C bus #0. The example I posted uses the input of the IMU to control the motors via the PicoBorgRev board. Reading the IMU on I²C bus 0 works like a charm, btw. Only reading from the motor controller does not work.

Since you can write to the device, and a write requires an acknowledgement from the device, there is nothing wrong down at the hardware and low-level driver level.

Ok, I didn’t know that.

If you are using Python, I would suggest using Python 2.7 rather than Python 3. At least to get started, until you are in control.

I’m a fairly advanced Python programmer and I don’t want to start off with something as deprecated as Python 2.7. Nonetheless, I tried a Python 2.7 of my code, and it yields the same results: Writing to the motor controller works, while reading from it doesn’t.

The last time I did Python control of I2C, you needed to load python-smbus, and it had not yet been updated for Python 3 compatibility.

There are inofficial ports that work. One is in my repo: GitHub - tkurbad/python3-smbus. Works well with Raspberry PI and the built-in devices of the Beaglebone that are connected to I²C bus #0 (i.e. IMU and barometric pressure sensor).

Just for completeness’ sake, I created a very simple test script using Python 2.7 (it does exactly the same as the original Python code for the motor controller does during init):

`

#!/usr/bin/python2

import smbus

address = 0x44
id_cmd = 0x99
i2c_max_len = 4

bus = smbus.SMBus(1)

i2cread = bus.read_i2c_block_data(address, id_cmd, i2c_max_len)

print “Raw I2C read result:”, i2cread
print “Would yield a version of:”, i2cread[1]

`

If I run the script, this is the result:

tkurbad@beaglebone:~$ python revision.py
Raw I2C read result: [0, 0, 204, 204]
Would yield a version of: 0

The correct value of i2read[1] would be 21 (or 0x15), not 0.

The raw result, btw., is also the same, regardless of what register of the motor controller I read from.

So, I’m still convinced that it has to do with the hardware and/or the setup of the I²C bus of the beaglebone…

Where else could I look?

Best, Torsten

Have you stuck an oscilloscope or logic analyzer on it to see what is actually on the bus?

What are the pinconf settings for the I2C pins?

I take back what I said about a non standard read sequence. I re-read the data sheet, and they describe a standard concatenated write/read sequence for a single byte read. But I do note that they do not describe a simple read only sequence, where the part would start reading from the last register position.

A lot of the tools do not actually do the concatenated write/read, but instead do a separate write-stop, read-stop. I have not seen a I2C part that would not accept this.

Do you have another “trusted” I2C device you could parallel across the bus as a test device?
I use an MCP9808 temperature sensor on most of my boards when bringing up a new design.

Or as suggested by David, put a bus analyzer on the bus to see if the chip is not sending good data, or the Beaglebone is loosing the good data when the chip sends it.

— Graham

I take back what I said about a non standard read sequence. I re-read the
data sheet, and they describe a standard concatenated write/read sequence
for a single byte read. But I do note that they do not describe a simple
read only sequence, where the part would start reading from the last
register position.

Yeap, that's standard I2C comms, I knew that, but kept my mouth shut. Also
for what it's worth, smbus I2C is the preferred I2C comms method in Linux.
But it's not impossible to use the older protocol.

Hi again,

Do you have another “trusted” I2C device you could parallel across the bus as a test device?
I use an MCP9808 temperature sensor on most of my boards when bringing up a new design.

I think I’ll do that on Monday, when I’m near my Beaglebone again,

Or as suggested by David, put a bus analyzer on the bus to see if the chip is not sending good data, or the Beaglebone is loosing the good data when the chip sends it.

I’ve only got a small oscilloscope (1 channel) that probably won’t help that much, but I can try.

Anyway, I tried i2cget on the two devices connected to the third I²C bus (i2c2) on the Beaglebone Blue. One is the MPU9250, which also works with my Python code.

If I ask this device for it’s ID, I get a perfectly response:

tkurbad@beaglebone:~$ i2cget -y 2 0x68 0x75
0x71

So, I’m more and more under the impression that somethings wrong in the way the second I²C bus (i2c1) is set up. This is the only broken out bus on the Beaglebone Blue, so I don’t have a chance but put my motor controller there.

So, I’ll try another - confirmedly working - device on Monday and report back.

Thank you so far and best regards,
Torsten

Hi again,

this morning, I connected another IMU unit (Polulu AltIMU10 v5) in parallel to the motor controller on I²C bus #1.
It works flawlessly and I can read the ID of the accel/gyro unit using i2cget:

tkurbad@beaglebone:~/projects/mipSIE/python3$ i2cget -y 1 0x6b 0x0f
0x69

However, I still can’t read from the motor controller. The working IMU however leads to the conclusion that the problem must lie with the motor controller, not with the Beaglebone.

I’ve ordered a PIC debugger to see what’s going on inside the PIC on the motor controller that does all the I²C communication.

Anyway, thanks for all your help!

Best,
Torsten

Torsten:

OK. That makes more sense.

If it is a PIC misbehaving, I would re-program it first, then make sure you have good bypass capacitor to ground, with short leads, on the power input pin to the ground pin on the PIC.

Good luck.

— Graham

Hi Graham,

just for reference: The guys who built the motor controller confirmed that they are having trouble with newer kernels on the Raspberry PI, too.

https://www.piborg.org/node/2428

They say it’s probably a timing issue. And with all the information I collected so far I must assume they are probably true. :wink:

I hope it’s not the PIC itself that can’t cope, but rather something that could be solved in software…

Best,
Torsten

What part number PIC?
— Graham

When they say drop the clock speed on the bus, I am sure they mean to drop it down to 50kbps or 10 kbps, and see if it starts working.
As a diagnostic, that would be strong indication of a timing problem in the PIC software.

If they are using the PIC hardware peripheral, then it is totally I2C compliant/conforming, although you could still screw up the response time servicing it slowly internally.

If they are “bit-banging” the I2C interface, then anything can happen, depending on the quality of the programmer.

— Graham

Hi Graham,

Status Update (a bit off topic for beagleboard, I suppose):

I took the MPLABX PIC code that the PiBorg folks provided for their motor controller and ported it to the sdcc compiler, so I have a chance to understand what’s going on.

Result is here:

https://github.com/tkurbad/PicoBorgRev_PIC

If I flash the hex file to the PIC it behaves exactly as it does with the original code, i.e. all I2C reads return 0x00 and all writes result in the desired action.

Now follows the debugging…

Best,
Torsten

FYI: It’s working now. The PIC code that came with the motor controller was not I²C re-start aware.

I re-implemented the ISR to accept both stop/start and re-start sequences before reading the slave’s output. That did the trick.

Best,
Torsten

Torsten:
Great job.
— Graham