Spider
Oct 17 2012, 13:30
Снова здарова!
Научился таки усыплять проц, КРУТО!

А вот будить не научился.
Основная задача просыпаться периодически и и опрашивать разную периферию, после чего снова спать. На AVR8 было всё просто, после усыпления проца он мог просыпать по прерыванию таймера2 и продолжать с момента усыпления. Тут же я немного в замешательстве. Вроде как можно будить проц по Событиям и Прерываниям, а пот по факту не получается

Подскажите как чего сделать то?
Помогите. ПЛЗ.
ЗЫ Видать основная проблема в том, что я не до конца разобрался в чём разница между прерываниями и событиями...
_Артём_
Oct 17 2012, 13:38
Цитата(Alexey Belyaev @ Oct 17 2012, 16:30)

Снова здарова!
Научился таки усыплять проц, КРУТО!

А вот будить не научился.
Основная задача просыпаться периодически и и опрашивать разную периферию, после чего снова спать.
Код
volatile uint8_t IntWas;
void SysTick_handler()
{
IntWas=1;
}
int main() {
SysTick_Config(10000);
while (1) {
if (IntWas) {
IntWas=0;
}
__WFI();
}
}
Наверное ещё надо смотреть какой sleep-режим - просто sleep или deepsleep. Также под отладчиком что-то может не работать.
Spider
Oct 17 2012, 13:59
А что проц после сна выходит в 0ой точке?
_Артём_
Oct 17 2012, 14:11
Цитата(Alexey Belyaev @ Oct 17 2012, 16:59)

А что проц после сна выходит в 0ой точке?
После неглубокого сна не от 0, просто продолжит выполнение.
Более глубокие режимы у всех производителей сделаны по разному.
Какой у вас проц?
Spider
Oct 17 2012, 14:17
STM32F103 я вгоняю в не глубокий сон, т.е. просто wfi/wfe без DEEPSLEEP.
т.е. как я понял из примера выше, достаточно "сотворить" любое прерывание?
_Артём_
Oct 17 2012, 14:21
Цитата(Alexey Belyaev @ Oct 17 2012, 17:17)

STM32F103 я вгоняю в не глубокий сон, т.е. просто wfi/wfe без DEEPSLEEP.
т.е. как я понял из примера выше, достаточно "сотворить" любое прерывание?
Да.
Spider
Oct 17 2012, 14:28
другими словами перед сном нужно предварительно запретить все прерывания, чтобы они, не дай бог, не потревожили чуткий сон CxM3?
А есть способ глобально запретить все прерывания? Или надо шерстить по периферии и запрещать, а затем по пробуждению вертать всё назад?
_Артём_
Oct 17 2012, 14:46
Цитата(Alexey Belyaev @ Oct 17 2012, 17:28)

другими словами перед сном нужно предварительно запретить все прерывания, чтобы они, не дай бог, не потревожили чуткий сон CxM3?
Зачем запрещать? Проснётся и опять уснёт.
Цитата(Alexey Belyaev @ Oct 17 2012, 17:28)

А есть способ глобально запретить все прерывания?
__disable_irq();
Вот ещё пример на тему:
Код
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);
}
Spider
Oct 17 2012, 15:07
Ничё не понял. Если перед __WFI() отключаются прерывания, то как же оно выйдет из сна по прерыванию?
_Артём_
Oct 17 2012, 15:54
Цитата(Alexey Belyaev @ Oct 17 2012, 18:07)

Ничё не понял. Если перед __WFI() отключаются прерывания, то как же оно выйдет из сна по прерыванию?
Почитайте по
ссылке.
Тут кстати у меня самого вопрос: код ИАРовский, при перекомпиляции в GCC он не заработал пока не вставил 2-3 nop-а. Почему?
Spider
Oct 17 2012, 16:00
Уже побывал там

Интересная штуковина. Ну а если не пользоваться этой "фичей", то надо тупо запрещать прерывания?
_Артём_
Oct 17 2012, 16:06
Цитата(Alexey Belyaev @ Oct 17 2012, 19:00)

Ну а если не пользоваться этой "фичей", то надо тупо запрещать прерывания?
Зачем? После возврата из прерывания ещё раз выполнится команда WFI и проц опять уснёт до следующего прерывания.
Или вы хотите чтобы вообще не проснулось никогда? Тогда глубжее засыпать надо.
Spider
Oct 17 2012, 16:37
Ну смысл такой, что надо просыпаться только по определённым событиям, игнорируя другия, ибо к примеру я не один на шине и прочее.
_Артём_
Oct 17 2012, 17:20
Цитата(Alexey Belyaev @ Oct 17 2012, 19:37)

по определённым событиям, игнорируя другия, ибо к примеру я не один на шине и прочее.
Что за события и шина?
PS. В посте по ссылке в сообщении 5 есть таблица, из которой следует, что можно настроить приоритеты прерываний так, чтобы пробуждение происходило только по нужным прерываниям.
Был бы у вас FreeRTOS (или другая прямая ось), то просто напросто в IdleHook поставили бы WFI и никаких больше забот не нужно.
Spider
Oct 18 2012, 15:42
усыпить я и тут могу, и тоже в ИдлХук, а проснуться то как?
_Артём_
Oct 18 2012, 15:49
Цитата(Alexey Belyaev @ Oct 18 2012, 18:42)

усыпить я и тут могу, и тоже в ИдлХук, а проснуться то как?
Так прерывание и разбудит.
Чем такой вариант не устраивает?
Spider
Oct 18 2012, 15:53
Прерываний то тма тмущая, в любой ОС есть же SysTick прерывания.
А надо только по КОНКРЕТНОМУ прерывания, от таймера через 200ms например.
_Артём_
Oct 18 2012, 15:56
Цитата(Alexey Belyaev @ Oct 18 2012, 18:53)

Прерываний то тма тмущая, в любой ОС есть же SysTick прерывания.
А надо только по КОНКРЕТНОМУ прерывания, от таймера через 200ms например.
Цитата
2.5.2.1 Wakeup from WFI or sleep-on-exit
Normally, the processor wakes up only when it detects an exception with sufficient priority to cause
exception entry.
Some embedded systems might have to execute system restore tasks after the processor wakes up, and
before it executes an interrupt handler. To achieve this set the PRIMASK bit to 1 and the FAULTMASK
bit to 0. If an interrupt arrives that is enabled and has a higher priority than current exception priority,
the processor wakes up but does not execute the interrupt handler until the processor sets PRIMASK
to zero. For more information about PRIMASK and FAULTMASK see Section 2.1.3.6 (p. 11)
esaulenka
Oct 19 2012, 10:43
Артём, можно вопрос по коду в
сообщении #8?
Что-то до меня не доходит необходимость флажка и while'а. Или это задел под несколько прерываний, по которым работу продолжать не надо (проснулись - отработали - сразу уснули) ?
AHTOXA
Oct 19 2012, 11:32
Цитата(esaulenka @ Oct 19 2012, 16:43)

Или это задел под несколько прерываний, по которым работу продолжать не надо (проснулись - отработали - сразу уснули) ?
Думаю, что да. Мало ли какие ещё прерывания разрешены к этому моменту.
_Артём_
Oct 19 2012, 11:35
Цитата(esaulenka @ Oct 19 2012, 13:43)

Или это задел под несколько прерываний, по которым работу продолжать не надо (проснулись - отработали - сразу уснули) ?
По сути - да (хотя прерывание в примере только одно).
В примере запускается RC-генератор и процессор засыпает пока не произойдёт wake-up по готовности RC. Таже можно запустить несколько прерываний, например SysTick и измерить время установления RC.
PS. Что странно в GCC такой код не заработал - пришлось добавить пару NOP-ов после __enable_irq. Или так и надо делать, а пример с ошибкой?
esaulenka
Oct 19 2012, 15:48
Цитата
код не заработал - пришлось добавить пару NOP-ов после __enable_irq
Я наблюдал похожие грабли:
Код
void TIMER0_IRQHandler (void) __irq
{
// что-то полезное
T0IR = 0x01; // Clear match 0 interrupt
}
Влетал в прерывание два раза - до контроллера прерывания не доходило, что флаг прерывания сброшен.
Нашёл рекомендации использовать инструкции для синхронизации (ISB, кажется), но сделал проще - перенёс сброс флага в начало. Конкретное место, в котором есть проблема, раскапывать поленился.
_Артём_
Oct 19 2012, 18:18
Цитата(esaulenka @ Oct 19 2012, 18:48)

Я наблюдал похожие грабли:
Да, ситуация похожая.
Цитата(esaulenka @ Oct 19 2012, 18:48)

Влетал в прерывание два раза - до контроллера прерывания не доходило, что флаг прерывания сброшен.
Нашёл рекомендации использовать инструкции для синхронизации (ISB, кажется), но сделал проще - перенёс сброс флага в начало. Конкретное место, в котором есть проблема, раскапывать поленился.
Хотелось бы знать какой барьер правильней ставить...
Помогает в общем-то любой, и даже NOP.
Мне кажется более правильным использовать DSB, но так ли это...
nx6310
Nov 23 2012, 09:03
Можно процессор переводить в STOP режим, Просыпаться по будильнику RTC ALARM. Из STOP можно выйти только по по внешнему прерыванию или по прерыванию будильника ALARM RTC, в этом режиме отключается вся периферия кроме внешних прерываний и часов реального времени. Потребление уменьшится и другие прерывания не надо будет отключать.
Можете запретить прерывания и будить когда вам надо по нужному event
инструкция __WFI
Для просмотра полной версии этой страницы, пожалуйста,
пройдите по ссылке.