Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Sleep mode и внешние прерывания
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
xelax
Всем здравствуйте ))

Столкнулся с проблемой. Курил доки на mcu, искал в инете, но ответа на свой вопрос не смог найти.
Суть собственно вот в чем:
Есть желание во время простоя микроконтроллера переводить его в sleep mode, что собственно получается успешно делать. Также на плате есть чип, который может сгенерировать внешнее для mcu прерывание в любой момент времени. То есть оно может случиться например в момент выполнения процедуры ухода в сон.
Код
void IdleMode(void)
{
  SCB->SCR &= ~SCR_SLEEPDEEP;
  
  //  например прерывание происходит вот здесь

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

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

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

Есть ли здесь подобные механизмы? Кто-нибудь сталкивался такой проблемой и как обходил её?
_Артём_
Цитата(xelax @ Jul 4 2012, 18:12) *
Есть ли здесь подобные механизмы? Кто-нибудь сталкивался такой проблемой и как обходил её?

Вот такой пример попадался (Cortex-M3).
CODE
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);
}

Тут правда не внешние прерывания, а прерывание по готовности осцилятора, но разница невелика.
xelax
Что-то я не совсем понимаю. Мы запрещая прерывания, запрещаем контроллеру прыгать на их обработчики, но при это даже в запрещенном сотоянии это прерывание способно пробудить микроконтроллер?
_Артём_
Цитата(xelax @ Jul 5 2012, 09:32) *
Что-то я не совсем понимаю. Мы запрещая прерывания, запрещаем контроллеру прыгать на их обработчики, но при это даже в запрещенном сотоянии это прерывание способно пробудить микроконтроллер?

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

Книжка называется "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 не сгенерируется.

Спасибо за то что идею подсказали, а то бы я долго лопатил все эти доки пока не наткнулся бы на эту таблицу.
_Артём_
Цитата(xelax @ Jul 5 2012, 12:28) *
Метод проб и ошибок конечно тоже вариант, но вот я к стати вроде как нашел теоретическое подтверждение такому поведению.

Значит можно пользоваться.
P.S. Нашёл откуда исходник "моего" примера:AppNota - это не sam3, но тоже Cortex-M3, поэтому в основном одинаково будет.
MiklPolikov
Вопрос : Правильно ли я понимаю смысл бита 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.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.