Hi,
After hours of trying to figure out why my serial comms dont work on the Uno, but did on the Duemilanove, myself and Tricia from #sparkfun have discovered something most odd.
It seems the Uno has the USART baud doubler ON by default where as the Duemilanove does not.
Test case:
#include <avr/io.h>
#include <util/delay.h>
#define BAUD 9600
//#include <util/setbaud.h>
void serial_init()
{
uint16_t ubbr;
/* set the baud, the traditional way */
ubbr = 103;
UBRR0H = ubbr >> 8;
UBRR0L = ubbr & 0xff;
/* Set the baud rate - the setbaud.h way */
#if 0
UBRR0H = UBRRH_VALUE;
UBRR0L = UBRRL_VALUE;
#endif
/* set the framing to 8N1 */
UCSR0C = (3 << UCSZ00);
/* Engage! */
UCSR0B = (1 << RXEN0) | (1 << TXEN0);
/* doubler off - Only needed on Uno XXX */
//UCSR0A &= ~(1 << U2X0);
return;
}
void serial_write(unsigned char c)
{
while ( !(UCSR0A & (1 << UDRE0)) );
UDR0 = c;
}
int main (void)
{
char i = 0;
char *str = "the quick brown fox jumps over the lazy dog. 1234567890\r\n";
unsigned char rd;
serial_init();
while (1) {
serial_write(str[i++]);
if (str[i] == '\0') {
i = 0;
_delay_ms(500);
}
}
return 0;
}
This is plain C. I am not using the IDE. To build this I have a Makefile which does:
avr-gcc -Wall -Os -DF_CPU=16000000UL -mmcu=atmega328p -o serial.elf serial.c
avr-objcopy -O ihex -R .eeprom serial.elf serial.hex
NOTE: the correctly set F_CPU value of 16MHz. Both the Uno and Duemilanove are 16Mhz.
I then upload the binary using avrdude in the normal way.
This code works on the Duemilanove out of the box, but on the Uno we must explicitely force the USART baud doubler off (uncomment the line marked by XXX).
You can use either setbaud.h or the manual method to set the baud rate register, it makes no difference.
I think this is a bug, but can someone confirm this. Anything wrong with the technique? Reproducable? A bug?
Cheers :-/
Edd