0
\$\begingroup\$

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?

\$\endgroup\$
6
  • \$\begingroup\$ You could always try just setting it up like normal then going to sleep and seeing if it works. According to the training powerpoints it is possible. \$\endgroup\$ – DKNguyen Feb 11 at 14:34
  • \$\begingroup\$ I sincerely have no clue how to use the DMA controller in circular mode. When I trigger a transfer directly, if in circular mode, it just sends all the data in the buffer continuously. \$\endgroup\$ – PauLEffect Feb 11 at 15:12
  • \$\begingroup\$ That's what it does. You have to have the MCU swoop in a grab the data before it wraps around and overwrites it. \$\endgroup\$ – DKNguyen Feb 11 at 15:14
  • \$\begingroup\$ I understand that. But im not receiving. Im trying to transmit. So data should not be overwritten. \$\endgroup\$ – PauLEffect Feb 11 at 15:17
  • \$\begingroup\$ Oh, circular mode shouldn't really be used for transmit I don't think. I can't think of cases where it is useful transmitting since you need the MCU to wake up to place new data anyways. \$\endgroup\$ – DKNguyen Feb 11 at 15:20
0
\$\begingroup\$

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.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.