Перейти к содержанию

Секция загрузчика (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Размер секцииНачало загрузчикаВ байтах
11256 слов (512 байт)0x3F000x7E00
10512 слов (1 КБ)0x3E000x7C00
011024 слова (2 КБ)0x3C000x7800
002048 слов (4 КБ)0x38000x7000

Чем больше секция, тем меньше места остаётся программе. Посчитать значения фьюзов можно в калькуляторе фьюзов 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, поэтому загрузчик может работать, пока переписывает приложение.

Источники

  1. 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 отдельной секции загрузчика нет
  2. Arduino. ArduinoCore-avr: boards.txt — Arduino Uno: high_fuses = 0xDE (BOOTSZ1:0 = 11, BOOTRST запрограммирован), upload.maximum_size = 32256 байт, загрузчик optiboot/optiboot_atmega328.hex
  3. Optiboot: README.md — Optiboot занимает всего 512 байт и освобождает 1,5 КБ по сравнению со старыми загрузчиками

Нашли ошибку?