集中折腾了两天,终于把低功耗搞定!以下操作都是调用的ASF函数,没有直接操作寄存器。
sleep模式就不说了,使用官方例程,任意中断都可以把系统唤醒,要不要再次进入低功耗就可以随意设置了。我不用它主要是定时中断的时间间隔太短了,而使用wait mode则可以让我想什么时候唤醒就什么时候唤醒,不唤醒的时候定时中断的时钟还不工作,多么省事啊!下面,我就主要讲一下wait模式低功耗的启用与唤醒问题。
在wait模式下,主时钟、PLL时钟、快速时钟全部掉电,可以唤醒系统的时钟只剩下了RTT和RTC。所以要想没有外部中断的情况下唤醒时钟,只能从这两个地方下手了。Atmel的说明文档介绍wait Mode下的唤醒方式的时候,反复列举的项目就三种:WKUP0-15 pins, RTT or RCC alarm, USB Wake-up。我在测试RTT在ASF下的示例程序时,也能进入RTT alarm,但是现在想来当时只是一个似懂非懂的状态而已。
在RTT_Handler这个中断函数里,有一个函数rtt_get_status(RTT)这个获取的是RTT初始化之后到现在的时间值,同时清除中断标志位。注意这个值:因为wait模式下,RTT时钟依然运行,所以进入wait模式后,这个值是一直在增加的!因此官方文档里面介绍的时候才说,RTT定时器可以累积2^32s的时间,大概一两百年吧。开始没意识到这一点,直到我反复读文档,才想明白。当我使用MCU进入休眠,过一会儿用外部中断把它唤醒的时候,再读取RTT时间,发现果然是一直增加。知道这点就好办了,RTT alarm可以唤醒wait mode下的MCU,那么设置好alarm时间,就相当于定时,一到时间就会把MCU唤醒啦!虽然在 wait mode下,RTT_Handle中断函数也进不去,但是不耽误进入RTT alarm。设置唤醒时间用的函数是rtt_write_alarm_time(Rtt *p_rtt, uint32_t ul_alarm_time)。
好了,到这里就简单了,整个流程:
1,初始化 RTT;
2,设置唤醒时间(先设置是为了减少执行后续程序产生的时钟误差);
3,设置wait mode唤醒方式是RTT alarm;
4,进入 wait mode 等待到时间唤醒;
5,唤醒之后立即再次设置下次唤醒时间,依次循环。
下面来点儿干货:
RTT初始化与中断函数:
- /************************************************************************/
- /* @brief RTT configuration function.
- /* Configure the RTT to generate a one second tick, which triggers the
- /* RTTINC interrupt
- /************************************************************************/
- void configure_rtt(void)
- {
- uint32_t ul_previous_time;
- // Configure RTT for a 1 second tick interrupt
- rtt_sel_source(RTT, false);
- rtt_init(RTT, 32768);
- ul_previous_time = rtt_read_timer_value(RTT);
- while(ul_previous_time == rtt_read_timer_value(RTT));
- // Enable RTT interrupt
- NVIC_DisableIRQ(RTT_IRQn);
- NVIC_ClearPendingIRQ(RTT_IRQn);
- NVIC_SetPriority(RTT_IRQn, 0);
- NVIC_EnableIRQ(RTT_IRQn);
- rtt_enable_interrupt(RTT, RTT_MR_RTTINCIEN);
- }
- /************************************************************************/
- /* @brief Set alarm time.
- /************************************************************************/
- void alarm_set(uint32_t alarm_time)
- {
- rtt_write_alarm_time(RTT, alarm_time);
- }
- /************************************************************************/
- /* @brief Interrupt handler for the RTT
- /* Display the current time on the terminal.
- /************************************************************************/
- void RTT_Handler(void)
- {
- uint32_t ul_status;
- // Get RTT status
- ul_status = rtt_get_status(RTT);
- printf(“Time = %d\n”, rtt_read_timer_value(RTT));
- if((ul_status & RTT_SR_RTTINC) == RTT_SR_RTTINC)
- {
- printf(“ALARM OVER!\n”);
- }
- if((ul_status & RTT_SR_ALMS) == RTT_SR_ALMS)
- {
- printf(“ALARM!\n”);
- }
- LED_Toggle(LED0_GPIO);
- }
进入wait mode模式函数:
- // Wakeup pin for wait mode: RTTAL (rtt alarm enable)
- #define WAKEUP_WAIT_RTTAL_ENABLE (1u<<16)
- /**
- * @brief Enter Wait Mode.
- * @param None
- * @retval None
- */
- void enter_wait_mode(void)
- {
- printf(“Enter into wait Mode.\n”);
- while(!uart_is_tx_empty(CONSOLE_UART))
- {
- }
- // Configure fast RC oscillator
- pmc_switch_mck_to_sclk(PMC_MCKR_PRES_CLK_1);
- pmc_switch_mainck_to_fastrc(CKGR_MOR_MOSCRCF_8_MHz);
- pmc_switch_mck_to_mainck(PMC_PCK_PRES_CLK_1);
- g_ul_current_mck = 4000000; // 4MHz
- // Disable unused clock to save power
- pmc_osc_disable_xtal(0);
- pmc_disable_pllack();
- // Set wakeup input for fast startup
- pmc_set_fast_startup_input(WAKEUP_WAIT_RTTAL_ENABLE);
- // enter into wait Mode
- pmc_enable_waitmode();
- // Set default clock and re-configure UART
- set_default_working_clock();
- reconfigure_console(g_ul_current_mck, CONF_UART_BAUDRATE);
- delay_ms(1);
- printf(“Exit from wait Mode.\n”);
- }