Загрузчик для AVR микроконтроллеров
Дата: 24 Января 2016. Автор: Алексей
Как-то ковыряясь с STM32 я в очередной раз заливая программу при помощи встроенного загрузчика, задумался об такой же интересной штуке но для AVR. В принципе Arduino это и есть AVR со своим загрузчиком. Далее блуждая по всемирной сети, я нарвался на два проекта. Один из них это chip45boot2, а второй AVRPROG compatible bootloader. Оба варианта бесплатные и даже у первого номенклатура поддерживаемых микроконтроллеров больше, но... Первый вариант имеет свою собственную программу для связи с МК и даже поддерживает RS-485, но при этом исходников нет. Второй вариант наоборот имеет исходники, но работает только с программой AVRProg которая идет в комплекте с AVR Studio. И конечно же последняя не поддерживает RS-485. А ведь хочется и то и то. В общем я решил выйти из положения следующим образом. В исходники загрузчика дописать поддержку RS-485, а чтобы не быть привязанным к AVRProg просто написать свою программулину под Win7. Что из этого вышло.
Начнем с загрузчика. Можно конечно скачать его с офсайта и допилить самому, можно скачать у меня исходник и просто внести небольшие поправки, а можно скачать под ATMega8 два HEX файла и просто залить их в МК. Какой вариант это решать вам.
Вариант с допилом прошивки или загрузки готовых хексов рассматривать не будем, а вот вариант с допилиной прошивкой рассмотрим подробно. Скачайте проект с исходником и запустите в AVRStudio. У меня версия 4.19. Далее в блокноте откройте makefile файл. В самом начале нужно выбрать нужный МК.
В частности у меня это восьмая мега. Забегу вперед, я в своей программе использовал поддержку только меги 8, 16, 32 и 64. Если нужны другие МК, то уже через AVRProg или пишите, добавлю в свою программу. И так, после выбора МК переходим к основной программе. Все что нужно настроить я подчеркнул красной чертой.
Сначала идет частота кварца. Данная строка нужна для расчета пауз и расчета скорости UART, Далее идет скорость в бодах для UART. 19200 рекомендованная скорость и она же потдерживается программой AVRProg. Следующий дефайн как раз включает поддержку RS-485. Если он раскомментирован, то RS-485 работает, если закомментирован, то работает чистый UART. Ниже, подчеркнутый синим, дефайн выставляет задержку в миллисекундах. Ее нужно подбирать опираясь на микросхему драйвер RS-485. Данная задержка дает время на устаканивания логики драйвера при переходах с чтения на запись и наоборот. Для MAX485 1 мс вполне хватает. Если вообще убрать задержку, то передача по RS-485 прекратится вообще. Так что эта настройка производится чисто эмпирически. После задания паузы идут настройки пинов. Первая настройка для индикации работы загрузчика. Здесь нужно выбрать на каком порту и к какому разряду будет подключен индикационный светодиод. Если МК находится в загрузчике, то на данном разряде будет единица, а если работает основная программа, то данный разряд переходит в распоряжение основной программы. Следующие за ним дефайны определяют на каком порту и каким разрядом будет вывод управления направления передачи данных. Как раз этот пин будет дергать направление передачи данных микросхемы драйвера. В принципе на этом настройка закончена. Компилируем и заливаем в МК. А , вот еще. Перед заливкой в МК, нужно выставить фьюз бит загрузчика. Называется он BOOTRST. После его установки МК после каждого рестарта будет уходить сначала в загрузчик, а если к нему никто не обратится, то он через 3 секунды перейдет к основной программе. Так же нужно выставить фьюз биты размера загрузчика. BOOTSZ0 = 1, BOOTSZ1 = 0. Вот теперь если все сделанно правильно, то после заливки загрузчика МК рестартанет и ввалится в загрузчик. Если подключен светодиод, то он загорится.
Программа для работы с загрузчиком.
Качаем архив и разархивируем его в любое удобное место на диске. Программа просто экзешник и не требует никаких библиотек. Далее запускаем программу.
Первым делом необходимо выбрать скорость и порт. У меня переходник USB <->RS-485 сидит на девятом порту. Выбрав скорость и порт можно подключатся. Рестартуем МК кнопкой ресет и жмем на кнопку Старт. Если все было сделано верно, то программа должна принять следующий вид.
Кнопка Старт станет неактивной и окрасится в зеленый цвет. Это будет означать что программа связалась с загрузчиком в МК. Так же появится информация о микроконтроллере, его сигнатура, тип и объем Flash памяти. В самом низу есть панель состояния в которой так же про дублируется надписью Подключен. Следующим действием нужно выбрать прошивку для МК. Для этого нажимаем на кнопку выбора пути до загружаемого файла и в появившемся окне выбираем HEX файл.
Здесь есть небольшой нюанс. Если посмотреть на строку состояния внизу программы, то можно увидеть размет прошивки в байтах. У меня это 1296 байт. В чем загвоздка. Дело в том, что загрузчик не может висеть в воздухе и для него выделяется память. Для данного загрузчика выделена память размеров 512 страниц. Эту память выделяли фьюзами BOOTSZ0, BOOTSZ1. А так как слово это два байта, то отсюда видно что загрузчику выделена память в 1024 байта от основной Flash памяти. За хорошую жизнь, нужно платить)) Отсюда вытекает следующая проблема. Размер основной программы не должен превышать размера Flash минус 1024 байта. Для восьмой меги это 8Кб - 1Кб = 7Кб или 7168 байт. Поэтому если вдруг программа окажется больше допустимого размера, а это возможно так как компилятор в душе не чает про какие-то там загрузчики и оперирует всей памятью МК, то данная программа проверив объем HEX файла не пропустит его для загрузки предупредив об этом. Если эту защиту снять, то загрузчик зальет программу, но при этом подотрет и частично себя. И после уже работать не будет. Вот что произойдет если попробовать залить прошивку большего размера.
Есть три решения данной проблемы. Первая, оптимизация кода для уменьшения его размера, вторая, удаления загрузчика и заливка простым программатором и третья, использовать МК с большей памятью. Поехали дальше. Для работы с Flash памятью у программы есть четыре кнопки. Записать, Сравнить, Прочитать, Очистить Flash. Последнюю пояснять не надо, она просто стирает все данные во Flash за исключением самого загрузчика. Записать эта кнопка записывает данные из HEX файла во Flash. При этом нужно запомнить, что перед записью программы Flash автоматически очищается и если прервать запись, то программу что стерлась, воссоздать уже не получится. Поэтому если текущая прошивка нужна, то ее необходимо сначала прочесть. Для этого есть кнопка Прочитать. Нажав на нее, сначала программа выведет предупреждения о том что текущая прошивка запишется в выбранный файл. Если этого не нужно, то необходимо заранее создать пустой HEX файл и записать текущую прошивку в него. Кнопка Сравнить, просто сравнивает записанную прошивку в МК с данными в выбранном на данный момент файле. При записи проверка происходит автоматически. Все действия программы подробно дублируются в строке состояния. А теперь давайте сначала прочитаем текущую прошивку, затем очистим Flash, потом зальем новую прошивку и сравним с HEX файлом. Перед тем как прочитать текущую прошивку нем необходимо создать пустой HEX файл. Делается это очень просто. Открываем блокнот. Далее Файл -> Сохранить как.. В окне выбираем Тип файла: Все файлы, Кодировка: UTF-8, а имя файла любое но с расширением .hex, у меня flash.hex.
Теперь создав файл выбираем его из программы. Соответственно размер его 0 байт.
Теперь нажимаем кнопку Прочитать и соглашаемся с предупреждением.
Чтение довольно длительный процесс и пугаться этого не надо. Связано это с тем, что программа понятия не имеет какого размера прошивка в МК. Поэтому чтение идет всей памяти Flash. Давайте теперь взглянем что нам записала программа в файл. Открываем в блокноте наш созданный ранее HEX файл.
Собственно ничего нового. Вычитанная прошивка за исключением кучи FF. Это как раз та часть Flash в которой ничего нет, но так как мы прочитали всю память, то и в файл записали эту пустоту. Да, именно пустоту, для МК 0xFF это чистая ячейка. Теперь давайте запишем прошивку в МК. Выбираем нужную прошивку на диске. У меня это тестовая для работы с внешней EEPROM AT24Cx и жмем на кнопку Записать. По окончанию заливки в статусе появится надпись Запись выполнена.
Все, МК прошит))) А теперь жмем на Сравнение и через некоторое время в статусе опять появится надпись Сравнение выполнено. Это говорит о том что прошивка в МК совпадает с данными в HEX файле.
А теперь об ошибках. Если при открытии HEX файла в какой либо строке не совпадет контрольная сумма, то программа об этом предупредит указав в какой именно строке произошла эта оказия. Такое возможно если случайно при изучении HEX файла какой-то символ был удален. Ну или сами чего решили поправить для красоты, а про существование контрольной суммы не знали. Вот как это выглядит. Я специально в файле, который мы создали и записали в него прошивку, подпортил один символ.
Все дело в том, что программа не просто читает HEX файл, но и еще параллельно проверяет контрольную сумму каждой строки, дабы избежать записи в МК битой прошивки. Если не совпадает прошивка в МК с выбранным файлом, то в строке состояния так и будет написано. Связано это с тем, что сравнивать можно не с текущим файлом, а например есть у нас МК и мы думает что в нем залита именно вот эта прошивка. Подключаемся к загрузчику, подгружаем HEX и просим сравнить. Программа читает прошивку из МК, а потом сравнивает с файлом и если они разные, то просто напишет об этом. А вот если выводить в какой строке что не совпало, то это может быть длинным списком. Вот что будет если прошивка не совпала с файлом.
А теперь плюшка. Если посмотреть на программу внизу, правее кнопки очистки Flash, то можно заметить чекбокс, поле для ввода и надпись Команда. Для чего это нужно. Например МК установлен в какой-нибудь коробке, а та в свою очередь находится глубоко под землей в коллекторе или на каком-нибудь столбе. В общем с ходу не добраться, а гандурас чешется как прошивку нужно перезалить. Че делать. Кнопку ресет не нажать. Часовая собака не поможет, так как при работе с загрузчиком все прерывания должны быть отключены. Тратить пин порта на дергания ресета жалко. Вот для этого и сделано это поле команды. В теле основной программы, создается какое-нибудь условие в котором проверяется присутствие команды на переход к загрузчику. А как ее переслать. Да очень просто. Записываем эту команду в данное поле и ставим галочку в чекбоксе и после нажатия на кнопку Старт программа сначала пошлет в порт эту команду, а потом попытается подключится к загрузчику. А уж как перейти из основной программы к загрузчику, это ваше дело. Вот самый простой пример. Когда приходит восклицательный знак, то основная программа глобально запрещает прерывания и перекидывает процессор в загрузчик.
if(uart_flag & (uart_old == '!')) { uart_flag = 0; cli(); asm("JMP 0x0E00"); }И самое главное. После всех манипуляций нажав на кнопку Стоп программа выходит из загрузчика и перезагружает МК. На этом мой рассказ заканчивается, если что я тут. Форум или комменты.
АНОНИМ 25.02.16 23:34
Для пк писалось в вижуал студии или на С#? А то проблема с framework, пока запустить не получается.
Алексей 26.02.16 08:03
На С#.
АНОНИМ 26.02.16 09:14
На Win7 х64 не работает
Алексей 26.02.16 13:18
Я писал под win7 x64. Какая ошибка?
АНОНИМ 10.04.16 14:50
Подскажите а если к примеру помимо флэша еще и еепром надо перезалить и все это с проверкой crc того что залилось?
Алексей 10.04.16 15:19
Данная программа не поддерживает заливки EEPROM. Для этого можно использовать родную Атмеловскую утилиту AVRProg с немецким загрузчиком, так как я из него выкинул запись EEPROM для уменьшения размера при партировании в 6 студию.
Виктор 09.08.16 16:20
Доброе время суток! Какая микросхема 485 на стороне МК? И по какой схеме его соединяли с МК? У меня с МАХ485 не видит МК.
Алексей 09.08.16 18:17
Схема включения как здесь, а пин направления PORTD2
Виктор 11.08.16 00:34
Спасибо!
Дмитрий 18.09.16 00:18
Я тоже написал нечто подобное, только с адресным доступом к устройствам (использовал режим MPCM). Если Вам будет интересно - avr-assm.ru
Алексей 18.09.16 08:35
Адресный доступ к устройству, на мой взгляд, бессмысленная задача, так как при общении с устройством по шине RS-485 у устройства и так есть адрес. Задачей перехода в загрузчик должен заниматся используемый протокол.
Дмитрий 18.09.16 16:17
Разумеется, протокол определяет способ передачи управления загрузчику. А выбор устройства на шине - это чья задача?
Алексей 18.09.16 17:41
Протокола. Например всеми известный MODBUS сначала идет адрес устройства затем команда, регистр, длигна поля и т.д. У любого протокола в пакете присутствует адрес адресуемого устройсва. Если конечно это не широковещательная передача.
Дмитрий 18.09.16 18:24
Именно это я и имел в виду, когда написал - адресный доступ. В программе со стороны компьютера реализован протокол, по которому происходит выбор устройства для перепрошивки. Выбор этот осуществляется по адресу, заложенному в самой прошивке ранее. И используется режим MPCM модуля USART.
Алексей 18.09.16 20:13
А если используется свой протокол и передача пакета фиксирована. Я написал команду для перехода в загрузчик и отвалил с линии, а по окончании заливки передал опять линию программе. Не всегда аппаратная реализация удобнее программной.
Дмитрий 18.09.16 21:02
Да у меня в общем-то аналогично, предусмотрена возможность доступа к загрузчику через протокол прошивки. Но в общем случае, когда к линии связи подключено не одно устройство требуется передавать какой-то префикс или признак того, что передаётся именно адрес устройства. И где гарантия, что в массиве передаваемых данных совершенно случайно не окажется последовательность, повторяющая команду передачи управления загрузчику. И другое устройство, подключенное к этой-же линии...
Алексей 18.09.16 22:34
Есть гарантия. Префиксом является стартовый байт. Он инициализирует начало пакета. Затем идет адрес устройства. После адреса идет команда. Вот как раз байт команды уникален и никогда не будет случайным. Если в пакете адрес не свой, то слейв его просто проигнорирует и ему будет все равно что за команда пришла. Так что случайность исключена.
Дмитрий 18.09.16 23:22
Спасибо, что уделили мне время, Алексей. Я Вас понял. Просто у меня данные передаются как бинарный файл и уникальных байт быть не может.
Алексей 19.09.16 07:40
Я понимаю. Просто Ваш протокол основан как протокол шины I2C. Я использую фиксированную шапку пакета, где адрес, команда и регистр всегда расположены в определенном месте. Такая система позволяет избежать коллизий на линии. Я за основу брал MODBUS.
Андрей 10.10.16 15:23
Алексей, добрый день. Такой вопрос. Можно ли использовать Ваш загрузчик совместно с модулем Wi-Fi ESP8266? Как в этой статье https://geektimes.ru/post/274092/
Алексей 10.10.16 16:38
Можно, если модуль создаст UART соединение, так как ему нужно только линия связи и все.
Артем 28.10.16 19:24
Подумал я написать бутлоудер для AVR. Прежде чем мастерить свое, решил погуглить, полазить по форумам, посмотреть готовые реализации. Вопрос был в makefile, что с ним делать и что там поменять, а тут уже готовый проект. Наткнулся на эту статью. Спасибо автору за то, что быстро ввел в курс дела и за полезные ссылки. Скачал, переписал под себя, все работает. Есть пожелание, а именно добавить возможность ввода команды в hex формате на 16 байт. Сейчас, как я понял, команда вводиться в виде строки? (я про переход в бутлоудер).
Алексей 28.10.16 19:30
Да, в виде строки.
Михаил 30.10.16 08:19
Здравствуйте, а где можно прочитать на русском языке как происходит обмен информацией boodloader'a и программы, какой протокол?! Хочется свою программу написать для обновления прошивки через boodloader.
Алексей 30.10.16 11:13
Вся информация есть в документации на МК. Причем только на английском. В качестве протокола используется AVR109, Документация тоже только на английском и очень скудна. Пришлось снимать данные логическим анализатором. Если писать свой бутлоадер, то можно использовать свой придуменный протокол.
Дмитрий 18.11.16 11:15
Подскажите как будет вести себя загрузчик если кварцевый резонатор у меня 8 и 12 мГц
Алексей 18.11.16 11:20
Плохо. Частота кварца используется в расчете скорости передачи по UART. Если меняется кварц, то нужно записать его частоту в константу #define F_CPU 8000000 или #define F_CPU 12000000. А потом снова собрать проект.
Дмитрий 18.11.16 11:36
спасибо все ясно, а не могли бы приплюсовать атмегу8535, поэкспериментировать , а то другого пока нет а магазин далеко... Заранее спасибо
Алексей 18.11.16 14:11
Это сложновато. В загрузчике не предусмотрен этот контроллер. Вот полный список поддерживаемых контроллеров.
## MCU = atmega8
## MCU = atmega16
## MCU = atmega162
## MCU = atmega169
## MCU = atmega32
## MCU = atmega324p
## MCU = atmega64
## MCU = atmega644
## MCU = atmega644p
## MCU = atmega128
## MCU = at90can128
## MCU = atmega8
## MCU = atmega16
## MCU = atmega162
## MCU = atmega169
## MCU = atmega32
## MCU = atmega324p
## MCU = atmega64
## MCU = atmega644
## MCU = atmega644p
## MCU = atmega128
## MCU = at90can128
Дмитрий 18.11.16 15:19
Алексей 18.11.16 16:10
Так этот загрузчик не я писал, а немец. Я только накатал прогу для ПК и адаптировал под МК. В принципе если почитать доку на МК, то можно и допилить до 8535.
Сергей 16.12.16 21:49
Программа не может определить Атмегу-128. Пишет - МК не известен.
Есть ли выход из положения?
Есть ли выход из положения?
Алексей 17.12.16 00:36
Пока нет. Прога не поддерживает 128 мегу.
Сергей 17.12.16 09:23
Понял.
Алексей, а есть ли сам "исходник" программы?
Ещё такой вопрос. У меня много разных проектов. В основном, на Меге-8. Столкнулся с проблемой при задействование загрузчика. Например две разные платы с интерфейсом RS-485. Полностью рабочие. Схема интерфейса одинаковая на обеих. Порт переключения направления данных - PD7. К одной плате программа подключается нормально. К другой пишет - нет ответа от контроллера. В чём может быть проблема?
Алексей, а есть ли сам "исходник" программы?
Ещё такой вопрос. У меня много разных проектов. В основном, на Меге-8. Столкнулся с проблемой при задействование загрузчика. Например две разные платы с интерфейсом RS-485. Полностью рабочие. Схема интерфейса одинаковая на обеих. Порт переключения направления данных - PD7. К одной плате программа подключается нормально. К другой пишет - нет ответа от контроллера. В чём может быть проблема?
Алексей 17.12.16 09:46
Программа выдает сообщение "нет ответа" если контроллер не ответил в течении 3 секунд. Кварцы на платах одинаковые? У загрузчиков частоты совпадают с частотами тактирования? Если ошибиться, то битрейт уползет.
Сергей 17.12.16 10:54
Да. Схема полностью одинакова, кроме управляющих выходов на сдвиговые регистры (другие порты. На одной PC0-PC2, на другой PC3-PC5). Вся "обвязка" одинаковая. Кварц 4, внешний и там и там.
Алексей 17.12.16 13:20
А фьюзы прошиты правильно, те что включают загрузчик и количество выделенной памяти под него? BOOTRST и BOOTSZ.
АНОНИМ 17.12.16 22:59
Да. Фьюзы прошиты верно.
Алексей 17.12.16 23:08
Значит должно все работать. Чудес не бывает. Все одинаково, а работает только один.
Сергей 08.01.17 09:16
Алексей.
Так есть ли сам исходник программы?
Так есть ли сам исходник программы?
Алексей 08.01.17 10:56
Ссылка на исходник лежит в начале статьи.
Сергей 08.01.17 19:22
Есть только уже скомпилированный екзешник.
Если не трудно, напишите прямую ссылку.
Если не трудно, напишите прямую ссылку.
Алексей 08.01.17 22:40
Это шутка? Второй абзац. Первая ссылка на офсайт, вторая отсюда и там и там исходники.
Сергей 09.01.17 21:13
То есть, Вы уверены что по всем эти ссылкам есть исходники файла AVR_Boot v1.0.exe ?
Ну не нашёл я их. Нету их там просто!
Ну не нашёл я их. Нету их там просто!
Алексей 09.01.17 22:16
Блин, а я не понял. Я то думал про исходники для МК. А на ко хрен нужны исходники программы для пк?
Сергей 09.01.17 22:40
Хотелось бы расширить прогу под другие процы. Например 8535, Atmega-128.
Алексей 10.01.17 12:12
Сразу предупреждаю, за испорченную нервную систему не отвечаю. На этих программах я начинал изучать MSDN.
Исходник
Исходник
Сергей 10.01.17 17:24
Спасибо! Надеюсь справлюсь.
Алексей 10.01.17 19:06
Главное не сломать мозг)))
Сергей 10.01.17 23:41
Алексей. К Вам можно будет обратиться напрямую, если будут вопросы? Я обычно пишу на VB6, но думаю здесь не так будет всё сложно. Сейчас столкнулся с проблемой при прошивке 32 атмеги. Всегда вываливается ошибка и, соответственно теряется связь с контроллером.
Алексей 10.01.17 23:47
avrki@avrki.ru
DENIS 16.02.17 19:30
Алексей. подскажите. Для включени режима загрузки PIND3 нужно садить на землю?
Алексей 16.02.17 19:50
Для входа в загрузчик нужно перегрузить МК. При рестарте МК будет ждать запроса в течении 4сек и если запрса не будет, то происходит переход в основную программу. PIND3 для индикации. На нем висит светодиод.
Васил 25.04.17 19:49
Ошибка
#ifdef START_POWERSAVE
uint8_t OK = 1;
#endif
BLDDR &= ~(1<<BLPNUM); // set as Input
BLPORT |= (1<<BLPNUM); // Enable pullup
А должно быть:
#ifdef START_POWERSAVE
uint8_t OK = 1;
BLDDR &= ~(1<<BLPNUM); // set as Input
BLPORT |= (1<<BLPNUM); // Enable pullup
#endif
#ifdef START_POWERSAVE
uint8_t OK = 1;
#endif
BLDDR &= ~(1<<BLPNUM); // set as Input
BLPORT |= (1<<BLPNUM); // Enable pullup
А должно быть:
#ifdef START_POWERSAVE
uint8_t OK = 1;
BLDDR &= ~(1<<BLPNUM); // set as Input
BLPORT |= (1<<BLPNUM); // Enable pullup
#endif
Алексей 25.04.17 20:35
Да, есть такая фигня. Я вообще их удаляю так как мне светодиод не нужен.
Васил 14.05.17 20:38
Алексей. Я попытался использовать TCP->rs485 переходник и avr_boot вылетает с ошибкой, я думаю, из за задержек в сети, похоже надо увеличить тайминги ожидания ответа.
Алексей 14.05.17 20:43
Да, есть такая штука. Тоже самое я наблюдал с радиоканалом. Тайминг добавлен и проверена работа. Чуть позже сюда загружу с поправкой.
Васил 14.05.17 20:49
Спасибо. Жду.
Васил 16.05.17 22:23
Avrprog отлично справился.
Алексей 17.05.17 08:45
Так он же родной.
Алексей 18.05.17 21:44
Загрузил с увеличенным таймаутом.
Sergey 15.09.18 21:12
Алексей, привет. Не получается прошить ATMega32 по RS485. Только начинает и тут же обмен прекращается. Чуть-чуть успевает записать. То ли из-за ошибок останавливается, то ли еще что. У меня кварц 16МГц, скорости разные пробовал. 9600 и 19200 подключаются норм. Но все остальные операции не идут. Пробовал по USART - все норм получается. Играл задержкой переключения RS485 - никак не помогло. Есть мысли?
Алексей 16.09.18 05:33
Какая микросхема драйвер стоит?
Sergey 16.09.18 20:23
ADM1485
Алексей 18.09.18 16:05
А в загрузчике прописаны 16МГц в makefile?