2

I have an atmega162 chip on stk500 dev board connected to ubuntu with serial cable. On atmega, I initialize usart and write some bytes. On Ubuntu side, something comes out of the pipe, but it's definitely not what was sent...

To be more precise: For each byte sent, I get a series of about 6 or 7 bytes, each of them with either 0x00 or 0xC0 values.

Relevant snippets of my code:

compile flags:

CFLAGS = -g
CFLAGS += -mmcu=atmega162
CFLAGS += -W -Wall -Wshadow
CFLAGS += -Os
CFLAGS += -mcall-prologues
CFLAGS += -finline-limit=10
CFLAGS += -mno-interrupts
CFLAGS += -ffunction-sections
CFLAGS += -DF_CPU=7372800ULL

usart functions:

void Serial0Init(int baud)
{
        unsigned int    ubrr;

        ubrr = ((F_CPU+8*baud)/(16*baud))-1;
        // Baud rate
        UBRR0H = (unsigned char)(ubrr>>8);
        UBRR0L = (unsigned char)ubrr;
        UCSR0A &= ~(1 << U2X0); // U2X off
        // Transmission settings
        UCSR0C = (1<<URSEL0)|(3<<UCSZ00);       // 8N1
        UCSR0B = (1<<RXEN0)|(1<<TXEN0);
}

unsigned char Serial0CheckTxReady()
{
        return (UCSR0A&_BV(UDRE0));     // nonzero if transmit register is ready to receive new data.
}

void Serial0Write(unsigned char data)
{
        while (Serial0CheckTxReady()==0)        // while NOT ready to transmit
                {}
        UDR0 = data;
}

main code:

Serial0Init(9600);
Serial0Write('!');

I receive data with simple python script:

import serial
import os

port = serial.Serial('/dev/ttyS0', 9600)

print 'Reading from serial...'
while True:
  c = port.read()
  print c, ord(c)

I double checked byte size settings and baud rate calculations, and everything seems okay... Any ideas what I'm doing wrong?

dsolimano
  • 8,870
  • 3
  • 48
  • 63
Bob
  • 39
  • 2
  • 1
    This issue definitely looks like a baud rate problem. Are you sure that your MCU is running at 7.372 MHz? I suggest to check the fuse setting of the clock source. If the external oscillator is selected as the clock source you should check its settings too (e.g. the STK500 clock generator frequency). Also check the Atmega161 compatibility fuse. As long as you are compiling for Atmega162 the compatibility mode should be disabled to prevent possible side-effects. – Pavel Zhuravlev Oct 21 '13 at 03:32
  • 1
    Also check the expression used to calculate `ubrr`. With sizeof(int)==2 its calculation may result in overflow and thus incorrect result. I suggest to hard-code the `UBRR0` value for test purposes. – Pavel Zhuravlev Oct 21 '13 at 03:46
  • Okay, your hints were very helpful. I found the problem. It was indeed baud rate calculation. Fixed formula looks like this: ubrr = ((F_CPU+8*(long int)baud)/(16*(long int)baud))-1; – Bob Oct 27 '13 at 19:00
  • In other words - the only problem was hidden conversion to 16-bit int, which ruined the result. – Bob Oct 27 '13 at 19:02

1 Answers1

1

As far as I can tell (and was already suspected in the comments), the baud rate calculation is wrong.
Try

UBRR = ((fOSC / (16 * BAUD)) - 1

what results in

UBRR = 47

for 9600 @ 7372800MHz.

Rev
  • 5,827
  • 4
  • 27
  • 51
  • The problem is not with the formula itself (I found it inside avr libraries, so I was pretty sure it was okay), but with conversion to 16-bit int. And indeed, after casting to long int, I got 47 and everything works fine. – Bob Oct 27 '13 at 19:04
  • @Bob: You are right that the cast was the problem, but the (8*(long int)baud)) part in your equation is wrong nevertheless. However, this this isn't much of an issue since it just results in 47.5, which becomes 47 due to the integer division anyway. – Rev Oct 27 '13 at 19:26
  • Like I said: I saw this trick inside avr libraries - it's obviously used to round the result to nearest integer value. In other words, it does round(ubrr) instead of floor(ubrr). (And indeed, when using usart friendly clock rates, it doesn't matter anyway) – Bob Oct 27 '13 at 20:51
  • @Bob: Ah OK, that makes sense. No further argument from here ;) – Rev Oct 28 '13 at 07:44