read NULL in uart receive ring buffer after _delay function

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

<20130313163640.419 TX>
gfh [len=3]
<20130313163640.872 RX>
gf
<20130313163641.823 TX>
gfh [len=3]
<20130313163641.932 RX>
gf
......
my main code is:
int main(void)
{
uart_init(UART_BAUD_SELECT);
while(1)
{
//TODO:: Please write your application code
_delay_ms(500);
// uart_puts("c");
uart_putc((unsigned char)uart_getc());
uart_putc((unsigned char)uart_getc());
_delay_ms(10);
uart_putc((unsigned char)uart_getc());
}
}

the problem here is i sent 3 characters, only receive two if there is a delay_ms in front of the third uart_putc, can anyone help me find where the problem is? thanks

my other two uart receive function are (i use atmega2560):

SIGNAL(USART0_RX_vect)
{
unsigned char temphead;
unsigned char lastRxError;

temphead = (UART_RxHead + 1) & UART_RX_BUFFER_MASK;

if (temphead != UART_RxTail)
{
UART_RxBuf[UART_RxHead] = UDR0;
UART_RxHead = temphead;
}
else
{
UCSR0B &= ~_BV(RXCIE0);

}
}

unsigned int uart_getc(void)
{
unsigned char temptail;
unsigned char rx_data;
temptail = (UART_RxTail + 1) & UART_RX_BUFFER_MASK;
if(UART_RxTail != UART_RxHead)
{
rx_data = UART_RxBuf[UART_RxTail];
UART_RxTail = temptail;
UCSR0B |= _BV(RXCIE0);
return rx_data;
}
else
{
return 0;
}

}

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

Where and how is UART_RxHead declared?

What does SIGNAL mean?

Did you get warnings from your compiler? -and which ones ,if any?

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

static volatile unsigned char UART_RxHead; and initialised in my uart_init function in my uart.c file
signal is a old way to write interrupt function.
no warnings from compiler.

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

leonzha wrote:

unsigned int uart_getc(void)
{
	unsigned char temptail;
	unsigned char rx_data;
	temptail = (UART_RxTail + 1) & UART_RX_BUFFER_MASK;
	if(UART_RxTail != UART_RxHead)
	{		
		rx_data = UART_RxBuf[UART_RxTail];
		UART_RxTail = temptail;
		UCSR0B |= _BV(RXCIE0);
		return rx_data;
	}
	else
	{
		return 0;
	}
}

Your code behaves just like it should. If application calls uart_getc() when no data is available, it returns 0. Which is exactly what you see is being returned on UART.

What you probably SHOULD do is to block in uart_getc() until data is available. Isn't this the way the original UART driver (looks like Atmel's example driver) is implemented? If so why did you modify it if you didn't want that behavior?

/Jakob Selbing

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

<20130313163640.419 TX>
gfh [len=3]
<20130313163640.872 RX>
gf
<20130313163641.823 TX>
gfh [len=3]
<20130313163641.932 RX>
gf
......
i tansmit(Tx) gfh but only recieve(Rx) gh. because of the _delay_ms(10); in front of last uart_putc((unsigned char)uart_getc()); without delay function call, i get gfh return. and ((unsigned char)uart_getc()); seems not called.

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

Change usart_getc() to return a signed int, return -1 if nothing is available in the buffer. That way you know if usart_getc() returns a valid value, or a 'true null'.

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

leonzha wrote:
<20130313163640.419 TX>
gfh [len=3]
<20130313163640.872 RX>
gf
<20130313163641.823 TX>
gfh [len=3]
<20130313163641.932 RX>
gf
......
i tansmit(Tx) gfh but only recieve(Rx) gh. because of the _delay_ms(10); in front of last uart_putc((unsigned char)uart_getc()); without delay function call, i get gfh return. and ((unsigned char)uart_getc()); seems not called.
No, no, and no.

You transmit "gfh" and receive "gf>NUL>". Think about what the "" actually means. HINT: it does NOT mean "nothing".

Further, I already gave you an explanation and suggested modification. Did you bother to read it and try it?

/Jakob Selbing

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

with out delay i get what i expected,

gfh [len=3]
<20130313182332.476 RX>
gfh
<20130313182333.396 TX>
gfh [len=3]
<20130313182333.552 RX>
gfh

while(1)
{
//TODO:: Please write your application code
_delay_ms(500);

uart_putc((unsigned char)uart_getc());

uart_putc((unsigned char)uart_getc());
//_delay_ms(50);
uart_putc((unsigned char)uart_getc());

}

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

thanks for all tring to help me find where went wrong.
now i think the problem is i enabled The Transmit Complete (TXCn) interrupt. when one uar_putc finish, after small amount of delay(which i am not sure how many clock cycles) enter transmit complete interrupt, so no other code can be executed.

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

leonzha wrote:
now i think the problem is i enabled The Transmit Complete (TXCn) interrupt. when one uar_putc finish, after small amount of delay(which i am not sure how many clock cycles) enter transmit complete interrupt, so no other code can be executed.
OK, one last attempt.

You have misunderstood how interrupts work. They normally run in the "background", while other code is executed. There is no need for any delay. What you need is to modify your uart_getc() function to either
1) wait until a character is available and THEN return it
or
2) return a "special" value if no new character is available (a value 0 is not a good idea since it is quite possible to transmit that value over UART), and THEN you can check the return value and determine if this is valid data that you want to echo back, or if no data was available.

/Jakob Selbing

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

Jakob:
I guess you suggested very few modifications (two lines)

/*unsigned*/ int uart_getc(void)
{
   unsigned char temptail;
   unsigned char rx_data;
   temptail = (UART_RxTail + 1) & UART_RX_BUFFER_MASK;
   if(UART_RxTail != UART_RxHead)
   {      
      rx_data = UART_RxBuf[UART_RxTail];
      UART_RxTail = temptail;
      UCSR0B |= _BV(RXCIE0);
      return rx_data;
   }
   else
   {
      return -1; // instead of 0
   }
} 

If OP wants a blocking receive, he just has to to read until one receives differs from -1; else, OP reads (and further processes)...