Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Портится старший бит при приёме через UART
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
xelax
Используется бридж USB to UART СР2101 silabs.
Запускаю передачу файла через гипиертерминал. Файл состоит из последовательности ASCII цифорок.
На меге творится что-то странное. На 9600 иногда принимается нормально, иногда через байт то есть например передаю несколько раз 2. на приёме вижу 0х32 0хb2 0x32 0xb2 ... и т.д. со всеми цифрами.
Ситауация исправилась, когда на гипертерминале ставлю два стоп бита.
На скорости 38400 два стоп бита уже не спасают.

Мега работаёт на внутреннем RC генераторе на 4 Мгц. При старте программы генератор калибруется по внешнему часовому кварцу, который для асинхронного таймера.

бодрейт считается так.
Код
#define UART_DOUBLE_SPEED 1ul

enum
{
UART_BAUDRATE_9600 =  (unsigned)((F_CPU * (UART_DOUBLE_SPEED + 1ul)) / (16ul * 9600ul) - 1ul),
UART_BAUDRATE_38400 = (unsigned)((F_CPU * (UART_DOUBLE_SPEED + 1ul)) / (16ul * 38400ul) - 1ul)
}


Вообще что это такое может быть?

З.Ы.

Гоняю данные другой терминальной программой всё ок и на приём и на передачу.
IJAR
[удалил НЕНУЖНОЕ цитирование]


Может быть установка параметра Com порта: "Управление потоком" в GT в в состояние "Нет"
поможет ?
GDI
Может дело не в меге, раз с другой терминалкой работает все? можно попробовать для теста затактировать мегу от кварца, например 7,3728 МГц, ну или с кратным ему, т.е. с таким при котором ошибка скорости заведомо небольшая, а может вы как то не правильно генератор калибруете, попробуйте его не программно откалибровать а воспользоваться калибровочной константой.
xelax
Ну затактировать от кварца к сожалению не могу. Изделия уже были разработаны до моего появления в компании.

Управление потоком тоже отключить не могу, так используется в данном Application.

Все мои тестовые аппликейшены по несколько часов работали на приём/передачу с компом без ошибок.

Калибровка производится правильно. Хотя... Вот код на поругание общественностью smile.gif
Код
#define INTERNAL_CLOCK F_CPU

#define EXTERNAL_TICKS 2*4
#define CYCLE_LENGTH 7
#define REFERENCE_CLOCK 32768
#define REFERENCE_COUNT (INTERNAL_CLOCK * EXTERNAL_TICKS) / (REFERENCE_CLOCK * CYCLE_LENGTH)

static uint16_t Measurement(void)
{
uint16_t cnt = 0;
  ASSR |= (1 << AS2);
  TCCR2B = 1 << CS20;
  ATOMIC_SECTION_ENTER
    TCNT2 = 0;
    while (ASSR & 0x1B);
    do
    {
      cnt++;
    } while (TCNT2 < EXTERNAL_TICKS);
  ATOMIC_SECTION_LEAVE
  return cnt;
}

void CalibrateInternalRc(void)
{
  uint16_t count;
  uint8_t cycles = 0x80;
  do
  {
    count = Measurement();
    if (count > REFERENCE_COUNT)
      OSCCAL--;
    if (count < REFERENCE_COUNT)
      OSCCAL++;
    if (count == REFERENCE_COUNT)
    {
      break;
    }
  } while (--cycles);
}
GDI
Цитата
Ну затактировать от кварца к сожалению не могу. Изделия уже были разработаны до моего появления в компании.

А на ноги припаять кварц нельзя чтоли? Я ж говорю, для теста.
Цитата
Все мои тестовые аппликейшены по несколько часов работали на приём/передачу с компом без ошибок.

А в чем тогда вообще проблема? В том что не работает с конкретным гипертерминалом? На другом компе можно еще попробовать, может это глюк конкретного компа.
xelax
Цитата(GDI @ Feb 29 2008, 13:50) *
А в чем тогда вообще проблема? В том что не работает с конкретным гипертерминалом? На другом компе можно еще попробовать, может это глюк конкретного компа.


Сейчас и попросил тестеров это сделать. Другим терминалом попробовать, попробовать запустить не через USB бридж а напрямую на уарт... Жду пока от них результатов.
=GM=
Цитата(xelax @ Feb 29 2008, 09:56) *
Калибровка производится правильно. Хотя... Вот код на поругание общественностью smile.gif

С первого взгляда вроде бы всё в порядке с программой калибровки, но создаётся такое впечатление, что частота откалибрована немного неверно, поскольку иногда вы принимаете стоп-бит посылки в качестве последнего бита. Возможно, это связано с тем, что программа калибровки написана на си, и в вашем частном случае количество МЦ в цикле измерения не совпадает с заданными в программе 7-ю МЦ, может быть из-за уровня оптимизации, может быть из-за различных версий компилятора или даже другого компилятора...

Попробуйте напрямую выдать сигнал на ножку OC2A (или OC2B) в режиме output compare match и померить частоту сигнала с помощью частотомера. Отсюда легко будет вычислить скорость приёма по рс232.
ReAl
Кроме отклонения RC от номинального значения есть ещё и отклонение частоты UART от номинала за счёт "неUART-ности" частоты в 4МГц.
Я на меге64 внутренний RC 8MHz калибровал по часовому кварцу на 7,373MHz (по апнотам по калибровке можно калибровать в пределах +-10% от базовой частоты) и на 115200 работало без проблем.
Но я калибровал не при старте, а постоянно - SQW от DS1338 было заведено на прерывание и замерялось внутренним таймером расстояние между перепадами (0,5с), подкалибровывался OSCCAL.
Даже "на столе" RC немного плывёт, особенно после старта, поэтому однократная калибровка сразу после включения может быть недостаточной для работы. А уж при изменении температуры...
Но при подкалибровке каждые 0,5секунды работало в том числе при нагреве феном и при охлаждении FREEZ-ом вплоть до образования инея на плате.
Stas633
Попробуйте "сменить" ПО на РС. AVR, наверняка, не при чем, потому что...:

Примерно год назад столкнулся с аналогичной проблемой. Даже тему по этому поводу открывал. Причем я был в полной уверенности, что неправильно работает контроллер. Вроде бы, нашел причину (скорость снизил), сказал "спасибо", а на следующий день проблема вернулась...
.....
Причина, на мой взгляд, не в контроллере и его инициализации, а в работе, настройках и инициализации последовательного порта, или VCP в Вашем случае, на PC.
Я писал свою программу на Borland'e, при этом для RS232 использовал класс ПП (Последовательного Порта) от "comspy" (freeofcharge).
Точно так же "болел" старший бит. Причем болезнь была приходящей (плавающей).
Не помогало ни чего... Ни изменение скорости обмена, ни замена контроллера, ни смена компьютера, ни экранировка каждого провода в соединительном кабеле (до "маразма" доходил в попытках понять причину болезни 05.gif )
Вылечил, заменив класс ПП от comspy на аналогичный от г-на Горского.
Все написанные позже проги с использованием класса от Горского работают с ПП (во всех его видах) на "Ура".
....

В "описании" происходящего процесса целиком и полностью согласен с =GM=:
Цитата(=GM= @ Feb 29 2008, 14:27) *
... иногда вы принимаете стоп-бит посылки в качестве последнего бита....

А вот чего я понять не смог, так это того в чем все-таки разница в инициализации ПП на РС. Оба указанных класса инициализируют ПП "классически" и фактически одинаково.
....
И еще по этому поводу...
http://electronix.ru/forum/index.php?act=S...f=48&t=7846
zltigo
Цитата(Stas633 @ Mar 1 2008, 02:44) *
Попробуйте "сменить" ПО на РС. AVR, наверняка, не при чем, потому что...:

Не верю! Читайте написанное ReAl.
Stas633
Цитата(zltigo @ Mar 1 2008, 13:11) *
Не верю! Читайте написанное ReAl.

Полемику по этому поводу считаю бессмысленной. Я, безусловно, могу ошибаться.
Во всяком случае, для поисков неисправности "в" контроллере сначала необходимо убедиться в правильной работе интерфейса. Именно о таких "граблях" я хочу предупредить.
Советуя обратить внимание на ПО РС, я исходил из:
Цитата(xelax @ Feb 29 2008, 10:10) *
...
З.Ы.
Гоняю данные другой терминальной программой всё ок и на приём и на передачу.

А необходимость правильной установки/калибровки скорости обмена, конечно же, является условием первостепенной значимости для надежной, без сбоев работы интерфейса.

P.S.
Вот comspy от г-на М.Белоусова.
А вот статья и собственно класс для работы с ПП от г-на Ю.Горского. Нажмите для просмотра прикрепленного файла
xelax
К стати баг проявляется только в гипертерминале, тестеры погоняли данные Zoc'ом и там всё ок.

Мне кажется, что здесь скорее зависит всё от дров которые на писишке применяются. Потому что мелкосхемы UART'ов имеют множество дополнительной функциональности. А юзеру писишки предоставляется некий стандартный интерфейс, который обеспечивается виндовыми дровами и который множество функций просто не задействует.
Сам с подобным сталкивался, когда писал софт на писишке для управления микросхемой расширения ISA шины в 4 UARTа. И когда решил применить свой код к UARTу, который стоял на материнке, то к удивлению аппаратные FIFO буферы, документированные для микросхемы, заработали и на материнке. smile.gif

Я думаю, что проблема комплексная гипертерминал кривой и калибровку генератора криво провожу. Посмотрел дизасм кода калибровки в раличных режимах оптимизации. В -O0 она действительно 7 тактов, а при -Os я так и не смог в процедуре понять где она эта калибровка начинается, а где заканчивается, но есть большое подозрение, что она уже не 7 тактов.
ReAl
Цитата(xelax @ Mar 3 2008, 08:59) *
И когда решил применить свой код к UARTу, который стоял на материнке, то к удивлению аппаратные FIFO буферы, документированные для микросхемы, заработали и на материнке. smile.gif
Насколько я помню, были чипы 16450 без FIFO, 16550 с глючным FIFO и 16550A с поправленным. И не помню - можна ли было определить разницу между 16550 и 16550А программно.
В свойствах порта у винды можна было поставить/снять галку "использовать FIFO" и подвигать ползунки порога прерывания на приём и передачу - может, просто в Вашем случае драйвер сам не понял, стоит у него чип с нормальным FIFO или с глючным и галка по умолчанию была снята.
Я сам иногда снимал, когда приходилось работать с чужим оборудованием с встроенной программой, которая захлёбывалась, если от компа валил "зафифошенный" поток без пауз.

Цитата(xelax @ Mar 3 2008, 08:59) *
Посмотрел дизасм кода калибровки в раличных режимах оптимизации. В -O0 она действительно 7 тактов, а при -Os я так и не смог в процедуре понять где она эта калибровка начинается, а где заканчивается, но есть большое подозрение, что она уже не 7 тактов.
А зачем было вообще так делать? Сделайте так:
Прерывание по таймеру2, когда он отсчитал нужное число циклов (причём это можно делать не только при старте, см. мой предыдущий пост), в этом прерывании чтение нового состояния таймера1, определение дельты с предыдущим состоянием таймера1 и подкоррекция OSCCAL прямо в прерывании. Разброс времени входа в прерывание чепуха по сравнению с периодом прерываний, RC-генератор всё равно грубее шаг имеет. Я метки времени от внешних часов даже не на ICP заводил а на обычное прерывание, смысла нет выжимать лучше нескольких сот микросекунд на фоне 0,5секунды (это 0,1%, куда тому RC).
И никакой зависимости от оптимизатора (если работа программы зависит от установленного уровня оптимизации компилятора, то в 99.9% случаев это ляп или как минимум недоработка разработчика программы).
xelax
Цитата(ReAl @ Mar 3 2008, 11:01) *
И никакой зависимости от оптимизатора (если работа программы зависит от установленного уровня оптимизации компилятора, то в 99.9% случаев это ляп или как минимум недоработка разработчика программы).


Полностью согласен.

smile.gif В свою защиту хочу сказать, что код достался мне по наследству, а посему досконально не проверялся.

А по поводу таймеров идея хорошая, но в моих условиях нереализуемая. Так как поверх моих функций народ пишет свои приложения и запросто может так совпасть, что прерывание от таймера возникнет в момент длинной по времени критической секции. Тогда все тайминги уплывут и откалибруется неправильно.
Надо существующий вариант доделывать до верного. Например переписать на асме, чтобы не зависеть от уровня оптимизации.
ReAl
Цитата(xelax @ Mar 3 2008, 13:48) *
smile.gif В свою защиту хочу сказать, что код достался мне по наследству, а посему досконально не проверялся.
Такой код надо проверят в первую очередь smile.gif

Цитата
запросто может так совпасть, что прерывание от таймера возникнет в момент длинной по времени критической секции. Тогда все тайминги уплывут и откалибруется неправильно.
Если "критическая секция" займёт аж милисекунду, то что-то очень неправильно в Датском королевстве. Но даже в этом случае ошибка будет на уровне 1мс/500мс = 0,2% - при шаге перестройке RC на единичку OSCCAL в несколько раз больше эта ошибка не повлияет на калибровку.

Цитата
Надо существующий вариант доделывать до верного. Например переписать на асме, чтобы не зависеть от уровня оптимизации.
Существующий вариант - с однократной калибровкой в начале - до верного можно доделать только методом переписывания на прерывания, чтобы обеспечить постоянную подкалибровку. Пальца на микроконтроллер достаточно, чтобы RC поплыл и понадобилось OSCCAL изменить. На этом фоне даже такой ужас, как критическая секция на четыре-восемь тысяч циклов процессора при постоянной подкалибровке повлияет меньше, чем открытое окно зимой при однократной калибровке.
alex1979
Цитата(xelax @ Feb 29 2008, 09:10) *
Используется бридж USB to UART СР2101 silabs.
Запускаю передачу файла через гипиертерминал. Файл состоит из последовательности ASCII цифорок.
На меге творится что-то странное. На 9600 иногда принимается нормально, иногда через байт то есть например передаю несколько раз 2. на приёме вижу 0х32 0хb2 0x32 0xb2 ... и т.д. со всеми цифрами.
Ситауация исправилась, когда на гипертерминале ставлю два стоп бита.
На скорости 38400 два стоп бита уже не спасают.

Мега работаёт на внутреннем RC генераторе на 4 Мгц. При старте программы генератор калибруется по внешнему часовому кварцу, который для асинхронного таймера.

бодрейт считается так.
Код
#define UART_DOUBLE_SPEED 1ul

enum
{
UART_BAUDRATE_9600 =  (unsigned)((F_CPU * (UART_DOUBLE_SPEED + 1ul)) / (16ul * 9600ul) - 1ul),
UART_BAUDRATE_38400 = (unsigned)((F_CPU * (UART_DOUBLE_SPEED + 1ul)) / (16ul * 38400ul) - 1ul)
}




Вообще что это такое может быть?

З.Ы.

Гоняю данные другой терминальной программой всё ок и на приём и на передачу.



недавно сам столкнулся с подобной проблеммой.
Решение: вместо вычистения скорости по формуле в регистр UBRR записал пердопределенную константу из даташита.

Пример:
u16 bauddiv = 51;
outb(UBRRL, bauddiv);
#ifdef UBRRH
outb(UBRRH, bauddiv>>8);
#endif
Lexdaw
А вот еще был случай...Короче опторазвязанный USART сбоил из-за оптрона - затягивал фронты.
xelax
wacko.gif Реально наблюдаю на осцилографе картинку, с писишки идут посылки через байт из посылки выкидывается последний бит, затем нормальная и т.д...

На писишке запускаю гипертерминал. Любые другие программульки отправляющие что-то через компорт отправляют байты нормально....

Я в шоке wacko.gif , похоже это первый и последний раз когда я использую гипертерминал.

З.Ы.
Один плюс из всего этого... Калибровку сделал нормальную smile.gif
alux
Цитата(alex1979 @ Mar 7 2008, 13:13) *
Решение: вместо вычистения скорости по формуле в регистр UBRR записал пердопределенную константу из даташита.

У меня тоже были проблемы с передачей данных по UART, пока не сделал так:
Код
#define ROUND(f) (signed long)((f)+(((f)>0.0)?(0.5):(-0.5)))

// USART setting
#define baud_rate   115200
#define baud_select ROUND((double)f_cpu/(baud_rate*8L)-1)

int main()
{
uart_Init(baud_select);
...........
}

void uart_Init(unsigned int ubrr)
{
  UCSR1A = (1<<U2X1);               // Double the USART Transmission Speed
  UCSR1B |= (1<<RXCIE1)|(1<<RXEN1)|(1<<TXEN1); //Разрешить прием и передачу, прерывание "Прием завершен"
  UCSR1C |= (3<<UCSZ10);            //8-бит данных, 1 стоп-бит, no parity    
  UBRR1H = (unsigned char)(ubrr>>8);
  UBRR1L = (unsigned char)ubrr;     // f=7.3728 MHz, 115200 baud, error 0.0%
}
xelax
smile.gif Тема древняя...
Ну раз подняли снова, просто опишу итог, чтобы поставить точку.

Проблема в Hyperterminal, причём проявлется только на машинах DELL. Почему не знаю.

Только данная проблема проявляется не только на avr, точно так же не работают атмеловские армы через uart. И что меня окончательно убедило в том, что проблемы в писюке, так это то, что реализованный virtual com port на usb, получил такие же проблемы. Битые подобным образом байты наболюдал usb sniffer'ом SnoopyPro в bulk out канале.

На сим тему считаю завершённой.
zltigo
Цитата(alex1979 @ Mar 7 2008, 12:13) *
недавно...

Moderator:
Не сочтите за труд не заниматься тупым ненужным цитированием постов.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.