Skip to main content
JTurn.2
Associate III
December 29, 2021
Question

STM32 UART shows inconsistent outputs

  • December 29, 2021
  • 16 replies
  • 3250 views

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 */
 
}

This topic has been closed for replies.

16 replies

TDK
December 29, 2021

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""."
JTurn.2
JTurn.2Author
Associate III
December 29, 2021

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

TDK
December 29, 2021

> 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""."
MM..1
Super User
December 29, 2021

As first change this

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

usw...

JTurn.2
JTurn.2Author
Associate III
December 29, 2021

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.

MM..1
Super User
December 29, 2021

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...

Bob S
Super User
December 29, 2021

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.

JTurn.2
JTurn.2Author
Associate III
December 30, 2021

I see. Thank you for your tip! I have updated my post if you have the time to check it out. Thanks!

S.Ma
Principal
December 30, 2021

This shows that we need more practical base examples around usart. Should the callback function names have something like ISR or IT suffix to remind these functions need to be brief and speedy?

JTurn.2
JTurn.2Author
Associate III
December 30, 2021

Hi, thank you for your reply. I do agree that there should be more practical base examples around usart. As a beginner in STM32, I find it difficult to find detailed yet practical examples on how to configure and code the usart. For example, it took me a day to realise that I needed to enable the global interrupt in STM32CUBEMX when using IT or DMA. I do know that there are some usart examples written somewhere, but it's difficult to find the one's that are useful to me as I have to individually check the examples for each evaluation board to see if it has an example similar to what I'm trying to do. As for the documentation on how to use different usart functions, I believe most of them are only breifly introduced. There aren't many practical examples so it's difficult for beginners to understand how to use them properly.

As I am transitioning from Arduino, I believe that functions names such as ISR would be more intuitive than just calling it a callback function. However, this is just my personal opinion.

Also, I have also updated my code which I am still having problems with. I would appreciate the help if you have the time. Thank you!

MM..1
Super User
December 30, 2021

Your code is now better but still big amount of mistakes

The C library function char *strncat(char *dest, const char *src, size_t n) appends the string pointed to by src to the end of the string pointed to by dest up to n characters long.

getChar isnt char *

Next FYI ISR is hidden in HAL for you and call virtual callbacks func, that you place in your code usw.