SPI Slave Driver

Use this forum for requesting small changes in ChibiOS. Large changes should be discussed in the development forum. This forum is NOT for support.
Tabulous
Posts: 509
Joined: Fri May 03, 2013 12:02 pm
Has thanked: 7 times
Been thanked: 17 times

Re: SPI Slave Driver

Postby Tabulous » Thu Mar 03, 2016 4:22 pm

Giovanni wrote:It should, you will know for sure after testing it :)

Giovanni


it all worked :-)

ive attached a modified driver that allows you to set Master or Slave mode from the config struct i.e.

Code: Select all

#define SPI_ROLE SPI_SLAVE

/*
 * SPI Config
 */
static const SPIConfig spicfg = {
     SPI_ROLE,
     0,
     0,
     0,
     SPI_CR1_BR_2 | SPI_CR1_BR_1
};


might come in useful for some one else
Attachments
SPIv1.zip
(6.26 KiB) Downloaded 339 times

iggarpe
Posts: 129
Joined: Sun Sep 30, 2012 8:32 pm

Re: SPI Slave Driver

Postby iggarpe » Mon Aug 08, 2016 2:55 pm

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

    dmaStreamDisable(SPID1.dmatx);
    dmaStreamDisable(SPID1.dmarx);
    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.

iggarpe
Posts: 129
Joined: Sun Sep 30, 2012 8:32 pm

Re: SPI Slave Driver

Postby iggarpe » Tue Aug 09, 2016 11:32 am

Addendum:

TL;DR - Turns out sipAbort() is not enough, blame the FIFO.

For me the most important functional difference between master and slave mode is that in master mode you have full control over the full transaction. When you start an exchange you're guaranteed that it will be done in a bound time (I suppose except when you use exotic SPIv2 features like multimaster NSS control). When you're in slave mode you may face a situation in which you programmed an exchange and something went wrong. If the problem is that master transfered less frames than you programmed, you're in trouble and need to implement some sort of timeout to resync communication.

As I mentioned in my previous message, the current ChibiOS SPI API lacks an spiAbort() function. This function should disable the DMA TX/RX channels and reset the SPI state to SPI_READY. That's what I implemented but turned out not to be enough: by the time the transaction times out the DMA TX channel has already put some extra bytes in the TX FIFO. If you disable DMA and reset SPI state, those bytes will still be in the TX FIFO. Even if you use spiStop() / spiStart() (which in practice just disables/enables the SPI peripheral) those bytes remain in the TX FIFO and will be output *before* the bytes you set out to be transmitted in the next transaction, bringing your communication out of sync with the master.

So far the only way I've found to clear TX FIFO is rccResetSPI1(). So the full recovery sequence in case of communication sync error is:

1- dmaDisableChannel both for TX/RX.
2- state = SPI_READY
3- spiStop();
4- rccResetSPI1();
5- spiStart();

All those operations should happen atomically which is currently not possible bcause there are no spiStopI() / spiStartI() functions.

User avatar
Giovanni
Site Admin
Posts: 14444
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1074 times
Been thanked: 921 times
Contact:

Re: SPI Slave Driver

Postby Giovanni » Tue Aug 09, 2016 12:28 pm

Hi,

The API has not been designed for slave operations because there is a strong assumption you know in advance the size of transfers.

The best approach would be to design a different driver model and name it "SSPI".

Giovanni

iggarpe
Posts: 129
Joined: Sun Sep 30, 2012 8:32 pm

Re: SPI Slave Driver

Postby iggarpe » Wed Aug 10, 2016 7:13 am

Giovanni wrote:Hi,
The API has not been designed for slave operations because there is a strong assumption you know in advance the size of transfers.
The best approach would be to design a different driver model and name it "SSPI".
Giovanni


I do totally agree. In this particular case and architecture the existing driver could be used with the described modifications, but I doubt that would be possible across all ports.

On a side note: do you know any other way of resetting the SPI FIFO other than rccResetSPIx() ?

Also, I've ended up using the existing master driver with the following modifications (besides removing MSTR bit setting):

1- In spi_lld_start call rccResetSPIx() after rccEnableSPIx().
2- In spi_lld_stop accept also state SPI_ACTIVE and in such case call dmaStreamDisable for TX/RX.

Maybe it would be a good idea to do that too in the existing master SPI driver? I mean, (1) ensures a clean start, and (2) allows for stopping the driver even if a transaction is taking place.

rew
Posts: 380
Joined: Sat Jul 19, 2014 12:59 pm
Has thanked: 2 times
Been thanked: 13 times

Re: SPI Slave Driver

Postby rew » Fri Aug 12, 2016 10:44 am

I have two projects where i've implemented SPI slave by simply poking the registers. Chibios helps by providing easy-to-use register definitions.

That said, the next time I (or you!) should FIRST write the "main program" that just calls the "SPI functions". Then you implement those calls. This way you get an easy-to-use library. The next step would be to integrate that into chibios.

Matthias
Posts: 12
Joined: Fri Jul 29, 2016 3:23 pm
Has thanked: 1 time
Been thanked: 3 times

Re: SPI Slave Driver

Postby Matthias » Wed Mar 01, 2017 1:32 pm

Hallo,

it would be nice, if SPI slave mode will be supported by ChibiOS. The only change that is required to support SPI slave mode for SPIv2 is changing line 429 in ChibiOS\os\hal\ports\STM32\LLD\SPIv2\hal_spi_lld.c

Code: Select all

spip->spi->CR1  = spip->config->cr1 | SPI_CR1_MSTR;

to

Code: Select all

spip->spi->CR1  = spip->config->cr1;


The SPI driver already provide all functionality that is required for implementing a SPI slave. The slave mode needs only to be activated.

Giovanni wrote:Hi,
The API has not been designed for slave operations because there is a strong assumption you know in advance the size of transfers.
The best approach would be to design a different driver model and name it "SSPI".
Giovanni


When you use the non blocking functions like spiStartExchange, spiStartSend, spiStartReceive you no longer need to know in advance how many data is received. You can simply process the data you get.

It would be nice, if this little change make it into the next release.

Cheers Matthias

User avatar
Giovanni
Site Admin
Posts: 14444
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1074 times
Been thanked: 921 times
Contact:

Re: SPI Slave Driver

Postby Giovanni » Wed Mar 01, 2017 2:45 pm

Hi,

Consider it from a state machine perspective, if data stops arriving the driver would still be in a "transfer" state so more functions would be required to stop the ongoing transfer. In addition some kind of NSS handling would be required.

It will certainly come but not on the current release (march hopefully).

Giovanni

plyatov
Posts: 25
Joined: Tue Feb 25, 2014 10:24 am
Been thanked: 2 times

Re: SPI Slave Driver

Postby plyatov » Wed May 31, 2017 1:59 pm

Hello!

I have made very simple support for SPI slave. See attached archive with patches.

It is already used for a while and it for sure will be useful for others.

Irrespective to all talks above, I does not see any issues in its operation. Better to have such implementation then do not have it at all.
Attachments
ChibiOS-SPI-slave.zip
(888 Bytes) Downloaded 444 times

User avatar
Giovanni
Site Admin
Posts: 14444
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1074 times
Been thanked: 921 times
Contact:

Re: SPI Slave Driver

Postby Giovanni » Wed May 31, 2017 2:03 pm

Hi,

Moving this topic in the "change requests" forum so it is not forget. I will consider this for next development cycle (HAL 6).

Giovanni


Return to “Small Change Requests”

Who is online

Users browsing this forum: No registered users and 7 guests