Официальный сайт компании Arduino по адресу arduino.cc
Как исполнить свой код ДО инициализации среды Arduino?
- Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии
Коллеги, тут как-то обсуждался вопрос, как выполнить некий код сразу же после загрузки процессора (до инициализации среды Arduino). Кажется, вопрос был связан с отключение сработавшего WatchDog'а, который, как известно, должен быть отключён очень быстро (сколько-то микросекунд) после загрузки, а среда инициализируется дольше.
Мне тут по другому поводу понадобилось нечто подобное. Сделал и решил показать всем, как это делается.
В приведённом примере функция preInit – это САМЫЕ ПЕРВЫЕ команды процессора, которые выполняются непосредственно после Reset. До них не выполняется ничего – не инициализирован стек, не инициализирован глобальные переменные, не отработали конструкторы глобальных объектов (привет Serial'у – он ещё не «родился») - ничего!
Имейте в виду – у Вас нет ничего, даже нормального стека!
Чисто показать «первость» не могу (просто верю документации), но косвенно, смотрите:
1. переменная cat2 объявлена «как обычно» (и стало быть она будет проинициализирована нулём при общей инициализации среды), а переменная cat1 объявлена с указанием «не инициализировать».
2. В функции preInit я записываю в обе переменные ненулевые значения.
3. При печати видно, что cat1 сохранила своё значение, а cat2 стала нулём.
Вывод: функция preInit выполнялась, по крайней мере, ДО инициализации глобальных переменных.
// // Эксперимент на кошках! // Проверка функций инициализации (функций исполняемых до всего остального) // // Глобальная переменная cat1 помечена как "неициализируемая", // чтобы предотвратить присваивание ей нуля в секции .init4 // cat2 описана стандартно. // int cat1 __attribute__ ((section (".noinit"))); int cat2; // // Функция preInit будет выполняться ДО ВСЕГО // прямо в момент "сотворения мира" (секция .init0) // Однако в этот момент ещё даже не инициализирован стек! // Стек инициализируется в секции .init2, потому, если возможно, лучше // нам использовать не .init0 как здесь, а .init3 // тогда хоть стеком можно пользоваться. // void preInit (void) __attribute__ ((naked)) __attribute__ ((section (".init0"))); void preInit (void) { cat1 = 321; cat2 = 123; } void setup() { Serial.begin(115200); Serial.println("Test on cats"); Serial.print("Cat #1:"); Serial.println(cat1); Serial.print("Cat #2:"); Serial.println(cat2); } void loop() {}
Т.е. если записать
Потребуется перепрошивка загрузчика?
ЕМНИП загрузчик как раз отработал и передал управление на код программы. Или всё это работает только без загрузчика?
ЕМНИП загрузчик как раз отработал и передал управление на код программы. Или всё это работает только без загрузчика?
подозреваю, что балалайка работает в загрузчике.
ЕМНИП загрузчик как раз отработал и передал управление на код программы. Или всё это работает только без загрузчика?
подозреваю, что балалайка работает в загрузчике.
Не. Работает именно до загрузчика. После ресета происходит команда безусловного перехода именно на этот код. Все остальное потом. В общем прелесно, можна вирусы писать или блокировать софт у заказчика нерасплатившегося, просто прелесно )))
прелесно, можна вирусы писать или блокировать софт у заказчика нерасплатившегося, просто прелесно )))
*откуда и когда бы это не запускалось - это записывается в секцию прикладной программы.
**проверил - на работу загрузчика пример не влияет.
мне это напоминает #крымнаш - кто до того запрещал писать вирусы и блокировать софт?
*откуда и когда бы это не запускалось - это записывается в секцию прикладной программы.
Блокировать после загрузчика не интересно, не мешает перезалить софт заново, залить другой софт. А до загрузчика - без программатора никак. А ведь можна так сделать запрос кода на розблокировку.
**проверил - на работу загрузчика пример не влияет.
А впишите типа A:goto A;
Т.е. если записать
Потребуется перепрошивка загрузчика?
не знаю, может я что-то не так сделал
почему же у меня работает загрузчик?, если всё должно повиснуть в бесконечном цикле цитирую: прямо в момент "сотворения мира" (секция .init0)
*оно виснет - дигиспарк не распознаётся системой, т.к. не грузится библиотека и не происходит инициализация в сетапе, но... прекрасно перепрошивается.
значит - волшебство происходит после загрузчика, а не до.
Т.е. если записать
Потребуется перепрошивка загрузчика?
Не знаю, я ж написал, что сейчас проверить не могу, приходится просто доверять документации (сижу на вокзале с ноутбуком на коленях, нанка есть, а вот программатора - нету :( )
Атмеловская документация говорит, что что код .init0 "will be jumped into immediately after a reset".
Да и знаете, для моих нужд необходимо было кое-что сделать до запуска конструкторов глобальных объектов (мне и .init3 выше головы хватило). А делать что-то до загрузчика мне не надо. Проверьте сами и скажите нам, что получилось, ладно?
Атмеловская документация говорит, что что код .init0 "will be jumped into immediately after a reset".
ясно - "will be jumped into immediately after a reset" прикладной программы делает загрузчик.
*расходимся - нас, в очередной раз, наебали.
По ресету происходит прыг на адрес 0, который в зависимости от настройки фьюзов, находится или в самом начале флеша ИЛИ в начале загрузчика. Я так перевел, с гугло-переводчиком. И где-то ещё читал про то, что загрузчик первым делом смотрит на USB и если там нет активности, то отдает управление на 0 адрес флеша.
Согласно документации на glibc (тоже поверил гуглю) в начало программы, с 0 адреса флеша, линкуются вектора прерываний и какие-то точки init.0 .. init.9, которые отвечают за начальную настройку памяти, пересылку в неё предустановленных значений глобалов, настройку классов объектов и ещё что-то, каждая за свое дело. Что именно так и не разобрался, плюнул.
По ресету происходит прыг на адрес 0, который в зависимости от настройки фьюзов, находится или в самом начале флеша ИЛИ в начале загрузчика.
Да. В этом вероятно и фишка. В начале флеша стоит прыг на код ТС. Надо фюзы смотреть.
Посмотрел. Действительно фюзы настроены на загрузчик (по крайней мере для наны и мини 328), соответственно код ТС будет после загрузчика. Жаль. Скайнет опечален )))
Посмотрел. Действительно фюзы настроены на загрузчик (по крайней мере для наны и мини 328), соответственно код ТС будет после загрузчика. Жаль. Скайнет опечален )))
Вообще-то, мне непонятна Ваша печаль.
Никто не заявлял, про "ДО или ПОСЛЕ" загрузчика. Заявлялось, что это выпоняется "в момент сотворения мира", т.е. первым делом после Reset - когда можно, например, поуправлять созданием глобальных объектов и т.п.
Некоторые читатели вбили себе в голову (неясно с чего), что это будет до загрузчика, а когда выяснилось, что не так - посчитали. что их обманули. А обманули-то сами себя. Нехрен было вбвать себе в голову то, что никто не писал.
Не моя печаль, скайнета ;)
Вся беда пошла от фразы:
функция preInit – это САМЫЕ ПЕРВЫЕ команды процессора, которые выполняются непосредственно после Reset. До них не выполняется ничего – не инициализирован стек, не инициализирован глобальные переменные, не отработали конструкторы глобальных объектов (привет Serial'у – он ещё не «родился») - ничего!
Её надо читать так:
функция preInit – это САМЫЕ ПЕРВЫЕ команды процессора, которые выполняются непосредственно после Reset и загрузчика. До них не выполняется ничего (кроме загрузчика) – не инициализирован стек, не инициализирован глобальные переменные, не отработали конструкторы глобальных объектов (привет Serial'у – он ещё не «родился») - ничего (загрузчик это не делает, а может и делает, но не так как нам надо, потому надо считать что это не сделано)!
Никто не заявлял, про "ДО или ПОСЛЕ" загрузчика. Заявлялось, что это выпоняется "в момент сотворения мира", т.е. первым делом после Reset - когда можно, например, поуправлять созданием глобальных объектов и т.п.
Некоторые читатели вбили себе в голову (неясно с чего), что это будет до загрузчика, а когда выяснилось, что не так - посчитали. что их обманули. А обманули-то сами себя. Нехрен было вбвать себе в голову то, что никто не писал.
Не моя печаль, скайнета ;)
Вся беда пошла от фразы:
функция preInit – это САМЫЕ ПЕРВЫЕ команды процессора, которые выполняются непосредственно после Reset. До них не выполняется ничего – не инициализирован стек, не инициализирован глобальные переменные, не отработали конструкторы глобальных объектов (привет Serial'у – он ещё не «родился») - ничего!
функция preInit – это САМЫЕ ПЕРВЫЕ команды процессора, которые выполняются непосредственно после Reset и загрузчика.
Вопрос, можно? А зачем это вообще нужно? Есть задачи, когда требуется лезть в код этих init.0 .. init9, какие? Интересно просто, особенно в применении к Wiring, поскольку у вас упор сделан "до инициализации среды Wiring" :)
Вопрос, можно? А зачем это вообще нужно? Есть задачи, когда требуется лезть в код этих init.0 .. init9, какие?
Первый абзац первого поста читали? Или "чукча - не читатель ..."?
Вопрос, можно? А зачем это вообще нужно? Есть задачи, когда требуется лезть в код этих init.0 .. init9, какие? Интересно просто, особенно в применении к Wiring, поскольку у вас упор сделан "до инициализации среды Wiring" :)
не задавай глупых вопросов, а перечитай все темы ТС, которые он написал - это не для ускоренного самообразования, это для выноса мозга желтушным заголовком и умолчания деталей.
*не знаю для кого он это пишет - для себя, наверное.
Да, читал .. "вот тут спрашивали" .. типичный прием, "обоснования" непонятно зачем. Читаю темы, просматриваю .. не попадалось. При собственном изучении вопроса, ещё в мае пришел к выводу что это "нафиг не надо"... да и "инициализация среды" там в реальности сведена к нескольким действиям, по большей части "общеполезного" характера. вот и возник вопрос уже к Вам.
Хотелось бы вместо оскорблений увидеть живой пример где это реально требуется, а не очередной "шедевр эквилибристики".
Возможно таким путем можно получить информацию была ли попытка обновления прошивки и успешна ли она.
Читаю темы, просматриваю .. не попадалось.
Тем и вопросов о том, что watchdog необходимо выключить при загрузке, а в setup - уже поздно, было много. Например:
Из того, Вам они не попадались, вовсе не следует, что их не было.
Там предлагалось лечение путём установки нестандартного загрузчика. Здесь другой рецепт.
Возможно таким путем можно получить информацию была ли попытка обновления прошивки и успешна ли она.
Как? Есть идеи как это сделать?
Да, читал .. "вот тут спрашивали" ..
здесь спрашивали, но походу у хабражителя ничего не вышло
http://geektimes.ru/post/255800/
Судя по статье вопрос гарантированно решается перекомпиляцией и перепрошивкой загрузчика, а вовсе не предложенным способом. Я не работал ещё с watchdog .. хотя, возможно в ближайшем будущем и понадобится. У нас идет активная подготовка к февральским соревнованиям, хотим таки туда попасть .. а там потребуется переводить контроллер в спящий режим, хотя бы на время его стояния в карантинах, дабы не жрать батарейки. Разберусь - отпишусь, если интересно. Но вряд ли потребуется лезть в init секции.
Судя по статье вопрос гарантированно решается перекомпиляцией и перепрошивкой загрузчика, а вовсе не предложенным способом.
в той статье из интересного этот код
Я не работал ещё с watchdog .. хотя, возможно в ближайшем будущем и понадобится. У нас идет активная подготовка к февральским соревнованиям, хотим таки туда попасть .. а там потребуется переводить контроллер в спящий режим, хотя бы на время его стояния в карантинах, дабы не жрать батарейки. Разберусь - отпишусь, если интересно. Но вряд ли потребуется лезть в init секции.
если будет интересно, то лучше посмотри и напиши компилляцию на тему "Application reset, который делает bootloader" или, подозреваю, не делает.