2016-05-09 03:53 AM
In our project we have two boards communicating with eachother through SPI. A controller board based on an STM32F405 is SPI master over a sensor board for which we have two instances. One is based on an STM32F071, the other on an STM32F031. They share the same SPI slave code (apart from pin assignment and peripheral number), but only on the 031 we experience a problem.
Once every ~10000 transactions, the SPI peripheral will not reset the BSY bit, even though it is obvious that it should. I have conducted a number of experiments which leave me slightly baffled. I have observed/tried the following:2016-05-31 06:30 AM
For anyone running into this problem and finding this thread through google:
I have had contact with ST support, made it possible for them to reproduce the problem using a nucleo board and a discovery board, and just now received the verdict: it is a known HW bug that is not (yet) in the errata list. They suggest a workaround keeping track of RXNE (as that is reliable as opposed to BSY). As I am using DMA to a circular buffer for reception, I cannot use the flag, but I can use the amount of unconsumed data in the DMA buffer. I am not yet in a hurry to implement it because the workaround with nSS going high (marking the end of transfer according to the master) also works, even though I cannot distinguish between the HW bug and a real glitch on the SPI lines this way.2016-06-17 01:30 AM
I ran into the same problem. Unfortunately I didn't find your post until I pinpointed the source of my problem.
In my case I have an STM32F030 based board which is connected to a Cortex-A based host as SPI slave. In my communication protocol there is a receiving part followed by a transmitting part. The error mainly occurs at the end of the transmitting however the TXE flags indicates a successful transmission. The error is more frequent for me than for you and it is present both in IT and DMA mode. In my project we use HAL driver. With HAL (v1.3.1) this problem is much more severe. At the end of the SPI receiving or transmission the implementation waits for the BSY flag. (SPI_EndRxTransaction() and SPI_EndRxTxTransaction()). These waiting functions are called from the interrupt handler (SPI or DMA interrupt based on the chosen communication). To make it more severe the STM32Cube sets priority 0 for these interrupts. So the waiting for a stuck flag blocks the interrupt handling. However there is a timeout in the waiting code but it requires SysTick (also priority 0). So in the reality the next SPI communication will unblock the system. Originally I detected the data loss at the SPI communication and the anomalies at the interrupts. These were my main issues, and my investigation revealed the BSY flag and the HAL error. In my fix I disabled the BSY waiting in SPI slave mode in the upper functions. Since that the communication seems to be stable.2018-11-09 06:22 AM
I am facing the same exact issue on a STM32F779.
I found that now it is on the device errata document:
BSY bit may stay high at the end of a data transfer in Slave mode
Description
The BSY flag may sporadically remain high at the end of a data transfer in slave mode. This occurs upon coincidence of internal CPU clock and external SCK clock provided by master.
In such an event, if the software only relies on BSY flag to detect the end of SPI slave data transaction (for example to enter low-power mode or to change data line direction in half-duplex bidirectional mode), the detection fails.
As a conclusion, the BSY flag is unreliable for detecting the end of data transactions.
Workaround
Depending on SPI operating mode, use the following means for detecting the end of transaction:
• When NSS hardware management is applied and NSS signal is provided by master,
use NSS flag.
• In SPI receiving mode, use the corresponding RXNE event flag.
• In SPI transmit-only mode, use the BSY flag in conjunction with a timeout expiry event.
Set the timeout such as to exceed the expected duration of the last data frame and
start it upon TXE event that occurs with the second bit of the last data frame. The end
of the transaction corresponds to either the BSY flag becoming low or the timeout
expiry, whichever happens first.
Prefer one of the first two measures to the third as they are simpler and less constraining.
Alternatively, apply the following sequence to ensure reliable operation of the BSY flag in
SPI transmit mode:
1.Write last data to data register
2. Poll the TXE flag until it becomes high, which occurs with the second bit of the data
frame transfer
3. Disable SPI by clearing the SPE bit mandatorily before the end of the frame transfer
4. Poll the BSY bit until it becomes low, which signals the end of transfer
Note: The alternative method can only be used with relatively fast CPU speeds versus relatively slow SPI clocks or/and long last data frames. The faster is the software execution, the shorter can be the duration of the last data frame.
Using the HAL, since I am relying on a hardware NSS, i tried to remove the BSY flag check in the SPI_EndRxTransaction callback.
In this way the problem seems to be gone.
static HAL_StatusTypeDef SPI_EndRxTransaction(SPI_HandleTypeDef *hspi, uint32_t Timeout, uint32_t Tickstart)
{
if ((hspi->Init.Mode == SPI_MODE_MASTER) && ((hspi->Init.Direction == SPI_DIRECTION_1LINE)
|| (hspi->Init.Direction == SPI_DIRECTION_2LINES_RXONLY)))
{
/* Disable SPI peripheral */
__HAL_SPI_DISABLE(hspi);
}
/* Control the BSY flag */
// if (SPI_WaitFlagStateUntilTimeout(hspi, SPI_FLAG_BSY, RESET, Timeout, Tickstart) != HAL_OK)
// {
// SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_FLAG);
// return HAL_TIMEOUT;
// }
if ((hspi->Init.Mode == SPI_MODE_MASTER) && ((hspi->Init.Direction == SPI_DIRECTION_1LINE)
|| (hspi->Init.Direction == SPI_DIRECTION_2LINES_RXONLY)))
{
/* Empty the FRLVL fifo */
if (SPI_WaitFifoStateUntilTimeout(hspi, SPI_FLAG_FRLVL, SPI_FRLVL_EMPTY, Timeout, Tickstart) != HAL_OK)
{
SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_FLAG);
return HAL_TIMEOUT;
}
}
return HAL_OK;
}
2018-11-09 11:52 AM
I did the same modification. Also the SPI_EndRxTxTransaction callback function had a similar part so I removed that too.
The software is used since that without any issue.