Skip to content

Commit

Permalink
Merge #19431
Browse files Browse the repository at this point in the history
19431: cpu/stm32: Fix periph_spi operation in non-DMA mode r=MrKevinWeiss a=maribu

### Contribution description

The driver previously failed to reliably clear the RXNE bit, resulting in the next transfer to incorrectly read a stale register value. This was noticed with the SD card SPI driver on an STM32F4, in which the 0xff byte of the previous byte transfer was returned instead of the actual status byte, throwing the SD card driver off the rails.

### Testing procedure

Connecting an SD card via SPI to a Nucleo-2F429ZI should now result is almost reliable operation.

### Issues/PRs references

None

Co-authored-by: Marian Buschsieweke <marian.buschsieweke@ovgu.de>
  • Loading branch information
bors[bot] and maribu authored Apr 3, 2023
2 parents ca6bca5 + b2199bb commit 985a38c
Showing 1 changed file with 15 additions and 12 deletions.
27 changes: 15 additions & 12 deletions cpu/stm32/periph/spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -356,33 +356,36 @@ static void _transfer_no_dma(spi_t bus, const void *out, void *in, size_t len)
/* transfer data, use shortpath if only sending data */
if (!inbuf) {
for (size_t i = 0; i < len; i++) {
while (!(dev(bus)->SR & SPI_SR_TXE));
while (!(dev(bus)->SR & SPI_SR_TXE)) {}
*DR = outbuf[i];
}
/* wait until everything is finished and empty the receive buffer */
while (!(dev(bus)->SR & SPI_SR_TXE)) {}
while (dev(bus)->SR & SPI_SR_BSY) {}
while (dev(bus)->SR & SPI_SR_RXNE) {
dev(bus)->DR; /* we might just read 2 bytes at once here */
}
}
else if (!outbuf) {
for (size_t i = 0; i < len; i++) {
while (!(dev(bus)->SR & SPI_SR_TXE));
while (!(dev(bus)->SR & SPI_SR_TXE)) { /* busy wait */ }
*DR = 0;
while (!(dev(bus)->SR & SPI_SR_RXNE));
while (!(dev(bus)->SR & SPI_SR_RXNE)) { /* busy wait */ }
inbuf[i] = *DR;
}
}
else {
for (size_t i = 0; i < len; i++) {
while (!(dev(bus)->SR & SPI_SR_TXE));
while (!(dev(bus)->SR & SPI_SR_TXE)) { /* busy wait */ }
*DR = outbuf[i];
while (!(dev(bus)->SR & SPI_SR_RXNE));
while (!(dev(bus)->SR & SPI_SR_RXNE)) { /* busy wait */ }
inbuf[i] = *DR;
}
}

/* wait until everything is finished and empty the receive buffer */
while (!(dev(bus)->SR & SPI_SR_TXE)) {}
while (dev(bus)->SR & SPI_SR_BSY) {}
while (dev(bus)->SR & SPI_SR_RXNE) {
/* make sure to "read" any data, so the RXNE is indeed clear.
* Otherwise we risk reading stale data in the next transfer */
(void)*DR;
}

_wait_for_end(bus);
}

Expand All @@ -404,7 +407,7 @@ void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
}
else {
#endif
_transfer_no_dma(bus, out, in, len);
_transfer_no_dma(bus, out, in, len);
#ifdef MODULE_PERIPH_DMA
}
#endif
Expand Down

0 comments on commit 985a38c

Please sign in to comment.