Hello,
While trying to read asynchronous serial data with the particular 9 bits format I came upon a 'double' mistake in the document I suppose we all use : the ATmegaXX datasheet
It is in chapter 22.7.2 in the C-code example (the assembly code is correct) (p.211)
unsigned int USART_Receive( void )
{
unsigned char status, resh, resl;
while ( !(UCSRnA & (1<<RXCn)) ) /* Wait for data to be received */
;
status = UCSRnA; /* Get status and 9th bit, then data from buffer */
resh = UCSRnB;
resl = UDRn;
if ( status & (1<<FEn)|(1<<DORn)|(1<<UPEn) ) return -1; /* If error, return -1 */
resh = (resh >> 1) & 0x01; /* Filter the 9th bit, then return */
return ((resh << 8) | resl);
}
With this code you don't stand a chance to get any data since it always returns on error.
In the line :
if ( status & (1<<FEn)|(1<<DORn)|(1<<UPEn) ) return -1;
there is a missing level of parenthesis that results in the expression being always true. When there is no mistake the return value is always 12 ( or 0xC or 0b1100) since status & (1<<FEn) = 0 but 0 or 1000 or 100 makes 01100.
The right expression should be :
if ( status & ((1<<FEn)|(1<<DORn)|(1<<UPEn) ))
but then the return value is -1 although the return type is unsigned integer that is in fact 65535. We can detect an error with this latter value of course but it is poor programming. I suggest this code that works alright for me :
bool ERR_FLG = false; // error flag declared as a global variable
unsigned int USART_Receive( void )
{
unsigned char dummy, resh, resl;
ERR_FLG = false; // reset flag error
while ( !(UCSR1A & (1<<RXC1))); // Wait for data to be received
if ( UCSR1A & ((1<<FE1)|(1<<DOR1)|(1<<UPE1)) )
{ while (UCSR1A & (1<<RXC1)) dummy = UDR1; // flush the register if error
ERR_FLG = true; // then set the error flag
}
/* Get 9th bit, then data from buffer */
resh = UCSRnB;
resl = UDRn;
resh = (resh >> 1) & 0x01; /* Filter the 9th bit, then return */
return ((resh << 8) | resl);
}
It is simple then to admit the return value as valid only if the ERR_FLG is false.