Bootloader usb что это
Об использовании USB-загрузчика у NXP имеется аппноут AN10986 (код). Я же попробую в рамках курса для новичков рассказать его по-русски.
На данном этапе отладчик нам не нужен, поэтому отключаем его от USB.
Для данного урока вам не подойдет LPC1114 поскольку в нем нет USB, не спотря на то, что они подписаны на плате.
Схема
- Земля, aka GND. Тут как бы без вопросов: земля разъема USB обязана быть объединена с землей контроллера;
- Питание для платы будем брать с USB. На самой плате предусмотрен вывод +5VIN предназначенный для подключения внешнего источника питания на 5 вольт. Соответственно этот вывод и подключаем к USB +5V;
- D- заводим на USB-DM вывод платы;
- D+ заводим на USB-DP вывод платы;
- Что бы контроллер мог обнаружить подключение к USB шине (и понял, что требуется USB версия загрузчика взамен UART), подключаем +5 вольт с USB на вывод USB-VBUS платы;
- Что бы компьютер, в свою очередь, смог определить, что к нему подключено USB full-speed устройство, линию D+ подключаем через резистор 1.5КОм к выводу +3.3вольта. Номинал желательно не менять. У меня работало и с резюками 1.3к-1.6к, но нет гарантии, что оно будет работать стабильно.
- Что бы контроллер понял, что требуется режим загрузчика, вывод FT/GPIO платы подключаем через переключатель на землю. При замкнутом за землю выводе у нас будет режим загрузки, а при разомкнутом – режим выполнения прошивки.
Возможные проблемы
Если что-то начало сильно греться, или вдруг задымилось, то, вероятно, вы просто перепутали полярность.
Если ОС сообщает что подключено неизвестное устройство, то проверьте правильность монтажа. Правильно ли подключено питание. Не перепутаны ли выводы D+ и D-. Правильный ли установлен резистор.
Думаю так же стоит упомянуть про возможность защиты кода. Как видно на картинке, метка диска у контроллера CRP disabld, что означает отключенную защиту. У вас будет точно так же, если вы конечно прежде ни где ничего не натворили. Но если вдруг метка другая, то у вас могут возникнуть трудности с чтением/записью прошивки. Подробнее написано в аппноуте.
Прошиваем контроллер
- Копируем файл firmware.bin с контроллера (съемного диска, соответствующего нашей плате) к себе на диск.
- Удаляем файл с контроллера. Это приведёт к стиранию прошивки.Отключаем плату от USB и разрываем соединение FT/GPIO с землёй, тем самым вернув контроллер в режим исполнения прошивки.
Подключаем плату к компьютеры через USB-разъем отладчика и видим что светодиод просто тускло светит. И правильно, в контроллере то нет никакой прошивки.
Отключаем плату от USB и восстанавливаем подключение FT/GPIO с землёй.
Подключаем плату через новый USB разъем. Должен снова появиться диск с файлом firmware.bin, но в нем уже будет мусор.
Возвращаем сохраненный файл firmware.bin на контроллер (на запрос заменить, отвечаем утвердительно).
Повторно отключаем плату от USB и разрываем соединение FT/GPIO с землёй, повторно вернув контроллер в режим исполнения прошивки.
Снова подключаем плату к компьютеры через USB-разъем отладчика и видим что светодиод снова начал мигать.
Отступление для Linux и MacOS
В Linux и MacOS не всё на столько удобно. В связи с особенностью этих систем (по непонятным причинам) писать на пустой диск новый файл, начиная не с первого сектора, а со второго, контроллер в итоге прошивается не правильно.
Но выход есть и тут. Достаточно файл прошивки принудительно записать начиная с первого сектора, например, с помощью dd. Конечно менее удобно чем простое перетаскивание файлов, но линуксойдам не привыкать.
В статье описывается, как быстро запустить USB bootloader для микроконтроллера ATmega32 на примере загрузчика usbasploader компании Objective Development.
Технология USB bootloader дает одну-единственную возможность — отсутствие необходимости в специальном программаторе для замены программного обеспечения (firmware) в приборе — достаточно подключения к компьютеру по USB. Больше нет необходимости таскать с собой программатор, так как компьютер и USB есть везде. Если Ваша макетная плата оснащена bootloader, то можно сэкономить деньги на покупке программатора или время на его изготовлении — это бывает немаловажно для начинающих.
Для AVR понаделано очень много bootloader-ов — см. [1]. Для статьи я выбрал именно usbasploader [2] потому, что он совместим с очень популярным программатором USBasp. Это позволяет перепрошивать firmware как под Linux, так и под Windows с использованием популярных программ (см. [3]) avrdude, eXtreme Burner — AVR, Khazama AVR Programmer и даже из среды программирования BASCOM-AVR (система программирования на бейсике BASCOM-AVR — маленькое чудо, достойное отдельной статьи). Кроме того, usbasploader поставляется со всеми исходниками, отлично задокументирован и легко адаптируется под нужды пользователя (об этом далее).
Загрузчик usbasploader работает очень просто — при подключении к USB он прикидывается программатором USBasp. Поэтому все программы, его поддерживающие, будут перезаписывать firmware в Вашем устройстве, как будто они используют программатор USBasp. Bootloader расположен в старших адресах flash-памяти программ микроконтроллера, и записывает программу пользователя в младшие адреса (обычно начиная с адреса 0), т. е. при перепрошивке микроконтроллера bootloader не затирается. После окончания записи bootloader передает управление программе пользователя. Теперь подробнее, как это работает с микроконтроллерами ATmega, на примере ATmega32.
Для ATmega32 usbasploader скомпилирован так, чтобы он размещался во flash с адреса 7000h (напомню, что адресное пространство памяти программ ATmega32 составляет 0000h..7FFFh, и адрес команды кратен двум байтам, т. е. адреса команд лежат в диапазоне 0000h..37FFh). Для программы пользователя остается свободным пространство 0000h..6FFFh (28672 байт). Загрузчик usbasploader использует заложенную в микроконтроллер ATmega32 возможность запуска с адреса, расположенного в старших адресах памяти программ (доступно несколько фиксированных адресов, выбираемых перемычками — фьюзами, см. [4]). Чтобы при включении питания и сбросе управление всегда передавалось на адрес 0x7000, необходимо запрограммировать перемычки (фьюзы, fuse-bits) BOOTSZ0 и BOOTSZ1 в соответствующее состояние (под bootloader должно отводиться 4000h байт, или 2048 слов кода программы), а также запрограммировать перемычку BOOTRST. После этого код при сбросе или включении будет стартовать не с адреса 0, а с адреса 3800h в словах команд AVR, или с адреса 7000h в байтах flash (напомню, что минимальный размер команды AVR — два байта).
Получив управление после сброса, код usbasploader проверяет условие своей активизации, т. е. сигнал, по которому он должен начать работать как программатор USBasp. Обычно таким сигналом является замыкание какой-нибудь ножки на землю. Для макетной платы в качестве такой ножки я выбрал PB5 микроконтроллера ATmega32. Эта ножка является одновременно и сигналом MOSI, выведенным на коннектор, поэтому перемычкой между контактами 4 и 6 коннектора U1 ISP очень удобно подавать на PB5 сигнал лог. 0. Итак, код usbasploader проверяет уровень на порте PB5, и если там лог. 0 (перемычка между ножками 4 и 6 коннектора U1 ISP установлена), то начинается работа как программатора USBasp. Т. е. при установленной перемычке в момент включения питания bootloader активизируется, и если его подключить к компьютеру, то в компьютере появится USB-устройство USBasp. Если в момент включения питания перемычки нет (при этом на PB5 микроконтроллером читается лог. 1), то usbasploader сразу передает управление в программу пользователя (на адрес 0). Вот такой нехитрый алгоритм запуска.
В usbasploader есть возможность изменить поведение bootloader, для этого достаточно отредактировать три функции (они очень простые, и находятся в файле bootloaderconfig.h) — bootLoaderInit, bootLoaderCondition, bootLoaderExit. Назначение функций практически очевидно по названиям. Функция bootLoaderInit предназначена для конфигурирования окружения, в котором возможно отслеживание условие активизации bootloader:
static inline void bootLoaderInit( void )
DDRB |= (1 //на PB5 (MOSI, контакт 4 коннектора U1 ISP) подключаем pull-up и зажигаем светодиод
PORTB |= (1 >
Код очень прост — он только подключает на ножку PB5 подтягивающий к плюсу внутренний нагрузочный резистор (pull-up) — это позволяет определить наличие перемычки между контактами 4 и 6 коннектора U1 ISP, и зажигает красный светодиод на макетке. Функция bootLoaderCondition предназначена для проверки — есть или нет перемычка между контактами 4 и 6:
Если перемычка стоит, то ножка PB5 читается как лог. 0, и функция bootLoaderCondition вернет 1 (что означает — bootloader работает). Если перемычки нет, то функция вернет 0, что означает неактивность для bootloader (управление немедленно передается по адресу 0 — в программу пользователя). Функция bootLoaderExit у меня не делает ничего, только гасит красный светодиод макетки:
Приведенный код для функций bootLoaderInit, bootLoaderCondition, bootLoaderExit можно рассматривать в качестве примера — их можно и нужно переделать под Ваши нужды, и тогда usbasploader будет работать именно так, как Вы хотите. В заключение опишу процесс по шагам на платформе Windows (предполагается, что у Вас уже установлены AVRStudio и среда WinAVR. Если нет — читайте инструкции, как их установить, по ссылке [6]).
[Как встроить в Ваш проект usbasploader]
1. Нужно скачать последнюю версию usbasploader (см. [2]), например USBaspLoader.2009-03-20.zip. Если у Вас макетная плата AVR-USB-MEGA16, то предлагаю скачать вариант по ссылке [5] — там уже все готово, и шаги 2, 3, 4 можно пропустить. Распаковываете в любую удобную папку.
2. Отредактируйте установки в Makefile. Там нужно поменять:
а) определение F_CPU — частоту в Гц, на которой работает микроконтроллер. Домустимы частоты 12, 15, 16, 16.5 и 20 МГц.
б) определение DEVICE под Ваш тип микроконтроллера.
в) адрес (формат шестнадцатеричный, единицы в байтах) загрузки кода usbasploader BOOTLOADER_ADDRESS.
г) (необязательно, если Вы будете прошивать чип не из Makefile) проверить и при необходимости скорректровать определения FUSEOPT и LOCKOPT, а также определение AVRDUDE.
3. Отредактируйте bootloaderconfig.h. Там нужно проверить и при необходимости поменять:
а) макрос USB_CFG_IOPORTNAME — буква имени порта, к которому подключены сигналы USB D- и D+.
б) макросы USB_CFG_DMINUS_BIT и USB_CFG_DPLUS_BIT — номера портов, которым подключены сигналы D- и D+. Сигнал D+ обязательно должен быть подключен на ножку прерывания INT0.
в) код функций bootLoaderInit, bootLoaderExit и макрос bootLoaderCondition.
4. Перекомпилируйте проект, для этого введите make. В командной строке увидите что-то наподобие:
После успешной компиляции получите в корневой папке проекта файлы main.bin и main.hex — готовая прошивка для usbasploader. Кстати, в папке hexfiles уже есть несколько скомпилированных версий прошивок для кристаллов ATmega8, ATmega88, ATmega168, на разные частоты кварца.
5. Необходимо с помощью программатора прошить в чип код usbasploader, правильно установить фьюзы. Смысл этой операции — код usbasploader необходимо положить в верхнюю область памяти (по адресу BOOTLOADER_ADDRESS), и установить фьюзы таким образом, чтбы при сбросе или включении питания начал выполняться код bootloader (я уже об этом писал). Подробности по фьюзам см. по ссылке [4] и в даташите на Ваш микроконтроллер. Для микроконтроллера ATmega32, например, фьюзы должны быть установлены следующим образом:
LOW FUSE BYTE: 0xCF
HIGH FUSE BYTE: 0xD8 (можно и 0x98, чтобы разрешить JTAG-отладку)
LOCKOPT BYTE: 0xEF
Макетную плату AVR-USB-MEGA16 можно приобрести с уже прошитым usbasploader и фьюзами, поэтому шаги 1, 2, 3, 4, 5 проделывать не нужно.
6. Необходимо подключить прошитую макетную плату к компьютеру по USB. Если ничего не напутали, то макетка определится в системе как новое устройство и система Windows запросит драйвер. Драйвер можно скачать со странички [2], или взять из архива по ссылке [5]. Для Linux драйвер не нужен.
7. Нужна одна из программ, работающих с программатором USBasp (см. ссылки [3]). Для пользователей Linux подойдет avrdude, а для пользователей Windows выбор очень широк. Я рекомендую Khazama AVR Programmer с очень простым и удобным интерфейсом.
[Как работать с загрузчиком usbasploader на примере макетки AVR-USB-MEGA16 и Khazama AVR Programmer]
1. Поставьте перемычку между ножками 4 и 6 коннектора U1 ISP.
2. Подключите макетную плату к компьютеру по USB. На макетке загорится красный светодиод, и в системе Windows обнаружится программатор USBasp.
3. Запустите программу Khazama AVR Programmer. В настройках уберите опцию очистки памяти кристалла (Command -> Program Options -> снимите галку Erase Chip). Выберите из выпадающего списка Ваш чип. Загрузите hex-файл прошивки (через меню File -> Load FLASH file to Buffer). Нажмите большую кнопку Auto Program, запускающую программирование. Программируется кристалл очень быстро, за несколько секунд.
После окончания программирования красный светодиод погаснет, и начнет выполняться Ваша программа с адреса 0 (которую Вы только что записали).
4. Снимите перемычку между ножками 4 и 6 коннектора U1 ISP.
UPD100711: написал статью про другой USB bootloader — BootloadHID. По исходному коду и стилю работы очень похож на USBASPloader. Отличается тем, что требует специальной программы на компьютере, но зато легче встраивается в младшие чипы (начиная с ATmega8), т. к. снижены требования к размеру 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
- conf_usb_host.h – конфигурирует USB и настраивает обработчики прерываний (Callback),
- conf_access.h – конфигурирует абстрактный уровень для работы с памятью.
Так же добавляем в этот файл строку:
Теперь требуется глобально определить переменную-счетчик в файле main.c, именно ее будем увеличивать при каждом вызове соответствующего обработчика:
Добавляем собственно обработчик прерывания (callback):
Файловая система
Добавляем FAT FS file system service (c помощью ASF wizard). Раскрываем модуль и выбираем режим RTC драйвера calendar_polled.
Для полноценного функционирования модуля файловой системы добавляем в начале main.c:
Работа с энергонезависимой памятью
Добавляем NVM-Non-volatile memory (driver). Кроме этого определяем необходимые константы и переменные в файле main.c:
Еще нужно сконфигурировать контроллер энергонезависимой памяти. Для этого добавляем конфигурационную структуру (глобально), считываем настройки по умолчанию, изменяем необходимое и устанавливаем (оформляем в отдельную функцию):
Все необходимые модули добавлены, можно писать код.
Стоит отметить, что если в бутлоадер использует ту же периферию, что и application, то ее нужно обязательно сбросить перед переходом в application. Сброс (reset) осуществляется специальными функциями в ASF.
Также замечу, что обращаться к USB устройству можно только после 1-2 секунд с момента его подключения к шине, так как до этого происходит инициализация устройства.
Краткий алгоритм работы (только bootloader) приведен на рисунке ниже:
В этом уроке мы рассмотрим загрузку прошивки в ардуино через внешние “программаторы”. Давайте вспомним, о чем уже говорили в одном из первых уроков: загрузка прошивки в Arduino возможна двумя способами:
- “Напрямую” во flash память микроконтроллера при помощи ISP (In System Programming) внутрисистемного программатора.
- При помощи загрузчика (bootloader), который живёт в конце Flash памяти МК, принимает программный код по протоколу TTL (UART) и записывает его во Flash память.
ISP программатор
USBasp
Дешёвые ISP программаторы также есть в ассортименте у китайцев, рекомендую брать USBasp как самый распространенный. Поискать на алиэкспресс, мне нравится версия в корпусе. USBasp имеет не очень удобный выход 10-пин на шлейфе, поэтому рекомендуется купить также переходник 10-пин на 6-пин, который позволяет сразу подключаться к ISP header’у, который есть на большинстве плат Arduino. Внимание! Очень часто встречается брак в виде непропая контактов, поэтому во избежание проблем рекомендуется пропаять переходник и отмыть флюс (зубная щётка + бензин калоша).
Фьюзы
Конфигуратор платы в Arduino IDE устроен следующим образом: каждой плате в Инструменты > Плата соответствует свой набор настроек, включая фьюзы, которые прошиваются вместе с загрузчиком . Некоторые из них:
- Загрузчик (путь к файлу)
- Скорость загрузки (через загрузчик)
- Объем доступной flash и sram памяти
- Весь набор фьюзов и лок-биты
Файл конфигурации называется boards.txt и найти его можно в папке с ядром Arduino: C:\Program Files (x86)\Arduino\hardware\arduino\avr\boards.txt. Документацию на boards.txt можно почитать здесь. При желании можно вывести нужные фьюзы через калькулятор (читайте выше), изменить их в boards.txt (главное не запутаться, для какой выбранной конфигурации платы делается изменение) и прошить в МК, нажав Инструменты > Записать загрузчик.
- Фьюзы подписаны как low/high/extended fuses, можно вставлять полученное в калькуляторе значение.
- Локбиты работают следующим образом: unlock_bits это локбиты, которые прошьются до записи загрузчика (при нажатии на кнопку Записать загрузчик). А вот после прошивки загрузчика будут автоматически прошиты lock_bits, которые и определят доступ к памяти контроллера во время его работы. Чтобы защитить прошивку от чтения – ставим lock_bits 0x3C.
Такая работа с фьюзами максимально неудобна, но есть и другие варианты:
- Ядро GyverCore для atmega328, в нем мы сделали кучу готовых настроек фьюзов прямо в настройках платы, читайте в уроке про GyverCore. Несколько загрузчиков, включая вариант без загрузчика, выбор источника тактирования и другие настройки в один клик мышкой.
- Программа AVRdudeprog, про нее поговорим ниже
Фьюзы (Pro)
Фьюзы (фьюз-биты) являются низкоуровневыми настройками микроконтроллера, которые хранятся в специальном месте в памяти и могут быть изменены только при помощи ISP программатора. Это такие настройки как выбор источника тактирования, размер области памяти под загрузчик, настройка отсечки по напряжению и прочее. Фьюз-биты собраны по 8 штук в байты (т.н. байты конфигурации), как типичный регистр микроконтроллера AVR. Таких байтов может быть несколько, они называются low fuses, high fuses, extended fuses. Для конфигурации байтов рекомендуется использовать калькулятор фьюзов (например, вот такой), в котором просто ставятся галочки на нужных битах, и на выходе получается готовый байт в hex виде. Рассмотрим на примере ATmega328p:
Важный момент: в AVR биты у нас инверсные, то есть 1 это выкл, 0 это вкл. Расставляя галочки в калькуляторе, мы формируем байт, галочка стоит – бит включен, но в результирующем байте включенные биты являются нулями. Об этом стоит задумываться при ручном составлении фьюз-байта, при использовании калькулятора можете об этом даже не вспоминать. Что позволяют настроить биты?
- CKSEL0–CKSEL3 – выбор источника и частоты тактирования (уточняй в даташите на свой МК, какая конфигурация за что отвечает)
- SUT0–SUT1 – задержка старта МК после перезагрузки
- CKOUT – дублирование тактирования на один из пинов (см. в даташите на какой)
- CKDIV8 – делит тактовую частоту на 8
- BOOTRST – если включен, МК запускается с загрузчика
- BOOTSZ0–BOOTSZ1 – задаёт размер сектора загрузчика
- EESAVE – защита EEPROM от стирания во время выполнения полной очистки чипа
- WDTON – если включить, то Watchdog будет принудительно включен без возможности отключения
- SPIEN – опасный бит , при его отключении пропадает возможность прошивки через ISP, и возможность выключить этот бит в том числе*
- DWEN – вкл/выкл отладочный интерфейс DebugWire. На других моделях бывает и JTAG, и его бит – JTAGEN
- RSTDISBL – опасный бит , при его включении можно использовать ногу RST как обычный цифровой пин, но пропадает возможность прошивки через ISP и выключить этот бит как следствие*
- BODLEVEL0–BODLEVEL3 – настройка контроля напряжения (МК сбросится при падении ниже установленного напряжения)
* – прошивка возможна при помощи высоковольтного программатора
Загрузка скетча
В Arduino IDE можно зашить скетч через программатор, для этого надо нажать Скетч > Загрузить через программатор. Это очень удобно в том случае, когда МК используется без загрузчика, или просто голый МК.
Avrdudeprog
- Чтение/запись/очистка flash памяти
- Чтение/запись/очистка eeprom памяти
- Полная очистка чипа
- Калькулятор фьюзов и локбитов (чтение/запись)
Более подробный обзор на avrdudeprog можно посмотреть здесь . Давайте посмотрим на калькулятор фьюзов. Выбираем свой микроконтроллер и программатор (можно добавить другие модели микроконтроллеров и программаторов, читай тут). Переходим во вкладку Fuses, нажимаем прочитать. При успешном чтении увидим текущий набор настроек своего чипа. Можно их поменять и загрузить. Важно! Галку инверсные биты не трогаем! Лок-биты и отключение RST заблокирует микроконтроллер, не трогайте их, если такой цели нет! Можно загружать прошивку или загрузчик из .hex файла, указав путь к ней на первой вкладке в окне Flash. Очень удобная утилита для низкоуровневой работы с МК.
Решение проблем
Решение большинства проблем с загрузкой через программатор (независимо от того, что написано в логе ошибки):
- Вытащить и обратно вставить usbasp в usb порт
- Вставить в другой usb порт
- Переустановить драйвер на usbasp
- Проверить качество соединения USBasp с МК
- Перепаять переходник и отмыть флюс
Для прошивки микроконтроллера, тактирующегося низкой частотой (менее 1 МГц внутренний клок):
- USBasp: на плате есть перемычка JP3, которая включает режим низкой скорости загрузки. В новых версиях прошивки для USBasp скорость выбирается автоматически, но китайцы продают старую версию. Как прошить новую – ищите в интернете.
Решение проблем
Для прошивки микроконтроллера, тактирующегося низкой частотой (менее 1 МГц внутренний клок):
- Arduino ISP: нужно изменить частоту загрузки прошивки в скетче Arduino ISP и снова прошить его в ардуино-программатор (см. строку в скетче 45 и ниже);
Загрузчик (bootloader)
Загрузчик живёт в самом конце Flash памяти МК и позволяет записывать прошивку, отправляемую через UART. Загрузчик стартует при подаче питания на МК, ждёт некоторое время (вдруг кто-то начнёт слать код прошивки по UART), затем передаёт управление основной программе. И так происходит каждый каждый раз при старте МК.
- Загрузчик позволяет прошивать МК через UART;
- Загрузчик замедляет запуск МК, т.к. при каждом запуске ждёт некоторое время для потенциальной загрузки прошивки;
- Загрузчик занимает место во Flash памяти. Стандартный старый для Arduino NANO занимает около 2 кБ, что весьма существенно!
- Именно загрузчик мигает светодиодом на 13 пине при включении, как индикация работы.
Работа в Arduino IDE
Прошивка загрузчика
Из Arduino IDE при помощи ISP программатора мы можем записать другой загрузчик (по факту загрузчик + фьюзы) и загрузить скетч, а также настроить/прошить фьюзы и лок-биты, но не очень удобным способом. Когда мы выбираем плату в Инструменты > Плата и загрузчик в Инструменты > Плата (загрузчик, bootloader), Arduino IDE автоматически делает “активным” нужный загрузчик. Нажимая Инструменты > Записать загрузчик мы прошиваем загрузчик, соответствующий выбранной плате и её настройкам. Также одновременно с загрузчиком прошиваются фьюзы и лок-биты, соответствующие выбранной плате в Arduino IDE. Как и где их поменять, смотрите чуть ниже. Рассмотрим на примере записи загрузчика для atmega328, стоящей на китайской плате Arduino NANO. На данный момент китайцы прошивают в МК старую версию загрузчика, которая называется old bootloader в меню платы. Оригинальные платы идут с более современным загрузчиком, поэтому при работе с китайскими платами нам приходится выбирать old bootloader для загрузки прошивки через бортовой usb порт. Подключим usbasp по схеме выше, выберем его как программатор в Инструменты > Программатор, выберем плату Arduino NANO, загрузчик для atmega328 (первый в списке). Нажмём записать загрузчик. Всё! Теперь плату можно шить через бортовой usb порт, выбирая первый загрузчик. Он кстати легче, быстрее “прошивает” и сама прошивка быстрее “запускается”.
Arduino as ISP
Почти любая другая плата Arduino может стать ISP программатором, для этого нужно просто загрузить в неё скетч ArduinoISP:
- Открыть скетч Файл > Примеры > 11. ArduinoISP > ArduinoISP
- Всё! Ваша Arduino теперь стала ISP программатором
- Подключаем к ней другую Arduino или голый чип по схеме ниже
- Выбираем Arduino as ISP в Инструменты > Программатор
- И можем писать загрузчики, фьюзы или загружать прошивку напрямую во Flash
ISP программатор подключается к четырем пинам микроконтроллера, не считая питания: один из пинов передает сброс, остальные – для передачи данных. Чтобы плата-программатор не сбрасывалась при загрузке, на неё нужно:
- Либо поставить поставить конденсатор ёмкостью ~10 мкФ между RST и GND (рекомендуется)
- Либо просто закоротить пины RST и 5V проводом
По использованию других плат Arduino в качестве программатора читай на официальном сайте.
Лок-биты (Pro)
Лок-биты (lock-bits) позволяют управлять доступом к памяти микроконтроллера, что обычно используется для защиты устройства от копирования. Лок-биты собраны опять же в конфигурационный лок-байт, который содержит: BOOTLOCK01, BOOTLOCK02, BOOTLOCK11, BOOTLOCK12, LOCKBIT1, LOCKBIT2 (для ATmega328). Калькулятор лок-битов можно использовать этот. BOOTLOCK биты позволяют запретить самому МК запись (самопрограммирование) во flash память (область программы и область загрузчика)
А вот локбиты LOCKBIT позволяют запретить запись и чтение flash и EEPROM памяти извне, при помощи программатора, т.е. полностью защитить прошивку от скачивания и копирования:
Таким образом включив LOCKBIT1 (лок-байт будет 0x3E) мы запретим внешнюю запись во Flash и EEPROM память, т.е. при помощи ISP программатора, а включив LOCKBIT1 и LOCKBIT2 (лок-байт: 0x3C) полностью заблокируем заодно и чтение данных из памяти микроконтроллера. Повторюсь, всё описанное выше относится к ATmega328p, для других моделей МК читайте в соответствующих даташитах.
Основные ошибки в логе Arduino IDE
- Проверить и сменить USB порт
- Попытаться переустановить драйвер
- Проверить пайку USB разъема на плате программатора
- Проверить наличие и целостность элементов вблизи usb разъема программатора, кварцевый резонатор
- Возможно программатор криво прошит – при возможности попытаться перепрошить
- Возможно микроконтроллер на плате программатора – брак или же мертв, попытаться заменить и прошить
avrdude: error: program enable: target doesn't answer. Причина – usbasp не видит подключаемый микроконтроллер
- Проверить правильность и целостность соединения с МК
- Попытаться снизить частоту прошивки, джампером или же указав более низкую скорость в среде программирования
- Проверить пайку разъема 10 pin и переходника 10 pin – 6 pin
- Возможно прошиваемый микроконтроллер попался с браком, или же мертв.
USB-TTL (UART)
Этот способ реализован прямо на платах Arduino при помощи USB-TTL (USB-UART) преобразователя, именно поэтому мы можем подключить плату к компьютеру и загрузить код. USB-TTL позволяет только загрузку данных во flash, остальные возможности (как у ISP программатора) ему недоступны. В то же время он ограничен только возможностями загрузчика, но в этом уроке мы рассматриваем только стандартные. Также USB-TTL мост позволяет микроконтроллеру общаться с компьютером по последовательному соединению (тот самый Serial и монитор com порта). Есть платы без бортового USB-TTL, например Arduino Pro Mini. Для работы с ними нужно купить внешний USB-TTL преобразователь. Также загрузка прошивки через UART возможна и в “голый” микроконтроллер при условии наличия там загрузчика, который запишет принятый код во flash. Про запись загрузчика мы поговорим ниже. UART “загружатор” подключается к пинам RX и TX Ардуино (или микроконтроллера), RX->TX и TX->RX, также обязательно подключается земля GND. Если у прошиваемой платы нет своего питания, то подключается и питание. Загрузчик отрабатывает при запуске МК, поэтому непосредственно перед загрузкой прошивки МК должен быть сброшен (перезагружен), и для этого на платах USB-UART есть вывод DTR (Data Terminal Ready), который подключается к пину RST Reset и собственно выполняет сброс перед перед загрузкой прошивки. На платах Pro Mini есть отдельный пин DTR.
USB-TTL | Arduino |
DTR | DTR |
RX | TX |
TX | RX |
GND | GND |
VCC/5V/3.3V | VCC |
Китайцы выпускают USB-TTL модули в широком ассортименте, но в целом они все одинаковые по своей сути. Ссылка на результат поиска на aliexpress, и ссылка на все USB-TTL в моём любимом магазине WAVGAT. Что использую я? В основном платку на CP2102. Перед заказом модуля обязательно убедитесь в том, что у него есть выход DTR, иначе этот модуль можно будет использовать только для “общения” с контроллером через COM порт. Для работы с таким преобразователем нужно установить драйвер для чипа, на базе которого собран модуль, это может быть CP2102, CH340/341, FT232, PL2303 и другие. Прошивка загружается как обычно: выбираем порт, на котором сидит преобразователь, версию загрузчика и жмём загрузить, всё! Важный момент: на некоторых китайских версиях плат Arduino Pro Mini не распаян пин DTR, т.е. он не идёт на RST и автоматический сброс перед загрузкой прошивки не выполняется. В этом случае сброс нужно производить вручную, кнопкой RST, непосредственно перед загрузкой прошивки… Загрузка прошивки посредством загрузчика (bootloader) возможна с любого UART устройства, даже через Bluetooth. Но об этом мы поговорим в отдельном уроке.
Программатор
Помимо записи прошивки во flash память, программатор позволяет:
- Считывать содержимое Flash памяти (скачать прошивку на компьютер)
- Полностью очищать чип от всех данных и настроек
- Записывать и читать загрузчик
- Считывать/записывать EEPROM память
- Читать и настраивать фьюзы (fuses, fuse-bits) и лок биты.
Программатор – ваш единственный друг при работе с “голым” микроконтроллером, то есть для его низкоуровневой настройки и загрузки прошивки.
Видео
Приветствую всех на нашем сайте, и сегодня мы после небольшого перерыва вернемся к теме микроконтроллеров. А если быть совсем точным, то начинаем обсуждать одну очень интересную и важную тему, а именно использование bootloader'а (загрузчика). Сегодня разберем теоретическую часть - зачем bootloader нужен, как он работает, и что это вообще такое. Следующая статья будет посвящена целиком и полностью практике. Забегая вперед, скажу, что мы реализуем свой bootloader для STM32 с нуля.
Итак, простыми словами, bootloader - это специальная программа, которая располагается в памяти контроллера и может самостоятельно перепрограммировать его. Давайте для лучшего понимания процесса посмотрим, как вообще выполняется программа, прошитая в контроллер, и где она физически располагается.
Как вы помните из статьи, посвященной Flash-памяти микроконтроллеров STM32, основная пользовательская программа начинается с первой страницы памяти, а точнее с адреса 0х08000000. То есть при подаче питания контроллер сразу же отправляется по этому адресу.
При использовании загрузчика все выглядит несколько иначе. Основная программа записывается уже по другим адресам и располагается начиная, например, с адреса 0х0800A000. А область памяти (0х08000000 - 0х0800А000) целиком и полностью отдается bootloader'у. В итоге в Flash-памяти контроллера находятся две полноценные программы. При включении устройства управление получает bootloader (поскольку он находится в области, начинающейся со "стартового" адреса 0х08000000), а при дальнейшей работе bootloader, выполнив все свои задачи, передает управление основной программе, которая располагается по адресу 0х0800А000 (этот адрес мы взяли для примера). Вот небольшая схема для иллюстрации работы загрузчика:
Вроде бы понятно как устроено, но возникает вопрос - зачем все это надо? Давайте разбираться.
Первостепенной задачей bootloader'а является перепрограммирование контроллера. Он не просто выполняет какие-то действия, а затем передает управление основной программе (переходит на адрес, который соответствует началу основной программы), он, в первую очередь, самостоятельно записывает эту основную программу в Flash-память по нужным адресам.
Разберем небольшой пример для лучшего понимания. Пусть мы создали bootloader (bootloader - точно такой же обычный проект, как и любая другая программа для микроконтроллера), который реализует взаимодействие с внешней картой памяти, ищет на карте файл прошивки и, если находит, записывает программу в нужную область памяти.
Небольшое отступление от основной темы. Поясню, что я тут имею ввиду под файлом прошивки. Когда мы создаем проект (Keil, IAR - без разницы), то на выходе получаем скомпилированный файл для прошивки в микроконтроллер. Чаще всего мы использовали формат .hex. Так вот именно этот файл нам и нужен в данном случае.
Но именно hex-файл не совсем подходит для наших целей, поскольку помимо кода программы он несет в себе дополнительную служебную информацию. Чтобы ее не обрабатывать и не вытаскивать из hex-файла нужные нам данные, который bootloader должен записать во Flash, мы в настройках IDE активируем генерацию bin-файла вместо hex.
Бинарник, в отличие от hex, содержит в себе только последовательный код программы и ничего больше. То есть bootloader'у остается только читать байты из bin-файла и записывать их во Flash-память. Таким образом, в нашем примере задачей загрузчика является чтение байт из файла на карте памяти и запись их по адресам, начиная с 0х0800A000. Вот псевдокод для наглядности:
Конечно, это сильно упрощенная версия загрузчика. Здесь мы в вечном цикле пытаемся открыть файл с программой, а как только это нам удается, bootloader программирует Flash-память и перескакивает на адрес записанной им же прошивки. После этого контроллер начинает выполнять пользовательскую программу. Еще раз повторюсь, это всего лишь псевдокод для примера, полноценный bootloader для STM32 мы обязательно реализуем в следующей статье.
Все это, конечно, очень интересно, но по-прежнему, непонятно, зачем нужны все эти сложности.
На самом деле с этим все просто. Вот, например, первая ситуация: есть некое количество устройств, на заводе работники прошили в каждый контроллер (например, при помощи ST-Link) на каждой плате bootloader, который при подключении к плате флешки (в заранее предусмотренный разъем) ищет на ней файл прошивки и выполняет программирование. Основную программу, конечно же, тоже можно прошить вместе с bootloader'ом через ST-Link. Но тонкость тут в том, что проект bootloader'а остается всегда неизменным, и перепрошивать его не надо, а вот версия основной программы может многократно обновляться в процессе тестирования устройств.
И тут уже гораздо проще один раз подключить ST-Link и прошить загрузчик, а впоследствии просто скидывать новую версию основной программы на флешку и втыкать ее в готовое устройство, где перепрошивкой займется bootloader, чем по сто раз бегать от одной платы к другой, втыкать программатор, при этом перенося с собой ПК и т. д. Как видите, польза загрузчика очевидна.
Вторая ситуация еще лучше это демонстрирует. Устройство уже выпущено и куча экземпляров распродана пользователям. Как бы хороша не была финальная версия программы, никто не застрахован от неожиданного появления ошибок в процессе эксплуатации. И тут уже человек, купивший устройство, точно не сможет разобрать его, чтобы выполнить перепрошивку через программатор. То есть программу обновить фактически нереально. Совсем другое дело, если изготовители предусмотрели встроенный bootloader. Пользователь может без проблем скинуть на карту памяти или на флешку скачанный бинарник и подключить эту карту/флешку к устройству. Изготовителю остается только выкладывать новые версии прошивок на своем сайте.
В этом на самом деле кроется куча возможностей - изготовитель устройств может спокойно выпустить девайс на рынок с базовой прошивкой, которая реализует все нужные функции, но не содержит всяких приятных графических вещей или возможности подключения к ПК или некого другого дополнительного функционала (зависит от того, что это за устройство). Производителю не нужно ломать голову над тем, чтобы выпустить с первого раза идеальную прошивку, в которой будет реализовано абсолютно все, что только можно, ведь он знает что встроенный bootloader без проблем поможет пользователю в будущем обновиться.
В общем, о пользе и применениях загрузчика можно говорить очень и очень долго. Помимо упомянутых возможностей обновления прошивки при помощи флешки или карты памяти, bootloader может использовать какой-нибудь из интерфейсов передачи данных, например, CAN или USART.
В общем-то, вроде разобрались с теоретической частью, посвященной использованию bootloader'а, но давайте еще один момент обсудим в этой статье - а именно встроенный загрузчик микроконтроллеров STM32.
В STM32 уже есть bootloader, который инженеры ST поместили в специально отведенную для этого область памяти контроллера (System Memory). Удалить его оттуда нельзя, да и незачем. Для того, чтобы ввести контроллер в режим загрузчика необходимо подать определенные сигналы на ножки BOOT0 и BOOT1. После этого микроконтроллер готов принимать по USART (один из вариантов) новую прошивку. Для этого необходимо подключить плату к ПК, скачать специальную утилиту от ST (Flash Loader Demonstrator) и загрузить в нее свой файл прошивки. Я, честно говоря, дефолтным загрузчиком предпочитаю не пользоваться по нескольким причинам.
Во-первых, прошивка никак не шифруется, что для коммерческих устройств зачастую недопустимо. Если я использую свой собственный bootloader, то я могу сделать с bin-файлом все, что угодно. Если такой файл попадет в руки конкурентов, то это ничего не даст, поскольку только мой bootloader знает механизм расшифровки. При использовании аппаратного botloader'а такое невозможно - Flash Loader Demonstrator принимает bin-файл в исходном виде.
Во-вторых, пользователю будет необходимо подключать свою плату к ПК и скачивать дополнительный софт для перепрошивки устройства, что не очень хорошо. Чем проще устройство в использовании, тем лучше 👍 Но есть и плюсы аппаратного bootloader'а - он не занимает Flash-память. При использовании своего загрузчика нужно иметь ввиду, что и загрузчик, и основная программа должны уместиться в ограниченный объем памяти. С системным bootloader'ом такой проблемы нет - он расположен в специальной области, использовать которую программист так и так не может.
Давайте на этом на сегодня и закончим, не пропустите статью, посвященную практической реализации загрузчика 🤝
Загрузчик (bootloader)
Загрузчик живёт в самом конце Flash памяти МК и позволяет записывать прошивку, отправляемую через UART. Загрузчик стартует при подаче питания на МК, ждёт некоторое время (вдруг кто-то начнёт слать код прошивки по UART), затем передаёт управление основной программе. И так происходит каждый каждый раз при старте МК.
- Загрузчик позволяет прошивать МК через UART;
- Загрузчик замедляет запуск МК, т.к. при каждом запуске ждёт некоторое время для потенциальной загрузки прошивки;
- Загрузчик занимает место во Flash памяти. Стандартный старый для Arduino NANO занимает около 2 кБ, что весьма существенно!
- Именно загрузчик мигает светодиодом на 13 пине при включении, как индикация работы.
Как убрать загрузчик?
Читайте также: