Hi All,
I would like to implement power saving modes for SAM3 microcontrollers (Arduino due board) so that RIOT's idle thread can actually save power by entering sleep or wait modes.
I have a RIOT "user space" program successfully entering and exiting WAIT mode. My reference is Atmel Application Note AT03498.
However, when I put the same functionality into cpu/sam3/lpm_arch.c - lpm_arch_set(), I observe several restarts of the board after which the CPU stalls without any possibility of wakeup.
What am I doing wrong?
I attached the new lpm_arch_set() function and my main.c file for reference.
Thanks, Moritz
//=================== lpm_arch.c =================== enum lpm_mode lpm_arch_set(enum lpm_mode target) { uint32_t j=0; //configure WKUP0 (PA1, pin no 24, "CANRX0") gpio_init(GPIO_PIN(PA, 1), GPIO_IN); SUPC->SUPC_WUIR = SUPC_WUIR_WKUPEN0_ENABLE; //enable WKUP0 as wakeup source SUPC->SUPC_WUIR |= SUPC_WUIR_WKUPT0_LOW_TO_HIGH; //low to high transition creates wakeup event SUPC->SUPC_WUMR = SUPC_WUMR_WKUPDBC_32_SCLK; //set debounce period to 32 slow clk cycles
//configure fast startup
PMC->PMC_FSPR = PMC_FSPR_FSTP0; //set polarity of WKUP0 to active high
PMC->PMC_FSMR = PMC_FSMR_FSTT0; //enable fast startup input enable at WKUP0
switch(target) {
case LPM_IDLE:
DEBUG("lpm_arch_set(): setting WAIT mode.\n");
//enable fast RC oscillator but do not switch to RC now.
PMC->CKGR_MOR = CKGR_MOR_MOSCSEL | (0x37 << 16) | CKGR_MOR_MOSCXTEN | CKGR_MOR_MOSCRCEN;
//wait for fast RC oscillator to stabilize
while (!(PMC->PMC_SR & PMC_SR_MOSCRCS));
//switch from main xtal oscillator to Fast RC
PMC->CKGR_MOR = (0x37 << 16) | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN;
//wait for main oscillator selection status bit MOSCSELS
while (!(PMC->PMC_SR & PMC_SR_MOSCSELS));
REG_UART_BRGR = (4000000UL / (16 * 9600UL)); //adjust baudrate generator
//disable main xtal oscillator
PMC->CKGR_MOR = (0x37 << 16) | CKGR_MOR_MOSCRCEN;
//change frequency of fast rc oscillator
PMC->CKGR_MOR = (0x37 << 16) | PMC->CKGR_MOR | CKGR_MOR_MOSCRCF_4_MHz;
//wait for fast rc oscillator to stabilize
while (!(PMC->PMC_SR & PMC_SR_MOSCRCS));
//switch from PLL to main clock
PMC->PMC_MCKR = (PMC->PMC_MCKR & (uint32_t)~PMC_MCKR_CSS_Msk)| PMC_MCKR_CSS_MAIN_CLK;
while (!(PMC->PMC_SR & PMC_SR_MCKRDY));
PMC->PMC_MCKR = (PMC->PMC_MCKR & (uint32_t)~PMC_MCKR_PRES_Msk) | PMC_MCKR_PRES_CLK_1;
while (!(PMC->PMC_SR & PMC_SR_MCKRDY));
PMC->CKGR_PLLAR = 0x2 << 14; // Stop PLL A, STMODE must be set at 2 when the PLLA is Off
PMC->PMC_FSMR |= (PMC_FSMR_LPM); //Set LPM bit in PMC Fast Startup Mode Register (PMC_FSMR) SCB->SCR &= (uint32_t)~SCB_SCR_SLEEPDEEP_Msk;
__DSB(); // ensure all memory accesses have completed
__WFE(); // go to low power mode (issue wait-for-event instruction)
for(j=0;j<500;j++) {
__NOP();
}
while (!(PMC->CKGR_MOR & CKGR_MOR_MOSCRCEN));
break;
case LPM_SLEEP:
DEBUG("lpm_arch_set(): setting SLEEP mode.\n");
break;
case LPM_POWERDOWN:
DEBUG("lpm_arch_set(): setting BACKUP mode.\n");
break;
default:
DEBUG("lpm_arch_set(): unhandled low-power mode.\n");
return 0;
}
return 0; }
//=================== main.c =================== #include <stdio.h> #include "xtimer.h" #include "timex.h" #include "periph/gpio.h"
#include "thread.h" #include "msg.h"
#include "lpm.h" #include "arch/lpm_arch.h"
/* set interval to 200 millisecond */ #define INTERVAL (2000 * MS_IN_USEC) #define LED_RED GPIO_PIN(PB, 25) #define LED_GREEN GPIO_PIN(PC, 28)
char blink_stack[THREAD_STACKSIZE_MAIN]; xtimer_t xtimer;
int main(void)
{
uint32_t i=0;
uint32_t last_wakeup = xtimer_now();
gpio_init(LED_RED, GPIO_OUT);
gpio_clear(LED_RED);
kernel_pid_t me = thread_getpid();
printf("thread started, pid: %" PRIkernel_pid "\r\n", me);
while(1) {
printf("going to sleep...\r\n");
xtimer_periodic_wakeup(&last_wakeup, INTERVAL);
printf("main(): slept until %" PRIu32 "\r\n", xtimer_now());
if(i==1) {
gpio_set(LED_RED);
i=0;
} else {
gpio_clear(LED_RED);
i=1;
}
}
return 0; }
// =============== terminal output (scheduler debug enabled) ================ 2016-11-23 12:51:15,104 - INFO # Created thread idle. PID: 1. Priority: 15. 2016-11-23 12:51:15,157 - INFO # sched_set_status: adding thread 1 to runqueue 15. 2016-11-23 12:51:15,202 - INFO # Created thread main. PID: 2. Priority: 7. 2016-11-23 12:51:15,255 - INFO # sched_set_status: adding thread 2 to runqueue 7. 2016-11-23 12:51:15,300 - INFO # sched_run: active thread: 0, next thread: 2 2016-11-23 12:51:15,349 - INFO # sched_run: done, changed sched_active_thread. 2016-11-23 12:51:15,444 - INFO # main(): This is RIOT! (Version: 2016.10-devel-407-gd1111-christina.ias.rwth-aachen.de) 2016-11-23 12:51:15,468 - INFO # thread started, pid: 2 2016-11-23 12:51:15,489 - INFO # going to sleep... 2016-11-23 12:51:15,546 - INFO # sched_set_status: removing thread 2 from runqueue 7. 2016-11-23 12:51:15,591 - INFO # sched_run: active thread: 2, next thread: 1 2016-11-23 12:51:15,640 - INFO # sched_run: done, changed sched_active_thread. 2016-11-23 12:51:15,652 - INFO # idle thread 2016-11-23 12:51:17,488 - INFO # Created thread idle. PID: 1. Priority: 15. 2016-11-23 12:51:17,541 - INFO # sched_set_status: adding thread 1 to runqueue 15. 2016-11-23 12:51:17,586 - INFO # Created thread main. PID: 2. Priority: 7. 2016-11-23 12:51:17,639 - INFO # sched_set_status: adding thread 2 to runqueue 7. 2016-11-23 12:51:17,684 - INFO # sched_run: active thread: 0, next thread: 2 2016-11-23 12:51:17,733 - INFO # sched_run: done, changed sched_active_thread. 2016-11-23 12:51:17,827 - INFO # main(): This is RIOT! (Version: 2016.10-devel-407-gd1111-christina.ias.rwth-aachen.de) 2016-11-23 12:51:17,852 - INFO # thread started, pid: 2 2016-11-23 12:51:17,872 - INFO # going to sleep... 2016-11-23 12:51:17,930 - INFO # sched_set_status: removing thread 2 from runqueue 7. 2016-11-23 12:51:17,975 - INFO # sched_run: active thread: 2, next thread: 1 2016-11-23 12:51:18,024 - INFO # sched_run: done, changed sched_active_thread. 2016-11-23 12:51:18,036 - INFO # idle thread 2016-11-23 12:51:19,871 - INFO # Created thread idle. PID: 1. Priority: 15. 2016-11-23 12:51:19,925 - INFO # sched_set_status: adding thread 1 to runqueue 15. 2016-11-23 12:51:19,970 - INFO # Created thread main. PID: 2. Priority: 7. 2016-11-23 12:51:20,023 - INFO # sched_set_status: adding thread 2 to runqueue 7. 2016-11-23 12:51:20,068 - INFO # sched_run: active thread: 0, next thread: 2 2016-11-23 12:51:20,117 - INFO # sched_run: done, changed sched_active_thread. 2016-11-23 12:51:20,211 - INFO # main(): This is RIOT! (Version: 2016.10-devel-407-gd1111-christina.ias.rwth-aachen.de) 2016-11-23 12:51:20,236 - INFO # thread started, pid: 2 2016-11-23 12:51:20,256 - INFO # going to sleep... 2016-11-23 12:51:20,314 - INFO # sched_set_status: removing thread 2 from runqueue 7. 2016-11-23 12:51:20,359 - INFO # sched_run: active thread: 2, next thread: 1 2016-11-23 12:51:20,408 - INFO # sched_run: done, changed sched_active_thread. 2016-11-23 12:51:20,420 - INFO # idle thread ...