Компактный USB HID Bootloader для ATtiny85


Представляю вашему вниманию новый компактный Bootloader для AVR Tiny 45/85. Данный автозагрузчик распространяется под лицензией GNU GPL, как того требует лицензия V-USB. Основой для данного автозагрузчика послужил ATtiny85 USB Boot Loader от Embedded Creations и его потомок micronucleus-t85, используемый платами Digispark.
Также как и вышеупомянутые, TinyHID Loader основан на библиотеке V-USB.

Ключевые особенности:


  • Работает под ATtiny45 и ATtiny85
  • Компактен (2кб с базовыми функциями)
  • Расширяем (есть ряд дополнительных функций, включение которых увеличит размер)
  • Не треубет драйверов (что особенно важно под новые версии Windows)
  • Не работает с AVRdude, использует вместо этого кросплатформенное API на C#
  • Умеет обновлять сам себя


А почему вообще AVR Tiny 85?


Экономика должна быть экономной, господа. А с AVR Tiny x5 вы экономите дважды да ещё и в двух вопросах. Первый — это вопрос цены: «тиньки» дешевле «мег». Но персонально у Tiny x5 есть PLL генератор, позволяющий также отказаться от кварцевого резонатора. Так что экономим на нём да и на двух конденсаторах. Кроме того есть ещё и вопрос места на плате. В QNF корпусе таракан размером 2,5 на 2,5 мм. И снова нам не нужен резонатор. Всю схему можно легко уместить на смехотворных 12x5 мм. Как резюме — использование AVR Tiny 85 уместно всегда, и особенно для USB девайсов пока не появится необходимость в функционале, которого данный таракан не поддерживает (например когда нужно много IO портов)

А зачем специальный автозагрузчик?


Автозагрузчиков для AVR Mega пруд пруди, но с Tiny 85 всё не так просто. Для понимания этих сложностей, излагаю алгоритм работы классики:

  • Если конфигурационный бит BOOTRST установлен в 0, то после перезапуска контроллер начинает исполнение не с нулевого адреса, а с Boot Reset Address (специфичен для разных моделей и может настраиваться).
  • По Boot Reset Address располагается сам автозагрузчик, который первым делом перемещает таблицу прерываний на Boot Reset Address.
  • автозагрузчик определяет, нужно ли грузиться ему самому или нет. Если нужно, то он запускается как обычная прошивка, хоть и расположенная не в нулевом адресе.
  • Если загружать автозагрузчик не надо, то он перемещает таблицу прерываний обратно на нулевой адрес, и переводит туда же управление, тем самым загружая прикладную прошивку.
  • Во время записи данных на Flash, автозагрузчик продолжает работать с USB протоколом, отвечая на запросы хоста.
  • Также область памяти автозагрузчика является незаписываемой, что не даёт автозагрузчику повредить себя.


А теперь нюансы 85-ой Tiny:

  • ATtiny всегда загружается с нулевого адреса, сконфигурировать его на другой адрес нельзя.
  • Вектора прерываний также никуда не переносятся.
  • Во время записи контроллер приостанавливает работу на 4.5 мс, и не на что не способен реагировать.
  • Ну и аппаратной защиты от самозаписи у автозагрузчика тоже нет.


И способы обхода.

  • Очищенная память заполнена единицами, которые трактуются контроллером как NOP. А это значит что после сброса, управление до автозагрузчика таки дойдёт. Хоть перед этим и будет выполнены полторы тысячи NOP-ов.
  • Но для функционирования USB протокола этого ещё мало. Нужна также реакция на прерывание PCINT0. Таблицу векторов прерываний перемещать нельзя, но можно записать в эту таблицу адреса автозагрузчика. Поэтому сразу после первой загрузки автозагрузчик записывает в RESET и PCINT0 вектора адреса своих обработчиков.
  • Во время записи прикладной прошивки автозагрузчик также заменяет RESET и PCINT0 вектора.
  • Изначальные RESET и PCINT прикладной прошивки автозагрузчик пишет в адреса непосредственно перед автозагрузчиком.
  • Доработка V-USB шного обработчика PCINT0 таким образом, чтобы он мог вызывать PCINT0 обработчик прикладной прошивки. Условием для работы обработчика автозагрузчика считаем TCCR1 == 0 && TCNT1 == 0xff. Иначе запускаем обработчик приложения.
  • Задержка перед выполнением записи или очистки памяти. В это время контроллер успевает сообщить хосту о успехе операции, и хост его не теряет.
  • После проведения операции очистки памяти, автозагрузчик всегда записывает свои вектора RESET и PCINT0.
  • Перед записью прикладной прошивки, автозагрузчик производит очистку FLASH из конца в начало. Такое направление очистки гарантирует, что даже если процесс очистки/записи будет прерван неожиданным отключением питания, автозагрузчик останется в рабочем состоянии. Либо первая страница FLASH ещё не затёрта/уже записана, и управление на автозагрузчик перейдет по вектору. Либо очищена вся память, и управление перейдет на автозагрузчик через цепочку NOP-ов.
  • Производится программная проверка записи в автозагрузчик вместо аппаратной.


Более подробно о особенностях работы автозагрузчика на AVR Tiny 85 можно почитать на сайте Embedded Creations на английском

А зачем изобретать велосипед?


Использование классических MEGA-вских автозагрузчиков на AVR tiny не возможно по причинам, описанным в предыдущей главе. Но даже без них есть 2 реализации автозагрузчика: ATtiny85 USB Boot Loader и micronucleus-t85, и обе они эмулируют некогда популярный программатор USBasp. А вышеупомянутый программатор работает на хосте через библиотеку libusb. Это замечательная и многофункциональная библиотека, и её использование под Mac OS или Linux элементарно как 2x2. И если вы свои творения собираетесь использовать сами, то TinyHID Loader вам может приглянуться разве что более компактными размерами. Но вот под Windows 8.1 x64 установка libusb драйвера уже не является тривиальной задачей. Глубоко-глубоко в настройках есть пункт, позволяющий разово перезагрузить компьютер с отключенной проверкой электронной подписи драйверов. И горе тому, кто будет объяснять типичному юзеру этот способ. Поэтому основной идеей было создание автозагрузчика, способного работать через HID Feature Report-ы. Для всех HID устройств используются стандартные драйвера ОС, и дополнительные ставить не надо. Также оказалось, что отказ от поддержки avrdude приносит возможность сократить вес загрузчика. При отключении всех опций кроме записи/очистки FLASH и программного выхода в прикладную прошивку, автозагрузчик весит 2кб, что меньше чем у конкурентов.

А как использовать?


Для начала нужно сконфигурировать прошивку. Для этого нужно скорректировать файл firmware/usbloader/usbloader.h под вашу схему и ваши нужды:

// Нога ATtiny, к которой подключен USB D-
#define USB_CFG_DMINUS_BIT 2

// Нога ATtiny, к которой подключен USB D+
#define USB_CFG_DPLUS_BIT 1

// Нога ATtiny, к которой подключен светодиод
// (можно раскоментить, но объём увеличится)
// #define LED_PIN 4

// Нога ATtiny, заземление которой приводит к старту загрузчика (экстренное включение загрузчика)
// (можно закоментить для сохранения места)
#define START_JUMPER_PIN 0

// Установить в 1, если требуется возможность очистки EEPROM (что заметно увеличит объём загрузчика)
#define CAN_ERASE_EEPROM 0
// Установить в 1, если требуется возможность чтения FLASH (что заметно увеличит объём загрузчика)
#define CAN_READ_FLASH 0
// Установить в 0, если не нужен программный переход в прикладную прошивку (что уменьшит объём загрузчика)
#define CAN_LEAVE_LOADER 1


При этом не нужно заботиться, чтобы USB_CFG_DPLUS_BIT попал на ногу INT0, так как автозагрузчиком используется прерывание PCINT0, которое можно сконфигурировать на любую ногу.
В приведённом выше варианте загрузчик укладывается в 2кб, хотя и впритык. Включение любых дополнительных опций выведет его за эти пределы, и придётся заодно менять его расположение в памяти. Делается это по разному в зависимости от того, используете ли вы AtmelStudio, или Makefile

Atmel Studio

Удостоверьтесь, что выбрана конфигурация Release.
Откройте свойства проекта, перейдите на вкладку Toolchain, и в пункте «AVR/GNU Linker/Memory Settings» уменьшите значение ".text=0xc00". Уменьшать можно только порциями по 32 слова. То есть 0xbe0, 0xbc0, 0xba0. 0xba0 хватит для работы всех доступных опций, дальше уменьшать не надо. Помимо этого, нужно также уменьшить значение константы BOOTLOADER_WADDRESS. Это можно сделать на странице «AVR/GNU C Compiler/Symbols». Значение должно равняться значению ".text=".
После конфигурирования нужно скомпилировать проект (F7) и можно его заливать на контроллер внешним программатором.

Makefile

Откройте файл Makefile, и уменьшите константу BOOTLOADER_ADDRESS до требуемого значения. Уменьшать можено только порциями по 64 байта (AtmelStudio использует слова, а Makefile — байты). То есть 17c0, 1780, 1740. 1740 хватит для работы всех доступных опций, дальше уменьшать не надо.
После конфигурирования нужно скомпилировать проект, набрав в коммандной строке make и можно его заливать на контроллер внешним программатором.
Готово, внешний программатор вашей схеме более не нужен, переходим к софту на компьютере.

Software

Утилита, заливающая прошивку на контроллер написана на C#, проект разработан в VisualStudio 2012, но его можно открыть и в Xamarin для дальнейшей работой с MONO. Для общения с HID используется кроссплатформенная библиотека HidSharp, что сделает ваш MONO проект по настоящему кроссплатформенным.
Утилита загрузки крайне проста в использовании:
TinyLoaderCmd.exe firmware.hex

И через 3 секунды таракан прошит и готов к работе. Если прошивка была создана с конфигом по-умолчанию, то запуск утилиты не только прошьёт контроллер, но и по готовности запустит записанную прошивку.
Кроме того, можно использовать API TinyHID Loader из вашего проекта на C#:
void UploadNewFirmware(string file)
{
	HexFile file = new HexFile(args[0]);
	Loader ldr = Loader.TryGetLoader(40);
	byte[] programm = new byte[Loader.LOADERSTART];
	for (int i = 0; i < programm.Length; i++) programm[i] = 0xff;
	file.Fill(programm);
	ldr.WriteFlash(programm, 0);
	ldr.LeaveBootloader();
}

А если в вашей прошивке добавить функцию загрузки автозагрузчика:
void runBootloader()
{
	cli();
	TCCR1 = 0;
	TCNT1 = 0xff;
	asm volatile ("rjmp __vectors");
}

То перепрошивка превратиться для пользователя в нажатие одной кнопки. А ваш проект в то время:

  • Сообщит вашей прошивке, что нужно загрузить автозагрузчик.
  • Дождётся (Loader.TryGetLoader) момента, когда система подцепит автозагрузчик.
  • Запишет новую прошивку.
  • Сообщит автозагрузчику, что нужно загрузить прошивку.
  • Дождётся момента, когда система подцепит вашу новую прошивку.


А если понадобился другой набор опций?


Поставили полный набор опций и новая прошивка теперь не влезает? Или жалеете, что не добавили возможность чтения памяти? Ну или вам вообще не подходит TinyHID Loader, и без avrdude жизнь не мила? А ведь микроконтроллер уже не только прошит, но и запаян. И выпаивать его совсем не хочется. Не вопрос — TinyHID Loader умеет перерошивать сам себя!
Алгоритм самоперепрошивки такой:

  • С командной строки пользователь воодит TinyLoaderCmd.exe reload bootloader.hex (как вариант — никто ничего не вводит, и процесс вы реализуете через API из вашего софта на хосте)
  • Утилита создаёт прошивку для перезаливки. В неё входит образ нового автозагрузчика, сводная информация о нём (целевой адрес в FLASH и CRC16) а также специальная утилита обновления (reloader).
  • Прошивка заливается на микроконтроллер обычным путём как и любая другая прошивка.
  • Девайс перезагружается (может и программно, если эта опция не отключена), и управление передётся reloader-у.
  • Reloader проверяет корректность нового автозагрузчика, сверяя CRC16 а таже его размеры и способность уместиться на девайсе.
  • При успехе всех проверок reloader очищает первую страницу памяти. С этого момента дороги назад нет. И если произойдёт выключение питания, управление на старый bootloader передано не будет.
  • Основной этап — копирование нового автозагрузчика из образа в реальные адреса, а также очистка страницы непосредстенно перед автозагрузчиком (так как её используют все автозагрузчики)
  • И в финале — переход по вектору RESET нового автозагрузчика — при этом автозагрузчик переинициирует FLASH и начнёт работу

Гарантиями безопасности reloader-а являются проверка CRC и логика процесса, который запустится снова в случае непредвиденного завершения. Но некорректная новая прошивка превратит таракана в кирпич, и воскресить его сможет только программатор. Поэтому будьте аккуратны — проверяйте корректность настроек.
Также при помощи reloader-а можно прошить TinyHID Loader на девайс с другим программатором. То есть заменить вообще любой автозагрузчик AVR Tiny 85 на любой другой.

Особые благодарности:

  • Библиотеке V-USB для микроконтроллеров Atmel за саму возможность работы с USB
  • ATtiny85 USB Boot Loader от Embedded Creations за описание тонкостей создания автозагрузчика для AVR Tiny 85
  • автозагрузчику micronucleus-t85 за саму идею уменьшения объёма.
  • BootloaderHID за мысль о том, что переход на HID только кажется дорогим в вопросе веса. Отказ от совместимости с avrdude позволяет выиграть больше.
  • Рассово немецкому FunkUsb за идею сменить osccal.c на osctune.h, что существенно уменьшает вес кода
  • +23
  • 42.6k
  • 5
Share post

Comments 5

    0
    Также приглашаю желающих присоединиться к проекту. Требуется — профилирование, перевод комментов на English, создание build скриптов под разные платформы. Да и любой вклад, который вам интересно преподнести.
      0
      Было бы интересно, если бы получилось меньше 2кб, потому что 2кб это то, что получается из V-USB с автоподстройкой частоты.

      Я писал софт для обновления прошивок на Adobe Air (Win/Mac), расширение для работы с HID выложил в свободный доступ code.google.com/p/air-hid-usb/.
        0
        тоже самое бы на C#, уже несколько дней мучаюсь перебираю библиотеки для работы с HID…
          0
          Лучшее для работы с HID, что я нашёл для C# (и что использую в приведённой выше статье) — HidSharp; он работает под Win/Mac/Linux.
        0
        Я так понимаю что порт RESET становиться простым портом ввода/вывода в данном случае?

        Only users with full accounts can post comments. Log in, please.