заливка прошивки (hex файл) в ардуино через UART с SD карты другой ардуинки
- Войдите на сайт для отправки комментариев
Доброго времени суток!
Интересует тема, как можно залить прошивку в ардуино не через ISP, а через UART, по типу как это делается с помощью программатора USB-TTL, но используя не Arduino IDE, а другую Ардуино.
Суть задачки следующая. Есть несколько ПроМини, объединенных модифицированной RS-485 шиной. Модификация заключается в дополнительной линии, обеспечивающей аппаратный ребут ПроМини. Среди объединенных МК есть мастер с SD картой, на которой лежит прошивка (hex файл). Идея в следующем, чтобы мастер послал команду, какую ПроМини он сейчас будет прошивать, на ней выставился флаг прошивки, далее мастер дергает линию аппаратного ребута, все ПроМини перегружаются и та, на которой выставлен флаг прошивки входит в "режим прошивки". Далее мастер считывает прошивку с SD и льет ее по UART, соответственно она занимает свое место в памяти нужной ПроМини. После этого мастер еще раз дергает линию ребута, все ПроМини ребутятся еще раз и начинается выполнение программы.
Но это я так "красиво" написал, как я себе это представляю в общем, но при реализации возникает гора вопросов, пока основным является алгоритм взаимодействия мастера с ПроМини после ребута - как войти в "режим прошивки", если я правильно понял, чтобы ПроМини стала ожидать заливки прошивки нужно что-то послать заргузчику. По обрывочным сведениям должно быть что-то типа "бутлоадер по идее должен подхватить команду DTR (тройное сочетание не помню каких символов) и перепрошиться. И да, все модули должны быть настроены так: по умолчанию (подтяжкой,безо всяких действий со стороны МК) должны быть в режиме Rx."
Интернет мне не смог помочь, либо я пока не знаю, как правильно спросить), может уважаемое сообщество располагает какими-либо сведениями в этом вопросе.
Всем заранее спасибо за ответы!
А не жестоко все сразу перегружать ради того, чтобы прошить одну? Если той одной сказали, что ей надо ребутиться, она могла бы и сама перегрузиться, нет?
А не жестоко все сразу перегружать ради того, чтобы прошить одну? Если той одной сказали, что ей надо ребутиться, она могла бы и сама перегрузиться, нет?
Это пока нюансы, понятно как сделать, для упрощения допустим, что она вообще одна))) Как заставить ее принять прошивку
А не жестоко все сразу перегружать ради того, чтобы прошить одну? Если той одной сказали, что ей надо ребутиться, она могла бы и сама перегрузиться, нет?
Это пока нюансы, понятно как сделать, для упрощения допустим, что она вообще одна))) Как заставить ее принять прошивку
Наверное так же, как IDE заставляет...
https://forum.arduino.cc/index.php?topic=512836.0
https://forum.arduino.cc/index.php?topic=512836.0
Да, это я читал, но если я правильно понял это история не для ардуино
Я использую optiboot загрузчик https://github.com/Optiboot/optiboot Вроде как там открытый код, но я не понимаю его структуры, если не затруднит, ткните, где можно почитать об этом, или в двух словах как он устроен.
Вроде как есть какие-то команды для работы с загрузчиком, но как их использовать, я не понял.
Да, это я читал, но если я правильно понял это история не для ардуино
так вся ваша задача - это "история не про ардуино". В ардуино нет наработок для написания загрузчиков. если вы не в курсе.
Придется "голый Си" изучать.
Придется "голый Си" изучать.
Пока проблема в понимании, как устроен загрузчик и как с ним работать
Пока проблема в понимании, как устроен загрузчик и как с ним работать
Вкратце, что где в исходниках оптибута - я вам ответил на Амперке.
Но судя по вопросу, корень ваших проблем, а том числе и с "пониманием оптибута" - в низком уровне владения предметом "программирование МК".
Обучайтесь. другого пути нет.
А мне нравится! Люди ставят себе задачи в сложности реализации которых понятия не имеют ))) Ну а чё )))
Через тернии к звёздам.
Ставить-то пусть ставят. Это полезно. Но вот когда после начинается катание ваты по форумам, а не втыкание в даташиты - это абзац, я считаю.
А мне нравится! Люди ставят себе задачи в сложности реализации которых понятия не имеют ))) Ну а чё )))
Ну, в общем-то, да. Задача-то идеально решается написанием собственного бутлоадера. Тогда можно всё сделать аккуратно и без костылей.
Зачем писать свой загрузчик? То, что человеку надо это стандартная функция существующего бутлоадера - прошивать данные поступающие из сериал порта, если сразу после ресета была получена соответствующая команда.
Вот логика работы оптибута:
1. При ресете Optiboot запускается и считывает причину ресета из MCUSR. По любой причине, кроме «внешнего ресета», ардуино запускается немедленно. В противном случае optiboot пытается загрузить новое программное обеспечение:
Там много чего вылезет, что придётся решать костылями, а свой загрузчик был бы специально под эту задачу заточен.
Там много чего вылезет, что придётся решать костылями, а свой загрузчик был бы специально под эту задачу заточен.
Зачем же свой писать? Добавить одну команду в Оптибут и все. А если использовать не общий ресет для всех, а развести индивидуально (можно по кольцу, что бы кол-во проводов не увеличивать, одна ардуина управляет ресетом следующей), то тогда вообще ничего в бутлоадере менять не надо.
Дело за малым перевести RS-485 в хардовый rs232
https://ru.aliexpress.com/item/5PCS-LOT-MAX485-module-RS485-module-TTL-t...
https://ru.aliexpress.com/item/5PCS-LOT-MAX485-module-RS485-module-TTL-turn-RS-485-module-MCU-development-accessories/32348018283.html
Это два пина RX и TX.
Вопрос в другом - как обеспечивается доступ к пину DTR???
Это два пина RX и TX.
Вопрос в другом - как обеспечивается доступ к пину DTR???
А зачем доступ к DTR если ресет будет отдельной линией?
Это два пина RX и TX.
Вопрос в другом - как обеспечивается доступ к пину DTR???
А зачем доступ к DTR если ресет будет отдельной линией?
ТС написал - Есть несколько ПроМини, объединенных модифицированной RS-485 шиной. Модификация заключается в дополнительной линии, обеспечивающей аппаратный ребут ПроМини
но не написал как это сделано, думаю это важно, если ребут обеспечивается стандарными средствами управления (аналогично DTR) то видимо реализуемо
Ого тут понаписали)))
Во первых спасибо asam за поддержку, я тоже не понимаю, зачем писать свой загрузчик, если есть готовый, и какие там будут мифические костыли о которых мне так упорно рассказывают сразу на двух форумах, но не говорят какие, я не знаю. В общем то, загрузчик - такая же программа, которая специально создана для загрузки прошивки, я покопался в нем, благо дело код открытый, там все достаточно просто.
программа ожидает по UART прихода символа.
вот список команд
далее идет обработка
это тот фронт, через который и будет общение.
Будет всего два допила, во первых нужно будет перед передачей от бутлоадера дернуть ногу RE DE на MAX485 трансмитторе. То есть исправить вот эту функцию
Во вторых, более сложная задача, решить вопрос, чтобы отвечала только одна ПроМини на линии, пока не знаю, как ее решать оптимально, отложил ее решение на второй этап. Сейчас отлажу процесс с одной ПроМини и одним мастером. Asam предложил перегружать П индивидуально, но бось так не получится, так как топология сети - елочная гирлянда, на которую нанизываются ПроМини. Есть лини питания, А,В, служебные, одна из них "DTR", то есть подключена через кондер к ресету. Соответственно, как только на ней появляется 0, все ПроМини перегружаются.
Сейчас буду делать эксперимент, подключу между ПроМини и програматором Мегу с двумя Serial интерфейсами, хочу перехватывать и выводить в монитор порта, что шлют друг другу программатор и бутлоадер, чтобы удостовериться, что алгоритм, описанный в статье действительно так работает.
А вот собственно решение первой проблемы. За меня уже все умные люди придумали. В коде еще не копался, но на вскидку - это то, что нужно
Соответственно, как только на ней появляется 0, все ПроМини перегружаются.
И все перешиваются разом - я правильно понимаю?
Соответственно, как только на ней появляется 0, все ПроМини перегружаются.
И все перешиваются разом - я правильно понимаю?
Нет, и это как раз вторая проблема, разом прошивать нельзя, так как прошивка - это результат двустороннего общения мастера и пациента. Посмотрите ссылку, что я привел, там это как раз описано.
Ой, а ссылочка то пропала)))
Форум заглючил, пришлось переписывать пост и забыл.
Вот ссылка https://switch-case.ru/52426629
Там расписан протокол общения optiboot с МК
Ну... шить прямо через сеть - это, конечно, по-ковбойски... А сли глючить будет - дергать всю сеть будете постоянно за reset? Может проще сначала спокойно сгрузить прошивку в I2C EEPROM, а потом дернуть за ногу? Под I2C не находили Optiboot mod?
То, что ты не знаешь - это понятно, но я что-то не заметил, чтобы ты хоть раз спросил. Тебе проще так людей послать, что мол чушь несут. Хотя, и там и здесь тебе это не "последние чайники" говорят. Ну, смотри, тебе жить. Хочешь делать через жопу, - делай. :)))
вот список команд
Я в исходники опитбута не смотрел, но, согласно их документации они поддерживают очень маленький набор команд
Остальные или просто игнорируются или посылается ответ об успешном завершении, но ничего другого не делается.
Главный вопрос здесь - как будете с Half-Duplex разбираться? Или у вас будет 2 пары 485 для Full-Duplex?
Во вторых, более сложная задача, решить вопрос, чтобы отвечала только одна ПроМини на линии, пока не знаю, как ее решать оптимально, отложил ее решение на второй этап.
Ну, это как раз просто.
- Присваиваете каждой ардуине уникальный номер, который хранится или в EEPROM или во Flash.
- Добавляете одну команду в бутлоадер - уходить в беспробудный сон (ну или бесконечный цикл) всем кроме особи с переданным номером.
Тогда алгоритм прошивки выглядит так
- Дергайте ресет
- Передаете вышеописанную команду. В результате все ардуины кроме одной отваливаются и вы остаетесь с ней один на один.
- Программируете
- Дергаете ресет еще раз, но команд больше не передаете.
- Через секунду все счастливо бутятся.
А почему не ресетить только одну, которую прошивать надо? Зачем всю сеть ресетить ради одной засранки?
А почему не ресетить только одну, которую прошивать надо? Зачем всю сеть ресетить ради одной засранки?
Ну, ТС так не хочет, я уже предлагал. А еще, если не ресетить, то работающая основная программа может сойти с ума от непонятного трафика на RS-485 если она им пользуется.
так нехрен чужой трафик подслушивать :)
>Я в исходники опитбута не смотрел, но, согласно их документации они поддерживают очень маленький набор команд
Вообще этот список я выдрал как раз из исходников оптибута. В любом случае набор команд достаточный для прошивки)))
>Главный вопрос здесь - как будете с Half-Duplex разбираться? Или у вас будет 2 пары 485 для Full-Duplex?
Так работа как раз в half-duplex идет, запрос - ответ. Тут ничего придумывать не придется, послал - слушай ответ - получил ответ - послал следующую.
>А почему не ресетить только одну, которую прошивать надо? Зачем всю сеть ресетить ради одной засранки?
А как это сделать если линия ресета общая, и линии данных общие, все сразу ребутятся, все сразу читают данные из линии. Если есть идеи, с удовольствием их выслушаю, но переделывать топологию сети нет возможности. Скорее всего делать буду так, как предложил asam, и собственно об этом писал выше, у меня каждая проМини имеет уникальный ID, пакет команды содержит этот ID, поэтому все понимают кому идет пакет, и если не ему, то просто его игнорирует, поэтому проблем с непонятным трафиком не будет.
Ввести команду "reset" и дергать... ребут по вачдогу, вроде, не пропускает бутлоадер?
А как это сделать если линия ресета общая, и линии данных общие, все сразу ребутятся,
Ребутить всю сеть (нарушать работоспособность) из-за одного контроллера - ну, я даже не знаю, как это инженерно назвать.
Делать очень просто, линия ресета вообще не нужна. Даёте команду контроллеру (одному, а не всей толпе) "ресетнись", он спокойно подаёт "LOW" на свою ногу reset и перегружается.
А как это сделать если линия ресета общая, и линии данных общие, все сразу ребутятся,
Ребутить всю сеть (нарушать работоспособность) из-за одного контроллера - ну, я даже не знаю, как это инженерно назвать.
Делать очень просто, линия ресета вообще не нужна. Даёте команду контроллеру (одному, а не всей толпе) "ресетнись", он спокойно подаёт "LOW" на свою ногу reset и перегружается.
Может, для индикации прохождения "нестандартно" пакета использовать линию, что освободилась от reset'а?
Ребутить всю сеть (нарушать работоспособность) из-за одного контроллера - ну, я даже не знаю, как это инженерно назвать.
Делать очень просто, линия ресета вообще не нужна. Даёте команду контроллеру (одному, а не всей толпе) "ресетнись", он спокойно подаёт "LOW" на свою ногу reset и перегружается.
[/quote]
Ну если апдейт проводится не часто, а простой сети в течении минуты допустим, то почему нет?
Вопрос, что нам выгоднее - допустить редкослучамый кратковременный простой сети или потратить N человеко-месяцев, для разработки софта позволяющего этого избежать.
Делать очень просто, линия ресета вообще не нужна. Даёте команду контроллеру (одному, а не всей толпе) "ресетнись", он спокойно подаёт "LOW" на свою ногу reset и перегружается.
Тогда придется обучать штатное приложение основам STK. Вариант реализуемый, но на вопрос, что лучше, может ответить только ТС.
>Делать очень просто, линия ресета вообще не нужна. Даёте команду контроллеру (одному, а не всей толпе) "ресетнись", он спокойно подаёт "LOW" на свою ногу reset и перегружается.
Класс!! Спасибо, изящное решение! И в бутлоадере не придется ничего прописывать, только плату немного переделать. Вопрос попутно, а при старте МК не будет на этой ноге, которая к reset подключена все время LOW, что будет вызывать boot-loop и до setup дело не дойдет?
>Вопрос, что нам выгоднее - допустить редкослучамый кратковременный простой сети или потратить N человеко-месяцев, для разработки софта позволяющего этого избежать.
простой сети допустим (в моем случае), а переписывать практически ничего не придется, так как протокол общения плат уже написан, нужно только внедрить обработку еще одной команды - это не проблема.
>Тогда придется обучать штатное приложение основам STK
Не понял эту фразу, что Вы имеете в виду?
Не, ну, это как сделать. По уму, нога "ресет" должна быть притянута к питанию резистором килоом в 10 и соединена с какой-нибудь цифровой ногой МК (управляющей ногой). Управляющую ногу надо постоянно держать в состоянии INPUT (она уже в нём при включении питания, вот и не трогать). А когда нужно ребутнуться, перевести в OUTPUT и подать LOW. При таком подходе, при включении питания никаких фокусов не будет.
>Тогда придется обучать штатное приложение основам STK
Не понял эту фразу, что Вы имеете в виду?
Я не знаю деталей того что ваши ардуины делают в штатном режиме. Если они не работают при этом с RS-485, то проблем нет. А вот если работают...
Представте, что одна ардуино каким-то образом переключилась в режим прошивания и вы шлете в нее новую прошивку. При этом все остальные будут видеть поток данных на их UART и может случиться, что в прошивке найдется комбинация выглядящая как команда для них. Реакция будет мало предсказуемая. Что бы этого избежать придется в них встраивать распазнование комманд программатора, что бы они на них не реагировали.
То есть решение с вачдогом, при котором переделывать плату вообще не требуется - не подходит. Ну, ОКчё.
> То есть решение с вачдогом, при котором переделывать плату вообще не требуется - не подходит.
Тут придется синхронизировать время от команды резет до срабатывания вачдога и после этого посылать команду для вхождения в бутлоадер. По моему это менее эффективно, чем просто дернуть резет и можно сразу слать команду синхронизации с бутлоадером.
> По уму, нога "ресет" должна быть притянута к питанию резистором килоом в 10 и соединена с какой-нибудь цифровой ногой МК
То, что должна быть притянута - это само собой.
> Управляющую ногу надо постоянно держать в состоянии INPUT (она уже в нём при включении питания, вот и не трогать). А когда нужно ребутнуться, перевести в OUTPUT и подать LOW. При таком подходе, при включении питания никаких фокусов не будет.
Да, все логично. Нужно ли ставить кондер между управляющей ногой и резетом как в случае с ногой DTR у ПроМини?
>Представте, что одна ардуино каким-то образом переключилась в режим прошивания и вы шлете в нее новую прошивку. При этом все остальные будут видеть поток данных на их UART и может случиться, что в прошивке найдется комбинация выглядящая как команда для них. Реакция будет мало предсказуемая. Что бы этого избежать придется в них встраивать распазнование комманд программатора, что бы они на них не реагировали.
Пакет команды расчитан на это, в пакете есть СтартБайт, Стопбайт, ID получателя, Подпись пакета, и определенная длина пакета. В теории конечно может случиться, что все условия совпадут и выполнится какая-то команда, но это маловероятно, да и ничего криминального не должно произойти.
Разве в ситуации с дёрганьем себя за ногу синхронизация не нужна? Как удаленный прошивальщик узнает, что принимающий МК уже ждет посылку?
Ну, Вы то чего ... :) Вы ж отлично понимаете, что есть 100500 способов сделать какую-никакую (а более точная и не нужна) синхронизацию.
Да я так, интересуюсь модными тенденциями - может интересного чего узнаю.
Тогда поинтересуйтесь языком Idris :)
> Разве в ситуации с дёрганьем себя за ногу синхронизация не нужна? Как удаленный прошивальщик узнает, что принимающий МК уже ждет посылку?
Стандартный протокол отпибут посылает 3 посылки с некоторым интервалом времени STK_GET_SYNC + CRC_EOP и ждет ответ STK_INSYNC + STK_OK. Если ответ пришел - все ок, можно начинать прошивку. То есть дернул себя за ногу, шлешь посылки и ждешь ответа, если ответа нет - ребут по вачдогу.
Всех с прошедшими!!!
На досуге поковырялся немного по теме, удалось подключить Мегу между программатором и ПроМини, посмотрел, кто что куда передает. Если кому интересно, вот результаты:
Вот содержимое blink.hex
Если кто не знает, вот выдержка структуры hex файла
Если у нас есть строка
: NN AAAA CC DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
SS
: - маркер начала строки
NN - определяет количество байтов данных в строке
AAAA - начальный адрес, с которого данные будут записаны в память микроконтроллера
CC - поле команды CC. Программатор, ориентируясь на поле CC, распознает функциональное назначения строки. Ассемблер и другие компиляторы языков высокого уровня для AVR могут установить следующие значения данного параметра:
00 – в строке находятся данные для записи в память,
01 – последняя строка в файле,
02 – строка содержит начальный адрес сегмента памяти,
04 – строка содержит адрес в пределах сегмента памяти.
DDDDD... - собственно данные
SS - контрольная сумма. Сумма всех байтов в неповрежденной строке без учета переполнения всегда нулевая, то есть DD + DD +... + DD + SS = 0
Вот лог arduino ide при загрузке скетча
А вот собственно лог, снятый с Меги при работе программатора
Соответственно знак > - это направление от программатора в МК, < - от МК к программатору
Из лога понятно, что программатор начинает общение командой, далее идут парамерты (если необходимо), заканчивается передача коммандой 20 (CRC_EOP). Соответственно МК отвечает обязательно вначале посылки командой 14 (STK_INSYNC) и заканчивает коммандо 10 (STK_OK).
Структура общения описана на страничке в приведенной мною ссылке выше и полностью ей соответствует, так что повторяться не буду.
Теперь то, что вызвало у меня вопрос, ответ на который пока не ясен.
Размер страницы составляет 128 байт (Page Size), а адресация коммандой STK_LOAD_ADDRESS идет со смещением на 64 байта, то есть в половину, то есть
>55>00>00>20 //STK_LOAD_ADDRESS - установили адрес 00 00 (первый параметр addr_low второй addr_high)
>64>00>80>46 //STK_PROG_PAGE - записываем (64) 128 байт (00 80) типа Flash (46 = 'F')
далее данные
>20 (CRC_EOP)
>55>40>00>20 //STK_LOAD_ADDRESS - установили адрес 40 00, вот тут не понятно, почему????
В протоколе STK500 (https://www.microchip.com/wwwAppNotes/AppNotes.aspx?appnote=en591659) ничего по этому поводу не нашел. Дальнейшие смещения адреса тоже происходят на 64 байта, а не на 128, что было бы логично.
Может кто подскажет, почему?
Дальше планирую написать скетч для прошивки по UART с SD-карты teensy 3.5.
Результаты выложу в этой теме.
Теперь то, что вызвало у меня вопрос, ответ на который пока не ясен.
Размер страницы составляет 128 байт (Page Size), а адресация коммандой STK_LOAD_ADDRESS идет со смещением на 64 байта, то есть в половину,
невнимательно читаете документацию. Параметр STK_LOAD_ADDRESS указывается не в байтах, а в 16-битных словах:
кстати, об этом сказано и в описании структуры общения оптибута и дудки, на которую вы сами ссылаетесь, вот цитата:
Load address (initially 0x0000). The address is in words (ie. a word is two bytes). This sets the address for where the next page of data will be written.