On NULL
Адрес 0 не имеет нулевого указателя.«Нулевой указатель» - это нечто более абстрактное: специальное значение, которое применимые функции должны признать недействительным.C говорит, что специальное значение равно 0, и хотя язык говорит, что разыменование - это «неопределенное поведение», в простом мире микроконтроллеров это обычно имеет очень четкий эффект.
ATmegaBootloaders
Обычно при сбросе программный счетчик AVR (ПК) инициализируется равным 0, поэтому микроконтроллер начинает выполнять код по адресу 0.
Однако, если предохранитель перезагрузки перезагрузки ("BOOTRST"), счетчик программы вместо этого инициализируется по адресу блока в верхнем конце памяти (где это зависит от того, как установлены предохранители, см. таблица данных (PDF, 7 МБ)) для уточнения).Код, который начинается там, может делать все что угодно - если вы действительно хотите, вы можете поместить свою собственную программу туда, если вы используете ICSP (загрузчики обычно не могут перезаписать себя).
Часто это специальная программа - загрузчик - он может считывать данные из внешнего источника (часто через UART, I 2 C, CAN и т. Д.) Для перезаписи программыкод (хранится во внутренней или внешней памяти, в зависимости от микро).Загрузчик обычно ищет «специальное событие», которое может быть буквально любым, но для разработки удобнее всего что-то на шине данных, из которой он будет извлекать новый код.(Для производства это может быть специальный логический уровень на выводе, поскольку его можно проверить почти мгновенно.) Если загрузчик видит специальное событие, он может войти в режим загрузки, где он перепрошивает память программы, в противном случае он передает управление.выключен к пользовательскому коду.
Кроме того, смысл плавкого предохранителя и верхнего блока памяти загрузчика состоит в том, чтобы разрешить использование загрузчика с без модификаций исходного программного обеспечения (до тех пор, покаон не распространяется на весь адрес загрузчика).Вместо того, чтобы просто мигать только оригинальным HEX и нужными плавкими предохранителями, можно прошить оригинальный HEX, загрузчик и модифицированные предохранители, а также presto, добавленный загрузчик.протокол от 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 Bootloaders
На ATtinys, как вы упомянули, нет ничего особенного в плавких предохранителях или памяти загрузчика, поэтому ваш код всегда будет начинаться с адреса 0. Возможно, вы сможете поместить свой загрузчик на несколько более высоких страниц памяти и указать вектор RESETпри этом каждый раз, когда вы получаете новый шестнадцатеричный файл для прошивки, возьмите команду с адресом 0: 1, замените его адресом загрузчика, затем сохраните замененный адрес в другом месте, чтобы вызвать его для нормального выполнения.(Если это RJMP
(« относительный скачок»), значение, очевидно, необходимо пересчитать)