AnsweredAssumed Answered

STM32F103CB and RTC interrupt

Question asked by tuset.pere on Mar 25, 2012
Latest reply on Mar 26, 2012 by tuset.pere
Hi all,

I am using the  STM32F103CB microcontroller to develop an embedded application for wireless communications that needs to sleep and wake up periodically in order to save energy, as it runs from batteries. I have already developed the drivers to manage the GPIO, EXTI, SPI, etc. and right now I am trying to get the low power stuff to work using the STOP mode.

What I do is enable the LSE clock (32kHz clock) to drive the RTC unit following the examples available.  After that I put the microcontroller to STOP mode using the PWR_EnterSTOPMode instruction. Then, when the counter associated to the RTC unit overflows an interruption (RTC_IT_OW) should be fired. I have configured the NVIC_IRQChannel to handle the RTC_IRQn interrupt and have written the code to manage the interrupt. After the interruption is handled the code should keep running from where it stopped (the PWR_EnterSTOPMode instruction).

I have set up an example as described and tried it using a logic analyzer using the GPIOs as debug ports. From what I see in the logic analyzer, the stop mode is entered and exited when the interrupt is produced but this happens only once, so that is weird. Could you please provide your insights? Thanks in advance. The code is as follows.

Here's the code to init the RTC clock:

void stm32f10x_rtc_init(void) {
 
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); // Enable PWR/BKP
 
    PWR_BackupAccessCmd(ENABLE); // Allow access to BKP Domain
 
    BKP_DeInit(); // Reset Backup Domain
 
    RCC_LSEConfig(RCC_LSE_ON); // Enable LSE
 
    while ((RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET))
        // Wait till LSE is ready
        ;
 
    RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); // Select LSE as RTC Clock Source
    RCC_RTCCLKCmd(ENABLE); // Enable RTC Clock
    RTC_WaitForSynchro(); // Wait for RTC registers synchronization
    RTC_WaitForLastTask(); // Wait until last write operation on RTC registers has finished
    RTC_ClearITPendingBit(RTC_IT_OW);
    RTC_ITConfig(RTC_IT_OW, ENABLE); // Enables overflow interrupt
    RTC_WaitForLastTask(); // Wait until last write operation on RTC registers has finished
    RTC_SetPrescaler(1000); // Set RTC prescaler period to 10ms
    RTC_WaitForLastTask(); // Wait until last write operation on RTC registers has finished
 
    NVIC_InitTypeDef NVIC_InitStructure; // Configure the interrupt handler
    NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

Here's the code to put the microcontroller to STOP mode:

void stm32f10x_rtc_stop(void) { // Puts the microcontroller to stop mode
 
    stm32f10x_gpio_toggle(debug2_p, DISABLE);
    PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFI); // stm32f10x_pwr.c
    stm32f10x_gpio_toggle(debug2_p, ENABLE);
 
    stm32f10x_rtc_sysclk_conf();
}

Here's the code to get the clocks back to work:

void stm32f10x_rtc_sysclk_conf(void) {
    ErrorStatus HSEStartUpStatus;
 
    /* Enable HSE */
    RCC_HSEConfig(RCC_HSE_ON);
 
    /* Wait till HSE is ready */
    HSEStartUpStatus = RCC_WaitForHSEStartUp();
 
    if (HSEStartUpStatus == SUCCESS) {
        /* Enable PLL */
        RCC_PLLCmd(ENABLE);
 
        /* Wait till PLL is ready */
        while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) {
        }
 
        /* Select PLL as system clock source */
        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
 
        /* Wait till PLL is used as system clock source */
        while (RCC_GetSYSCLKSource() != 0x08) {
        }
    }
}

Finally, here's the code to handle the interrupt:

volatile uint8_t rtc_status = 0;
 
void RTC_IRQHandler(void) { // @todo RTC interrupt handler
    if (RTC_GetITStatus(RTC_IT_OW) != RESET) {
        rtc_status = !rtc_status;
        stm32f10x_gpio_toggle(debug1_p, rtc_status);
 
        RTC_WaitForLastTask();
        RTC_ClearITPendingBit(RTC_IT_OW);
        RTC_WaitForLastTask();
    }
}

Last but not least, here's the main code:

int main(void) {
 
    stm32f10x_init(); // Inits GPIO, EXTI, etc.
 
    stm32f10x_rtc_init(); // Inits the microcontroller RTC timer
 
    while (1) {
        stm32f10x_rtc_stop(); // Puts the microcontroller to stop mode
    }
}

What am I overlooking? Any ideas? Thanks in advance!

Regards,

Pere

Outcomes