DMA, прерывание и соединение UART в STM32 для обнаружения символов

Я пытаюсь сделать проект и планирую использовать DMA для моего UART от одного STM32 к другому STM32. Вот некоторые подробности того, что я использую:

  • Чип: STM32F107RB
  • Отладчик и программист: Atollic для STM и CubeMX

Один из моих UART внутри моего STM32 должен иметь возможность обнаруживать символ при его получении (в данном случае это «e» и «f»). Затем оттуда он должен что-то сделать, а именно зажечь светодиод для этого примера.

Вот в чем дело ... Я все еще пытаюсь узнать о DMA, прерываниях и STM, и мне трудно это понять.

Мой подход для этого заключается в использовании:

HAL_UART_TXCpltCallback 

как вы видели в коде ниже. Он обнаруживает персонажа, но может пройти только один раз. Когда я попытался отправить другого персонажа, он не отвечает.

Следовательно, мой вопрос:

Как я могу заставить свой STM правильно определять символ из UART и правильно реагировать?

У меня есть ощущение, что мне нужно будет использовать что-то похожее, например, HAL_GPIO_IRQHandler , но вместо GPIO должен ли я использовать HAL_DMA_IRQHandler ?

Я попробовал обработчик DMA IRQ, но он выдает ошибку: множественное определение «HAL_DMA_IRQHandler».

Я надеюсь, что я ответил на это достаточно ясно, и был бы признателен за любые предложения от сообщества.

    #include "main.h"

    UART_HandleTypeDef huart1;
    UART_HandleTypeDef huart2;
    UART_HandleTypeDef huart3;
    DMA_HandleTypeDef hdma_usart1_rx;
    DMA_HandleTypeDef hdma_usart1_tx;
    DMA_HandleTypeDef hdma_usart2_rx;
    DMA_HandleTypeDef hdma_usart2_tx;
    DMA_HandleTypeDef hdma_usart3_rx;
    DMA_HandleTypeDef hdma_usart3_tx;
    
    uint8_t tx1_buff[12], rx1_buff[12], tx2_buff[12], rx2_buff[12], tx3_buff[24], rx3_buff[12];
    void SystemClock_Config(void);
    static void MX_GPIO_Init(void);
    static void MX_DMA_Init(void);
    static void MX_USART1_UART_Init(void);
    static void MX_USART2_UART_Init(void);
    static void MX_USART3_UART_Init(void);

    void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart){

        HAL_UART_Transmit_DMA(&huart1,tx1_buff,sizeof(tx1_buff));
        HAL_UART_Transmit_DMA(&huart2,tx2_buff,sizeof(tx2_buff));
        HAL_UART_Transmit_DMA(&huart3,tx3_buff,sizeof(tx3_buff));
    
    
    }

      void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){

                if(rx3_buff[0] == 'e'){
                    HAL_GPIO_WritePin(GPIOC, red_Pin, GPIO_PIN_SET);
                    rx1_buff[0]='e';
                    return;
            
                }
                else if (rx3_buff[0] == 'f') {
                    HAL_GPIO_WritePin(GPIOC, red_Pin, GPIO_PIN_RESET);
                    rx1_buff[0] = 'f';
                    return;
                }
                HAL_UART_Receive_DMA(&huart3, rx3_buff, sizeof (rx3_buff));
            }
        
        
        int main(void)
        {
       
          HAL_Init();
        
          SystemClock_Config();
        
          MX_GPIO_Init();
          MX_DMA_Init();
          MX_USART1_UART_Init();
          MX_USART2_UART_Init();
          MX_USART3_UART_Init();
        
          
          HAL_UART_Transmit_DMA(&huart3,tx3_buff,sizeof(tx3_buff));
          HAL_UART_Receive_DMA(&huart3,rx3_buff,sizeof(rx3_buff));
        
          HAL_UART_Transmit_DMA(&huart1,tx1_buff,sizeof(tx1_buff));
          HAL_UART_Transmit_DMA(&huart2,tx2_buff,sizeof(tx2_buff));
        
          HAL_UART_Receive_DMA(&huart1,rx1_buff,sizeof(rx1_buff));
          HAL_UART_Receive_DMA(&huart2,rx2_buff,sizeof(rx2_buff));
        
        
        
          while (1)
          {
              HAL_GPIO_TogglePin(GPIOC, green_Pin);
              HAL_Delay(250);
            
          }
        }

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.Prediv1Source = RCC_PREDIV1_SOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  RCC_OscInitStruct.PLL2.PLL2State = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure the Systick interrupt time 
  */
  __HAL_RCC_PLLI2S_ENABLE();
}

/**
  * @brief USART1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */

  /* USER CODE END USART1_Init 2 */

}

/**
  * @brief USART2 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART2_UART_Init(void)
{

  /* USER CODE BEGIN USART2_Init 0 */

  /* USER CODE END USART2_Init 0 */

  /* USER CODE BEGIN USART2_Init 1 */

  /* USER CODE END USART2_Init 1 */
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  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;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART2_Init 2 */

  /* USER CODE END USART2_Init 2 */

}

/**
  * @brief USART3 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART3_UART_Init(void)
{

  /* USER CODE BEGIN USART3_Init 0 */

  /* USER CODE END USART3_Init 0 */

  /* USER CODE BEGIN USART3_Init 1 */

  /* USER CODE END USART3_Init 1 */
  huart3.Instance = USART3;
  huart3.Init.BaudRate = 115200;
  huart3.Init.WordLength = UART_WORDLENGTH_8B;
  huart3.Init.StopBits = UART_STOPBITS_1;
  huart3.Init.Parity = UART_PARITY_NONE;
  huart3.Init.Mode = UART_MODE_TX_RX;
  huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart3.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart3) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART3_Init 2 */

  /* USER CODE END USART3_Init 2 */

}


static void MX_DMA_Init(void) 
{
  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();

  /* DMA interrupt init */
  /* DMA1_Channel2_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
  /* DMA1_Channel3_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
  /* DMA1_Channel4_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel4_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
  /* DMA1_Channel5_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
  /* DMA1_Channel6_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel6_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel6_IRQn);
  /* DMA1_Channel7_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);

}

Ответы (1)

Я настоятельно рекомендую пока забыть о DMA. Это запутанный беспорядок из смешивания трех UART, DMA, полных обратных вызовов Tx/Rx, которые используют ВСЕ uarts, независимо от того, какой из них вызвал обратный вызов. DMA используется в основном для передачи блоков по многим байтам, когда либо заранее известно, сколько будет данных, либо, по крайней мере, для получения блоков фиксированной длины из произвольного потока. Нет смысла ждать одного нажатия клавиши с использованием DMA, получение одного байта за раз требует еще больше времени для настройки каждого байта, чем использование только прерываний. Я даже не использую DMA со скоростью 3 Мбит/с (хотя, может, и стоило бы). Просто сконцентрируйтесь на одном UART за раз, заставьте его получать отдельные байты через прерывания, а затем обрабатывайте их, возможно, используя кольцевой буфер между приемом прерывания и обработкой в ​​основном цикле. Затем расширить соответственно,

Я вижу, спасибо за ваше предложение! Я попытаюсь использовать прерывания вместо DMA. Надеюсь, в этот раз получится!
Отличный ответ - прерывание завершения DMA для одного символа займет почти столько же времени, что и прерывание char rx, но со всеми накладными расходами на установку :(