Подтвердить что ты не робот

Загрузчик Arduino

Может кто-нибудь объяснить, как работает загрузчик Arduino? Я не ищу здесь ответа на высокий уровень, я прочитал код, и я понял суть его.

Взаимодействие между протоколами между Arduino IDE и кодом загрузчика происходит в результате взаимодействия с протоколом, в результате чего получается ряд встроенных инструкций по сборке, которые самопрограммируют флэш-память с передачей программы через последовательный интерфейс.

То, что я не понимаю, находится в строке 270:

void (*app_start)(void) = 0x0000; 

... который я распознаю как объявление и инициализацию NULL, указателя функции. Последующие вызовы app_start в местах, где загрузчик должен делегировать выполнение исполняемого пользователем кода.

Конечно, как-то app_start нужно получить значение, отличное от NULL, в какой-то момент, чтобы все это собралось вместе. Я не вижу этого в коде загрузчика... это магически связано с программой, загружаемой загрузчиком? Я полагаю, что основная часть загрузчика является точкой входа в программное обеспечение после reset чипа.

Завершение в 70-ти строках сборки должно быть секретом секретного декодера, который сообщает основную программу, где действительно существует приложение_ app_start? Или, возможно, некоторые неявные знания используются в среде Arduino IDE? Все, что я знаю, это то, что если кто-то не изменит app_start, чтобы указать где-то, кроме 0, код загрузчика будет просто вращаться навсегда навсегда... так что трюк?

Edit

Мне интересно попытаться подключить загрузчик к Tiny AVR, который не имеет отдельного пространства памяти для кода загрузчика. Как мне становится очевидным, что код загрузчика зависит от определенных настроек плавких предохранителей и поддержки чипов, я думаю, что мне действительно интересно знать, что нужно, чтобы перегрузить загрузчик на чип, у которого нет этих предохранителей и аппаратных средств поддержка (но все еще имеет возможность самопрограммирования)?

4b9b3361

Ответ 1

В NULL

Адрес 0 не содержит нулевой указатель. "Нулевой указатель" - это нечто более абстрактное: специальное значение, которое применимые функции должны признать недопустимыми. C говорит, что специальное значение равно 0, и, хотя язык говорит о разыменовании, это "поведение w90 > ", в простом мире микроконтроллеров он обычно имеет очень четко определенный эффект.

Загрузочные загрузчики ATmega

Обычно на reset программный счетчик AVR инициализируется на 0, поэтому микроконтроллер начинает выполнять код по адресу 0.

Однако, если установлен Boot Reset Fuse ( "BOOTRST" ), счетчик программ вместо этого инициализируется адресом блока в верхнем конце памяти (где это зависит от того, как установлены предохранители, см. спецификацию (PDF, 7 МБ) для специфики). Код, который начинается там, может что-то сделать, если вы действительно хотите, чтобы вы могли разместить свою собственную программу там, где вы используете ICSP (загрузчики обычно не могут перезаписывать себя).

Часто, это специальная программа загрузчик — которая может считывать данные из внешнего источника (часто через UART, я 2 C, CAN, и т.д.), чтобы переписать программный код (сохраненный во внутренней или внешней памяти, в зависимости от микро). Обычно загрузчик обычно ищет "специальное событие", которое может буквально быть чем угодно, но для разработки наиболее удобно что-то на шине данных, из которого он вытащит новый код. (Для производства это может быть особый логический уровень на штыре, поскольку его можно проверить почти мгновенно.) Если загрузчик видит специальное событие, он может войти в режим начальной загрузки, где он будет перепрограммировать память программы, иначе он пройдет контроль отключить код пользователя.

Как и в стороне, точка плавкого предохранителя загрузчика и верхнего блока памяти позволяет использовать загрузчик без каких-либо изменений в исходном программном обеспечении (при условии, что он не будет полностью распространяться на адрес загрузчика), Вместо того, чтобы мигать только с оригинальным HEX и желаемыми предохранителями, можно мигать исходным HEX, загрузчиком и модифицированными предохранителями, а также добавлен предварительный загрузчик.

В любом случае, в случае с Arduino, который, как я полагаю, использует протокол из STK500, он пытается связаться через UART, и если он не получит ответа в течение отведенного времени:

uint32_t count = 0;
while(!(UCSRA & _BV(RXC))) { // loops until a byte received
    count++;
    if (count > MAX_TIME_COUNT) // 4 seconds or whatever
        app_start();
}

или если он слишком сильно ошибся, получив неожиданный ответ:

if (++error_count == MAX_ERROR_COUNT)
    app_start();

Он передает управление обратно в основную программу, расположенную в 0. В источнике Arduino, показанном выше, это делается путем вызова app_start();, определенного как void (*app_start)(void) = 0x0000;.

Поскольку он используется как вызов функции C, прежде чем ПК перейдет на 0, он вытолкнет текущее значение ПК в стек, который также содержит другие переменные, используемые в загрузчике (например, count и error_count сверху). Означает ли это кражу оперативной памяти из вашей программы? Ну, после того, как ПК установлен в 0, операции, которые выполняются, явно "нарушают" то, что должна сделать надлежащая функция C (которая в конечном итоге возвращается). Среди других шагов инициализации он сбрасывает указатель стека (эффективно стирает стек вызовов и все локальные переменные), восстанавливая ОЗУ. Глобальные/статические переменные инициализируются до 0, адрес которых может свободно перекрываться с тем, что использовал загрузчик, потому что загрузчик и пользовательские программы были скомпилированы независимо.

Единственными прочными эффектами от загрузчика являются модификации аппаратных (периферийных) регистров, которые хороший загрузчик не покидает в неблагоприятном состоянии (включение периферийных устройств, которые могут потерять энергию при попытке спать). Как правило, хорошая практика также полностью инициализирует периферийные устройства, которые вы будете использовать, поэтому даже если загрузчик сделал что-то странное, вы установите его так, как хотите.

Загрузители ATtiny

На ATtinys, как вы уже упоминали, нет роскоши для плагинов или памяти для загрузчика, поэтому ваш код всегда будет начинаться с адреса 0. Возможно, вы можете поместить ваш загрузчик на несколько более высоких страниц памяти и указать свой Reset в нем, тогда всякий раз, когда вы получаете новый шестнадцатеричный файл для флеш-памяти, возьмите команду, которая по адресу 0: 1, замените ее адресом загрузчика, а затем сохраните замененный адрес в другом месте, чтобы вызвать нормальное выполнение. (Если это RJMP ( "относительный скачок" ), значение, очевидно, необходимо будет пересчитать)

Ответ 2

Изменить

Мне интересно попытаться подключить загрузчик к Tiny AVR, который не имеет отдельного пространства памяти для кода загрузчика. Как мне становится очевидным, что код загрузчика зависит от определенных настроек плавких предохранителей и поддержки чипов, я думаю, что мне действительно интересно знать, что нужно, чтобы перегрузить загрузчик на чип, у которого нет этих предохранителей и аппаратных средств поддержка (но все еще имеет возможность самопрограммирования)?

В зависимости от вашей конечной цели может быть проще просто создать собственный загрузчик, а не пытаться его перенести. Вам действительно нужно только изучить несколько предметов для этой части.

1) uart tx

2) uart rx

3) программирование самопроверки

Что можно узнать отдельно, а затем объединить в загрузчик. Вам понадобится часть, которую вы можете использовать spi или что-то еще, чтобы написать флеш-память, чтобы, если ваш загрузчик не работает или что-то еще не получилось, вы все равно сможете продолжить разработку.

Если вы портируете или свернете свой собственный, вам все равно нужно понять эти три основные вещи относительно этой части.