STM32F0 UART + DMA + Interrupt mit STM32CubeMX HAL 1.2.1 Problem

Hallo liebe Elektroniker!

Ich habe ein kleines Problem damit, das STM32F072-Nucleo-Board als kleine Shell einzurichten (ich möchte Befehle über UART senden und verschiedene Einstellungen der von mir vorgenommenen Anwendung festlegen / abrufen). Verwenden Sie den UART mit DMA in Unterbrechungsmodus.

Der Code basiert auf BrinirController . Das Problem ist, dass ich zwar das erste Zeichen empfangen und zurückgeben kann, die MCU nach diesem ersten Interrupt jedoch keinen weiteren Interrupt ausführt, wenn ich versuche, ein weiteres Zeichen zu schreiben. Die von mir verwendete HAL ist 1.2.1 (zusammen mit dem STM32CubeMX) und verfügt nicht über das Makro __HAL_UART_FLUSH_DRREGISTER(&huart2)zum Leeren des RX-Datenpuffers des UART.

Macht die Funktion __HAL_UART_SEND_REQ(&huart2, UART_RXDATA_FLUSH_REQUEST)dasselbe wie das Makro __HAL_UART_FLUSH_DRREGISTER(&huart2)in der vorherigen Version von HAL?

Könnte dies das Problem sein: Der RX-Datenpuffer ist voll, sodass kein weiterer Interrupt gestartet wird, solange er nicht gelöscht/gelesen wird?

Die RxCpltCallbackCallback-Funktion wird nur aufgerufen, wenn ich zum ersten Mal etwas in das serielle Terminal eingebe ... Beim zweiten Mal unterbricht es einfach nicht ... Ich habe anscheinend alles versucht! :D Was könnte die Lösung sein? Ich verwende das STM32F072RBT6 (STM32F072-Nucleo-Board)

Der Code geht so:

UART_HandleTypeDef huart2;
DMA_HandleTypeDef hdma_usart2_rx;
DMA_HandleTypeDef hdma_usart2_tx;

/* USART2 init function */

void MX_USART2_UART_Init(void)
{

  huart2.Instance = USART2;
  huart2.Init.BaudRate = 9600;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  huart2.Init.OneBitSampling = UART_ONEBIT_SAMPLING_DISABLED ;
  huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  HAL_UART_Init(&huart2);

}

void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{

  GPIO_InitTypeDef GPIO_InitStruct;
  if(huart->Instance==USART2)
  {
  /* USER CODE BEGIN USART2_MspInit 0 */

  /* USER CODE END USART2_MspInit 0 */
    /* Peripheral clock enable */
    __USART2_CLK_ENABLE();

    /**USART2 GPIO Configuration    
    PA2     ------> USART2_TX
    PA3     ------> USART2_RX 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_2;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF1_USART2;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF1_USART2;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* Peripheral DMA init*/

    hdma_usart2_rx.Instance = DMA1_Channel5;
    hdma_usart2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_usart2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart2_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart2_rx.Init.Mode = DMA_NORMAL;
    hdma_usart2_rx.Init.Priority = DMA_PRIORITY_MEDIUM;
    HAL_DMA_Init(&hdma_usart2_rx);

    __HAL_LINKDMA(huart,hdmarx,hdma_usart2_rx);

    hdma_usart2_tx.Instance = DMA1_Channel4;
    hdma_usart2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_usart2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart2_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart2_tx.Init.Mode = DMA_NORMAL;
    hdma_usart2_tx.Init.Priority = DMA_PRIORITY_LOW;
    HAL_DMA_Init(&hdma_usart2_tx);

    __HAL_LINKDMA(huart,hdmatx,hdma_usart2_tx);

  /* USER CODE BEGIN USART2_MspInit 1 */

  /* USER CODE END USART2_MspInit 1 */
  }
}

und die Interrupt-Callback-Funktion:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  __HAL_UART_SEND_REQ(&huart2, UART_RXDATA_FLUSH_REQUEST); // Clear the buffer to prevent overrun
  int i = 0;
  HAL_UART_Transmit_DMA(&huart2, (uint8_t *)&rxBuffer, 1);

  if (rxBuffer == 8 || rxBuffer == 127) // If Backspace or del
    {
      printf(" \b"); // "\b space \b" clears the terminal character. Remember we just echoced a \b so don't need another one here, just space and \b
      rxindex--;
      if (rxindex < 0) rxindex = 0;
    }

  else if (rxBuffer == '\n' || rxBuffer == '\r') // If Enter
    {
      executeSerialCommand(rxString);
      rxString[rxindex] = 0;
      rxindex = 0;
      for (i = 0; i < MAXSTRING; i++) rxString[i] = 0; // Clear the string buffer
    }

  else
    {
      rxString[rxindex] = rxBuffer; // Add that character to the string
      rxindex++;
      if (rxindex > MAXSTRING) // User typing too much, we can't have commands that big
    {
      rxindex = 0;
      for (i = 0; i < MAXSTRING; i++) rxString[i] = 0; // Clear the string buffer
      printf("\r\nKonsole> ");
    }
    }
}

Natürlich rufe ich in der Hauptroutine vor der Endlosschleife HAL_UART_Receive_DMA(&huart2, &rxBuffer, 1) auf und habe diese Variablen als Puffer definiert:

uint8_t rxBuffer = '\000';
uint8_t rxString[MAXSTRING];
int rxindex = 0;

Antworten (1)

Schalten Sie den RX-DMA-Modus auf DMA_CIRCULAR um. Der normale DMA-Modus wird einmal ausgeführt und Sie müssen ihn erneut konfigurieren. Im Zirkularmodus können Sie denselben Vorgang ausführen, bis Sie ihn explizit stoppen.

Ich hatte einen ähnlichen Fall, und das Umschalten des USART RX DMA-Modus (innerhalb des DMA-Konfigurationsfensters von Cube) von NORMAL auf CIRCULAR hat geholfen -> jetzt werden ISRs für empfangene Zeichen/Daten regelmäßig aufgerufen und müssen nicht erneut aktiviert werden (was bedeutet nur, dass sie stabiler arbeiten). Vielen Dank für den Hinweis! :-)