ATmega64 | RX data is missing

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

I send data to UART, revert it and send it back. Problem is somehow delay - related.

 

This value between received chars was selected in experiment, this way eveything works great:

_delay_us(150);

 

When i use code below, eveything works as intended, problems start, when i uncomment _delay_ms(100);

 

When I send up to 3 char everything is stil ok, but if i send:

 

1234 i receive 421

123456 - 721

12345678 - 821

 

Can sameone explain what is happening ?

 

 

#define F_CPU 1843200UL// Clock Speed
#define BAUD 115200UL
#define MYUBRR ((F_CPU/(8*BAUD))-1)
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdlib.h>
#include "avr/iom64a.h"


int main(void)
{
		UBRR0H = (unsigned char)(MYUBRR>>8);
		UBRR0L = (unsigned char)MYUBRR;
		UCSR0A = (1 << U2X0);
		/* Enable receiver and transmitter */
		UCSR0B = (1 << RXEN0) | (1 << TXEN0); //| (1 << RXCIE0);
		/* Set frame format: 8data, 1stop bit, no parity */
		UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); //0x06;
		//sei();
	int8_t aa = 0x31;
    while (1) 
    {
		//_delay_ms(100);
		if(( UCSR0A & 0x80))//RX
		{
			char table[10];
			int8_t iii = 0;
			for(; UCSR0A & 0x80;)
			{
				table[iii] = UDR0;
				_delay_us(150);
				if(UCSR0A & 0x80)
					iii++;		
			}
			PORTA ^= 0x08;
			for(int8_t kkk = iii; kkk >= 0; kkk--)
				{		
					while ( !( UCSR0A & 0x20) );
					UDR0  = table[kkk];
				}
		}
	}
}

 

This topic has a solution.
Last Edited: Sun. Aug 4, 2019 - 06:47 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Get rid of the delays.  When you sit in the _delay_ms(xX) the CPU is sitting in a loop until the 100ms in your case elapses.  THEN it continues.  So it's possible that the CPU does not see your:

if(( UCSR0A & 0x80))//RX

in time and another character is received causing data corruption.

 

JIm

 

EDIT:

To expand a little more.  Instead of IF statements use WHILE to test the flags.  Hence you still sit in a loop, but you are at least looking at the flag to indicate a received character.

 

Me personally I would use a RX interrupt and let the hardware do the work for you

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

Last Edited: Fri. Aug 2, 2019 - 01:03 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for response. I know how to handle this. My question is, why is this happening ? I started from similar solution with RX interrupt. It was something like:

 

while(1)
{
send_3_chars();
sei();
_delay_ms(100);
cli();    }

And result was the same. I don't know why is this happening. Is this somehow described in datasheet ?

 

 

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

Read my response about what happens in _delay_ms(). And you should not use the delay_ms() in an ISR.

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

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

michalnow wrote:
I know how to handle this
I'm not sure...

 

Your code is a little hard to follow, not helped out by the formatting, your use of magic numbers, and e.g. using for in place of while.

 

I've cleaned it up a bit, and added some comments:

#define F_CPU 1843200UL
#define BAUD 115200UL
#define MYUBRR ((F_CPU/(8*BAUD))-1)
#include <avr/io.h>
#include <util/delay.h>

int main(void)
{

  UBRR0H = (unsigned char)(MYUBRR >> 8);
  UBRR0L = (unsigned char)MYUBRR;
  UCSR0A = (1 << U2X0);
  UCSR0B = (1 << RXEN0) | (1 << TXEN0);

  while (1)
  {

    // When one or more bytes have been received.
    if (UCSR0A & (1 << RXC0))
    {

      char table[10];
      int8_t iii = 0;

      // Receive all bytes.
      while (UCSR0A & (1 << RXC0))
      {
        // Fill table in order with received bytes.
        table[iii] = UDR0;
        // Give another byte the chance to come in.
        _delay_us(150);
        // If there's another byte, prepare for it.
        if (UCSR0A & (1 << RXC0))
        {
          iii++;
        }
      }

      // Toggle PA3 <-- where do you make this an output?
      PORTA ^= 0x08;

      // Push out table[] in reverse order.
      for (int8_t kkk = iii; kkk >= 0; kkk--)
      {
        // Wait for room in TX.
        while ( !(UCSR0A & (1 << UDRE0)) );
        UDR0  = table[kkk];
      }

    }

  }

}

 

I see what you're doing, and it could work, but it's brittle (as you have found).

You are waiting 150 us for another byte, and if it doesn't show up then you consider the burst of bytes from the sender to have completed, after which you retransmit that burst in reverse order.

 

Here's where the trouble lies.  An 8-bit serial byte takes 10 serial bits to transfer (start + 8 + stop).  At 115200 baud, that will take 86.8 microseconds.

 

The RX hardware in the USART has a 2-deep buffer, plus the incoming shift register, for a total of three bytes.  So while you're waiting 150 us, nearly two full new bytes may have come in (about 14 of the 16 bits).  That's fine (at first), since the RX buffer + shift register can hold nearly three bytes.

 

Then you read the second byte, leaving not quite one unread byte in the shift register (about 6 bits), but then you wait another 150 us during which another 14 bits come in, with the buffer + shift register now totalling 20 bits.

 

See the pattern?  You're falling behind with every read and every delay of 150 us.  Eventually, and after not very many turns, the hardware buffer will overflow and you will lose incoming bytes.

 

You need to implement a timeout, not a delay.  There are lots of ways to do this.  One is to set up a hardware timer.  Then, in the loop in which you wait for an incoming byte, you also check for the timer to expire.  In this way you can respond immediately to an incoming byte instead of waiting a fixed amount of time during which new bytes might still be filling up the hardware buffer.

 

Another flaw in your code is that you don't do bounds checking on table[].  What happens if a burst of more than 10 bytes comes it?

 

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

Why not simply use the RX interrupt and let the hardware do all the herd work rather than complicated waiting loops then?

 

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

I'm with east coast jim on this, use a ring buffer RX interrupt, where you store the char in a ring buffer, and reset a timer.

When the timer times out, your burst has ended, and then send the buffer contents out in reverse order.

Jim

 

 

(Possum Lodge oath) Quando omni flunkus, moritati.

"I thought growing old would take longer"

 

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

Your baud rate [115.2K] is much too fast for your system clock [1.8MHz].  Try everything with a baud rate of 9600 or 19200 and see if it works.  Then create transmit and receive buffers with head and tail pointers.  Next set up the interrupts so that the UART gets any new data from the TX buffer and puts any new incoming data into the receive buffer.   This is the standard way to get UARTs to work with data strings.

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

jgmdesign wrote:
Why not simply use the RX interrupt and let the hardware do all the herd work rather than complicated waiting loops then?
That's preferable, but not necessary.  Preferable in that it will mesh better with a real app that may have other things going on.  Unnecessary for solving the problem at hand.  Polling is sufficient for that.

 

Walk before run.

 

Simonetta wrote:
Your baud rate [115.2K] is much too fast for your system clock [1.8MHz].
It's tight, but not overly so.  There are 16 cpu cycles per bit, and 160 cpu cycles per 8N1 serial frame.  That's plenty to accomplish the task at hand.  Although agree that slower at first may be better in order to get a handle on the task.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]