STM32 - ¿Cómo activar una transferencia DMA a través del temporizador de hardware, mientras que la CPU está en modo SLEEP?

Estoy tratando de configurar un proyecto simple que hace lo siguiente:

  1. Ingrese al modo de suspensión y en el ciclo principal, espera la interrupción - __WFI().

  2. Transmite datos desde un búfer[4] a la PC, a través de UART.

Idealmente, el segundo punto del programa se haría a través de DMA, para que la MCU no se despertara del modo de suspensión.

En ese sentido, estaba pensando en conectar una transferencia DMA en modo circular. Entonces, cada vez que un temporizador (por ejemplo, timer1) se desborda, activa automáticamente una transferencia UART. Cuando el DMA transfiera el cuarto byte del búfer, comenzará de nuevo desde el principio.

¿Puedo activar un DMA cuando la CPU está en modo de suspensión?

Siempre puede intentar configurarlo como de costumbre, luego irse a dormir y ver si funciona. Según los powerpoints de entrenamiento es posible.
Sinceramente, no tengo idea de cómo usar el controlador DMA en modo circular. Cuando activo una transferencia directamente, si está en modo circular, simplemente envía todos los datos en el búfer de forma continua.
Eso es lo que hace. Tienes que hacer que la MCU se acerque y tome los datos antes de que se ajusten y los sobrescriban.
Entiendo que. Pero no estoy recibiendo. Estoy tratando de transmitir. Por lo tanto, los datos no deben sobrescribirse.
Oh, el modo circular realmente no debería usarse para transmitir, no creo. No puedo pensar en casos en los que sea útil transmitir, ya que de todos modos necesita que la MCU se despierte para colocar nuevos datos.
entiendo. Seguiré buscando, entonces.

Respuestas (1)

Entonces, generé un proyecto CubeMX estándar. Usé USART1 y 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();
}

En la función principal, después de la inicialización de los periféricos, simplemente llamo

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 es una matriz de 4 bytes {0, 1, 2, 3}

El bucle principal está vacío, no se utilizan devoluciones de llamada en el código. El controlador DMA envía 0 1 2 3 a la PC a través de UART, en cada evento de desbordamiento del temporizador. Cuando llega a 3, vuelve a 0.