PicoBorg Reverse and Beaglebone

Hi,

I'm trying to get the Picoborg Reverse working with a Beaglebone Blue. Since the Beaglebone has electrical characteristics similar to the Raspberry PI (i.e. 3v3 input tolerance, several I2C buses, ...), I thought it to be an easy task.

However, the PicoBorg Reverse behaves a bit strange in this setup. In particular, I can set the motors spinning, set a new board address, etc. In fact, all "write" operations work just fine.

If it comes to reading values from the PicoBorg Reverse, e.g. its ID, it'll always return 0x00.

This is true regardless of

  • programming language and/or tool (i.e., i2cget -y 1 0x44 0x99 returns 0x00 as does the respective code in Python)
  • the PicoBorg Reverse being alone on the I2C bus or not
  • the connection being minimal, i.e. only 3v3, GND, SCL, and SDA or whith the additional 5V lines applied
  • the PicoBorg Reverse's I2C address

The I2C bus on the Beaglebone seems to work properly. I'm able to get data from other devices connected to the same bus.

I've already swapped all cables, too.

Still, all reads from the PBR return 0x00.

What else could I try? Could it be something with the PIC code?

Thank you very much in advance!
Best,
Torsten

piborg's picture

We are not sure exactly what causes this problem, but we have seen it on Raspbian as well: New build - PicoBorg Reverse fails to load.

It seems that at some stage an update to the kernel / firmware has changed the I2C behavior in some way, preventing the reads working as intended. We are unsure what the actual cause is, but at a guess it could be that the read of the first byte is a little too quick for the PicoBorg Reverse to respond to.

The only things I can think to try are:

  1. Slowing the I2C bus down - I am not sure if this will make any difference, but it is worth a go
  2. Try an older kernel - on Raspbian versions 4.4.50 and below seemed to function fine

We do not have a BeagleBone here to test with, so there is not too much more I can tell you.

Hi again,

thank you for the fast reply. Unfortunately, I tried both of your suggestions already. I downgraded to kernel 4.4.49 and slowed the I2C bus to 100kHz (from Beaglebone's default of 400 kHz).

Anyway, I'll try and keep investigating what might cause this issue...

Best,
Torsten

Hi,

just to let you know:

I ported your code for the PIC to the Small Devices C Compiler (sdcc), an opensource alternative to MPLAB(X).

The repository can be found here:

https://github.com/tkurbad/PicoBorgRev_PIC

The problem that initiated this thread persists through the sdcc port. Therefore I must assume that there's something fundamentally wrong here.

The only non 0x00 reads I could produce so far occured when I assigned constant values to SSP1BUF in the ISR routine. It really looks like a timing problem to me.

Thus, next thing I'll try is to incorporate the "read" commands from ProcessI2C directly into the ISR routine, thus using ProcessI2C for "write" commands, e.g. SET_A_FWD, only...

Btw., congratulations on your code. It is as readable as it is understandable. I'm no experienced C programmer, but had no problems seeing what your software does.

For me, this makes the PicoBorgRev an even greater product - and one that should definitely run with the Beaglebone... ;-)

Best,
Torsten

piborg's picture

Thanks for the complement, we have tried to keep all of our code clear and concise where possible :)

You are certainly right that trying to reduce the amount of code involved before the PIC fills in the data to return on reads could help, in particular the parts I would try and remove / simplify are:

  1. The function call (as per your comment)
  2. The switch statement, it seems to compile to a fall-through if / else structure in assembly rather than a lookup table. The result from experimentation is that earlier commands run slightly quicker than the ones towards the bottom
  3. Maybe change the command numbers for a quick test between reads and writes, for example having all reads as odd numbered commands

Having said all that there is a second possibility which may be easier to play with first - clock stretching.
When we originally coded the PicoBorg Reverse we intended to use clock stretching to hold the Raspberry Pi back until we had finished processing, this was a miserable failure.
I am not sure if this is still true, but what we found with the early Raspberry Pis running Raspbian was that the clock stretching was ignored, causing clock pulses to be missed entirely.

Because of the trouble we ended up with code which from memory has the clock line release coded, but the act of clock stretching has been left turned off.
These are the two lines in question which control the automatic clock stretching:

	SSP1CON3bits.AHEN = 0;			// Automatic holding of the clock after address disabled
	SSP1CON3bits.DHEN = 0;			// Automatic holding of the clock after data disabled

If my memory is correct you should be able to simply turn on the holding of the clock after data and everything should work if the BeagleBone does support clock stretching, potentially solving the whole problem on its own.

Hi,

thank you for all the suggestions.

Yes, I've already been suspicious about clock stretching. And renumbering and/or reordering the commands came to mind, too. Will try all of that on Monday, when I'm near my beaglebone again and report back here.

Best,
Torsten

Hi again,

I tried all the suggestions now, unfortunately without success.

Setting the clock holding bits during PIC initialization as far as I've been able to determine prevents the stop bit from ever reaching the slave (or - even more probable - being ever sent by the master). So, using the automatic holding of the clock would require a rewrite of the whole ISR routine in a way that it recognizes the commands from the master and reads the appropriate number of parameters, then sending back the response and releasing the clock line, without ever using the command stop interrupt.

While it wouldn't be wizardry to implement it this way, it wouldn't be as elegant as the current code. Thus, I'm still trying to fix the matter using as many of the intrinsic hardware I²C features of the PIC as possible to minimize code complexity and processing time.

Re-ordering and/or re-numbering the commands also does not help, unfortunately. Even if I change the ProcessI2C routine to directly set the answer sequence for the "get id" command in the i2cSend array - without a single 'if... then...' block, the master never receives this answer, whereas commands like "set led" work. In the latter case, the command and parameters need to be sent back to the master to acknowledge their reception. This "command echo" obviously works, otherwise the master would complain. So, there seems to be a fundamental difference between the "write" and "read" commands and/or implementation that needs to be uncovered.

To get to the bottom of this, I ordered a logic analyzer now that should reveal how the clock and data lines behave in different situations and maybe set me to the right track...

Best,
Torsten

piborg's picture

It looks like the problem may be related to either the delay between writes and reads, or perhaps using the repeated start instead of a full stop and start sequence.

We have a working fix for our ThunderBorg code that we will give some more detailed testing to tomorrow, after which I will re-code PicoBorgRev.py to behave the same way. Hopefully your problem on the BeagleBone is the same as the one we see on a freshly updated copy of Raspbian.

If you are using our PicoBorgRev.py script as-is then the new version should be a drop-in replacement. If not you will want to swap any calls into the I2C / SMBus libraries for simple binary write and read operations on the I2C device driver instead.

See this post for a bit more detail: I think we have a solution.

piborg's picture

I have finished testing our updated version of PicoBorgRev.py on the updated version of Raspbian which displays the same behaviourPicoBorg Reverse library fix.

Hopefully the same change will fix the problem on your BeagleBone as well :)

Let us know if it helps or if the problem remains.

Thank you for the quick fix. Did you know that there are pure Python implementations of the smbus module around (e.g., smbus2) that do the exact same thing as your new code does?

Unfortunately, dealing with it this way doesn't fix my problem. On the contrary, with the new library, no communication whatsoever with the motor controller occurs. If I use smbus2 as a drop-in replacement for smbus, on the other hand, I get the same behaviour as with the original smbus module.

But as promised, I now hooked everything up to my brand new logic analyzer (awesome tool for just €15) and found that what you expected earlier is certainly true: If a start signal is sent while the clock is still low, the PIC responds with 0x00 and a NACK. The repeated start only occurs with the GET_... commands, not with the SET...s, so that's there all this odd behaviour is coming from.

Conclusion: While re-sending the start bit is common practice for I²C, the PIC doesn't seem to deal with it in the correct manner.

Thus, I'll try and code a new ISR that accepts those start resends - in the hopes that the PIC hardware is designed to let me do so.

I finished rewriting the PIC code and it now works well on the BeagleBone with the old and new versions of your Python library.

The new code is probably not as elegant as yours, but it is much more explicit.
It handles both the stop/start sequence for reads you use in the new library as well as the start/re-start sequence smbus and the i2ctools use.

The PIC code can be found in my GitHub repository. The source is for the sdcc compiler. I included the .hex file, so you can test it easily.

I also rewrote both your Python libraries to work with Python3 (note, that my versions are not backwards compatible with Python 2.x). They are on GitHub, too.

PicoBorgRev.py uses smbus, while PicoBorgRev2.py is your drop-in replacement using raw reads and writes from/to the I²C device files. I took the liberty to adapt it to the new Python3 bytes datatype.

If you'd get the chance to test, I'd be interested to know, if the PIC code works for the RPi as well.

piborg's picture

Glad to hear your persistence has paid off, awesome work :)

I am also quite interested to see if this works with the Raspberry Pis myself. This week is rather busy as we are shipping out Kickstarter rewards, but I will try and find some time to test the hex file at least in the next week or so.

Subscribe to Comments for "PicoBorg Reverse and Beaglebone"