USB bootloader на микроконтроллере: обновление прошивки с флешки
Возможность обновления прошивки на серийно выпускаемых изделиях, или на единичных изделиях, находящихся в эксплуатации у заказчика трудно переоценить. Это не просто даёт возможность последующего устранения багов и расширения функционала, но и позволяет разработчику с более лёгким сердцем выпускать «еще сыроватый» продукт на рынок, если руководство того требует.
Поэтому важность наличия bootloader'а во вновь разрабатываемых устройствах в большинстве случаев не вызывает сомнений. В данной статье пойдет речь о разработке bootloader'а по интерфейсу USB на микроконтроллере Atmel SAM D21 с ядром Cortex M0+. А конкретно на SAMD21J18A. У микроконтроллеров SAM D20/21 нет предзаписанного бутлоадера, поэтому придётся заниматься его программной реализацией. На сайте Atmel можно найти Application notes, как сделать его с использованием стандартных интерфейсов (UART, I2C, SPI, USB). Под катом описание процесса создания USB-бутлоадера.
Постановка задачи- Необходимо разработать наиболее простой, с точки зрения конечного пользователя, способ обновления прошивки устройства. Для этого потребуется скопировать на обыкновенную флешку файл с новой прошивкой, воткнуть флешку в устройство и нажать кнопку reset (или пересбросить питание). После этого стартует bootloader, проверяет наличие файла с прошивкой на флешке и заливает содержимое этого файла в качестве application
- В качестве «защиты от дурака» используем заранее известное специальное название файла прошивки, что бы исключить случайное совпадение имен с другими файлами на флешке. При этом если «злоумышленник» самостоятельно создаст сторонний файл с именем, совпадающим с ожидаемым, устройство будет пытаться использовать его в качестве прошивки. Разумеется, в этом случае работоспособность устройства будет нарушена, но её можно будет впоследствии восстановить подсунув флешку с корректной прошивкой
- В качестве USB интерфейса используется аппаратный USB микроконтроллера устройства
- Устройство не имеет постоянного подключения к интернету, что бы самостоятельно скачать новую прошивку
- Считаем что подключение ПК к устройству и обновление прошивки с помощью сторонней утилиты является более сложным для конечного пользователя
Адресное пространство в памяти микроконтроллеров серии SAMD20/21 устроено просто:
Энергонезависимая память организована рядами, каждый ряд содержит 4 страницы. Размер 1 страницы 64 байта. Энергонезависимая память стирается рядами, а записывается постранично. Это важно помнить. Нижние (младшие) ряды в основном адресном пространстве энергонезависимой памяти могут быть использованы для бутлоадера (настраивается с помощью фьюзов BOOTPROT), а верхние ряды для эмуляции EEPROM. Bootloader-секция защищена соответствующими этому адресному пространству lock-битами и фьюзами BOOTPROT. Фьюзы BOOTPROT одновременно определяют размер bootloader-секции и защищают выделенную область памяти от чтения. EEPROM может быть записана несмотря на защиту соответствующей ей области памяти.
Что потребуется для организации bootloader'а?- Работа с памятью контроллера – за это отвечает контроллер энергонезависимой памяти Non-volatile memory (NVM);
- Работа с USB – за это отвечает контроллер USB;
- Работа с файловой системой – это под силу FATFS.
- И по мелочи: работа с портами ввода/вывода, тактирование.
Примечание: в качестве среды разработки используется Atmel Studio версии 6.2 (наследница AVR Studio) и фреймворк ASF (Atmel Software Framework)
Тонкости USBВ соответствии со стандартом USB для реализации шины необходимо очень точное тактирование. Мы будем использовать внешний кварц на 32 кГц как опору для DFLL (Digital Frequency Locked Loop). Выход DFLL будет использоваться как для тактирования USB модуля, так и всего контроллера. Для работы USB модуля необходимо настроить DFLL так, чтобы на выходе было ровно 48 МГц. Для стабильности и точности выходной частоты DFFL он должен быть сконфигурирован в режиме closed loop.
Собираем проектС помощью ASF wizard подключаем все необходимые нам модули, перечисленные выше.
USB HostДобавляем USB Host service в режиме mass storage.
- conf_usb_host.h – конфигурирует USB и настраивает обработчики прерываний (Callback),
- conf_access.h – конфигурирует абстрактный уровень для работы с памятью.
Для этого щелкаем правой кнопкой мыши по проекту, выбираем Properties -> Toolchain -> ARM/GNU C Compiler -> Symbols. Комментируем строку "#define Lun_usb_unload — NULL" в USB LUNs Definitions в файле conf_access.h для предотвращения ошибок при компиляции. Для отслеживания подключенных устройств на шине USB вводится обработчик прерывания (callback) по событию Start of Frame. Это прерывание происходит только один раз при каждой посылке SOF, а так как SOF посылается раз в 1 мс, когда устройство подключено к шине, то это событие можно использовать как таймер. Обработчик прерывания прописываем в файле conf_usb_host.h. Для этого добавляем прототип функции main_usb_sof_event() в начале файла conf_usb_host.h после всех #include'ов.
Так же добавляем в этот файл строку:
Теперь требуется глобально определить переменную-счетчик в файле main.c, именно ее будем увеличивать при каждом вызове соответствующего обработчика:
Добавляем собственно обработчик прерывания (callback):
Файловая системаДобавляем FAT FS file system service (c помощью ASF wizard). Раскрываем модуль и выбираем режим RTC драйвера calendar_polled. Для полноценного функционирования модуля файловой системы добавляем в начале main.c:
Имя файла (#define FIRMWARE_FILE «firmware.bin») должно совпадать с именем файла прошивки на подключаемой флешке.
Работа с энергонезависимой памятьюДобавляем NVM-Non-volatile memory (driver). Кроме этого определяем необходимые константы и переменные в файле main.c:
Еще нужно сконфигурировать контроллер энергонезависимой памяти. Для этого добавляем конфигурационную структуру (глобально), считываем настройки по умолчанию, изменяем необходимое и устанавливаем (оформляем в отдельную функцию):
Все необходимые модули добавлены, можно писать код.
Стоит отметить, что если в бутлоадер использует ту же периферию, что и application, то ее нужно обязательно сбросить перед переходом в application. Сброс (reset) осуществляется специальными функциями в ASF. Также замечу, что обращаться к USB устройству можно только после 1-2 секунд с момента его подключения к шине, так как до этого происходит инициализация устройства. Краткий алгоритм работы (только bootloader) приведен на рисунке ниже: