WFI и WFE
В пустом цикле программы для Cortex-M обычно стоит одна команда — WFI или WFE. Обе останавливают ядро до нужного события и экономят ток, но будят его по-разному, и от выбора зависит, не проспит ли программа прерывание.
Обновлено Редакция GAW
WFI (Wait For Interrupt) и WFE (Wait For Event) — команды ядер Cortex-M, которыми программа сообщает, что ей нечего делать, и разрешает ядру уснуть. Что именно выключится, решает производитель кристалла: по DUI 0552A обычный сон останавливает тактирование процессора, а глубокий (бит SLEEPDEEP регистра SCR) — системную частоту, PLL и flash-память (разд. 2.5). У STM32 это режим Sleep при SLEEPDEEP = 0 и режим Stop при SLEEPDEEP = 1.
Что будит ядро
| WFI | WFE | |
|---|---|---|
| Засыпает | сразу, если нет условия пробуждения | только если регистр событий равен 0 |
| Будит исключение с достаточным приоритетом | да | да |
| Будит внешнее событие и команда SEV | нет | да |
| Будит запрещённое прерывание | нет | да, при SEVONPEND = 1 |
Регистр событий — один скрытый бит. Его ставят любое событие пробуждения WFE и любой возврат из исключения, а сбрасывает только сама команда WFE; прочитать его программа не может (ARMv7-M ARM, B1.5.18). Отсюда частая загадка: первая WFE после прерывания не усыпляет ядро, потому что бит стоит, — она его лишь сбрасывает.
Приёмы
- Сон без обработчика. Если перед WFI поставить PRIMASK = 1, разрешённое прерывание разбудит ядро, но обработчик не запустится, пока программа не сбросит PRIMASK. Так успевают восстановить тактирование до входа в ISR (DUI 0552A, разд. 2.5.2).
- Пробуждение по флагу. WFE с SEVONPEND = 1 будит ядро по любому новому ожидающему прерыванию, даже запрещённому в NVIC, — обработчик не нужен вовсе.
- Спать между прерываниями. Вместо WFI в цикле можно включить sleep-on-exit: ядро засыпает само при возврате из последнего обработчика.
Язык C сам эти команды не порождает, в CMSIS для них есть __WFI() и __WFE(). Обе — подсказки: реализация вправе выполнить их как пустую команду, а пробуждения бывают ложными, например от отладчика, поэтому условие проверяют в цикле (ARMv7-M ARM, B1.5.17). У STM32 вход в сон по WFI или WFE происходит, только если нет ожидающего прерывания или события (RM0090, разд. 5.3). Режимы сна ядра разобраны в статье «Cortex-M3».
Частые вопросы
Чем WFI отличается от WFE?
WFI ждёт прерывание: ядро спит, пока не придёт исключение с приоритетом, достаточным для входа в обработчик. WFE ждёт событие и сначала смотрит регистр событий: если там 1, команда сбрасывает его и не засыпает. Событием считаются прерывание, сигнал внешнего события, команда SEV, а при SEVONPEND = 1 — и любое новое ожидающее прерывание, даже запрещённое.
Почему после WFE программа не засыпает?
Регистр событий уже стоит в 1: его ставит любое событие пробуждения и любой возврат из исключения. Первая WFE только сбрасывает его и сразу возвращает управление. Поэтому WFE вызывают в цикле, который проверяет условие, — вторая команда уже усыпит ядро.
Нужно ли проверять условие после пробуждения?
Да. Arm прямо указывает, что пробуждения бывают ложными, например при остановке отладчиком, а сами WFI и WFE — подсказки, которые реализация вправе не выполнять. Правильный цикл ожидания проверяет флаг, засыпает и после пробуждения проверяет флаг снова.
Источники
- Arm. Cortex-M3 Devices Generic User Guide, DUI 0552A, 2010 — разд. 2.5.1: WFI — немедленный вход в сон, если нет условия пробуждения; WFE — сон в зависимости от однобитного регистра событий: при 0 ядро засыпает, при 1 сбрасывает его и продолжает работу; регистр ставят внешний сигнал события или команда SEV, программа не может читать его напрямую; система может давать ложные пробуждения, например от отладчика; разд. 2.5.2: WFI будит исключение с достаточным приоритетом; приём с PRIMASK = 1 и FAULTMASK = 0 — ядро просыпается, но не входит в обработчик, пока PRIMASK не сброшен; WFE будят исключение, внешнее событие, SEV и при SEVONPEND = 1 любое новое ожидающее прерывание, даже запрещённое; разд. 2.5.5: в CMSIS __WFI() и __WFE(); табл. 4-19: SCR — SEVONPEND (бит 4), SLEEPDEEP (бит 2)
- Arm. ARMv7-M Architecture Reference Manual, ARM DDI 0403C_errata_v3, 2010 — B1.5.17: WFI и WFE — подсказки (hint), реализация может не выполнять их вовсе; уровень экономии и время пробуждения зависят от реализации; код должен переносить ложные пробуждения; B1.5.18: регистр событий ставится любым событием пробуждения WFE и выполнением возврата из исключения, сбрасывается только командой WFE, значение после сброса не определено; SEV сигналит событие всем процессорам системы
- STMicroelectronics. RM0090 Reference manual STM32F405/415, STM32F407/417, STM32F427/437, STM32F429/439 (Rev 21) — разд. 5.3: режимы пониженного потребления включаются командами WFI и WFE или битом SLEEPONEXIT при возврате из ISR; вход через WFI или WFE выполняется, только если нет ожидающего прерывания или события; табл. 25: Sleep-now — WFI или WFE при SLEEPDEEP = 0, выход по прерыванию (WFI) или событию пробуждения (WFE), при SEVONPEND = 1 — и по запрещённому в NVIC прерыванию
Нашли ошибку?
Смотрите также
- Режимы снаSleep mode: Idle, Power-down, пробуждение и ток
- Режим StopРежим низкого потребления STM32: такты остановлены, ОЗУ и регистры сохранены
- Sleep-on-exit (SLEEPONEXIT)Автоматический сон ядра при возврате из последнего обработчика
- Включение тактирования периферииБиты RCC, без которых периферия STM32 не работает
- Cortex-M3Регистры, карта памяти, bit-banding, NVIC, SysTick, MPU, старт, пример