Skip to content

Commit e1b5fc2

Browse files
committed
Improve STM32 SPI asynchronous API stability
`HAL_SPI_Receive_IT` HAL function causes dummy reads in 3-wire mode, that causes data corruption in RX FIFO/register. It isn't possible to fix it without signification refactoring, but we may prevent data corruption with the following fixes: - RX buffer/register cleanup after asynchronous transfer in 3-wire mode - Explicit RX buffer/register cleanup after SPI initialization (for cases if we re-create SPI object).
1 parent 918396b commit e1b5fc2

File tree

1 file changed

+17
-3
lines changed

1 file changed

+17
-3
lines changed

targets/TARGET_STM/stm_spi_api.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,9 @@ void init_spi(spi_t *obj)
149149
if (HAL_SPI_Init(handle) != HAL_OK) {
150150
error("Cannot initialize SPI");
151151
}
152+
/* In some cases after SPI object re-creation SPI overrun flag may not
153+
* be cleared, so clear RX data explicitly to prevent any transmissions errors */
154+
spi_flush_rx(obj);
152155
/* In case of standard 4 wires SPI,PI can be kept enabled all time
153156
* and SCK will only be generated during the write operations. But in case
154157
* of 3 wires, it should be only enabled during rd/wr unitary operations,
@@ -1320,11 +1323,12 @@ void spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx,
13201323
inline uint32_t spi_irq_handler_asynch(spi_t *obj)
13211324
{
13221325
int event = 0;
1326+
SPI_HandleTypeDef *handle = &(SPI_S(obj)->handle);
13231327

13241328
// call the CubeF4 handler, this will update the handle
1325-
HAL_SPI_IRQHandler(&obj->spi.handle);
1329+
HAL_SPI_IRQHandler(handle);
13261330

1327-
if (obj->spi.handle.State == HAL_SPI_STATE_READY) {
1331+
if (handle->State == HAL_SPI_STATE_READY) {
13281332
// When HAL SPI is back to READY state, check if there was an error
13291333
int error = obj->spi.handle.ErrorCode;
13301334
if (error != HAL_SPI_ERROR_NONE) {
@@ -1342,9 +1346,19 @@ inline uint32_t spi_irq_handler_asynch(spi_t *obj)
13421346
// disable the interrupt
13431347
NVIC_DisableIRQ(obj->spi.spiIRQ);
13441348
NVIC_ClearPendingIRQ(obj->spi.spiIRQ);
1349+
#ifndef TARGET_STM32H7
1350+
if (handle->Init.Direction == SPI_DIRECTION_1LINE && obj->rx_buff.buffer != NULL) {
1351+
/**
1352+
* In case of 3-wire SPI data receiving we usually get dummy reads.
1353+
* So we need to cleanup FIFO/input register before next transmission.
1354+
* Probably it's better to set SPI_EVENT_RX_OVERFLOW event flag,
1355+
* but let's left it as is for backward compatibility.
1356+
*/
1357+
spi_flush_rx(obj);
1358+
}
1359+
#endif
13451360
}
13461361

1347-
13481362
return (event & (obj->spi.event | SPI_EVENT_INTERNAL_TRANSFER_COMPLETE));
13491363
}
13501364

0 commit comments

Comments
 (0)