cancel
Showing results for 
Search instead for 
Did you mean: 

stm32f4xx_hal_spi.c, HAL_SPI_TransmitReceive - why would you need synchronisation variable?

Marcin Wolcendorf
Associate II
Posted on June 04, 2018 at 16:16

Hi Everyone,

In HAL_SPI_TransmitReceive, in the part actually transmitting data, there is a txallowed variable, blocking sending until the reception is done. If SR is cached and checked for the RXNE flag first, before the TXE is checked, this flag is not necessary. Why would you need it? 

BR,

M.W.

#spi #hal_spi_transmitreceive #tx-rx-sync #data-integrity
2 REPLIES 2
Petr Sladecek
ST Employee
Posted on June 06, 2018 at 17:30

Hello,

the variable helps to keep number of transmitted and received data balanced when SPI is handled by polling. Note timing of TXE and RXNE flags is different. After data is written to DR, TXE becomes active back again once its first bit is transacted out on the bus (DR becomes empty and ready to accept next data as its content is copied into the internal shift register) while RXNE becomes active once the corresponding data frame is fully completed (and data is copied from internal shift register to the DR). It can happen easily, that SPI master has written two data ahead while any of them is received yet. Such an approach produces continuous clock transaction with a risk of data overrun at reception if software doesn’t manage all the DR reading in time. The function is dedicated rather for SPI master and it is written in passive way when clock is not continuous and new data transaction (write) is protected till the current data is fully completed. I don’t suggest this approach at slave case as slave can never rely on not continuous clock provided by master.

Best regards,

Petr

Posted on June 07, 2018 at 09:22

Hi Petr,

I understand what you say. However, I disagree. 

What you are saying is - the CPU might be too slow to get the byte before the next one is copied to the DR, overwriting the first one and setting the Overflow (which is not tested BTW).

So let me explain why I think this is not the case.

Let's assume you are the bus master. Let's also assume you sample the SR at the beginning of the transceive part of the SendReceive. Let's have RXNE test (and DR reading) first, before TXE. Since the RXNE for frame N will be set before the TXE for the frame N+2 (this is because all the bits of frame N would be received before the first bit of the frame N+1 is shifted out) how would transceive look like?

Let's assume first that the CPU is fast enough to loop through transceive of 1 frame faster, than the frame is sent. 

  1. RXNE reset, TXE set: send the first frame,
  2. RXNE still reset (because the CPU is faster than sending 1 frame), TXE set: send the second frame,
  3. Now the RX shift register is being fed, the TX shift register feeds, what can happen?
    1. receiving of the first frame is not finished, DR(tx) still contains 2'nd frame - RXNE and TXE still reset. That it easy - we do nothing.
    2. receiving of the first frame has finished, TX shift register has been fed the second frame, but nothing came out yet - RXNE set and TXE reset. That is also easy - we take the data from DR.
    3. receiving of the first frame has finished, some bits of the second frame has been shifted out - RXNE and TXE set. But CPU is faster than sending 1 frame, so the frame No. 2 is not finished yet, and we read from DR before we write to it, so we do have a time advantage.

Conversely - let's assume CPU is slower than sending 1 frame. But then again there is no problem at all. Since the RXNE is set before TXE, after sending the first frame, on the next loop the RXNE will already be set (CPU is slower than sending 1 frame) so we will get the data out before we have any chance of transmitting the next frame at all. 

Let's assume the CPU is the same speed as transceiving one byte. But then (because of bus synchronisation) we either end up in 'faster' or 'slower' scenario. Again - since RXNE will be set before TXE and we read DR before writing to it, we are safe. 

To summarise - since RXNE(N) is set before TXE(N+2) and we read before we write - if we are fast enough to send the second frame before the first is received, we are also fast enough to get the data out before overflow. If we are not fast enough to send the second byte before the first is received, then there is no problem, because we read DR before we write to it. 

Edit:

OK, it does not account for discontinuous CPU clock. How likely is that scenario with software-based SPI transmission?