UART Rx missing byte issue

Go To Last Post
18 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think I know the reason but wants to have a good suggestion to solve the issue.

 

1. I have a timer which starts interval 3ms to 0.3ms (it's for sending a pulse to Motor driver IC, accel and decel)

2. I also receive Uart Rx 1 packet (6 to 7 bytes) every 30 ms (115200 bps)

 

in this situation, I lost 1 byte in every 40 to 50 packets (which makes checksum error of the packet)

 

What could solve this issue? 

below is what I'm trying to do

 

1. speed up and down the UART baud rate

2. Motor Timer interval change to longer

3. change calling functions in ISR to inline function (reduce context changing)

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Do some measurements first. Use the atmel studio simulator to measure the timer isr execution time. At 115200 baud, you can get a character every 104us. Therefore your timer isr time must be less than this. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Implement a suitable UART receive interrupt driver.
Or post here as small a code as possible that reproduces your problem.
If you use a UART, use a clock source with an accuracy that satisfies it.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

What you need is a buffered USART.  Note:  Your AVR should be using a USART, not a UART - the 's' means there are many improvements, including better buffering.

 

kabasan wrote:

Implement a suitable UART receive interrupt driver.

 

That's kinda the idea.  Something that takes the incoming data and very quickly shoves it into SRAM somewhere, and immediately exits.  Do all the CRC processing in the main loop.

 

I imagine you're already doing this, but don't loiter around in your timer interrupt for the whole delay.  Fire the interrupt and get out.

 

But you might, depending on allowable jitter in the motor drive pulse, have an application that justifies one interrupt interrupting another, which can be done but is generally considered evil*.

 

For a stupid suggestion, throw another AVR down beside the first one.  Use it as the serial port buffer, and read data into the motor driver chip over some other bus when the motor chip feels like it.  AVRs are cheap!

 

S.

 

* This is because it can do very horrible things; to timing, drop you into infinite loops, smash your stack, transport your daughter across state lines...  It's very easy to get wrong, and beastly to debug when you do.

 

Edited to add PS:  Just looked again, and there's a bit signal for this.  Check your USART DOR bit all the time, and make sure it is actually a data overrun error.  S.

Edited again to address Clawson's remarks in case this comes up in a topic search or something...  S.

Last Edited: Tue. Apr 30, 2019 - 08:52 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Scroungre wrote:
the 's' means better buffering.
No it doesn't?!?

 

USART = Universal Synchronous and Asynchronous Receiver and Transmitter

 

While almost no one ever really uses the UART in Synchronous mode, the fact is that S mean Synchronous and has nothing to do with buffering.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Not what the letter means, no, but it's from the AVR spec sheet.  This one's from the 169, under 'compatibility with UART':

However, the receive buffering has two improvements that will affect the compatibility in
some special cases:
• A second Buffer Register has been added. The two Buffer Registers operate as a
circular FIFO buffer. Therefore the UDR must only be read once for each incoming
data! More important is the fact that the Error Flags (FE and DOR) and the ninth
data bit (RXB8) are buffered with the data in the receive buffer. Therefore the status
bits must always be read before the UDR Register is read. Otherwise the error
status will be lost since the buffer state is lost.

So they added a buffer when they made the AVR UART into a USART.  S.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yeah but that buffer and the fact that it has synchronous mode are two completely unrelated changes.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Granted, but they changed both of them at the same time, and didn't call it a USBIx2ART (Universal Synchronous Buffer Improvement Times Two and Asynchronous Reciever / Transmitter, so I was using the 'S' as a shorthand for 'The Improved Version'.  S.

 

Edited to add:  Perhaps a better turn of phase would have been "Look for the S, because when the Atmel designers put in the synchronous stuff that the 'S' means, they also included some other improvements that might be applicable to your situation.  S.

Last Edited: Tue. Apr 30, 2019 - 08:47 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you all. 

Just short of time, I will let you know more story later. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:

Do some measurements first. Use the atmel studio simulator to measure the timer isr execution time. At 115200 baud, you can get a character every 104us. Therefore your timer isr time must be less than this. 

 

1. So I may get Uart rx interrupt every 104 us when the packet is coming

- then lower baudrate like38400, 57600 would help in this situation? 

 

2. Could you link me how to measure time with simulator? 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Scroungre wrote:

Not what the letter means, no, but it's from the AVR spec sheet.  This one's from the 169, under 'compatibility with UART':

However, the receive buffering has two improvements that will affect the compatibility in
some special cases:
• A second Buffer Register has been added. The two Buffer Registers operate as a
circular FIFO buffer. Therefore the UDR must only be read once for each incoming
data! More important is the fact that the Error Flags (FE and DOR) and the ninth
data bit (RXB8) are buffered with the data in the receive buffer. Therefore the status
bits must always be read before the UDR Register is read. Otherwise the error
status will be lost since the buffer state is lost.

So they added a buffer when they made the AVR UART into a USART.  S.

 

But using USART means I need more pin connections, right? 

- At this moment, it's not possible

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No. You can simply use the Rx and Tx pins. Not to worry.

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How (and where) do you handle the CRC ?

 

I'm not 100% sure about your needed timing, but for me it sounds like it would be better to deal with the 3 - 0.3ms timing in a timer ISR and then handle the UART in main (without ISR), just by pooling.

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I lost 1 byte in every 40 to 50 packets

Well, what do you mean by "lost"  ...the usual assumption is that the reception is fumbling and losing a byte here & there...however, you should verify that  the "lost" byte is actually being sent to you (such as using a scope, logic analyzer, bus analyzer, etc).   You could spend a long time only to find you were investigating a ghost.  At least keep this possibility in mind, until you eliminate it.

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 2

Hello New member,

the community said you should make time measurements.,

I assume You use this Settings: baud 115200, 8N1. That mean a full Byte needs 10*8,68 us + a Little wait.

 

This should be no problem when you use Interrupt Service Routine (ISR) on Usart0. But you must fetch the Byte very fast.

 

Here a sample for USART0 ISR. It takes 6,0 us: In Appendix you see the the timing on scope.

 

I hope I can help greetings Ellen

 

 

// Deklarationen Usart0 ISR
int RX0_Cnt = 0;		// number received bytes

char* RX0_Ptr;			// Writepointer to rxbuff

uint8_t RX0_Error;		// RX0_Error: FE0:Frame error, DOR0:Data Overrun, UPE0:Parity error

unsigned char RX0_Byte;	// actual received byte

uint8_t RX0_Status;		// status process progress

/**
*	Interrupt service routine Usart0 (connected with simulator)
*	one byte received. Ready to fetch this

*/
ISR(USART0_RX_vect)
{	RX0_Error = 0;
	LED0_ON
	if(!(UCSR0A & (1<<RXC0))) RX0_Error = UCSR0A;	//dataregister empty

	//if(!(UCSR0A & 0x80)) status = UCSR0A;			//no data to be received

	RX0_Byte = UDR0;
	// ready for next record all previous bytes are ignored

	if (RX0_Status & U0_Inquiry_Start)
	{
		// normal operation byte into read buffer

		*RX0_Ptr = RX0_Byte;
		RX0_Cnt++;
		RX0_Ptr++;
		// every frame must be terminated by 0D
		if (RX0_Byte == 0x0D)
		{
			// last byte received

			Set_U0_Inquiry_Ready

			RX0_Byte = 0;			// delete receive buffer byte

			*RX0_Ptr = RX0_Byte;	// replace 0D with 00 > string terminating

			//RX0_Cnt = 0;			// counter will used in routines not delete here

			RX0_Ptr = rxBuff;		// set pointer to beginning

		}// (RX0_Byte == 0x0D)
	}// (RX0_Status & U0_Inquiry_Start)
	LED0_OFF
}//ISR

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As said before: interrupt triggered data handling.

But from your info it's not clear if there is anything wrong with your firmware, (on the receiving or sending end! ) or there is something wrong with the cable / connectors which causes troubles.

nicewook wrote:
3. change calling functions in ISR to inline function (reduce context changing)
Oops. Calling functions from within an ISR used to be a no-no, because GCC was not smart enough to handle it and just saved the AVR registers out of caution. All 32 of them... Newer GCC releases do not do that anymore I believe, but it is still an indication of sloppy programming. The longest ISR for an AVR I have ever written is about a page of code with a worst case execution time of around 200CPU cycles.

 

 

Doing magic with a USD 7 Logic Analyser: https://www.avrfreaks.net/comment/2421756#comment-2421756

Bunch of old projects with AVR's: http://www.hoevendesign.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:

Do some measurements first. Use the atmel studio simulator to measure the timer isr execution time. At 115200 baud, you can get a character every 104us. Therefore your timer isr time must be less than this. 

Thank you. can I ask you 

 

1. how to use atmel studio simulator for time measure? can I have useful url at least?

2. where 104 us comes from? I think I need 8+2bit (start/stop bit) for 1 byte transfer, so I calculated like this 

1000000 / (115200 / 10) = 86.8056

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

1. I can't remember. I didn't need to google to figure it out, so must be pretty obvious. I've not used Atmel Studio for some time and it's not on my current computer. I think what you need to look for is the cycle count or suchlike. Run the simulator and you should be able to find it.

2. Yes, you're correct. 104us is the time per bit at 9600 baud!

Last Edited: Thu. May 9, 2019 - 03:24 AM