Open petegibson opened 11 months ago
Commenting on this issue, because it is relevant to me as well. DMA transfers lead to an incorrect behavior compared to a blocking SPI transfer. Disabling of SPI peripheral is crucial information for many applications, as many devices will stop working/loose synchronization when it happens. When it is done implicitly at the end of every DMA transaction, it breaks asynchronous code, compared to the same implementation for synchronous code which doesn't disable the peripheral.
Commenting this single expression in finish_dma(:858) function leads to a correct behavior.
// Disable the spi peripheral
regs.cr1().modify(|w| {
w.set_spe(false);
});
There is some relevant discussion in Matrix if you search "set_spe".
The RM seems to suggest that you need to set_spe(false)
before disabling DMA "to close communication", and @Dirbaio commented that SPI can hang if this is messed with. So maybe it needs to be disabled, DMA stopped, then SPI re-enabled?
Some chips have the ability to keep the lines driven when SPI is disabled but I don't think that's the case for my device
Ref man for STM32f446xx
You are correct in that sense that in order to close communication, one has to:
So the problem boils down to the concept what is DMA communication. Current implementation suggests that each transaction is a separate communication sequence, which means DMA is enabled/disabled after each transaction. This assumption may be wrong for certain applications which require persistent line state, like mine device driver does.
Additionally, this teardown procedure is also not free, as it takes a not insignificant amount of time after each transaction, which means that DMA results being more CPU intensive than a regular blocking transfer (or at least very similar).
That alone would be acceptable, but as an author of a generic device driver using embedded-hal I need to have a possibility to allow my code to run on any implementation, including embassy and current behavior is a major blocker.
I would love to see some configuration parameter, which would allow for disabling of this automatic shutdown of a peripheral, as an opt-in feature.
I'm using SPI to drive some WS2812 RGB LEDs (only using MOSI). On stm32, SPI::write/read calls finish_dma after the transaction, which disables the peripheral. That appears to leave MOSI & CLK floating on my board (STM32F412) which is making them susceptible to interference.
https://github.com/embassy-rs/embassy/blob/2543bcafafbe56f925c39c37b72f634674ccba65/embassy-stm32/src/spi/mod.rs#L816
blocking_write
doesn't have the same issue, so as a workaround, I'm sending an empty list after the async write