I’m trying to use the SPI bus to communicate with a raspeberry PI but i’m having some issues with the communication. The main issue is that the camera gets disconnected from the IDE after a running the script from some time.
I want know if there are specifics speeds the openMV supports. The IDE itself allows me to set any customize speed without showing any errors, but i don’t know if this has an effect when the openMV actually runs the script.
The openMV CAM model i’m using is H7 R2 which in the product page says that has an SPI bus that can run up to 80Mbs.
Also, sometimes when it disconnects i get this error: OSError: [Errno 5] EIO
What does this error means?
The code i’m running in the openMV is really simple (see attached). And the code running on the raspberry pi which is acting as the master, is also very simple (see attached).
We made an interface library for this. Please use it… or atleast pull examples from it:
Everyone likes to roll their own comms and this is very hard. I don’t not recommend it unless you are a very good programmer and have a protocol debugger like a saleae logic analyzer. If you do not have these tools it’s foolhardy.
Anyway, please pull from the script above code to configure your SPI interface.
Unfortunately, I don’t have the Raspberry Pi code setup for SPI with the interface library. That’s a todo. This would make your life really easy.
See the init and deinit around SPI send. It is required per transaction. The hardware driver can lockup pretty easily. Note, we are enabling DMA on SPI. So, when you send or receive it will pack data at the speed without any spaces between bytes. You can easily move 80 Mb/s.
Yes, I tested your code and got the same error. Just use the class template above. It will work for you.
Here’s master mode btw:
class spi_master():
@micropython.viper
def _same(self, data, size: int) -> bool: # private
if not size:
return False
d = ptr8(data)
old = d[0]
for i in range(1, size):
new = d[i]
if new != old:
return False
old = new
return True
def __init__(
self, cs_pin="P3", freq=1000000, clk_polarity=1, clk_phase=0, spi_bus=2
): # private
self.__pin = pyb.Pin(cs_pin, pyb.Pin.OUT_PP)
self.__freq = freq
self.__polarity = clk_polarity
self.__clk_phase = clk_phase
self.__spi = pyb.SPI(spi_bus)
self._get_short_timeout = 10
def get_bytes(self, buff, timeout_ms):
self.__pin.value(False)
pyb.udelay(100) # Give slave time to get ready.
self.__spi.init(
pyb.SPI.MASTER, self.__freq, polarity=self.__polarity, phase=self.__clk_phase
)
try:
self.__spi.send_recv(buff, buff, timeout=timeout_ms) # SPI.recv() is broken.
except OSError:
buff = None
self.__spi.deinit()
self.__pin.value(True)
if buff is None or self._same(buff, len(buff)):
pyb.delay(self._get_short_timeout)
return buff
def put_bytes(self, data, timeout_ms):
self.__pin.value(False)
pyb.udelay(100) # Give slave time to get ready.
self.__spi.init(
pyb.SPI.MASTER, self.__freq, polarity=self.__polarity, phase=self.__clk_phase
)
try:
self.__spi.send(data, timeout=timeout_ms)
except OSError:
pass
self.__spi.deinit()
Note… some of the issues with things being broken actually go down to the HAL from ST. I debugged this a few years back. But, like when it mentions that SPI.recv() is broken it’s like that it actually can’t work in DMA mode.
You’d save yourself some time if you just write the SPI layer for the RPC library for the RPi. Would love a PR for that. Then you could just use the RPC library directly which has already debugged most of these issues.
I don’t know if I will be able to get to doing the RPi SPI/I2C/CAN driver for the RPC library this year.