вторник

Минус 7 миллисекунд

Кратко:
При прошивке AVR через PINBOARD2+AVRDUDE (программатор 2ftbb) в буфер FT2232 может попасть лишний байт, который вызовет сдвиг всего остального массива и неправильное чтение данных - короче, работать нихера не будет. Такое несчастье случается, если за 7 миллисекунд (плюс-минус километр) до фактического начала прошивки (сброса МК) линия MOSI (которая соединена с пином RX на FT2232) находится в низком уровне. При переключении из BitBang режима в UART FT2232 заглатывает байт 0x00.
В качестве основного симптома - строчка "ft245r_drain called but queue is not empty 1" в логе AVRDUDE перед тем, как он скажет, что ничего не работает.

Чуть подробнее :)



Вечер. На часах пол четвертого. Сижу, пишу код - прошиваю - тестирую - правлю - опять прошиваю.... обычная рабочая обстановка. На столе стоит PINBOARD2 с ATTiny2313 и мешаниной из соединительных проводков.

Хьюстон, у нас проблема!
Хочу добавить в проект работу с индикатором. Обычным таким, светодиодным. В самом начале main() настраиваю порт B на выход. На скорую руку пишу обработку индикатора на таймере. Прошиваю... не пашет. Ну обычная ситуация - туплю в код, правлю баг, собираю проект прошива... ОЙ. Не прошивается!


avrdude.exe: BitBang OK
avrdude.exe: pin assign -
  MISO:2
  SCK:0
  MOSI:1
  RESET:4
  GATES:0
ft245r_drain called but queue is not empty 1
avrdude.exe: drain OK
SET=> ft245r:  bitclk 230400 -> ft baud 115200
avrdude.exe: ft245r_program_enable: failed
avrdude.exe: initialization failed, rc=-1
             Double check connections and try again, or use -F to override
             this check.
Стал вспоминать - что же такое я сделал, что все сломалось. В голову ничего не шло. А руки сами тянулись к ящичку с МК, где должен был лежать еще один 2313. Вот он! Ставим, прошиваем - все ок. После некоторой возни в исходниках, пробую еще раз проши... ОЙ. Опять...

Где-то в ящике со старыми платами должен лежать управляющий контроллер для символьного LCD, а на нем еще один, последний, 2313. Но завтра воскресенье и если я добью и этот камень, то купить новые пока не получится. Мозг, поняв всю опасность положения, туго и со скрипом, но начинает соображать: "Программатор не может общаться с МК" -> "Ему что-то мешает" -> "У нас порт B, где висит интерфейс к программатору, настраивается на выход при старте" -> "Попробуем..."

Убираю в коде настройку DDRB. Грустно глядя две первые жертвы, лежащие рядом с платой, ставлю в панельку третий МК. Прошиваю... все, естественно, ОК. В прошлые разы тоже так было. Пробую прошить второй раз... все работает

Еще немного работаю над кодом и отключаюсь...

Реванш
Просыпаюсь под вечер с мыслью, что так быть не должно. При прошивке МК находится в состоянии сброса (пин RESET прижат к земле) и то, что там понаписано в программе, вообще никак не должно влиять на ситуацию. 

А строчка 
ft245r_drain called but queue is not empty 1 
Из лога AVRDUDE подсказала ответ. 

Кто занимался программированием этой хрени (я про чипы FTDI), тот знает, что у них есть буфер, в который попадают принятые данные. И зовется он как-раз RX Queue. 

А те странные ребята, которые пытались реализовать различные протоколы (SPI, I2C....) при помощи режима Synchronous BitBang в FTDI, знают и помнят, как все ломается, если в RX Queue оказался лишний байт....

На пальцах это выглядит так:
Для того, чтобы переключить пины микросхемы, мы отправляем в микросхему байт, каждый бит которого соответствует определенному пину  (всего можно рулить 8 ножками). В этот момент с ножек, настроеных на выход, считывается текущее состояние, упаковывается в байт и пихается в RX Queue. 

Если затолкать в микросхему 16 байт, в каждом из которых, бит соответствующий 1 пину, будет переключаться (0-1-0-1...), то мы получим 8 импульсов на ножке DBUS1. Так AVRDUDE формирует тактовый сигнал для МК. 
А в RX Queue попадут 16 байт, прочитанных с порта DBUS (биты 0-7). Если теперь взять второй бит из байтов 1, 3, 5... и из этих битов сложить байт, то получим ответ от МК (при условии что он выдает данные на пин DBUS2). Каждый бит будет соответствовать состоянию пина DBUS2 перед переключением DBUS1 в единицу. 
А теперь, представьте, что в самом начале в RX Queue уже был один байт. Тогда нам следовало-бы читать байты со сдвигом (вместо 1,3,5... читать 2,4,6). А если этого не учесть, то в итоге мы "соберем" неправильный ответ от МК. И AVRDUDE посчитает, что произошла ошибка. Так оно и выглядит.

Но есть одно но... а какого фига там будет лишний байт? И почему только тогда, когда пины прижаты к земле? 

* * *
Далее идет немного скучная и нудная история, состоящая из идей, тестов, новых идей, новых тестов, килотонн чая и литров печенек, рейда в логово осьмикота (github.com) за исходниками AVRDUDE, разглядывания данных с лог анализатора...


В действительности все не так, как на самом деле

Первая прошивка проходит нормально. Но после завершения работы, AVRDUDE оставляет чип в режиме Synchronous BitBang. В этом нет ничего плохого, тем более, что на PINBOARD канал "А" у FT2232, как правило, постоянно занят под программатор и в других режимах не используется. Но тем не менее, это часть ошибки. И эта часть всецело принадлежит разработчику патча ft245r для AVRDUDE. 

Вторая прошивка. 
После того, как AVRDUDE открывает нужный канал FT2232, вызывается функция ft245r_drain
static int ft245r_drain(PROGRAMMER * pgm, int display)
{
  FT_STATUS r;
  DWORD n;
  r = FT_SetBitMode(handle, 0, 0x0); // reset 
  if (r != FT_OK) return -1;
  r = FT_SetBitMode(handle, ft245r_ddr, 0x4); // set Synchronuse BitBang
  if (r != FT_OK) return -1;
  r = FT_GetQueueStatus(handle, &n);
  if (r != FT_OK) return -1;
  if (n) {
fprintf(stderr, "ft245r_drain called but queue is not empty %d \n",
(int)n);
  }
  return 0;
}
Она нужна (и вы сейчас поймете всю иронию ситуации!) для сброса чипа, и очистки буферов от всякой фигни. Жирным выделена функция, сбрасывающая чип в начальный режим работы (UART Mode). В тот момент, когда выполняется эта функция, до сброса МК (и фактического начала процесса прошивки) еще около 7 миллисекунд

Переключившись в этот режим, микросхема настраивает ножки в соответствии со схемой UART: TX (DBUS0) - на выход, RX (DBUS1) - на вход. На PINBOARD2 пин DBUS1-RX используется программатором как линия MOSI. А зря.... (и это бага DI HALTa).

Если он болтается в воздухе, то FT2232, через внутренние резисторы подтянет его к линии питания, и в момент переключения в UART-режим, там будет высокий уровень. Затем, когда микросхема будет переведена в BitBang, пин будет прижат к земле (см на экран осциллографа на фотке).

Но у нас PORTB на МК прижат к земле, функция ft245r_drain вызывается в самом начале - то есть МК еще работает, а не сброшен. Пин RX на FT2232 оказывается в низком уровне в тот момент, когда она переключается из режима BitBang (в котором осталась с прошлого раза) в UART-режим. И вот в этот момент в буфер попадает лишний байт! (и это, кажется бага FTDI) Он всегда равен 0x00. И он всегда один. 

Далее порядок байт сдвигается и AVRDUDE не может прочитать сигнатуру МК. При выходе она опять оставляет микросхему в BitBang режиме и все повторяется с начала. 

Итак, 
Future Technology Devices International оставили где-то в чипе или драйвере баг, из за которого при переключении из альтернативного режима в UART-режим, в буфер падает лишний байт, если пин RX находится в низком уровне. 
Японец, замутивший ft245r патч, забыл (забил?) перевести FTDI в UART-режим перед закрытием (это решило бы все проблемы, т.к. переключения Bitbang-UART в самом начале не было бы) или хотя бы тупо очистить буферы, вызвав функцию FT_Purge.
DI HALT, рисуя плату-переходник для программатора AVR, использовал пин RX для линии MOSI. А ведь пинов DBUS там целых 8 штук!

Если бы хоть один из них поступил иначе, все бы нормально работало. И это, черт возьми, красиво! 

Как с этим жить?
Не использовать пин RX в программаторах, работающих с AVRDUDE. 

Патчить AVRDUDE, исправляя косяки Японца. Что-то подобное делал Reddy на http://www.reddylab.eu

Иногда помогает сброс FT2232 кнопкой RESET. Что характерно, помогает именно иногда. А это не вписывается в теорию. Значит есть что-то еще. 

Так-же иногда помогает такой трюк: открыть COM-порт, соответствующий нужному каналу FT2232 в терминале - закрыть - а потом юзать AVRDUDE. Терминалка сбрасывает FTDI в UART-режим после чего AVRDUDE нормально работает (один раз!).

Не трогать MOSI! Если не переводить его в низкий уровень, то все будет отлично работать. Это конечно сильно ущемляет чувства разработчика (как-так?! Нельзя трогать пин?), но зато эффективно. 

7 комментариев:

  1. Лучше бы ты это в we.ee опубликовал.
    P.S. На кой хер, интересно, мне гугльаккаунт, если при попытке написать коммент от него мне все равно предлагается создать аккаунт blogger'а...

    ОтветитьУдалить
    Ответы
    1. А ты авторизуйся имя-урл, и ничего не предлагает :)

      Удалить
    2. Как можно заметить, к этому варианту и прибег. Но нахрена предлагать авторизацию десятком способов, если се равно предлагает завести новый акк? Опять же, у нормального аккаунта плюсы - уведомления, например, не нужно имя каждый раз заново вбивать.
      Спасибо хоть dcoder капчу оторвал.

      Удалить
  2. К перечислению FTDI, японца и DI HALT'а добавь себя, пожелавшего юзать порт. Как-никак именно 4 компоненты приводят к сбою.
    Вывод RX думаю был использован для возможности юзать готовые переходники. Там хорошо, если RTS/CTS выведены, об остальых и говорить не приходится.

    ОтветитьУдалить
    Ответы
    1. Ну переходники тут в принципе ни при чем, поскольку это пинборд и рассчитан он исключительно на встроенную FT-шку.

      Удалить
    2. Ты что, он же весь в белом :)))

      Удалить
  3. Доброго времени dcoder, а как можно с вами связаться?
    Есть несколько глупых вопросов а на форуме как то их игнорируют.

    ОтветитьУдалить