×

Embedded: відхід процессора до сну

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті

Вітаю.

Маю Cortex-M4, там є команда WFI (wait for interrupt) котра вирубає проц допоки не прийде переривання.
І є у мене змінна, яка є індикатором того, що в черзі тасків є робота і спати не можна. Додати тасків в чергу можна в тому числі в перериванні, що я і використовую. Схоже, що в той момент, коли я йду спати відбувається таке:
1. перевірка змінної — можна спати
2. іду спати

а між цими двома кроками приходить переривання, яке модифікує змінну. виходить, що обробка цього таску відбуваєьться тільки тоді, коли приходить наступне переривання.

Можна на асмі написати так, що все робиться у дві команди (лоад в регістр, кондішнал сліп), але між двома командами все-одно може прийти переривання.

От якби була команда, яка включає переривання і іде в сліп одночасно, тоді можна було-б:
1. вимкнув переривання
2. перевірка змінної
3. суперкоманда

Але такої, схоже, немає.

Підкажіть, як така проблема вирішується в інших процесорах? Або чому вона не потребує вирішення / не повинна виникати?

👍ПодобаєтьсяСподобалось0
До обраногоВ обраному0
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Введи флаг «готовлюсь спать» и после его установки проверяй спискок заданий. При прерывании необходимо проверять готовимся спать или нет. Типа флаг входа в критическую область. Классика.

При прерывании необходимо проверять готовимся спать или нет.
И что делать, если я зашел в прерывание, а флаг «готовлюсь спать» установлен?

Сори. Я не внимательно посмотрел задачу, просто на автомате посоветовал отметить семафором критический участок. А так не вижу проблем. Если по прерыванию создается новое задание, то ты его должен запустить. Может даже перейдя на эту же самую проверку.

Я понимаю, что должен. Вопрос в том как.

Ну, если совсем конкретно то командой типа JMP :) А если серьезно, то я ж не знаю как ты систему построил. Вот после того как создал задание наверное ты в его список заносишь? Ну, и джампай.. Фактически проверка этой переменной и есть твой планировщик задач. Или нет?

Нет времени объяснять, проблемма решена давно.
В решении нет никаких джампаний и притулить их там некуда. Ниже ссылку давали на популярное объяснение решения: dou.ua/...c/10352/#501725

Рішення знайдено:
1. Вимкнути переривання
2. Перевірка
3. WFI
4. Ввімкнути переривання

(переривання розбудить процессор незалежно від того, ввімкнене воно глобально, чи ні)

Якщо будеш це робити у головному циклі — переривання не увімкнуться. Ядро піде у сон відразу. А якщо робиш із переривання — треба виставити біт SLEEPONEXIT (принаймні на M3 так).

Якщо будеш це робити у головному циклі — переривання не увімкнуться. Ядро піде у сон відразу.
Не піде, якщо є pending interrupt

Можливо, я ж казав про M3, що там у M4 я не знаю. Хоча перевір RM.

Там ще має бути настройка, аби він відразу після переривання йшов у сон, якщо раніше було виконано WFI/WFE.

P.S.: Якщо так робить — не чіпай.

Проблема давно відома у інших краях — можна подивитись, наприклад, «signal pipe» і причини введення pselect() та ppoll() у юніксах. На x86 це вирішується за рахунок того, що STI дозволяє переривання не відразу, а після наступної команди (тобто послідовність STI; HLT дозволить переривання тільки після входу процесору до зупиненого стану). Щодо ARM — нічого гарантованого не можу сказати, не гоняв їх. Але: тут, якщо я зрозумів вірно, кажуть, що WFI виходить зі сну навіть якщо переривання заборонені. Тобто, Ви їх повинні заборонити перед цією командою, а вона сама в себе вмикає дозвіл на час сну. Як на мене, дуже логічно.

Ну якщо ти використовуєш якийсь диспетчер — то він напевне крутиться на системному таймері SysTic. От і дивишся: нема більше тасків у диспетчера — спати. А systic — сам пробудить ядро і відтак — запустить обробку черги.
Якщо прийшло переривання і воно додало задачу — то і нехай, диспетчер його виконає якщо воно додано в саму чергу і засне, а якщо додане з інтервалом — то диспетчер побачить що нічого нема і зановуж таки засне.
А по перериванню таймера — диспетчер прокинеться і розбереться що і як робить.

І взагалі WFI/WFE доволі слабо (30%) економлять живлення. Добре економити можна якщо вимикати всю непотрібну перифірію або засипати повністю і будитись по RTC.
А для всіляких RTOS є напевне якісь конфігураційні змінні.

Справа в тому, що в моєму випадку обробка таску, пов’язаного з перериванням, буде виконана не відразу, а тоді, коли процессор прокинеться наступного разу. А це може бути і через місяць — системний таймер будить процессор не з рівними інтервалами, а тоді, коли це треба.

Коли пробудить тоді і обробиться.

Нехай у нас додається таск із затримкою.
У перериванні додали таск і вийшли. Ядро працює далі і переключається на основний цикл де у вас диспетчер. Диспетчер бачить що зараз нічого нема і йде у сон. А коли таск піде на виконання — виконається, диспетчер побачить що знову нічого нема і знову у WFI.

А якщо таск додається на негайне виконання — тоді ще простіше. Додали, перейшли у головний цикл, виконали, нічого нема? — заснули.

Підписатись на коментарі