Browse Source

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.
pull/3527/merge
Damien George 7 years ago
parent
commit
c0496fd44d
  1. 13
      ports/stm32/spi.c

13
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) { 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(); 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) { if (HAL_GetTick() - start >= timeout) {
return HAL_TIMEOUT; return HAL_TIMEOUT;
} }

Loading…
Cancel
Save