Ok, so I've been fiddling with the ChibiOS SPI driver in slave mode and have what I think may be useful input.
I'm working on a STM32F0 device using ChibiOS 16.1.5.
First, in the low level driver I had to comment out the setting of bit SPI_CR1_MSTR in CR1, otherwise master mode is always forced. That alone allowed me to use the existing driver in slave mode without any further modifications.
However, as already discussed in this thread, data transfer size must be known in advance, which is responsibility of the protocol. Even if you're always using fixed size transfers there is a problem: what happens in the slave misses a clock pulse? It will remain waiting forever for that extra bit of data. This is how I tackled this issue:
1- Set up a rising edge interrupt on NSS. When detected the current exchange is aborted.
2- Use the asynchronous calls (spiStartXXX) together with an event mechanism so I can set a timeout waiting for completion. If completion times out then the current exchange is aborted.
PROBLEM is that the current driver provides no way to abort a started transmit/receive/exchange. I fixed this in an ugly way:
Code: Select all
SPID1.state = SPI_READY;
I say "ugly" because it is fiddling with low (DMA) and high (state) level driver internals.
As I see it, the proper way to provide slave functionality to the existing ChibiOS SPI driver is:
1- In low level drivers, do not enforce master mode. Make it clear that the specific SPI configuration must account for this and set master/slave mode bits accordingly depending on the platform.
2- Provide spiAbort() and spiAbortI() functions that will:
2.1- Abort the ongoing SPI transaction.
2.2- Reset the SPI driver state back to SPI_READY.
I haven't gone as far as looking whether the STM32 allows triggering an interrupt when an SPI transaction is finished before all data is received (i.e. NSS goes high). As I described, by solution just configured the NSS GPIO pin as an EXT interrupt source and worked with that.