Почему скетч Arduino Uno запускается с задержкой после нажатия RESET?
Обновлено Редакция GAW
У Arduino Uno в последних 512 байтах флеш-памяти записан загрузчик Optiboot, а фьюз BOOTRST направляет сброс не в скетч, а в него. Задача загрузчика — принять новую прошивку по UART, если она идёт. Как он решает, ждать ли её, видно в исходнике optiboot.c и листинге optiboot_atmega328.lst из ядра Arduino.
Логика Optiboot
- Прочитать регистр причины сброса MCUSR и очистить его.
- Если флаг внешнего сброса EXTRF не установлен — сразу запустить скетч.
- Иначе включить сторожевой таймер на 1 с и мигнуть светодиодом: в сборке ядра Arduino LED_START_FLASHES = 3, то есть 6 переключений по 1/16 с — 0,375 с, а сторожевой таймер во время вспышек сбрасывается.
- Ждать команд по UART. Нет команд 1 с — сторожевой таймер сбрасывает кристалл, причина уже WDRF, и загрузчик сразу запускает скетч.
Наш расчёт задержки после внешнего сброса: 0,375 с + 1 с ≈ 1,4 с.
| Как запустилась плата | Флаг в MCUSR | Что делает Optiboot | Задержка |
|---|---|---|---|
| подача питания | PORF | сразу запускает скетч | нет |
| кнопка RESET | EXTRF | мигает и ждёт прошивку | около 1,4 с |
| открытие порта (автосброс) | EXTRF | мигает и ждёт прошивку | около 1,4 с |
| сторожевой таймер скетча | WDRF | сразу запускает скетч | нет |
| просадка питания | BORF | сразу запускает скетч | нет |
Флаги и их смысл подробно разобраны в статье о флагах причины сброса, а сброс от открытия порта — в статье об автосбросе.
Как убрать задержку
- Ничего не делать, если плата включается подачей питания — ожидания нет.
- Прошивать через программатор без загрузчика; рекомендуется и снять BOOTRST: старший байт фьюзов Uno 0xDE становится 0xDF, и сброс начинается с адреса 0. Прошивать по USB плата после этого не сможет, пока загрузчик не записан снова.
- Пересобрать Optiboot без вспышек или с меньшим таймаутом — вариант для тех, кому нужен и загрузчик, и быстрый старт после кнопки.
Другие особенности платы — на странице Arduino.
Похожие вопросы
Почему скетч перезапускается, когда я открываю монитор порта?
Это автосброс: при открытии порта преобразователь USB–UART на Uno сбрасывает микроконтроллер, чтобы загрузчик был готов принять прошивку. Для загрузчика это внешний сброс, поэтому перед стартом скетча снова будет пауза ожидания.
Можно ли сократить ожидание, не убирая загрузчик?
Только пересобрав Optiboot — без вспышек (LED_START_FLASHES=0) или с другим таймаутом сторожевого таймера — и записав его программатором. Готовый файл из ядра Arduino тратит около 0,375 с на вспышки и ещё 1 с на ожидание; если же плата перезапускается от питания, а не кнопкой, ожидания и так нет.
Сотрёт ли прошивка через программатор загрузчик?
Да: перед записью avrdude стирает весь кристалл, и Optiboot пропадает. Вместе с этим рекомендуется снять фьюз BOOTRST — старший байт 0xDE меняется на 0xDF, — чтобы сброс по табл. 27-4 даташита сразу шёл на адрес 0, а не в стёртую загрузочную область.
Источники
- Arduino. ArduinoCore-avr, коммит 11b9130: bootloaders/optiboot/optiboot.c, optiboot_atmega328.lst, Makefile, boards.txt — main(): ch = MCUSR; MCUSR = 0; если не установлен EXTRF — сразу appStart(); иначе watchdogConfig(WATCHDOG_1S), flash_led(LED_START_FLASHES * 2) и приём команд; flash_led() — каждое переключение светодиода через 1/16 с по Timer1 (TCNT1 = −F_CPU/(1024·16)) со сбросом сторожевого таймера; Makefile — цель atmega328 собирается с -DLED_START_FLASHES=3 и BAUD_RATE=115200; appStart() выключает сторожевой таймер и переходит к программе; загрузчик с адреса 0x7E00; uno.bootloader.high_fuses = 0xDE
- Microchip. ATmega48A/PA/88A/PA/168A/PA/328/P Data Sheet, DS40002061B, 2020 — 11.9.1 — MCUSR: флаги PORF, EXTRF, BORF, WDRF; табл. 28-8 — BOOTRST, бит 0 старшего байта ATmega328P; табл. 27-4 — BOOTRST = 1: вектор сброса 0x0000, BOOTRST = 0: сброс в загрузочную область
Нашли ошибку?
Смотрите также
- Загрузчик (bootloader)Прошивка МК без программатора через UART или USB
- Флаги причины сбросаКак узнать, почему перезапустился микроконтроллер
- Автосброс через DTR и RTSСброс и вход в загрузчик линиями DTR и RTS моста USB–UART
- Arduino и AVRЧто делают init(), millis(), analogWrite(), analogRead() и загрузчик