Pages: [1]   Go Down
Author Topic: Possible Arduino Uno USART Bug  (Read 3332 times)
0 Members and 1 Guest are viewing this topic.
UK
Offline Offline
Newbie
*
Karma: 0
Posts: 8
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
#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
Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 208
Posts: 12931
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
« Last Edit: December 21, 2010, 02:15:25 pm by bcook » Logged

UK
Offline Offline
Newbie
*
Karma: 0
Posts: 8
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
« Last Edit: December 21, 2010, 02:22:17 pm by vext01 » Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 208
Posts: 12931
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


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?
Logged

UK
Offline Offline
Newbie
*
Karma: 0
Posts: 8
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

SF Bay Area (USA)
Offline Offline
Tesla Member
***
Karma: 134
Posts: 6762
Strongly opinionated, but not official!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Forum Administrator
Cambridge, MA
Offline Offline
Faraday Member
*****
Karma: 12
Posts: 3538
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Pages: [1]   Go Up
Jump to: