Sleep-on-exit (SLEEPONEXIT)
Бывают программы, где весь полезный код живёт в обработчиках прерываний, а основной цикл только засыпает. Для них в Cortex-M есть бит SLEEPONEXIT: ядро уходит в сон прямо при возврате из последнего обработчика и даже не возвращается в main.
Обновлено Редакция GAW
Sleep-on-exit — режим ядер Cortex-M, в котором процессор засыпает сам при возврате из последнего обработчика исключения. Его включает бит SLEEPONEXIT (бит 1) регистра SCR по адресу 0xE000ED10. По DUI 0552A, когда этот бит равен 1 и ядро закончило все обработчики, оно возвращается в режим Thread и сразу уходит в сон; Arm предлагает этот механизм для программ, которым процессор нужен только по исключению (разд. 2.5.1, табл. 4-19).
Как это работает
Без этого бита цикл программы, управляемой прерываниями, выглядит так: обработчик отработал, ядро сняло кадр со стека, вернулось в main, выполнило WFI и уснуло. С битом SLEEPONEXIT ядро засыпает прямо в момент возврата. По ARMv7-M ARM возврат при этом вообще не выполняется, и следующее прерывание входит в обработчик как хвостовая цепочка — без повторного сохранения регистров (B1.5.17). Экономятся и такты на возврат и вход, и ток, потраченный на них. Сколько тактов занимает вход в обработчик обычным путём, видно в статье «Задержка прерывания».
Глубину сна выбирает соседний бит SLEEPDEEP. У STM32 при SLEEPDEEP = 0 это режим Sleep, при SLEEPDEEP = 1 — Stop или Standby по битам контроллера питания (RM0090, разд. 5.3).
SCB->SCR |= SCB_SCR_SLEEPONEXIT_Msk; /* sleep on return from the last ISR */
__WFI(); /* first sleep; ISRs run from now on */
Ловушки
- Основной цикл перестаёт выполняться. Это не ошибка, а смысл режима. Если
mainдолжна что-то сделать, обработчик сбрасывает SLEEPONEXIT перед выходом. - Ложные пробуждения. Архитектура допускает выход из этого сна без причины, и программа должна это переносить (B1.5.17).
- PRIMASK. Приём «проснуться без входа в обработчик» с PRIMASK = 1 работает для WFI, но для sleep-on-exit архитектура выход в этом случае не гарантирует.
- Отладка. Отладчику нужны такты ядра и шины, поэтому у STM32 он заранее ставит биты DBG_SLEEP или DBG_STOP в регистре DBGMCU_CR — иначе в сне связь теряется (RM0090, разд. 38.16.1).
Режимы сна ядра и их выбор описаны в статье «Cortex-M3», глубокий сон STM32 — в статье «Режим Stop».
Частые вопросы
Когда включать sleep-on-exit?
Когда вся работа выполняется в обработчиках: таймер будит ядро, обработчик опрашивает датчик и выходит, и до следующего прерывания делать нечего. С битом SLEEPONEXIT ядро засыпает прямо при выходе из обработчика, не тратя такты на возврат в основной цикл и повторную команду WFI.
Почему после включения SLEEPONEXIT код в main больше не выполняется?
Так и задумано: ядро возвращается в режим Thread только формально и сразу засыпает, а следующее прерывание входит в обработчик без возврата в main. Если основному циклу нужно отработать, обработчик сбрасывает бит SLEEPONEXIT в регистре SCR перед выходом, и возврат в программу произойдёт обычным образом.
Куда уходит ядро: в Sleep или в Stop?
Это решает бит SLEEPDEEP того же регистра SCR. При SLEEPDEEP = 0 ядро уходит в обычный сон, у STM32 это режим Sleep; при SLEEPDEEP = 1 — в глубокий, у STM32 это Stop или Standby в зависимости от битов контроллера питания.
Источники
- Arm. Cortex-M3 Devices Generic User Guide, DUI 0552A, 2010 — разд. 2.5.1: при SLEEPONEXIT = 1 ядро, закончив все обработчики исключений, возвращается в режим Thread и сразу засыпает; механизм для программ, которым процессор нужен только по исключению; разд. 2.5.2: пробуждение — как у WFI, по исключению с достаточным приоритетом; табл. 4-19: SCR по адресу 0xE000ED10, бит 1 SLEEPONEXIT — сон или глубокий сон при возврате из ISR, «позволяет приложению, управляемому прерываниями, не возвращаться в пустую основную программу»; бит 2 SLEEPDEEP выбирает сон или глубокий сон
- Arm. ARMv7-M Architecture Reference Manual, ARM DDI 0403C_errata_v3, 2010 — B1.5.17: если при возврате из исключения активных исключений, кроме возвращающегося, нет, бит конфигурации приостанавливает выполнение: возврат не выполняется, а следующее исключение входит как хвостовая цепочка; из этого состояния возможны ложные выходы, программа должна их переносить; при PRIMASK = 1 и FAULTMASK = 0 архитектура не обязывает выходить из этого сна, в отличие от WFI
- STMicroelectronics. RM0090 Reference manual STM32F405/415, STM32F407/417, STM32F427/437, STM32F429/439 (Rev 21) — разд. 5.3, табл. 25–26: режим Sleep-on-exit — вход при возврате из ISR при SLEEPDEEP = 0, SLEEPONEXIT = 1 и отсутствии ожидающих прерываний; выход — по прерыванию; тот же бит в описании режимов Stop и Standby (SLEEPDEEP = 1); разд. 38.16.1: в сеансе отладки отладчик заранее ставит DBG_SLEEP или DBG_STOP в DBGMCU_CR, чтобы в Sleep и Stop сохранялись такты HCLK и FCLK, нужные для связи
Нашли ошибку?
Смотрите также
- WFI и WFEКоманды ожидания прерывания и события для входа ядра в сон
- Режимы снаSleep mode: Idle, Power-down, пробуждение и ток
- Режим StopРежим низкого потребления STM32: такты остановлены, ОЗУ и регистры сохранены
- Задержка прерыванияВремя от запроса до обработчика: Cortex-M3 и AVR
- Cortex-M3Регистры, карта памяти, bit-banding, NVIC, SysTick, MPU, старт, пример