Как программно перезагрузить микроконтроллер?
Обновлено Редакция GAW
Программный сброс нужен после обновления прошивки, смены настроек или при обнаруженной ошибке. Правильный способ — тот, который даёт настоящий аппаратный сброс: регистры периферии возвращаются к исходным значениям, как при нажатии кнопки RESET.
| Микроконтроллер | Чем сбросить | Что записать |
|---|---|---|
| STM32, другие Cortex-M | регистр AIRCR, 0xE000ED0C | VECTKEY = 0x5FA и SYSRESETREQ = 1 |
| ATmega328P (Arduino UNO) | сторожевой таймер | режим System Reset, период 16 мс |
Cortex-M: бит SYSRESETREQ
По руководству Arm регистр AIRCR защищён ключом: запись без значения 0x5FA в старших 16 битах процессор игнорирует. С ключом бит SYSRESETREQ запрашивает сброс всей системы, кроме отладочного блока. Готовая функция — NVIC_SystemReset() из CMSIS: она дожидается окончания записей в память барьером DSB, сохраняет поле приоритетов PRIGROUP и ставит бит.
У STM32F1 по RM0008 такой сброс — один из источников системного сброса наравне с выводом NRST и сторожевыми таймерами. Он возвращает к исходным значениям все регистры, кроме флагов причины сброса и резервного домена с часами. Подробнее о системных регистрах ядра — в статье о Cortex-M3.
AVR: сторожевой таймер
У ATmega328P отдельного бита сброса нет, поэтому включают сторожевой таймер в режиме System Reset с периодом 16 мс и не сбрасывают его: через 16 мс контроллер перезапустится так же, как от вывода RESET. Значения регистров для нужного периода подберёт калькулятор сторожевого таймера AVR. В Arduino это две строки по примеру из FAQ avr-libc:
#include <avr/wdt.h>
wdt_enable(WDTO_15MS);
while (1) {}
Ловушка в том, что после такого сброса флаг WDRF оставляет таймер включённым. Даташит требует в начале программы сначала очистить WDRF в MCUSR, а потом бит WDE, иначе контроллер будет перезагружаться бесконечно; avr-libc для этого предлагает функцию в секции .init3 с MCUSR = 0 и wdt_disable(). Чем такой сброс отличается от сброса при включении питания, показывают флаги MCUSR: PORF, EXTRF, BORF и WDRF.
Похожие вопросы
Почему после перезагрузки сторожевым таймером Arduino перезагружается снова и снова?
У ATmega328P флаг WDRF после такого сброса держит сторожевой таймер включённым. Если программа или загрузчик не сбросят сначала WDRF в регистре MCUSR, а затем бит WDE, таймер через 16 мс снова перезагрузит контроллер.
Как узнать, что STM32 перезагрузился программно?
По флагам в регистре RCC_CSR: программный сброс ставит флаг SFTRSTF, сторожевые таймеры — свои флаги, вывод NRST — флаг PINRSTF. Флаги переживают системный сброс и стираются записью бита RMVF.
Можно ли перезагрузить микроконтроллер переходом на адрес 0?
Переход на начало программы — не сброс: регистры периферии сохраняют настройки, сделанные раньше, и код запуска встретит их не в исходном состоянии. Аппаратный сброс через SYSRESETREQ или сторожевой таймер возвращает регистры к исходным значениям — у STM32F1 по RM0008 все, кроме флагов сброса и резервного домена.
Источники
- Arm. Cortex-M3 Devices Generic User Guide, DUI 0552A, 2010 — 4.3.5 — регистр AIRCR по адресу 0xE000ED0C: запись игнорируется без 0x5FA в поле VECTKEY (биты 31:16); бит 2 SYSRESETREQ запрашивает сброс всей системы, кроме отладки; биты VECTRESET и VECTCLRACTIVE зарезервированы для отладчика
- STMicroelectronics. RM0008 Rev 21. Reference manual: STM32F101xx, STM32F102xx, STM32F103xx, STM32F105xx and STM32F107xx — 7.1.1 — системный сброс от вывода NRST, сторожевых таймеров WWDG и IWDG и программный через SYSRESETREQ; сбрасывает все регистры, кроме флагов в RCC_CSR и резервного домена; флаг SFTRSTF в RCC_CSR
- Microchip. ATmega48A/PA/88A/PA/168A/PA/328/P Data Sheet (DS40002061B) — 11.6, 11.8 и 11.9 — сброс от сторожевого таймера по истечении периода в режиме System Reset; период от 16 мс до 8 с; флаг WDRF в MCUSR принудительно держит WDE включённым, поэтому в начале программы сбрасывают WDRF, затем WDE
- Arm. CMSIS 6, v6.4.0: CMSIS/Core/Include/core_cm3.h — __NVIC_SystemReset(): барьер __DSB(), запись в SCB->AIRCR ключа 0x5FA, сохранённого поля PRIGROUP и бита SYSRESETREQ, затем ожидание сброса
- avr-libc 2.3.2. Frequently Asked Questions: How do I perform a software reset of the AVR? — программный сброс через сторожевой таймер: wdt_enable(WDTO_15MS) и бесконечный цикл из <avr/wdt.h>; у новых AVR сторожевой таймер остаётся включённым после сброса — его отключают в секции .init3: MCUSR = 0, wdt_disable()
Нашли ошибку?
Смотрите также
- Сторожевой таймер AVRВремя WDT по WDP, режимы, константы WDTO, код с последовательностью WDCE
- Сторожевой таймерWatchdog: сброс МК при зависании программы
- Cortex-M3Регистры, карта памяти, bit-banding, NVIC, SysTick, MPU, старт, пример
- Сторожевые таймеры STM32PR и RLR у IWDG, WDGTB, счётчик и окно у WWDG, разброс LSI, код