Секция загрузчика (Boot Loader Section)
У ATmega328P флеш-память разделена на две части: в начале — программа, в конце — загрузчик, через который Arduino прошивается по USB-UART без программатора. Границу между ними задают фьюзы, и только из второй части микроконтроллер может переписывать собственную флеш.
Обновлено Редакция GAW
Секция загрузчика (Boot Loader Section, BLS) — область в конце флеш-памяти микроконтроллеров AVR серии ATmega, в которой размещают загрузчик. Её особенность в том, что только код, выполняемый отсюда, может переписывать флеш-память командой SPM: по даташиту ATmega328P (разд. 27.3) из секции приложения команда SPM запрещена. В ATmega48A/48PA отдельной секции нет.
Размер: фьюзы BOOTSZ
Флеш делится на секцию приложения и секцию загрузчика, граница задаётся фьюзами BOOTSZ1:0. Для ATmega328P (таблица 27-13, адреса в словах):
| BOOTSZ1:0 | Размер секции | Начало загрузчика | В байтах |
|---|---|---|---|
| 11 | 256 слов (512 байт) | 0x3F00 | 0x7E00 |
| 10 | 512 слов (1 КБ) | 0x3E00 | 0x7C00 |
| 01 | 1024 слова (2 КБ) | 0x3C00 | 0x7800 |
| 00 | 2048 слов (4 КБ) | 0x3800 | 0x7000 |
Чем больше секция, тем меньше места остаётся программе. Посчитать значения фьюзов можно в калькуляторе фьюзов AVR.
Старт: фьюз BOOTRST
Без дополнительных настроек после сброса программа начинается с адреса 0. Если запрограммировать фьюз BOOTRST, вектор сброса переносится на начало секции загрузчика. Даташит (разд. 27.6) подчёркивает, что сама программа фьюзы изменить не может: их меняют только внешним программатором. Второй способ попасть в загрузчик — переход из приложения по команде.
RWW и NRWW
Независимо от BOOTSZ, флеш разделена ещё на две фиксированные области. У ATmega328P RWW (Read-While-Write) — слова 0x0000–0x37FF, NRWW — 0x3800–0x3FFF. Пока идёт запись страницы в RWW, процессор может выполнять код из NRWW; при записи в NRWW он останавливается на всю операцию. Секция загрузчика всегда лежит в NRWW, поэтому загрузчик продолжает работать, пока переписывает приложение. Защиту секций друг от друга задают отдельные биты защиты, а механизм записи описан в статье о самопрограммировании.
Частые вопросы
Какой BOOTSZ выбрать для Optiboot в Arduino Uno?
По README Optiboot занимает 512 байт, то есть 256 слов. В Arduino Uno старший байт фьюзов — 0xDE: BOOTSZ = 11, минимальная секция с началом в слове 0x3F00 (байт 0x7E00), и запрограммирован BOOTRST, чтобы после сброса стартовал загрузчик. Скетчу остаётся 32 256 байт — это число указано в boards.txt. Размеры секций и адреса для ATmega328P — в таблице 27-13 даташита.
Можно ли вызвать загрузчик из своей программы?
Да. Даташит (разд. 27.6) описывает два способа входа: переход или вызов из приложения — например, по команде, принятой по UART, — или старт с загрузчика после каждого сброса при запрограммированном фьюзе BOOTRST. Сама программа фьюзы изменить не может, это делается только внешним программатором.
Что такое RWW и NRWW?
Это фиксированное деление флеш-памяти, не зависящее от BOOTSZ. Пока загрузчик записывает страницу в области RWW (Read-While-Write), процессор может продолжать выполнять код из области NRWW. При записи в саму NRWW процессор останавливается на всё время операции. Секция загрузчика всегда лежит в NRWW, поэтому загрузчик может работать, пока переписывает приложение.
Источники
- Microchip. ATmega48A/PA/88A/PA/168A/PA/328/P Data Sheet, DS40002061B, 2020 — разд. 27.2: в ATmega88A–328P загрузчик может читать и записывать всю флеш-память, включая себя, размер секции задаётся фьюзами, два набора битов защиты; разд. 27.3: флеш делится на секцию приложения и секцию загрузчика, размер — фьюзы BOOTSZ; команда SPM из секции приложения запрещена, поэтому загрузчик может работать только из BLS; разд. 27.4: отдельно — фиксированные области RWW и NRWW: при записи страницы в RWW код из NRWW читается, при записи в NRWW CPU остановлен на всю операцию; BLS всегда в NRWW; разд. 27.6, табл. 27-4: фьюз BOOTRST = 0 переносит вектор сброса на начало загрузчика, сама программа фьюзы менять не может; табл. 27-13 (ATmega328/328P), адреса в словах: BOOTSZ = 11 — 256 слов, начало 0x3F00; 10 — 512 слов, 0x3E00; 01 — 1024 слова, 0x3C00; 00 — 2048 слов, 0x3800; табл. 27-14: RWW 0x0000–0x37FF (224 страницы), NRWW 0x3800–0x3FFF (32 страницы); в ATmega48A/48PA отдельной секции загрузчика нет
- Arduino. ArduinoCore-avr: boards.txt — Arduino Uno: high_fuses = 0xDE (BOOTSZ1:0 = 11, BOOTRST запрограммирован), upload.maximum_size = 32256 байт, загрузчик optiboot/optiboot_atmega328.hex
- Optiboot: README.md — Optiboot занимает всего 512 байт и освобождает 1,5 КБ по сравнению со старыми загрузчиками
Нашли ошибку?
Смотрите также
- Загрузчик (bootloader)Прошивка МК без программатора через UART или USB
- Самопрограммирование (SPM)Запись флеш-памяти AVR самой программой через команду SPM по страницам
- Фьюзы AVRБиты конфигурации AVR: тактирование, загрузчик, BOD
- Биты защиты AVR (lock bits)Запрет чтения прошивки и защита загрузчика от перезаписи
- Фьюзы AVRБиты фьюзов, заводские значения и avrdude
- ATmega328PРаспиновка, фьюзы, Optiboot, периферия, питание, схема и код на C