STM32 HAL UART DMA-Übertragungsproblem

Nachdem ich mein Projekt für ein benutzerdefiniertes STM32F7-Board eingerichtet hatte, das einen FT2232H-UART <-> USB-Konverter enthält, traten beim Senden (und Empfangen von Daten) mehrere Probleme auf. Der von mir verwendete Code wird größtenteils von CubeMX generiert und befindet sich am Ende des Beitrags.

Erstens kann ich den Stm nicht dazu bringen, mit höheren Baudraten als dem Standard 115200 zu übertragen. Laut Datenblättern sollten sowohl der FT2232H als auch der STM32F7 mindestens 12 MB Baud können. Für den FT2232H funktioniert es, da ich einige Zeichen von meinem Terminal (USB-Seite) sende und das Zeichen zurückbekomme, als ich die RX- und TX-Pins auf der FT2232H-Ausgangsseite kurzgeschlossen habe.

Zweitens kann ich die Funktion sendUART () nicht mehrmals hintereinander aufrufen. Warum wird das DMA-Fifo nicht zum Speichern der Dinge verwendet, die ich senden möchte?

Was ist auch der richtige Weg, um alle empfangenen Daten zurückzusenden, aber das Fifo zu nutzen, damit keine Daten verloren gehen, wenn sie nicht rechtzeitig abgefragt werden?

Vielleicht sind das dumme Fragen, aber ich habe bereits versucht, hier und im Rest des Internets eine Lösung zu finden, kann aber keine finden.

void MX_UART4_Init(void)
{

  huart4.Instance = UART4;
  huart4.Init.BaudRate = 115200;
  huart4.Init.WordLength = UART_WORDLENGTH_8B;
  huart4.Init.StopBits = UART_STOPBITS_1;
  huart4.Init.Parity = UART_PARITY_NONE;
  huart4.Init.Mode = UART_MODE_TX_RX;
  huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart4.Init.OverSampling = UART_OVERSAMPLING_16;
  huart4.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  huart4.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  if (HAL_UART_Init(&huart4) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

}

void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct;
  if(uartHandle->Instance==UART4)
  {
  /* USER CODE BEGIN UART4_MspInit 0 */

  /* USER CODE END UART4_MspInit 0 */
    /* UART4 clock enable */
    __HAL_RCC_UART4_CLK_ENABLE();

    /**UART4 GPIO Configuration    
    PA0/WKUP     ------> UART4_TX
    PA1     ------> UART4_RX 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF8_UART4;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* UART4 DMA Init */
    /* UART4_TX Init */
    hdma_uart4_tx.Instance = DMA1_Stream4;
    hdma_uart4_tx.Init.Channel = DMA_CHANNEL_4;
    hdma_uart4_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_uart4_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_uart4_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_uart4_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_uart4_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_uart4_tx.Init.Mode = DMA_NORMAL;
    hdma_uart4_tx.Init.Priority = DMA_PRIORITY_MEDIUM;
    hdma_uart4_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
    hdma_uart4_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
    hdma_uart4_tx.Init.MemBurst = DMA_MBURST_SINGLE;
    hdma_uart4_tx.Init.PeriphBurst = DMA_PBURST_SINGLE;
    if (HAL_DMA_Init(&hdma_uart4_tx) != HAL_OK)
    {
      _Error_Handler(__FILE__, __LINE__);
    }

    __HAL_LINKDMA(uartHandle,hdmatx,hdma_uart4_tx);

    /* UART4_RX Init */
    hdma_uart4_rx.Instance = DMA1_Stream2;
    hdma_uart4_rx.Init.Channel = DMA_CHANNEL_4;
    hdma_uart4_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_uart4_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_uart4_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_uart4_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_uart4_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_uart4_rx.Init.Mode = DMA_NORMAL;
    hdma_uart4_rx.Init.Priority = DMA_PRIORITY_MEDIUM;
    hdma_uart4_rx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
    hdma_uart4_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
    hdma_uart4_rx.Init.MemBurst = DMA_MBURST_SINGLE;
    hdma_uart4_rx.Init.PeriphBurst = DMA_PBURST_SINGLE;
    if (HAL_DMA_Init(&hdma_uart4_rx) != HAL_OK)
    {
      _Error_Handler(__FILE__, __LINE__);
    }

    __HAL_LINKDMA(uartHandle,hdmarx,hdma_uart4_rx);

  /* USER CODE BEGIN UART4_MspInit 1 */

  /* USER CODE END UART4_MspInit 1 */
  }
}

void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{

  if(uartHandle->Instance==UART4)
  {
  /* USER CODE BEGIN UART4_MspDeInit 0 */

  /* USER CODE END UART4_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_UART4_CLK_DISABLE();

    /**UART4 GPIO Configuration    
    PA0/WKUP     ------> UART4_TX
    PA1     ------> UART4_RX 
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_0|GPIO_PIN_1);

    /* UART4 DMA DeInit */
    HAL_DMA_DeInit(uartHandle->hdmatx);
    HAL_DMA_DeInit(uartHandle->hdmarx);
  /* USER CODE BEGIN UART4_MspDeInit 1 */

  /* USER CODE END UART4_MspDeInit 1 */
  }
} 

/* USER CODE BEGIN 1 */
void sendUART(char msg[]){
    //HAL_UART_Transmit(&huart4,(uint8_t *) msg, strlen(msg),10000);
    HAL_UART_Transmit_DMA(&huart4,(uint8_t *) msg, strlen(msg));
}

void echo(){
    if(HAL_UART_Receive_DMA(&huart4, (uint8_t *)aRxBuffer, RXBUFFERSIZE) != HAL_OK){}
    else if(HAL_UART_Transmit_DMA(&huart4, (uint8_t*)aRxBuffer, RXBUFFERSIZE)!= HAL_OK){
    }
}

Antworten (1)

Erstens kann ich den Stm nicht dazu bringen, mit höheren Baudraten als dem Standard 115200 zu übertragen. Laut Datenblättern sollten sowohl der FT2232H als auch der STM32F7 mindestens 12 MB Baud können.

Die Hardware unterstützt Geschwindigkeiten von bis zu 27 Mbit (nun, Sie haben Ihre Teilenummer nicht angegeben, ich schaue mir das F756-Datenblatt an), aber laut , stm32f7xx_hal_uart.hakzeptiert HAL keine Geschwindigkeit über 9M

#define IS_UART_BAUDRATE(BAUDRATE) ((BAUDRATE) < 9000001)

Darüber hinaus hängt es von der Systemtaktrate ab, in der Standardkonfiguration, wenn Sie die Registerkarte Taktkonfiguration in STM32CubeMX nicht berühren, arbeitet alles mit dem internen 16-MHz-HSI-Takt. Das bedeutet höchstens 1 Mbit, wenn Sie verwenden UART_OVERSAMPLING_16, oder das Doppelte, wenn Sie zu wechseln UART_OVERSAMPLING_8(aber dann verlieren Sie die Rauscherkennung).

Zweitens kann ich die Funktion sendUART () nicht mehrmals hintereinander aufrufen. Warum wird das DMA-Fifo nicht zum Speichern der Dinge verwendet, die ich senden möchte?

Obwohl es einen 16-Byte-DMA-FIFO gibt, ist er für die Software nicht zugänglich. Es gibt keine Möglichkeit, einfach weitere Daten an eine laufende DMA-Übertragung anzuhängen. HAL tut nichts anderes, als eine DMA-Übertragung von der vom Aufrufer gelieferten Pufferadresse zu starten.

Sie müssen warten, bis die Übertragung beendet ist, oder DMA unterbrechen und immer noch warten, bis der FIFO leer ist. Sie können natürlich selbst einen Puffer zuweisen, Daten hinzufügen, sobald sie kommen, und DMA neu starten, wenn es beendet ist und sich neue Daten im Puffer befinden.

Was ist auch der richtige Weg, um alle empfangenen Daten zurückzusenden, aber das Fifo zu nutzen, damit keine Daten verloren gehen, wenn sie nicht rechtzeitig abgefragt werden?

Es sieht für mich so aus, als ob Sie nicht bei jedem empfangenen Zeichen sowohl DMA als auch Interrupts haben können. Zumindest ISRwäre der Wert des Statusregisters nutzlos, und der Interrupt-Handler kann nicht entscheiden, was zu tun ist. Das Lesen könnte sogar die DMA-Übertragung stören. Daher müssen Sie sich für eine entscheiden.

Wenn Sie DMA verwenden, um die Daten in einen Puffer (oder zwei) zu legen, können Sie den Übertragungszähler dann regelmäßig in der Leerlaufschleife oder einem Timer-Interrupt abfragen. Es wird nicht sofort eine Antwort geben, aber das wäre vielleicht auch egal, weil die USB-Schnittstelle auch etwas Verzögerung verursachen würde.

Danke für die Antwort. Ich habe die Uhren konfiguriert und der UART läuft auf dem 200 MHz SYSCLK, also sollte es laut CubeMX ein theoretisches Maximum geben. Baudrate von 12,5 M mit Oversampling auf 16 Samples eingestellt.
Wenn Sie die UART-Taktquelle auf den 200-MHz-SYSCLK einstellen (wo tun Sie das? Es ist nicht im obigen Code enthalten), erhalten Sie 12,5 MB, richtig, aber das sind nicht genau 12 MB, auf denen der FTDI-Teil ausgeführt wird. Da sind 4,167% Differenz, gepaart mit der Ungenauigkeit des HSI-Oszillators kann es funktionieren, wenn alles andere perfekt ist (Regler nicht zu warm, Signale scharf und rauschfrei), aber ich würde es mit 192 MHz versuchen um eine bessere Übereinstimmung zu erzielen.