Ох, уж эти AVR-ки!

Сижу, пишу проект. В проекте используется UART в режиме синхронной передачи данных.

Необходимость загонять UART в режим синхронной передачи продиктована требованиями протокола — нужно передавать по геофизическому кабелю данные в коде Manchester-II.

Я уже как-то писал, что для создания Манчестерского кода как нельзя лучше подходят AVR-ки. И в самом деле, среди других микроконтроллеров, которые я знаю и которые у меня есть в наличие — MSP430 и STM32, только ATMEGA способны генерить синхросигнал во время передачи данных по UART. Остальные либо вообще не умеют этого делать (MSP430), либо считают не нужным вырабатывать синхроимпульсы во время «стартового» и «стопового» битов (STM32).

В общем, написал я код, отправил заказчику. Сижу  в предвкушение удачного запуска оборудования оплаты договора.

Хрен там!

Заказчик рисует страшную картину: система то работает, то не работает. Начинаем разбираться. Оказывается, что система не работает в моменты, когда ширина первого Манчестерского импульса меньше, чем нужно. Ширина импульсов манчестерского кода напрямую зависит от ширины синхроимпульсов XCK.

Вот, одна осциллограмма, на которых желтый луч — это выход TXD: чёткий однозначный переход от единичного уровня к нулевому. Нулевой уровень — это стартовый бит.

Лиловый луч — выход XCK. Перед началом стартового бита на выходе XCK присутствует какая-то 10-ти микросекундная хрень.

Но это ещё цветочки!

На следующей осциллограмме ситуация ещё интереснее:

За 110 микросекунд до начала стартового бита выскакивает какой-то непонятный короткий импульс. Непосредственно перед стартовым битом присутствует полноценный синхроимпульс.

Вот, (неполный) код, который запускает работу передатчика UART:

void start_tx(const uint8_t *p, uint8_t len)
{
  ...

  ibuf_out = 0;
  UCSR0C |= _BV(UMSEL00); // Запускаем XCK
  UCSR0B |= _BV(UDRIE0);  // Разрешаем прерывание по пустому буферу
}

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

Время между запуском XCK и загрузкой UDR0 исчисляется единицами микросекунд — 1-2 мкс, максимум 5 мкс! Но на осциллограммах мы видим времена около 100 мкс.

Это наводи на мысль, что тактовый генератор работает сам по себе, и команда запуска XCK только открывает выход генератора на ножку микроконтроллера. Поскольку исполнение команд и тактовый генератор XCK не синхронизированы, то мы имеем на выходе XCK импульсы переменной ширины.

А вот что касается выхода TXD, то тут, как ни странно, производится какая-то внутренняя синхронизация со счётчиком-делителем UBBR0. Иначе чем объяснить запаздывание фронта стартового импульса, которое исчисляется сотней микросекунд? 100 микросекунд — это очень большой кусок времени.

Ладно. Я могу закрыть глаза, на то что синхроимпульсы появляются до фронта стартового бита. пусть будет хотя бы так:

Но ведь и такую картинку, чтобы получить, нужно написать не очень «чистый» с моей точки зрения код. Вот, он:

void start_tx(const uint8_t *p, uint8_t len)
{
  ...

  ibuf_out = 0;
  UCSR0C |= _BV(UMSEL00); // Запускаем XCK
  UCSR0B |= _BV(UDRIE0) | _BV(TXEN0);  // Разрешаем передачу
}

Здесь изменена последняя команда. Теперь вместо того чтобы просто разрешить прерывания по пустому входному буферы мы ещё умудряемся одновременно включить передатчик (бит TXEN0).

Я как-то не особо уверенно себя чувствую, когда так делается. Я привык, что сначала происходит включение периферийного узла, а затем настройка его параметров. Но, видимо, в AVR-ках считается нормальным делать это всё сразу. По крайней мере, оно работает. А других способов получить синхронные сигналы XCK и TXD я не вижу.

Реклама

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s