Go Down

Topic: Possible Arduino Uno USART Bug (Read 3778 times) previous topic - next topic

vext01

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:
Code: [Select]

#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

Coding Badly

#1
Dec 21, 2010, 08:14 pm Last Edit: Dec 21, 2010, 08:15 pm by bcook Reason: 1
Quote
my serial comms dont work on the Uno, but did on the Duemilanove

Don't work in what way?  From what I can tell, you've described a solution to a problem but haven't described the actual problem.

vext01

#2
Dec 21, 2010, 08:20 pm Last Edit: Dec 21, 2010, 08:22 pm by vext01 Reason: 1
ah sorry. You get junk out of the serial line on the Uno because it is transmitting at double the expected baud rate. This is due to the USART doubler being enabled for some reason.

So, if you set the baud rate to 9600, the Uno transmits at 19200, unless you explicitely turn off the doubler.

Cheers

Coding Badly


Quote
So, if you set

I can't.  You haven't provided enough detail to reproduce what you're seeing.

Quote
the baud rate to 9600, the Uno transmits at 19200

How do you know?

vext01

OK more info. I am using the unix command cu to connect to the serial line on the arduino. To use cu, i do `cu -l cuaU0 -s 9600`.

The above code untouched on the duemianove works fine, the string is sent at 9600 to the terminal emulator.

The same again on an Uno, you get junk because the board is sending at twice the baud rate it should. If you reconnect cu at speed 19200 (2 * 9600), you get the correct outcome.

The reason the Uno trasmits at 19200 instead of 9600 is that U2X0 (serial baud speed doubler) is ON. So the UART baud rate is doubled. In order to make the above program work as expected we turn U2X0 off, hence NOT doubling the serial baud rate.

So something (bootloader?) is setting U2X0 on by default on an Uno, whereas that is off by default on a Deumilanove.

I really can't spell it out more than that.

westfw

Quote
I think this is a bug

The new bootloader runs at 115200bps, and uses U2X mode to get closer to that bitrate.  The old bootloader ran at a different speed and didn't need this (or didn't do it, anyway.)

It may be less than desirable that the bootloader not return all the peripherals that it uses to their default power-on states, but the bootloader is very space constrained, and this is "relatively difficult."

Your program should make sure that it sets all the configuration bits that are needed for correct operation, rather than relying on some bits being in their power-on state.   The arduino libraries have explicitly set U2X for several releases now, initially for compatibility with alternate bootloaders, and more recently to get as close as possible to the correct bitrate.

mellis

Also, we modified the serial baud rate calculation in 0022 (now available), please test with the built-in Serial class in that version, too.

Go Up