1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-27 07:21:18 +01:00

cpu/stm32: Fix periph_spi operation in non-DMA mode

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.
This commit is contained in:
Marian Buschsieweke 2023-03-29 16:06:37 +02:00
parent 7f95ee7558
commit b2199bb744
No known key found for this signature in database
GPG Key ID: CB8E3238CE715A94

View File

@ -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);
}
@ -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