STM32 - Wie löst man eine DMA-Übertragung über einen Hardware-Timer aus, während sich die CPU im SLEEP-Modus befindet?

Ich versuche, ein einfaches Projekt einzurichten, das Folgendes tut:

  1. Wechseln Sie in den Schlafmodus und warten Sie in der Hauptschleife auf den Interrupt - __WFI().

  2. Überträgt Daten von einem Puffer[4] über UART an den PC.

Der zweite Punkt des Programms würde idealerweise über DMA erfolgen, damit die MCU nicht aus dem Ruhezustand aufwacht.

Zu diesem Zweck dachte ich daran, eine DMA-Übertragung im Zirkularmodus anzuschließen. Jedes Mal, wenn ein Timer (z. B. Timer1) überläuft, löst er automatisch eine UART-Übertragung aus. Wenn der DMA das 4. Byte des Puffers überträgt, würde er von vorne beginnen.

Kann ich einen DMA auslösen, wenn sich die CPU im Ruhemodus befindet?

Sie können immer versuchen, es wie gewohnt einzurichten, dann schlafen zu gehen und zu sehen, ob es funktioniert. Laut den Trainingspowerpoints ist es möglich.
Ich habe ehrlich gesagt keine Ahnung, wie man den DMA-Controller im Zirkularmodus verwendet. Wenn ich eine Übertragung direkt auslöse, werden im Umlaufmodus einfach alle Daten im Puffer kontinuierlich gesendet.
Das tut es. Sie müssen die MCU dazu bringen, die Daten im Handumdrehen zu erfassen, bevor sie umlaufen und überschrieben werden.
Ich verstehe das. Aber ich empfange nicht. Ich versuche zu übertragen. Daten sollten also nicht überschrieben werden.
Oh, der Kreismodus sollte nicht wirklich zum Senden verwendet werden, denke ich nicht. Ich kann mir keine Fälle vorstellen, in denen eine Übertragung sinnvoll ist, da die MCU sowieso aufwachen muss, um neue Daten zu platzieren.
Ich verstehe. dann suche mal weiter.

Antworten (1)

Also habe ich ein Standard-CubeMX-Projekt generiert. Ich habe USART1 & TIMER1 verwendet.

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 der Hauptfunktion rufe ich nach der Initialisierung der Peripherie einfach auf

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 ist ein 4-Byte-Array {0, 1, 2, 3}

Die Hauptschleife ist leer, im Code werden keine Rückrufe verwendet. Der DMA-Controller sendet bei jedem Timer-Überlaufereignis 0 1 2 3 über UART an den PC. Wenn es 3 erreicht, springt es zurück auf 0.