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

Sleep mode и внешние прерывания

Всем здравствуйте ))

 

Столкнулся с проблемой. Курил доки на mcu, искал в инете, но ответа на свой вопрос не смог найти.

Суть собственно вот в чем:

Есть желание во время простоя микроконтроллера переводить его в sleep mode, что собственно получается успешно делать. Также на плате есть чип, который может сгенерировать внешнее для mcu прерывание в любой момент времени. То есть оно может случиться например в момент выполнения процедуры ухода в сон.

void IdleMode(void)
{
  SCB->SCR &= ~SCR_SLEEPDEEP;
  
  //  например прерывание происходит вот здесь

  PMC->PMC_FSMR &= ~PMC_FSMR_LPM;
  __WFE();
}

Попав в прерывание я установлю флажок на его обработку в основном цикле и благополучно усну, при этом в основной обработчик могу попасть совсем не скоро, только когда еще одно прерывание произойдет.

 

Например я знаю как такая ситуация обходится в avr. Там разрешают прерывания sei перед инструкцией sleep, а согласно доке на ядро, следующая инструкция после sei выполнится гарантированно.

 

Есть ли здесь подобные механизмы? Кто-нибудь сталкивался такой проблемой и как обходил её?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Есть ли здесь подобные механизмы? Кто-нибудь сталкивался такой проблемой и как обходил её?

Вот такой пример попадался (Cortex-M3).

volatile bool lfrcoReady = false
void CMU_IRQHandler(void)
{ 
 /* Clear interrupt flag */
 CMU_IntClear(CMU_IF_LFRCORDY);

 /* Indicate that LFRCO is ready */
 lfrcoReady = true;
}


/***************************************************************************//**
* @brief Main function. Enables LFRCO and waits in EM1 until it is ready
******************************************************************************/
int main(void)
{ 
 /* Chip revision alignment and errata fixes */
 CHIP_Init();

 /* Enable CMU IRQ when LFRCO is ready */
 CMU_IntEnable(CMU_IF_LFRCORDY);

 /* Enable CMU interrupt vector in NVIC */
 NVIC_EnableIRQ(CMU_IRQn);

 /* Enable LFRCO but do not wait until it is ready */
 CMU_OscillatorEnable(cmuOsc_LFRCO, true, false);

 /* Wait in EM1 until LFRCO is ready.
  * Disable interrupts first to avoid interrupt executing between lfrcoReady
  * check and _WFI(); This would have caused the program to get stuck! */
 __disable_irq();
 while(!lfrcoReady)
 {
__WFI(); /* Pending and enabled IRQs will wake up the CPU, but not go to ISR */
__enable_irq(); /* ISR for any pending and enabled IRQs will be executed after this */
 }

 /* Wait here at the end */
 while(1);	 
}

Тут правда не внешние прерывания, а прерывание по готовности осцилятора, но разница невелика.

Изменено пользователем IgorKossak
[codebox] для длинного кода!!!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что-то я не совсем понимаю. Мы запрещая прерывания, запрещаем контроллеру прыгать на их обработчики, но при это даже в запрещенном сотоянии это прерывание способно пробудить микроконтроллер?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что-то я не совсем понимаю. Мы запрещая прерывания, запрещаем контроллеру прыгать на их обработчики, но при это даже в запрещенном сотоянии это прерывание способно пробудить микроконтроллер?

Так получается.

Попробуйте.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Метод проб и ошибок конечно тоже вариант, но вот я к стати вроде как нашел теоретическое подтверждение такому поведению.

 

Книжка называется "The definitive guide to the arm cortex-M3" second edition by Joseph Yiu

 

На 234 странице приведено "The rules of waking the Cortex-M3 processor from sleep modes"

 

Table 14.2 WFI and WFE Wakeup Behavior
WFI Behavior                                       Wake Up               IRQ Execution
IRQ with BASEPRI
IRQ priority > BASEPRIv                            Y                           Y
IRQ priority =< BASEPRI                           N                          N
IRQ with BASEPRI and PRIMASK
IRQ priority > BASEPRI                              Y                           N
IRQ priority =< BASEPRI                            N                          N
WFE Behavior
IRQ with BASEPRI, SEVONPEND = 0
IRQ priority > BASEPRI                               Y                           Y
IRQ priority =< BASEPRI                             N                           N
IRQ with BASEPRI, SEVONPEND = 1
IRQ priority > BASEPRI                               Y                           Y
IRQ priority =< BASEPRI                             Y                           N
IRQ with BASEPRI and PRIMASK, SEVONPEND = 0
IRQ priority > BASEPRI                               N                           N
IRQ priority =< BASEPRI                             N                           N
IRQ with BASEPRI & PRIMASK, SEVONPEND = 1
IRQ priority > BASEPRI                                Y                          N
IRQ priority =< BASEPRI                              Y                          N

 

То есть запрещая прерывание через cpsid i, мы устанавливаем PRIMASK, то есть попадаем в вариант 3, когда все прерывания приоритета выше чем BASEPRI будут будить ядро ноне будут инициировать прыжка на вектор. Но это только если уснуть через WFI. При засыпании через WFE эффекта не будет никакого, только если предварительно event не сгенерируется.

 

Спасибо за то что идею подсказали, а то бы я долго лопатил все эти доки пока не наткнулся бы на эту таблицу.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Метод проб и ошибок конечно тоже вариант, но вот я к стати вроде как нашел теоретическое подтверждение такому поведению.

Значит можно пользоваться.

P.S. Нашёл откуда исходник "моего" примера:AppNota - это не sam3, но тоже Cortex-M3, поэтому в основном одинаково будет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вопрос : Правильно ли я понимаю смысл бита SLEEPONEXIT ? Когда бит стоит и команда WFI стоит внутри прерывания, процессор сначала выходит из прерывания, а уже потом засыпает. А если бит сброшен, то процессор засыпает сразу после команды WFI , даже если он внутри прерывания.

 

 

Sleep-now: if the SLEEPONEXIT bit is cleared, the MCU enters Sleep mode as soon

as WFI or WFE instruction is executed.

Sleep-on-exit: if the SLEEPONEXIT bit is set, the MCU enters Sleep mode as soon as

it exits the lowest priority ISR.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...