реклама на сайте
подробности

 
 
3 страниц V   1 2 3 >  
Reply to this topicStart new topic
> Cortex и гонки при сне
ataradov
сообщение Mar 28 2016, 17:12
Сообщение #1


Профессионал
*****

Группа: Участник
Сообщений: 1 014
Регистрация: 8-01-07
Из: San Jose, CA
Пользователь №: 24 202



Я никогда раньше на сон внимания не обращал, все проекты были с нормальным питанием. А тут нужно сделать спящее устройство с просыпанием по кнопке.

При просыпании нужно выполнить много действий (пересылка данных через радио), так что все обработчик прерывания не засунуть точно.

Проблема видится в следующем: если сразу перед вызовом __WFI() происходит прерывание, которое начинает эту долгую работу. Но как только обработка прерывания завершится, все уйдет в сон.

Что я пропустил? Как правильно обрабатывать такие ситуации?

Edit:
Похоже __WFI() проснется даже если прерывания заблокированы, так что правильная последовательность:

__disable_irq();
// подготовка ко сну
__WFI();
__enable_irq();

Сообщение отредактировал ataradov - Mar 28 2016, 17:13
Go to the top of the page
 
+Quote Post
jcxz
сообщение Mar 28 2016, 17:34
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



А что собственно смущает? И зачем запрещать прерывания перед WFI? Прерывание происходит - работаем, вышли из последнего ISR - сразу в сон по WFI.
Go to the top of the page
 
+Quote Post
ataradov
сообщение Mar 28 2016, 17:48
Сообщение #3


Профессионал
*****

Группа: Участник
Сообщений: 1 014
Регистрация: 8-01-07
Из: San Jose, CA
Пользователь №: 24 202



QUOTE (jcxz @ Mar 28 2016, 10:34) *
А что собственно смущает? И зачем запрещать прерывания перед WFI? Прерывание происходит - работаем, вышли из последнего ISR - сразу в сон по WFI.


Обработчик прерывания устанавливает флаг, что нужно что-то послать, он не делает никакой полезной работы, так что если сразу заснуть, то данные не будут отправлены.

Go to the top of the page
 
+Quote Post
jcxz
сообщение Mar 28 2016, 17:55
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(ataradov @ Mar 28 2016, 23:48) *
Обработчик прерывания устанавливает флаг, что нужно что-то послать, он не делает никакой полезной работы, так что если сразу заснуть, то данные не будут отправлены.

А кто должен обслужить этот флаг? Код находящийся в другом ISR? Тогда нет проблем - произойдёт то IRQ и будет обработка.
Go to the top of the page
 
+Quote Post
ataradov
сообщение Mar 28 2016, 18:05
Сообщение #5


Профессионал
*****

Группа: Участник
Сообщений: 1 014
Регистрация: 8-01-07
Из: San Jose, CA
Пользователь №: 24 202



QUOTE (jcxz @ Mar 28 2016, 10:55) *
А кто должен обслужить этот флаг?


while (1) цикл в основной программе. Флаг имеется в виду программный - переменная.
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Mar 28 2016, 19:16
Сообщение #6


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(ataradov @ Mar 28 2016, 19:05) *
while (1) цикл в основной программе. Флаг имеется в виду программный - переменная.

Программу надо организовать таким образом, чтобы инструкция "спать" исполнялась условно только тогда, когда все необходимые действия уже исполнены.
Предположим, что после сна в результате прерывания процессор проснулся и побежал исполнять инструкции после команды __WFI(). В прерывании, которое, по-видимому, и разбудило процессор, будут произведены некоторые короткие действия, после чего будет установлен флаг для синхронного цикла, завершить начатое. По крайней мере пока такой флаг установлен, исполнять инструкцию __WFI() нельзя. Когда же синхронный процесс всё сделает, флаг будет сброшен, и инструкция __WFI() будет исполнена.
В более сложных системах, например с OS, можно послать некоторое сообщение всем участникам сабантуя на предмет готовности поспать. Если все ответили согласием, инструкция __WFI() исполняется. И т.д, и т.п.

Go to the top of the page
 
+Quote Post
ataradov
сообщение Mar 28 2016, 19:23
Сообщение #7


Профессионал
*****

Группа: Участник
Сообщений: 1 014
Регистрация: 8-01-07
Из: San Jose, CA
Пользователь №: 24 202



QUOTE (KnightIgor @ Mar 28 2016, 12:16) *
Когда же синхронный процесс всё сделает, флаг будет сброшен, и инструкция __WFI() будет исполнена.
И получили гонку. Так как внешнее прерывание от кнопки может произойти когда угодно.

1. Спим
2. Прерывание
3. Установили флаг
4. Работаем
5. Сбросили флаг
6. Готовимся ко сну
7. Спим

Но теперь если произойдет 6a - Прерывание, то мы успешно установим флаг и уйдем в сон.

Правильный способ:

CODE
if (flag == 0)
{
  __disable_irq();

  if (flag == 0)
  {
    // подготовка ко сну
    __WFI();
  }

  __enable_irq();
}

Повторная проверка обязательная, иначе гонка все-равно будет.

Сообщение отредактировал ataradov - Mar 28 2016, 19:23
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Mar 28 2016, 19:41
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Еще можно так:
Код
    /* Clear event register */
    __sev();
    __wfe();
    /* Sleep */
    if(sleep_en)
        __wfe();

Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Mar 28 2016, 19:45
Сообщение #9


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(ataradov @ Mar 28 2016, 20:23) *
И получили гонку.

Пока висит необработаное прерывание, __WFI() спать не кладёт. Конечно, если срубить флаг неатомарной операцией, то да, может получиться, что убъется только что установленный флаг. Но это не имеет отношения к __WFI(), это есть тема гонки с учетом неатомарности доступа к флагу. На то есть LDREX и иже с ним.
Go to the top of the page
 
+Quote Post
ataradov
сообщение Mar 28 2016, 19:51
Сообщение #10


Профессионал
*****

Группа: Участник
Сообщений: 1 014
Регистрация: 8-01-07
Из: San Jose, CA
Пользователь №: 24 202



QUOTE (KnightIgor @ Mar 28 2016, 12:45) *
Пока висит необработаное прерывание, __WFI() спать не кладёт.


Какой из флагов? Флаг наличия прерывания - будет сброшен обработчиком. До программных флагов __WFI() дела нет.
Go to the top of the page
 
+Quote Post
AVI-crak
сообщение Mar 28 2016, 20:01
Сообщение #11


Частый гость
**

Группа: Участник
Сообщений: 182
Регистрация: 16-10-15
Пользователь №: 88 894



Цитата(ataradov @ Mar 29 2016, 00:12) *
Что я пропустил? Как правильно обрабатывать такие ситуации?


Само понятие сна - это ожидание прерывания без работы ядра мк.

Допустим в коде без ос: прерывание связанное с точкой останова сбрасывает бинарный флаг, в точке сна в цикле проверяется флаг - профит, спим лишнее время.
do
{
__WFI();
}while(флаг);
сначала спим, а потом проверяем.

В коде с ос всё немного сложнее. Тут простой запрет прерываний применять нельзя, их необходимо выключать по одному - в момент когда они полностью отработали. Иначе получится банальный сбой программы. Ведь прерывание по сути - это отложенное событие. После - все задачи должны быть переведены в зависимость от главного потока (вытолкнуть из диспетчера в ожидание). Ну а сам основной поток - просто обязан "переключаться диспетчером в холостом режиме", но теперь он будет всё время находится в бесконечном цикле проверки флага от важного внешнего прерывания ( его есно нужно оставить). Всё это происходит очень быстро, а паузы между активностью просто громадные. МК спит, хотя это и не 100% сон, получается где-то 99,99% от номинала.

Сообщение отредактировал AVI-crak - Mar 28 2016, 20:10
Go to the top of the page
 
+Quote Post
ataradov
сообщение Mar 28 2016, 20:12
Сообщение #12


Профессионал
*****

Группа: Участник
Сообщений: 1 014
Регистрация: 8-01-07
Из: San Jose, CA
Пользователь №: 24 202



QUOTE (AVI-crak @ Mar 28 2016, 13:01) *
сначала спим, а потом проверяем.
Это все верно если ждем прерывания от внутренних источников, да и то не всегда.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Mar 28 2016, 23:48
Сообщение #13


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(ataradov @ Mar 29 2016, 02:12) *
Это все верно если ждем прерывания от внутренних источников, да и то не всегда.

Вам тут уже ответили об общем принципе:
WFI должна выполняться только тогда, когда выполнена вся запланированная работа и нет работы, которую надо выполнить.
Т.е. (в случае наличия ОС) задача самого нижнего приоритета (фоновая) должна выполнять простой цикл с всего одной инструкцией: WFI (или WFE).
Вся остальная работа - в ISR-ах или задачах ОС более высокого приоритета.
Всё моё ПО именно так и построено, вне зависимости от того - надо экономить энергию или нет - выполнение WFI в фоновом процессе - это просто правило хорошего тона если хотите wink.gif
Когда нужно установить Ваш флаг, ставите его (хоть в ISR, хоть в любой задаче) и какой-то объект синхронизации ОС (мэйлбокс например) переводите в состояние "готов'.
Далее - у Вас есть задача, ожидающая этот мэйлбокс. Как только мэйлбокс перешёл в сост. "готов" и нет более приоритетных задач, задача получает управление и обрабатывает его.
Любая установка готовности любому объекту синхронизации ОС - это вызов диспетчера ОС, который просмотрит список задач и переведёт те из них, которые готовы к выполнению, в состояние "готова".
Если окажется, что текущая задача ОС имеет приоритет ниже, чем новая готовая задача, то будет вызван переключатель контекста ОС. Вызов переключателя контекста ОС - это собственно программное возбуждение прерывания PendSV, имеющего самый низший приоритет из всех прерываний (ниже любого аппаратного IRQ).
Соответственно в ISR PendSV управление войдёт:
а) или сразу, если выполняется какая-то задача ОС (с более низким приоритетом, чем активизируемая);
б) или после завершения всех текущих ISR, если выполняется любой ISR.

Даже если Вы не используете ОС и у Вас всего одна полезная задача, всё равно лучше построить ПО по тому-же принципу: процедура установки Вашего флага, после его установки, возбуждает PendSV, которое переключит контекст с фоновой на полезную задачу (если уже не выполняется полезная), которая, сделав всю работу (и проверив в конце что флаг опять не установился), вызовет переключатель контекста на фоновую задачу.
Таким образом - как только возникает прерывание, ISR которого ставит флаг, управление находится в ISR-ах до тех пор, пока управление не получит полезная задача и не обработает флаг. И WFI может выполниться только тогда, когда флаг сброшен. И никакие гонки в принципе невозможны.

Цитата(ataradov @ Mar 29 2016, 01:23) *
1. Спим
2. Прерывание
3. Установили флаг
4. Работаем
5. Сбросили флаг
6. Готовимся ко сну
7. Спим
Но теперь если произойдет 6a - Прерывание, то мы успешно установим флаг и уйдем в сон.

6а - прерывание, установившее флаг и мэйлбокс (либо просто активировавшее PendSV если без ОС).
6б - сразу после завершения ISR вход в ISR PendSV (если без ОС); если с ОС - вход в PendSV только если выполнялась менее приоритетная задача, если более приоритетная - вход в PendSV после перехода её в сост. ожидания.
В любом случае после прерывания 6а и до пункта 7, будет выполнено PendSV (сразу или не сразу), которое переключит контекст на задачу обрабатывающую флаг. И управление дойдёт до пункта 7 только когда флаг уже будет обработан.
Запрет прерываний тут нигде не нужен. Хотя можно и запретить если сильно хочется - WFI вроде игнорит маску PRIMASK.
Можете, если без ОС, собственно сам обработчик PendSV сделать полезной задачей, обрабатывающей Ваш флаг. Тогда вся полезная работа у Вас всегда будет выполняться только в ISR-ах, установка Вашего флага будет всегда вызывать установку запроса PendSV.
Go to the top of the page
 
+Quote Post
Kabdim
сообщение Mar 29 2016, 06:30
Сообщение #14


Знающий
****

Группа: Свой
Сообщений: 558
Регистрация: 26-11-14
Из: Зеленоград
Пользователь №: 83 842



Вчера уткнулся ровно в ту же задачу. Кмк большинство отвечающих слишком привыкли к ртосам. Самому писать кусок с переключением контекстов при отсутсвии ртос - саму написать кусок ртос, непрактично. Мне приходили на ум 2 варианта:
1. Основной цикл перенести в SVC
2. Пробуждающий обработчик прерываний меняет режим энергосбережения на слип и устанавливает таймер на ~20 тактов вперед. Даже если в это время сработает WFI, то произойдет быстрый выход из сна. Выглядит как костыль, но должно работать и не потребует миграции на ртос/написания своего маленького велосипедного ядра.

А ваш вариант с запретом работает?
Go to the top of the page
 
+Quote Post
ataradov
сообщение Mar 29 2016, 06:33
Сообщение #15


Профессионал
*****

Группа: Участник
Сообщений: 1 014
Регистрация: 8-01-07
Из: San Jose, CA
Пользователь №: 24 202



QUOTE (Kabdim @ Mar 28 2016, 23:30) *
А ваш вариант с запретом работает?
Да, прекрасно работает. Проверял специально долгой задержкой перед сном.

Ну и естественно я не собираюсь городить переключение контекста.

Сообщение отредактировал ataradov - Mar 29 2016, 06:34
Go to the top of the page
 
+Quote Post

3 страниц V   1 2 3 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 4th July 2025 - 19:30
Рейтинг@Mail.ru


Страница сгенерированна за 0.01613 секунд с 7
ELECTRONIX ©2004-2016