Неверные данные, считанные с передачи AVR USART

У меня есть чип atmega162 на плате разработчика stk500, подключенный к Ubuntu с помощью последовательного кабеля. На атмеге я инициализирую usart и записываю какие-то байты. На стороне Ubuntu что-то выходит из канала, но это определенно не то, что было отправлено...

Чтобы быть более точным: для каждого отправленного байта я получаю серию примерно из 6 или 7 байтов, каждый из которых имеет значения либо 0x00, либо 0xC0.

Соответствующие фрагменты моего кода:

флаги компиляции:

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-функции:

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;
}

основной код:

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

Я получаю данные с помощью простого скрипта Python:

import serial
import os

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

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

Я дважды проверил настройки размера байта и расчеты скорости передачи данных, и все кажется в порядке ... Есть идеи, что я делаю неправильно?


person Bob    schedule 20.10.2013    source источник
comment
Эта проблема определенно выглядит как проблема со скоростью передачи данных. Вы уверены, что ваш MCU работает на частоте 7,372 МГц? Я предлагаю проверить настройку предохранителя источника тактового сигнала. Если в качестве источника тактовой частоты выбран внешний генератор, необходимо также проверить его настройки (например, частоту тактового генератора STK500). Также проверьте предохранитель совместимости Atmega161. Пока вы компилируете для Atmega162, режим совместимости должен быть отключен, чтобы предотвратить возможные побочные эффекты.   -  person Pavel Zhuravlev    schedule 21.10.2013
comment
Также проверьте выражение, используемое для вычисления ubrr. С sizeof(int)==2 его вычисление может привести к переполнению и, следовательно, к неверному результату. Я предлагаю жестко закодировать значение UBRR0 для целей тестирования.   -  person Pavel Zhuravlev    schedule 21.10.2013
comment
Хорошо, ваши подсказки были очень полезны. Я нашел проблему. Это действительно был расчет скорости передачи данных. Фиксированная формула выглядит так: ubrr = ((F_CPU+8*(long int)baud)/(16*(long int)baud))-1;   -  person Bob    schedule 27.10.2013
comment
Другими словами - единственная проблема заключалась в скрытом преобразовании в 16-битный int, что испортило результат.   -  person Bob    schedule 27.10.2013


Ответы (1)


Насколько я могу судить (и уже было подозрение в комментариях), расчет скорости передачи данных неверен.
Попробуйте

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

что приводит к

UBRR = 47

для 9600 @ 7372800 МГц.

person Rev    schedule 21.10.2013
comment
Проблема не в самой формуле (я нашел ее в библиотеках avr, поэтому был уверен, что все в порядке), а в преобразовании в 16-битный int. И действительно, после приведения к long int у меня получилось 47 и все работает нормально. - person Bob; 27.10.2013
comment
@Bob: Вы правы в том, что проблема была в приведении, но часть (8 * (long int) baud)) в вашем уравнении, тем не менее, неверна. Однако это не является большой проблемой, так как это просто приводит к 47,5, что в любом случае становится 47 из-за целочисленного деления. - person Rev; 27.10.2013
comment
Как я уже сказал: я видел этот трюк в библиотеках avr - очевидно, он используется для округления результата до ближайшего целого числа. Другими словами, он делает round(ubrr) вместо floor(ubrr). (И действительно, при использовании дружественных usart тактовых частот это не имеет значения) - person Bob; 28.10.2013
comment
@Bob: Ах, хорошо, это имеет смысл. Дальше спора нет ;) - person Rev; 28.10.2013