mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge #19431
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:
commit
985a38cd09
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user