cancel
Showing results for 
Search instead for 
Did you mean: 

Issue detecting and processing usart receive

jhanc.11
Senior

Hello again,

Here's what I want to do:

1) wait for the UART_FLAG_RXNE to be set

2) receive one character

3) switch based on that character (character is saved for further processing)

4) receive the proper number of following characters based on the command in #3

in the example below, when UART_FLAG_RXNE is set, no matter how I try, I only receive one character. In the command processing switch, I tried clearing various flags without effect. This is a simple example, the other part of the code where we receive a command from a GPS unit uses a switch statement for each returned value as they are received so we would really like to receive a select number of characters at a time. Polling is fine as we can't do anything until the commands are all processed. Also, there is a wide number of following characters based on the command. This is on a 32f769.

Thanks in advance for any help and the help in the past.

Jerry

 if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE)==SET){    // check if data is available
  HAL_UART_Receive(&huart1,recBuf,1,100);		  // receive the first character
 
  c=recBuf[0];
 
  switch (c) {
         case 'c':			// Cnnnn set coarse DAC
        // tried clearing ORE, RXNE, etc here but recieve below times out.
	  HAL_UART_Receive(&huart1,recBuf,4,1000);		// get the next 4 chars

6 REPLIES 6
KnarfB
Principal III

HAL overhead might miss some chars. A (cheap) LA might help to better understand what's going on here.

If polling is okay, you might poll for RXNE and read the next char into a buffer simply at register level like

while( !(USART1->ISR & USART_ISR_RXNE) );
buffer[i++] = 0xFF & USART1->RDR; 

Repeat this until some special char occurs (a newline for GPS or a trailing \0 depending on your protocol) or the buffer overflows (which may indicate a protocol error).

This could also be enhanced by using DMA for filling the buffer and the character match interrupt for stopping the DMA.

hth

KnarfB

This is illustrative of a method to read and process NMEA sentences from a GPS/GNSS receiver.

https://github.com/cturvey/RandomNinjaChef/blob/main/f746g_disco_gps.c

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

thanks, we only process two messages from the GPS and we know how to do that. I changed my mind and decided to use an interrupt for the command processing.

For example, say I receive c1234 or f12345 and depending on the first character (c or f) I want to read the next 4 or 5 bytes respectively. These are only two examples of about 20.

I issue this for the first command character:   status = HAL_UART_Receive_IT(&huart1,recBuf,1);;

and my interrupt and callback ( HAL_UART_RxCpltCallback ) kick off. Inside the rx callback I just set a flag that it is complete.

The mainline code checks the flag and then depending on the received character, it issues either :

 status = HAL_UART_Receive_IT(&huart1,recBuf,4);

or

 status = HAL_UART_Receive_IT(&huart1,recBuf,5);

but I suspect overrun or something is set because the code doesn't continue until I transmit again.

I assume I can check the number of characters in the buffer somehow and just process them but the code mainline is programmed to read, process, read more, process more, etc, with tons of switch statements that indicate the next read length.

Is there a way to read one of many and then continue? Assume the processor is fast enough to not miss any characters.

Thanks.

Jerry

jhanc.11
Senior

This is probably not the right way, but what I have working is an interrupt with two buffers and a pointer. I initiate a receive and then within the callback, I initiate another receive. This way I always have an outstanding read. The first buffer receives a byte at a time and I move it incrementally to another buffer with a pointer. Receiving a valid command character resets the the 2nd buffer pointer. So far, I'm not losing any data but it is a little more complex that receive 1 byte, ask for more.

If there is a way using a receive followed by another receive when the data is already possibly in the buffer, I'd like to know.

Thanks

Well generally you don't want to process live/active data.

The callback is under interrupt context, so won't receive any additional data until you leave.

The most STM32 have a 1-byte deep UART, so have an interrupt for each, and that builds up the buffer.

You could have one buffer, and point at the second byte for the subsequent request.

Probably best to copy the data to a holding buffer before processing, and start the next request.

Also the method you propose doesn't seem like it will handle failure, or synchronization issues.

The NMEA you do get a unique byte at the start of an sentence, and the end of the sentence also has a recognizable pattern, thus it's quite easy to resync, and determine how long sentences of variable length actually are.

To be honest I find the HAL paradigm to be unduly awkward, I tend to let the interrupts manage FIFO ring-buffers, and process the data in their own task, disconnecting the hard time deadlines of the USART from the more complex and unpredictable timing of the message parsing and processing.

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

We only receive and process three NMEA messages and they are on a separate usart. I'll look at that code that was attached.

The incoming data I need to process is from a PC user sending the device commands. I have it working now. I receive the data, move it to a buffer, check the "\n" is in the right place based on the first character type (command) and go from there. I start by kicking of the first read and then start another in my callback. Seems a little weird to have an outstanding read that doesn't seem to timeout.

The bigger problem is my project is blown up. I had tried converting it to C++ to bring in some classes I've converted and now nothing will compile. The includes were missing, I can fix that, then the c++ define wasn't set, I can fix that, but lastly, the uint32_t types are not defined. I tried adding the proper define to include cstdint or stdint but that wasn't found, could be more problems. I don't know why I didn't back it up yesterday before trying that conversion. I have a real mess on my hands and getting the interrupts working was a pain. I have the source but it takes more that just copying it into a new project.

Thanks for the input above. You guys are great.

Jerry