SPI.transfer() blocking or non-blocking? under Arduino

I’ve been trying to follow what happens when SPI.transfer() is called from an Arduino sketch, through the various layers of the SDK, in order to determine whether it is a blocking- or non-blocking function.
It appears to be non-blocking, but there is then no way to tell when the transfer is complete?
On the other hand, as it says that the function replaces the buffer data with the read results, it surely cannot be a non-blocking function - if it was, there would have to be a callback or a status poll.

My application requires me to send a number of SPI transfers in quick succession but to different devices (I will need to control the different SS lines).

If I treat it as a non-blocking function, the transfers get corrupted - I assume because I’m rewriting the transmit buffer before it has finished being sent out.

Can anyone help me work out how to do this?


The SPI class in Arduino writes the data into the SPI FIFO, the exact moment when the data is transmitted would depend on the SPI clock speed and how full the FIFO is.

For your application, I see two ways to proceed:

  1. Use the Mbed SPI API found in \component\common\mbed\hal\spi_api.h to set a tx done callback
  2. Use the raw SPI API found in \component\soc\realtek\amebad\fwlib\include\rtl8721d_ssi.h to either set a TX FIFO empty interrupt, or poll the TX FIFO empty status bit

Example code on how to use both sets of SPI API can be found in the standard SDK GitHub

Thanks. This is really helpful, and much appreciated. I will post back as and when I get it cracked.

1 Like

I successfully got dma and interrupts working thanks to wvy’s help.
However, working under Arduino, there seems to be some sort of scheduling going once every 10ms. I also found it necessary to insert a small delay between detecting the Tx Done event, and starting a new transaction - I’m using the Arduino micros() function to wait 100us, but I think sometimes this wait is stalling for much longer.
I’ve taken the decision I need to ‘dump’ Arduino and move to use the ‘proper’ SDK so I have slightly better control over what’s going on (my ‘norm’ is barefoot microcontrollers, so that’s more familiar territory to me, although this will have a bit of a learning curve).

1 Like

Great it works~

The standard SDK is a little more challenging than the Arduino framework, but it does give you more control and a clearer picture of what is going on under the hood

I’ve got my project working in the SDK framework, using the spi_api.h to hook the tx done callback. This works OK, but the callback fires well before the transmission is complete - presumably when all the data has been sent to the FIFO - proved by programming a wiggle on a spare GPIO when the callback occurs and using a 'scope to watch that as well as the SPI output stream.
So I’ll now start looking at the raw API to see if I can get an interrupt on FIFO empty status to get rid of the ‘kludge’ I have put in to get round this timing uncertainty.
However, the project is doomed unless I can solve the ‘packet loss’ problem raised in a separate thread :frowning:

1 Like

Hi @boatbodger,

Below are some ways you can check the FIFO empty status.

In rtl8721d_ssi.c, you can try to use SSI_GetTxCount which allows you to get the number of data in the FIFO. OR SSI_GetStatus where you can check the bit to see the FIFO empty status.

Another way is to use, while (!(HAL_READ32(spi_addr,0x28) & 0x04 )); to check if the FIFIO is empty.