I'm trying to set up a simple project that does the following:
Enter sleep mode and in the main loop, it waits for interrupt - __WFI().
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?
-
\$\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– DKNguyen2021年02月11日 14:34:23 +00:00Commented 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– PauLEffect2021年02月11日 15:12:03 +00:00Commented 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– DKNguyen2021年02月11日 15:14:37 +00:00Commented 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– PauLEffect2021年02月11日 15:17:59 +00:00Commented 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– DKNguyen2021年02月11日 15:20:24 +00:00Commented Feb 11, 2021 at 15:20
1 Answer 1
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.
-
\$\begingroup\$ I believe this answer will send one character per timer event, not the entire contents of testPWM. \$\endgroup\$gordonC– gordonC2023年09月29日 16:38:56 +00:00Commented Sep 29, 2023 at 16:38