Conexión DMA, interrupción y UART en STM32 para detectar caracteres

Estoy tratando de hacer un proyecto y planeo usar DMA para mi UART de un STM32 a otro STM32. Aquí hay algunos detalles de lo que estoy usando:

  • Microprocesador: STM32F107RB
  • Depurador y Programador: Atollic para STM y CubeMX

Uno de mis UART dentro de mi STM32 debería poder detectar un carácter cuando se recibe (en este caso, es una 'e' y una 'f'). Luego, a partir de ahí, debería hacer algo, que es solo encender un LED para este ejemplo.

Aquí está la cosa... Todavía estoy tratando de aprender sobre DMA, interrupciones y STM también, y me cuesta entenderlo.

Mi enfoque para esto es usar:

HAL_UART_TXCpltCallback 

como has visto en el siguiente código. Sí detecta al personaje, pero solo puede ir una vez. Cuando intenté enviar otro carácter, no responde.

Por lo tanto, mi pregunta es:

¿Cómo puedo hacer que mi STM detecte correctamente un carácter de UART y responda correctamente?

Tengo la sensación de que necesitaré usar algo similar como HAL_GPIO_IRQHandler pero en lugar de GPIO, ¿debería usar HAL_DMA_IRQHandler ?

Probé el controlador DMA IRQ, pero da un error que dice: definición múltiple de 'HAL_DMA_IRQHandler'.

Espero haberlo abordado lo suficientemente claro y agradecería cualquier sugerencia de la comunidad.

    #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);

}

Respuestas (1)

Sugiero encarecidamente olvidar DMA por ahora. Ese es un lío complicado de mezclar tres devoluciones de llamada completas de UART, DMA, Tx / Rx que usan TODOS los uarts, independientemente de cuál estaba causando la devolución de llamada. DMA se usa principalmente para transferencias de bloques en muchos bytes que se sabe de antemano cuántos datos habrá o al menos para recibir bloques de longitud fija de un flujo arbitrario. No tiene sentido esperar una sola pulsación de tecla usando DMA, recibir un byte a la vez lleva aún más tiempo configurar las cosas para cada byte que usar solo interrupciones. Ni siquiera uso DMA a 3 Mbits/seg (aunque tal vez debería hacerlo). Solo concéntrese en un UART a la vez, haga que reciba bytes individuales a través de interrupciones y luego procéselos, tal vez usando un búfer de anillo entre la recepción de interrupciones y el procesamiento en el bucle principal. Luego expanda en consecuencia,

Ya veo, gracias por tu sugerencia! Intentaré usar interrupciones en lugar de DMA. ¡Espero que funcione esta vez!
Excelente respuesta: una interrupción de finalización de DMA para un carácter tomaría casi el mismo tiempo que una interrupción de char rx, pero con toda la sobrecarga de configuración :(