We first initialize the project, including starting debug serial port and setting EXTI 20 (for RTC wakeup event):
Code: Select all
void extcb(EXTDriver *extp, expchannel_t channel)
{
(void) extp;
(void) channel;
/* Reset SLEEPDEEP bit of Cortex System Control Register */
SCB->SCR &= (uint32_t) ~((uint32_t) SCB_SCR_SLEEPDEEP_Msk);
/* switch off wakeup */
rtcSTM32SetPeriodicWakeup(&RTCD1, NULL);
chSysLockFromISR();
/* we must reinit clocks after waking up ESPECIALLY if use HSE or HSI+PLL */
stm32_clock_init();
chSysUnlockFromISR();
}
static const EXTConfig extcfg = {
{
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL}, //{EXT_CH_MODE_BOTH_EDGES | EXT_CH_MODE_AUTOSTART | EXT_MODE_GPIOB, extcb_enc}, // example interrupt
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_RISING_EDGE | EXT_CH_MODE_AUTOSTART, extcb}, /* 20 */
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL}
}
};
int main(void) {
/*
* Real-Time Operating System Initialization
* - HAL initialization, this also initializes the configured device drivers
* and performs the board-specific initializations.
* - Kernel initialization, the main() function becomes a thread and the
* RTOS is active.
*/
halInit();
chSysInit();
/*
* Activates the EXT driver 1.
*/
extStart(&EXTD1, &extcfg);
...
Next we initialize the RTC:
Code: Select all
void RTC_Init()
{
int i = 0;
// enable backup and pwr clocks
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
PWR->CR |= PWR_CR_DBP;
// reset RTC
RCC->CSR |= RCC_CSR_RTCRST;
RCC->CSR &= ~RCC_CSR_RTCRST;
// enable LSE and wait for it to stabilize
RCC->CSR |= RCC_CSR_LSION;
while (!(RCC->CSR & RCC_CSR_LSIRDY))
{
OsSleepMs(100);
i++;
if (i>50)
{
SysError("LSI did not stabilize.");
break;
}
if (i%5) SysInfo("Waiting for LSI to stabilize...");
}
SysInfo("LSI stable.");
// reset RTC
RCC->CSR |= RCC_CSR_RTCRST;
RCC->CSR &= ~RCC_CSR_RTCRST;
// enable RTC with external 32kHz xtal
RCC->CSR |= RCC_CSR_RTCSEL_LSI;
RCC->CSR |= RCC_CSR_RTCEN;
//RTC->CR &= (uint16_t)~0x0008;
//while (!(RTC->CR & 0x8));
//while (!(RTC->CR & 0x20));
//RTC->CR |= RTC_CR_ALRAIE;
//while (!(RTC->CR & 0x20));
}
And then set a 3 sec timer with RTC_DeepSleep(3):
Code: Select all
void RTC_DeepSleep(uint32_t seconds)
{
/*
* use ck_spre (1Hz internal clock)
* WUCKSEL[2:1] = 10 (1s to 18h)
* Clear WUTE in RTC_CR to disable wkup timer
* Poll WUTWF until it is set in RTC_ISR to make sure the access
* to the wakeup auto-reload counter and to WUCKSEL[2:0] bits is allowed.
* This takes ~2RTCCLK cycles.
* Program the wakeup auto-reload value WUT[15:0],
* and the wakeup clock selection (WUCKSEL[2:0] in RTC_CR).
* Set WUTE in RTC_CR to enable timer again.
*/
// sleep up to 18h
OsAssert(seconds < 65536,"RTC Assert");
// unlock RTC regs
RTC->WPR = 0xCA;
RTC->WPR = 0x53;
RTC->PRER |= RTC_PRER_PREDIV_A; // maximum async prediv
RTC->PRER = (RTC->PRER & RTC_PRER_PREDIV_S) | 0x122; // 1Hz from 37kHz
RTC->CR &= ~RTC_CR_WUTE;
while (!(RTC->ISR & RTC_ISR_WUTWF)) {};
RTC->WUTR = (RTC->WUTR & ~RTC_WUTR_WUT) | (seconds & RTC_WUTR_WUT);
RTC->CR = (RTC->CR & ~RTC_CR_WUCKSEL) | (RTC_CR_WUCKSEL_2 /* 10x */);
RTC->CR |= RTC_CR_WUTE;
RTC->CR |= RTC_CR_WUTIE;
// clear wakeup timer flag
RTC->ISR &= ~(RTC_ISR_ALRBF | RTC_ISR_ALRAF | RTC_ISR_WUTF | RTC_ISR_TAMP1F |
RTC_ISR_TSOVF | RTC_ISR_TSF);
// lock RTC regs
RTC->WPR = 0xFF;
}
And finally call WFI:
Code: Select all
/* ADC1->CR2 = 0; // ADC off
USART1->CR1 = 0;
USART2->CR1 = 0;
USART3->CR1 = 0;*/
PWR->CR |= PWR_CR_ULP;
PWR->CR |= PWR_CR_LPSDSR;
//PWR->CR |= PWR_CR_PDDS; // standby
for(int i = 0; i < 100; i++) {
__NOP();
__NOP();
__NOP();
__NOP();
__NOP();
}
SCB->SCR |= SCB_SCR_SLEEPDEEP;
for(int i = 0; i < 100; i++) {
__NOP();
__NOP();
__NOP();
__NOP();
__NOP();
}
__WFI();
Then three seconds later, the system wakes, we are able to print to the debug serial port, but then a call to OsSleepMs (chThdSleepMilliseconds) never returns. Debugger shows system enters but never leaves idle thread.
What might need to be re-initialized in ChibiOS to allow normal operation after waking from STOP?