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, 2021 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, 2021 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, 2021 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, 2021 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, 2021 at 15:20

1 Answer 1

2
\$\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\$
1
  • \$\begingroup\$ I believe this answer will send one character per timer event, not the entire contents of testPWM. \$\endgroup\$
    – gordonC
    Sep 29 at 16:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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