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

Как программно перезагрузить микроконтроллер?

Обновлено Редакция GAW

Программный сброс нужен после обновления прошивки, смены настроек или при обнаруженной ошибке. Правильный способ — тот, который даёт настоящий аппаратный сброс: регистры периферии возвращаются к исходным значениям, как при нажатии кнопки RESET.

МикроконтроллерЧем сброситьЧто записать
STM32, другие Cortex-Mрегистр AIRCR, 0xE000ED0CVECTKEY = 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 все, кроме флагов сброса и резервного домена.

Источники

  1. Arm. Cortex-M3 Devices Generic User Guide, DUI 0552A, 2010 — 4.3.5 — регистр AIRCR по адресу 0xE000ED0C: запись игнорируется без 0x5FA в поле VECTKEY (биты 31:16); бит 2 SYSRESETREQ запрашивает сброс всей системы, кроме отладки; биты VECTRESET и VECTCLRACTIVE зарезервированы для отладчика
  2. STMicroelectronics. RM0008 Rev 21. Reference manual: STM32F101xx, STM32F102xx, STM32F103xx, STM32F105xx and STM32F107xx — 7.1.1 — системный сброс от вывода NRST, сторожевых таймеров WWDG и IWDG и программный через SYSRESETREQ; сбрасывает все регистры, кроме флагов в RCC_CSR и резервного домена; флаг SFTRSTF в RCC_CSR
  3. 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
  4. Arm. CMSIS 6, v6.4.0: CMSIS/Core/Include/core_cm3.h — __NVIC_SystemReset(): барьер __DSB(), запись в SCB->AIRCR ключа 0x5FA, сохранённого поля PRIGROUP и бита SYSRESETREQ, затем ожидание сброса
  5. 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()

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