Using the I2C protocol

I finally have some more time for experimenting with OpenMV. Since I want it to control a hexapod robot, that’s a lot of servos to take care of. So I built myself a simple servo controller based on a Pro Mini, with which I can communicate over I²C, basically just sending the servo positions to the registers. I have tested it with Raspberry Pi and PyBoard, and it all works perfectly fine there.

Today I tried connecting it to OpenMV. Here are my results:

  • First of all, the labels at are wrong – the SDA and SCL are swapped. SCL is PB11 and SDA is PB10.
  • Scanning initially works. Just after connecting the OpenMV board and initializing the I2C class, I can do scan() and it shows my device.
  • Writing to the device doesn’t seem to do anything (at least my device doesn’t receive correct data).
  • As soon as I try writing, either with send() or mem_write(), scan() only returns an empty list, and any further writes result in OSError: 16.
  • That continues through soft-reset (ctrl+d) and reset of my device. Only switching the OpenMV off and on again resets it to the initial state.

Below is an example session demonstrating what I mean:

>>> import pyb
>>> import ustruct
>>> bus = pyb.I2C(2, pyb.I2C.MASTER)
>>> bus.scan()
>>> bus.mem_write(ustruct.pack("<H", 1500), 9, 0)
>>> bus.scan()
>>> bus.mem_write(ustruct.pack("<H", 1500), 9, 0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: 16
Micro Python v1.4.4-125-g07c8f99 on 2015-08-18; OPENMV2 with STM32F427
Type "help()" for more information.
>>> import pyb
>>> bus = pyb.I2C(2, pyb.I2C.MASTER)
>>> bus.scan()

Am I doing something wrong? Is there anything I should try?

I just checked with a pocket osciloscope, and after doing the read/write the SCL line stays permanently pulled down on the side of OpenMV.

Perhaps this is related? unable to recover from I2C bus error · Issue #1765 · micropython/micropython · GitHub

The following makes it work properly:

>>> import pyb
>>> import ustruct as struct
>>> bus = pyb.I2C(2, 0)
>>> bus.scan()
>>> pyb.disable_irq(); bus.mem_write(struct.pack("<H", 1500), 9, 0)
PYB: enabling IRQs

You know the camera doesn’t have pull-ups right ?

It is related, but it seems you’re getting an error first that triggers the DMA issue. When IRQs are disabled, I2C doesn’t use DMA.
I’ll apply that patch, thanks!

Docs should be updated now. Thanks!

(Sorry about this all being in a bad state right now. It will get much better soon).

I know this is pretty much beta, and I don’t expect everything to work out of the box. I’m experimenting with this because it’s fun (at least when you don’t do it as a job) and I hope it’s helpful. Thanks for your hard work!

If you want to bit bang the I2C… see this file for how to drive the lines perfectly:

Funny, but, we should just have python wrappers so you can call that code.

Yes, I noticed that you use that in the mlx python module. Is that because you also had problems with I2C?
By the way, that code also has the SDA and SCL pins swapped, I think?

No, When Ibrahim did the initial development he didn’t use the PYB module. As for the MLX code. That is all working now and has been tested.

I fixed the swap info in the docs.

It seems that this issue still persists with these functions. Is there a work around for the OSError 16 problem?

Are you using the correct i2c bus? I tested out the i2c functions with an eeprom and they worked.

I won’t have acess to a desktop PC until later this week so this is about the best I can help.

I am using bus #2. I would like to use the openMV cam as a master to an arduino uno using the slave sketch here:
I was able to send a few bytes of data, but after some time, the cam gives the OSError 16. I’m not entirely sure what I am doing incorrectly.

Ibrahim will have to take a look at this. It’s highly likely there’s a firmware bug for this. And… if there’s a bug a firmware fix can be put out very quickly.

I think the STHAL I2C driver needs a patch, will look into it and get back to you.

I already applied the I2C patch a while ago, make sure you have the latest firmware.

We’re using soft_i2c for MLX because it’s more flexible, it allows you to control the STOP condition after a read/write, the sthal I2C driver on the other hand always generates a STOP after a read/write.

Thanks, that makes sense.