STM32 – How to trigger a DMA transfer via hardware timer, while CPU is in SLEEP mode

dmastm32stm32cubemxtimer

I'm trying to set up a simple project that does the following:

  1. Enter sleep mode and in the main loop, it waits for interrupt – __WFI().

  2. Transmits data from a buffer[4] to the PC, via UART.

The second point of the program would ideally be done via DMA, so that the MCU wouldn't wake up from sleep.

To that effect, I was thinking of hooking up a DMA transfer in circular mode. So every time a timer (say timer1) overflows, it automatically triggers a UART transfer. When the DMA transfers the 4th byte of buffer, it would start over from the beginning.

Can I trigger a DMA when the CPU is in sleep mode?

Best Answer

So, I generated a standard CubeMX project. I used USART1 & TIMER1.

hdma_tim1_up.Instance = DMA2_Channel2;
hdma_tim1_up.Init.Request = DMA_REQUEST_TIM1_UP;
hdma_tim1_up.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_tim1_up.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tim1_up.Init.MemInc = DMA_MINC_ENABLE;
hdma_tim1_up.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_tim1_up.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_tim1_up.Init.Mode = DMA_CIRCULAR;
hdma_tim1_up.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_tim1_up) != HAL_OK)
{
  Error_Handler();
}

In the main function, after the initialization of the peripherals, I simply call

HAL_DMA_Start(htim1.hdma[TIM_DMA_ID_UPDATE], (uint32_t)&testPWM, (uint32_t)&huart1.Instance->TDR, 4);
__HAL_TIM_ENABLE_DMA(&htim1, TIM_DMA_UPDATE);
HAL_PWR_EnterSLEEPMode(PWR_LOWPOWERREGULATOR_ON, PWR_SLEEPENTRY_WFI);
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
  /* USER CODE END WHILE */
  __WFI();
  /* USER CODE BEGIN 3 */
}

testPWM is a 4 byte array {0, 1, 2, 3}

The main loop is empty, no callbacks are used in code. The DMA controller sends 0 1 2 3 to the PC via UART, on each timer overflow event. When it reaches 3, it wraps back to 0.