STM32 HAL UART Проблема передачи DMA

После настройки моего проекта для пользовательской платы STM32F7, которая включает преобразователь FT2232H UART <-> USB, у меня возникло несколько проблем при отправке (и получении данных). Код, который я использую, в основном сгенерирован CubeMX и находится в конце поста.

Во-первых, я не могу заставить stm передавать данные со скоростью выше стандартной 115200, согласно даташитам, и FT2232H, и STM32F7 должны поддерживать скорость не менее 12 Мбод. Для FT2232H это работает, так как я отправляю некоторые символы со своего терминала (сторона USB) и получаю символы обратно, когда я замыкал контакты RX и TX на выходной стороне FT2232H.

Во-вторых, я не могу вызывать функцию sendUART() несколько раз подряд, почему DMA Fifo не используется для хранения данных, которые я хочу отправить?

Также как правильно отобразить все полученные данные, но использовать fifo, чтобы данные не терялись, если они не опрашиваются вовремя?

Может быть, это глупые вопросы, но я уже пытался найти решение здесь и в остальном Интернете, но не могу найти.

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){
    }
}

Ответы (1)

Во-первых, я не могу заставить stm передавать данные со скоростью выше стандартной 115200, согласно даташитам, и FT2232H, и STM32F7 должны поддерживать скорость не менее 12 Мбод.

Аппаратно поддерживает скорость до 27 Мбит (ну вы не сказали номер детали, я смотрю даташит на F756), но по словам , stm32f7xx_hal_uart.hHAL не примет скорость выше 9М

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

Более того, это зависит от тактовой частоты системы, в конфигурации по умолчанию, когда вы не трогаете вкладку Clock Configuration в STM32CubeMX, все работает на внутренних тактовых частотах HSI 16 МГц. Это означает не более 1 Мбит при использовании UART_OVERSAMPLING_16или вдвое больше, если вы переключитесь на UART_OVERSAMPLING_8(но тогда вы потеряете обнаружение шума).

Во-вторых, я не могу вызывать функцию sendUART() несколько раз подряд, почему DMA Fifo не используется для хранения данных, которые я хочу отправить?

Хотя существует 16-байтовый DMA FIFO, он недоступен программному обеспечению. Невозможно просто добавить дополнительные данные к текущей передаче DMA. HAL ничего не делает, но запускает передачу DMA с адреса буфера, предоставленного вызывающей стороной.

Вы должны дождаться завершения передачи или приостановить DMA и все равно ждать, пока FIFO не опустеет. Конечно, вы можете выделить буфер самостоятельно, добавлять данные по мере их поступления и перезапускать DMA всякий раз, когда он завершается и в буфере появляются новые данные.

Также как правильно отобразить все полученные данные, но использовать fifo, чтобы данные не терялись, если они не опрашиваются вовремя?

Мне кажется, что вы не можете иметь одновременно DMA и прерывания для каждого полученного символа. По крайней мере, ISRзначение регистра состояния будет бесполезным, и обработчик прерывания не сможет решить, что делать. Его чтение может даже помешать передаче DMA. Следовательно, вы должны выбрать один.

Используя DMA для помещения данных в буфер (или два), вы можете затем регулярно опрашивать счетчик передачи в цикле простоя или прерывании таймера. Немедленного ответа не будет, но, возможно, это вообще не имеет значения, потому что интерфейс USB также будет иметь некоторую задержку.

Спасибо за ответ. Я настроил часы, и UART работает на 200 МГц SYSCLK, поэтому, согласно CubeMX, теоретически должен быть макс. скорость передачи данных 12,5 Мбит/с с передискретизацией, установленной на 16 выборок.
Если вы установите источник синхронизации UART на 200 МГц SYSCLK (где вы это делаете? Этого нет в приведенном выше коде), то вы получите 12,5 млн, верно, но это не совсем 12 млн, на которых работает часть FTDI. Есть разница в 4,167%, вкупе с неточностью генератора HSI может работать, когда все остальное идеально (контроллер не сильно греется, сигналы резкие и без шумов), но я бы попробовал на 192МГц чтобы получить лучшее совпадение.