Categories
Open Source

An SPI_debug

A small change for the hardware, a big relief for the software development 🙌

Breakout board development

We’re working on the breakout board, which is the sensory part of the plastic scanner. It contains all the electronics for measuring the reflectance of a plastic sample (e.g. a shampoo bottle) and sending its readings to a controller. This “controller” can be any microcontroller (e.g. Arduino), or a microcomputer (e.g. Raspberry Pi) or a NASA space shuttle’s motherboard – as long as it supports the Serial Peripheral Interface (SPI).

By designing the sensory part of the scanner as a separate breakout board and by using a standard communication protocol, we can enable others to use, adapt and create their own plastic scanners without forcing the use of any specific hardware- or software- platform.

The breakout board prototype (more details here). It uses the SPI for transferring data (plastic sample reflectance readings) and can be used with any kind of hardware platforms: Raspberry Pi, ESP32, Arduino or anything that has an Serial Peripheral Interface.

SPI communication issue

The breakout board has been delivered, assembled and it looks really cool! But our first test with a Raspberry Pi revealed an issue: the analog-to-digital converter (ADC) could not be identified by the software.

We connected the breakout boad to an Arduino and managed to successfully read the ADC’s status register via the SPI. This indicates that the hardware works fine! 🎉

Comparison of the software stacks between a Raspberry Pi and Arduino, where the latter only has one layer of software. Less software, less possible bugs.

What?

So what went wrong with the Rasbperry Pi, then? It had to be a software mistake, now that we know the hardware is ok.

We ran the same kind of a program, reading the ADC’s status register, on an Raspberry Pi and observed the SPI signals with an logic analyzer. We noticed an issue with the chip select (/CS) line, which was de-asserted after every byte, while it should remain low at all times during the “register read” operation. Deactivating the /CS line resets all the SPI registers on the ADC chip (ADS1256), causing communication failures in our scenario.

Logic analyzer traces obtained from reading the ADC’s status register with an Arduino and with a Raspberry Pi. In the second case, the chip-select line is being de-asserted before the third byte is transferred, causing a communication failure. Also, a side note about SPI signal naming: https://www.sparkfun.com/spi_signal_names

Why?

Looking deeper into the implementation of our test program revealed the root of all evil. We are using the PiPyADC python library, which talks to Wiring Pi library, which talks to the spidev (linux SPI driver), which in turn controls the SPI pins of the Raspberry Pi.

The PiPyADC library manipulates the /CS pin correctly and equally to our Arduino program (activating it in the beginning of the “register read” operation and releasing it at the end). The problem was that it was not the only piece of software which manipulated the /CS pin, since the spidev functions used in the Wiring Pi library also asserted the pin.

The chip select pin on the Raspberry Pi (CE0/GPIO 8) was controlled by two software layers simultaneously: the PiPyADC library and the spidev driver.

Workaround

Obviously having two pieces of software controlling the same hardware pin, without knowing about each other, will not work. There are multiple solutions to this problem:

  • drive the /CS line only in the ADC library (PiPyADC)
  • drive the /CS line only in the drivers (spidev)
  • do not use the CE0 (GPIO 8) pin at all, use another GPIO for driving the chip-select line

The first option requires us to configure the linux SPI driver (spidev) so that it “does not mess with the CE0 pin, ever”. While this is possible the pin remains “locked” by the driver and can not be controlled in other parts of software, rendering this solution unusable.

The second solution would require us to either modify the WiringPi library or remove it altogether and use spidev directly, which could take a lot of time and effort.

We chose the third and the simplest solution: to connect the /CS line to a different GPIO pin on the Raspberry Pi, circumventing the problem with the SPI drivers controlling the CE0 pin altogether.

Conclusion

Now that we use a different pin for the /CS we can still take full advantage of the spidev driver and the PiPyADC library.

Cheers, Jure 🥳

Leave a Reply

Your email address will not be published. Required fields are marked *