Description
TLDR
Currently, it is unclear when exactly the SPI transfer functions return. Some drivers assume that the functions return after the clock line has returned to idle state. This is not how some (most?) HALs implement SPI. The documentation should clarify the expected behaviour.
The Problem
I am currently building an application with https://github.com/astro/embedded-nrf24l01 on a system with an STM32F429 clocked at 168 MHz. I clocked the SPI bus at 500 KHz -- much slower than the system clock, which to a certain degree caused the following problems -- and subsequently saw very weird behaviour. embedded-nrf24l01 would pull the CS pin high and then low again before the SCK signal reached idle, so the device only ever registered one single long transfer instead of multiple small transfers as required to send individual commands. All but the first command was therefore ignored or incorrectly processed by the device.
The corresponding code in embedded-nrf24l01 is as follows:
self.csn.set_low().unwrap();
let transfer_result = self.spi.transfer(buf).map(|_| {});
self.csn.set_high().unwrap();
Changing the code as follows solves all problems, because then all CS changes occur while the SPI bus is idle:
cortex_m::asm::delay(200);
self.csn.set_low().unwrap();
cortex_m::asm::delay(200);
let transfer_result = self.spi.transfer(buf).map(|_| {});
cortex_m::asm::delay(200); // <- this line is what fixes the problem, the other delays are just to make the signal look more like in the datasheet
self.csn.set_high().unwrap();
The Solution(s)
- The documentation could state that the SPI functions return as soon as the last bit was read from the bus. Device drivers would then have to add delays where necessary, similar to the code above. I do not know how many devices would require this type of delay -- if many devices need it, this solution is a huge footgun and substantially increases complexity. I hardcoded the delay cycles in the example above, but that's only possible because I know the clock speed of the device.
- The documentation could state that the SPI functions return as soon as the SCK signal is idle again. Probably, all HALs would have to be modified.
Other Problems
If I understand it correctly, this bug is not completely identical to stm32-rs/stm32f0xx-hal#130, although that ticket shows a similar problem with SPI documentation: The documentation should (or should not?) state that transfer() finishes after the last bit has been transferred, not after the bits have been shoved into a FIFO.