summaryrefslogtreecommitdiff
path: root/ports/stm32/spi.c
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2018-02-01 11:45:29 +1100
committerDamien George <damien.p.george@gmail.com>2018-02-01 11:45:29 +1100
commitc0496fd44de562cd11e66acd9e42f796c3dcb5fb (patch)
tree74511ae894a574e6d98fcc1358d19398948c602d /ports/stm32/spi.c
parenta44892dd0d79e039b4a4d1ec3ec7b9a6ed829ee6 (diff)
stm32/spi: Make SPI DMA wait routine more power efficient by using WFI.
The routine waits for the DMA to finish, which is signalled from a DMA IRQ handler. Using WFI makes the CPU sleep while waiting for the IRQ to arrive which decreases power consumption. To make it work correctly the check for the change in state must be atomic and so IRQs must be disabled during the check. The key feature of the Cortex MCU that makes this possible is that WFI will exit when an IRQ arrives even if IRQs are disabled.
Diffstat (limited to 'ports/stm32/spi.c')
-rw-r--r--ports/stm32/spi.c13
1 files changed, 9 insertions, 4 deletions
diff --git a/ports/stm32/spi.c b/ports/stm32/spi.c
index 3cd470ccb..2b5bdb038 100644
--- a/ports/stm32/spi.c
+++ b/ports/stm32/spi.c
@@ -404,11 +404,16 @@ void spi_deinit(SPI_HandleTypeDef *spi) {
}
STATIC HAL_StatusTypeDef spi_wait_dma_finished(SPI_HandleTypeDef *spi, uint32_t timeout) {
- // Note: we can't use WFI to idle in this loop because the DMA completion
- // interrupt may occur before the WFI. Hence we miss it and have to wait
- // until the next sys-tick (up to 1ms).
uint32_t start = HAL_GetTick();
- while (HAL_SPI_GetState(spi) != HAL_SPI_STATE_READY) {
+ for (;;) {
+ // Do an atomic check of the state; WFI will exit even if IRQs are disabled
+ uint32_t irq_state = disable_irq();
+ if (spi->State == HAL_SPI_STATE_READY) {
+ enable_irq(irq_state);
+ return HAL_OK;
+ }
+ __WFI();
+ enable_irq(irq_state);
if (HAL_GetTick() - start >= timeout) {
return HAL_TIMEOUT;
}