cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 UART shows inconsistent outputs

JTurn.2
Senior

From what I understand, the UART gets a char/byte one by one. I am trying to test this by adding '-' between each character of the string I send to the UART. However, the outputted values are very inconsistent when more than 1 character is sent to the UART.

When 1 character is sent via serial console,

the output is correct: A-

When more than 1 character is sent, for example:

input:ABCDEFGH

output:A-C-F-H

The outputted values are different when sending the same string multiple times.

What is the cause of this issue and how do I get it to consistently receive and output data?

Thank you for your help.

uint8_t byte;
 
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  PeriphCommonClock_Config();
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_UART5_Init();
  MX_USART1_UART_Init();
  MX_USART6_UART_Init();
 
 
 
  while (1)
  {
    HAL_UART_Receive_IT(&huart6, &byte, sizeof(byte));
  }
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	uint8_t ya[]="-";
  if (huart->Instance == USART6)
  {
 
 
    HAL_UART_Receive_IT(&huart6, &byte, sizeof(byte));
 
    HAL_UART_Transmit(&huart6, &byte, sizeof(byte), 0);
    HAL_UART_Transmit(&huart6, &ya, sizeof(ya), 0);
 
  }
}

 Edit 1:

I have tried updating the code and using HAL_UART_Transmit_IT() without the hyphen in between characters. The output consistently missing the consecutive character. E.g.

input:ABCD

output:AC

Could this imply that using interrupts is too slow? If so, would polling or DMA be quicker?

Edit 2:

I have updated my code and tried using flags and avoiding using the blocking function in the callback loop.

The aim of this uart is to only get values within '[' and ']'.

E.g. data "abc" is received when "[abc]" is sent to the uart.

However, I noticed that there are 2 problems:

  1. The code outputs garbage text e.g. ˆ.
  2. The uart only receives once. I have to manually press reset for it to receive data again.

//Note: string format: [abcedfg]
 
char getChar=0; //get character
int read_flag=0;
int stop_reading_flag=0;
char str[100]; //string
 
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  PeriphCommonClock_Config();
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  MX_USART6_UART_Init();
  /* USER CODE BEGIN 2 */
  HAL_UART_Receive_IT(&huart6, &getChar, 1);
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
	  if(stop_reading_flag==1)
	  {
		  HAL_UART_Transmit(&huart6, str, strlen(str),0);
		  stop_reading_flag=0;
		  memset(str, 0, sizeof(str)); //flush string
	  }
  }
  /* USER CODE END 3 */
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  if (huart->Instance == USART6)
  {
    if (byte=='[') //Start reading from UART
    {
    	read_flag=1;
    	stop_reading_flag=0;
    }
    else if (byte==']')  //Stop reading from UART
    {
    	read_flag=0;
    	stop_reading_flag=1;
    }
    else if (read_flag==1)
    {
    	strncat(str,getChar,1); //appends to string
    }
    byte=0; //flush buffer
    HAL_UART_Receive_IT(&huart6, &getChar, 1);// start the next round of reception
  }
}
static void MX_USART6_UART_Init(void)
{
 
  /* USER CODE BEGIN USART6_Init 0 */
 
  /* USER CODE END USART6_Init 0 */
 
  /* USER CODE BEGIN USART6_Init 1 */
 
  /* USER CODE END USART6_Init 1 */
  huart6.Instance = USART6;
  huart6.Init.BaudRate = 115200;
  huart6.Init.WordLength = UART_WORDLENGTH_8B;
  huart6.Init.StopBits = UART_STOPBITS_1;
  huart6.Init.Parity = UART_PARITY_NONE;
  huart6.Init.Mode = UART_MODE_TX_RX;
  huart6.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart6.Init.OverSampling = UART_OVERSAMPLING_16;
  huart6.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  huart6.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  if (HAL_UART_Init(&huart6) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART6_Init 2 */
 
  /* USER CODE END USART6_Init 2 */
 
}

16 REPLIES 16
TDK
Guru

Calling blocking functions in an ISR is ill advised. If you receive bytes during this time, it will only receive the first one.

Try receiving multiple characters via HAL_UART_Receive. If that doesn't work, probably a clock mismatch. If it does work, probably the issue is your use of blocking calls within an interrupt.

Better to set a flag in the ISR and handle the request in the main loop. Note that since you're sending 2 chars for every 1 received, you will need to implement a buffer of some sort. Note also that controlling the UART within the main loop and the ISR may lead to problems, depending on your version of HAL and your board, which you do not provide.

If you feel a post has answered your question, please click "Accept as Solution".
MM..1
Chief III

As first change this

  MX_USART6_UART_Init();
 
   HAL_UART_Receive_IT(&huart6, &byte, sizeof(byte));
 
  while (1)
  {
//all other do callbacks
  }

usw...

Hi, thank you for your reply.

Do you mean that I shouldn't be calling HAL_UART_Transmit, which is blocking, in a non-blocking function(HAL_UART_Receive_IT)?

I have tried just using HAL_UART_Receive to receive data and it works. So does HAL_UART_Receive_IT without adding an extra character between 2 characters. Are there any examples I could reference to? I am not sure how to set a flag.

Also, the board I am using is an STM32F76I-DISCO and the version I am using is STM32Cube FW_F7 V1.16.2

From my understanding, this only allows the UART to receive once. What I want to do is to get the UART to continuously receive data with an abitrary number of characters, which is why I put it in the while loop.

> Do you mean that I shouldn't be calling HAL_UART_Transmit, which is blocking, in a non-blocking function(HAL_UART_Receive_IT)?

Yes

> I have tried just using HAL_UART_Receive to receive data and it works. So does HAL_UART_Receive_IT without adding an extra character between 2 characters. Are there any examples I could reference to? I am not sure how to set a flag.

So the issue was in fact blocking functions in the ISR.

I don't know of any existing examples that would serve your exact need. Seems like adding "-" to every character is unnecessary and doesn't serve a functional need, just a debugging/understanding need. Now that you understand what's happening, perhaps move on to the intended application.

Setting a variable as 0 or 1 to notify another part of the program that it should do something is a basic programming skill. Not sure this is the proper forum for learning that. Plenty of resources online.

https://www.geeksforgeeks.org/use-of-flag-in-programming/

If you feel a post has answered your question, please click "Accept as Solution".

Ahh this is missunderstanding non blocking IT

and you place this call too to callback, then next run in while is not needed.

As second you cant receive when send then ofcourse receive first char and send it plus next two chars because sizeof ya is 2 skips receive characters on RX line because MCU manages TX...

I see. Thank you very much for your help!

Ahh this is missunderstanding non blocking IT

and you place this call too to callback, then next run in while is not needed.

Do you mean that I only need to initialise non blocking IT once only and it is called (the call back function) every time there is something received by the uart?

As second you cant receive when send then ofcourse receive first char and send it plus next two chars because sizeof ya is 2 skips receive characters on RX line because MCU manages TX...

Do you mean that the MCU skips the 2nd received character as it is still outputting the 2nd character? If so, I don't quite understand why the RX and TX lines would cause conflicts with each other if there are 2 seperate data lines. Is this a limitation of the MCU? I've tried something similar on Arduino before without any problems.

Bob S
Principal

WARNING: "sizeof(ya)" is NOT 1, it is 2 (the single character '-' followed by a NULL/zero byte). Sending that NULL byte may be messing with your terminal program. Either declare "ya" as "char ya = '-'" or use strlen(ya).

I think I want to make this my signature line, as often as I see sizeof() mis-used in this fashion.