cancel
Showing results for 
Search instead for 
Did you mean: 

Why UART sometimes print twice the message?

ATeli.1
Associate III
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2022 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
 
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
/* USER CODE END Includes */
 
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
 
/* USER CODE END PTD */
 
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
 
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
 
/* USER CODE END PM */
 
/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart2;
 
/* USER CODE BEGIN PV */
//initialize the menu message
char welcome_message[] = "\r\nHELLO AND WELCOME TO STM32 TYPE YOUR COMMAND\r\n1)Togggles LED1\r\n2)Button status\r\n3)Initial menu\n\r";
//initialize flag for checking if there are data to send or receive data via UART
short int volatile tx_flag = 0; 
short int volatile rx_flag = 1;
//initialize a variable for the button status
short int volatile is_button_press = 0;
//variable to store received data
uint8_t rx_message[1];
char tx_message[100];
/* USER CODE END PV */
 
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
/* USER CODE BEGIN PFP */
 
/* USER CODE END PFP */
 
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
 
/* USER CODE END 0 */
 
/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
 
  /* USER CODE END 1 */
 
  /* MCU Configuration--------------------------------------------------------*/
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* USER CODE BEGIN Init */
 
  /* USER CODE END Init */
 
  /* Configure the system clock */
  SystemClock_Config();
 
  /* USER CODE BEGIN SysInit */
 
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  HAL_UART_Transmit(&huart2,(uint8_t*)welcome_message,sizeof(welcome_message),10); //tx initial menu
 
  while (1)
  { 
    if(rx_flag == 1){
      HAL_UART_Receive_IT(&huart2,rx_message,sizeof(rx_message));
    }
 
    if(tx_flag == 1 && rx_flag == 0){
      HAL_UART_Transmit_IT(&huart2,(uint8_t*)tx_message,sizeof(tx_message));
    }
 
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
 
/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
 
  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
 
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 16;
  RCC_OscInitStruct.PLL.PLLN = 336;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
  RCC_OscInitStruct.PLL.PLLQ = 7;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
 
  /** Initializes the CPU, AHB and APB buses 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();
  }
}
 
/**
  * @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 GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
 
  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
 
  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
 
  /*Configure GPIO pin : B1_Pin */
  GPIO_InitStruct.Pin = B1_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;
  GPIO_InitStruct.Pull = GPIO_PULLDOWN;
  HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);
 
  /*Configure GPIO pin : LD2_Pin */
  GPIO_InitStruct.Pin = LD2_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(LD2_GPIO_Port, &GPIO_InitStruct);
 
  /* EXTI interrupt init*/
  HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
 
}
 
/* USER CODE BEGIN 4 */
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart){
  //if a message has been send set in rx mode
  rx_flag = 1;
  tx_flag = 0;
}
 
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
  uint8_t error_message[] = "\r\nincorrect command\r\n";
 
  //check if command are correct and prepare the message to send
  if(rx_message[0] == '1'){
    HAL_GPIO_TogglePin(LD2_GPIO_Port,LD2_Pin);
  } else if(rx_message[0] == '2'){
    //set tx flag on
    tx_flag = 1;
    //set rx flag off
    rx_flag = 0;
    //check button status and save it in char to send it
    if(is_button_press == 1){
      sprintf(tx_message,"\r\nPRESS\r\n");
    } else if(is_button_press == 0){
      sprintf(tx_message,"\r\nNOT PRESS\r\n");
    }
  } else if(rx_message[0] == '3'){
    //set tx flag on
    tx_flag = 1;
    //set rx flag off
    rx_flag = 0;
    //prepare the message to be send
    sprintf(tx_message,"%s",welcome_message);
  } else {
    //incorrect command was receive
    HAL_UART_Transmit(&huart2,error_message,sizeof(error_message),10);
  }
}
 
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
  //set button status
  is_button_press = !is_button_press;
}
/* USER CODE END 4 */
 
/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}
 
#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

The code is working, but I don't understand why sometimes the serial terminal show me twice.

As shown "NOT PRESS" is printed twice.0693W00000WJgJGQA1.png 

9 REPLIES 9

>>I don't understand why sometimes the serial terminal show me twice.

Because you're in a tight loop, and send things based on a flag you don't clear immediately.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Sorry I am new in stm32 programming. I think that too but I've add in the Uart callback functions some lines that clear the flags(rx_flag and tx_flag). If I've understand correctly after the transmissions of the data, first the callback function is execute, and then the infinity loop starts again. Is this correct?

while(1)
{
    if(tx_flag == 1 && rx_flag == 0){
      HAL_UART_Transmit_IT(&huart2,(uint8_t*)tx_message,sizeof(tx_message)); // Called repetitively, returns immediately
    }
}
while(1)
{
...
    if(tx_flag == 1 && rx_flag == 0){
  tx_flag = 2; // stop repeatedly transmitting, clear in call back on COMPLETION
      HAL_UART_Transmit_IT(&huart2,(uint8_t*)tx_message,sizeof(tx_message)); // Returns immediately
    }
}

Stuff in the foreground is running continuously. The callbacks occur after something completes, not immediate before it starts.

RX likely needs some work on the logic too.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Also use strlen(), not sizeof() for some string of unpredictable length. Otherwise you'll seen the whole content of the buffer.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Sorry I bore you but I am not understanding. HAL_UART_Transmit_IT() is only use to start the trasmission and return immediately? Then when the transmission end the callback function is execute is this correct? This mean that the UART communication is only start in the while loop and then executed in background?

HAL_UART_Transmit_IT() starts a process by which each character is transmitted and generates an interrupt, when all the characters have been sent the interrupt routine calls your callback function.

HAL_UART_Transmit() would be a blocking function, it does not return until completion.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Karl Yamashita
Lead II

You should try to minimize doing any processing in the interrupt. You don't have much code so it's not going to take up many cycles, but you should poll you data in main loop instead. I've added/modified your code so you can see how I handle HAL status. It complains the text is too large so I've removed sections after main

Things I've noticed

  • You don't check for HAL return status. This will hurt you if you have lot's of data going back and forth.
  • In main while loop you keep calling HAL_UART_Receive_IT() until your flag is cleared. You just need to enable once. Then re-enable after you received a character(s).
  • Though you can call HAL_UART_Transmit_IT() in different places, you should just call it in one place.

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2022 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
 
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
/* USER CODE END Includes */
 
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
 
/* USER CODE END PTD */
 
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
 
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
 
/* USER CODE END PM */
 
/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart2;
 
/* USER CODE BEGIN PV */
//initialize the menu message
char welcome_message[] = "\r\nHELLO AND WELCOME TO STM32 TYPE YOUR COMMAND\r\n1)Togggles LED1\r\n2)Button status\r\n3)Initial menu\n\r";
//initialize flag for checking if there are data to send or receive data via UART
short int volatile tx_flag = 0; 
short int volatile rx_flag = 1;
//initialize a variable for the button status
short int volatile is_button_press = 0;
//variable to store received data
uint8_t rx_message[1];
char tx_message[100];
/* USER CODE END PV */
 
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
/* USER CODE BEGIN PFP */
 
/* USER CODE END PFP */
 
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
 
/* USER CODE END 0 */
 
/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
 
  /* USER CODE END 1 */
 
  /* MCU Configuration--------------------------------------------------------*/
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* USER CODE BEGIN Init */
 
  /* USER CODE END Init */
 
  /* Configure the system clock */
  SystemClock_Config();
 
  /* USER CODE BEGIN SysInit */
 
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */
  EnableUART_Interrupt();
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  UART_UpdateTx(welcome_message);
 
  while (1)
  { 
 
    CheckErrorFlag();
 
    UART_CheckData();
    UART_SendData();
 
    
 
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
bool UART_DataAvail = false;
bool UART_RxEnErrorFlag = false;
 
void UART_CheckData(void)
{
    uint8_t error_message[] = "\r\nincorrect command\r\n";
 
    if(UART_DataAvail)
    {
        UART_DataAvail = false;
        //check if command are correct and prepare the message to send
        if(rx_message[0] == '1'){
            HAL_GPIO_TogglePin(LD2_GPIO_Port,LD2_Pin);
        } else if(rx_message[0] == '2'){
            //check button status and save it in char to send it
            if(is_button_press == 1){
                UART_UpdateTx("\r\nPRESS\r\n");
            } else if(is_button_press == 0){
                UART_UpdateTx("\r\nNOT PRESS\r\n");
            }
        } else if(rx_message[0] == '3'){
            //prepare the message to be send
            UART_UpdateTx(welcome_message);
            //set tx flag on
        } else {
            //incorrect command was receive
            UART_UpdateTx(error_message);
        }
    }
}
 
void UART_SendData(void)
{
    if(tx_flag == 1){
      if(HAL_UART_Transmit_IT(&huart2,(uint8_t*)tx_message,sizeof(tx_message)) == HAL_OK)
      {
            tx_flag = 0; 
      }
    }
}
 
void UART_UpdateTx(char *data)
{
    strcpy(tx_message, data);
    tx_flag = 1;
} 
 
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
 
    UART_DataAvail = true;
    EnableUART_Interrupt();
}
 
void EnableUART_Interrupt(void)
{
	if(HAL_UART_Receive_IT(&huart2,rx_message,sizeof(rx_message)) != HAL_OK)
	{
		UART_RxEnErrorFlag = true;
	}
}
 
bool GetUartEnErrorFlag(void)
{
	return UART_RxEnErrorFlag;
}
 
void ClearUartEnErrorFlag(void)
{
	UART_RxEnErrorFlag = false;
}
 
void CheckErrorFlag(void)
{
	if(GetUartEnErrorFlag())
	{
		ClearUartEnErrorFlag();
		EnableUART_Interrupt();
	}
}

Thank you for your code! But it's not clear to me why in my code I am not cleaning the flag. I try to explain. When I enter in the loop for the transmission, first it start the HAL_TRASMIT_IT(), after this instruction then the interrupt start and there the flag are cleared. Why is it not correct?

Karl Yamashita
Lead II

It was already explained by @Community member​ by his code that i'm quoting below.

You need to clear your tx_flag or change it to something other than 1 once you test for it and before you start HAL_UART_Transmit_IT. However if the HAL status returns HAL_BUSY then whatever you're trying to transmit will fail so that is why you need to act upon the HAL status. What I posted will work but I should have added my ring buffer code because the tx_message can be overwritten by new data if you receive some new data before the transmit finishes.

while(1)
{
...
    if(tx_flag == 1 && rx_flag == 0){
  tx_flag = 2; // stop repeatedly transmitting, clear in call back on COMPLETION
      HAL_UART_Transmit_IT(&huart2,(uint8_t*)tx_message,sizeof(tx_message)); // Returns immediately
    }
}