1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
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>
This commit is contained in:
bors[bot] 2023-04-03 13:22:41 +00:00 committed by GitHub
commit 985a38cd09
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

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