From 596484ea5461acf1fde22bb9733463f12a9f8721 Mon Sep 17 00:00:00 2001 From: patacongo Date: Fri, 27 Jul 2012 00:14:38 +0000 Subject: [PATCH] PM update git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4982 42af7a65-404d-4744-a932-0658087f49c3 --- ChangeLog | 2 + arch/arm/src/stm32/stm32_pmstandby.c | 4 +- arch/arm/src/stm32/stm32_pmstop.c | 4 +- configs/stm3210e-eval/pm/defconfig | 1 + configs/stm3210e-eval/src/up_idle.c | 90 ++++++++++++++++++++++++---- configs/stm3210e-eval/src/up_lcd.c | 13 ++-- drivers/power/pm_changestate.c | 4 ++ 7 files changed, 100 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8a8c60ec95..34a4f5a61b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3078,3 +3078,5 @@ LCD found in the Motorola C155 telephone. The driver is specific to the C155 because it uses the uwire transport. Contributed by Denis Carilki and Alan Carvalho de Assis. + * drivers/power/pm_changestate.c. Correct a case where interrupts were not + being re-enabled. Found by Diego Sanchez. diff --git a/arch/arm/src/stm32/stm32_pmstandby.c b/arch/arm/src/stm32/stm32_pmstandby.c index 9aacfaa9a6..467edaec2a 100644 --- a/arch/arm/src/stm32/stm32_pmstandby.c +++ b/arch/arm/src/stm32/stm32_pmstandby.c @@ -86,7 +86,7 @@ int stm32_pmstandby(void) /* Clear the Wake-Up Flag by setting the CWUF bit in the power control * register. */ - + regval = getreg32(STM32_PWR_CR); regval |= PWR_CR_CWUF; putreg32(regval, STM32_PWR_CR); @@ -104,6 +104,6 @@ int stm32_pmstandby(void) /* Sleep until the wakeup reset occurs */ - asm("WFI"); + asm("wfi"); return OK; /* Won't get here */ } diff --git a/arch/arm/src/stm32/stm32_pmstop.c b/arch/arm/src/stm32/stm32_pmstop.c index 9bd4af73a9..14ce63b555 100644 --- a/arch/arm/src/stm32/stm32_pmstop.c +++ b/arch/arm/src/stm32/stm32_pmstop.c @@ -112,11 +112,11 @@ int stm32_pmstop(bool lpds) #ifdef CONFIG_PM_WFE /* Mode: SLEEP + Entry with WFE */ - __asm("wfe"); + asm("wfe"); #else /* Mode: SLEEP + Entry with WFI */ - __asm("wfi"); + asm("wfi"); #endif return OK; } diff --git a/configs/stm3210e-eval/pm/defconfig b/configs/stm3210e-eval/pm/defconfig index d4fb6e8b94..a5c8bd185b 100644 --- a/configs/stm3210e-eval/pm/defconfig +++ b/configs/stm3210e-eval/pm/defconfig @@ -468,6 +468,7 @@ CONFIG_SCHED_ATEXIT=n CONFIG_PM=y CONFIG_PM_CUSTOMINIT=y CONFIG_IDLE_CUSTOM=y +CONFIG_PM_SLEEP_WAKEUP=n # # Board/Application-Specific Power Management Configuration. diff --git a/configs/stm3210e-eval/src/up_idle.c b/configs/stm3210e-eval/src/up_idle.c index 2b92f9c5e2..b73b88c085 100644 --- a/configs/stm3210e-eval/src/up_idle.c +++ b/configs/stm3210e-eval/src/up_idle.c @@ -74,16 +74,50 @@ # define END_IDLE() #endif -/* Values for the RTC Alarm to wake up from the PM_STANDBY mode */ +/* Values for the RTC Alarm to wake up from the PM_STANDBY mode + * (which corresponds to STM32 stop mode). If this alarm expires, + * the logic in this file will wakeup from PM_STANDBY mode and + * transition to PM_SLEEP mode (STM32 standby mode). + */ #ifndef CONFIG_PM_ALARM_SEC -# define CONFIG_PM_ALARM_SEC 3 +# define CONFIG_PM_ALARM_SEC 15 #endif #ifndef CONFIG_PM_ALARM_NSEC # define CONFIG_PM_ALARM_NSEC 0 #endif +/* Values for the RTC Alarm to reset from the PM_SLEEP mode (STM32 + * standby mode). If CONFIG_PM_SLEEP_WAKEUP is defined in the + * configuration, then the logic in this file will program the RTC + * alarm to wakeup the processor after an a delay. + * + * This feature might be useful, for example, in a system that needs to + * use minimal power but awake up to perform some task at periodic + * intervals. + */ + +#ifdef CONFIG_PM_SLEEP_WAKEUP + +# ifndef CONFIG_RTC_ALARM +# error "CONFIG_RTC_ALARM should be enabled to use CONFIG_PM_SLEEP_WAKEUP" +# endif + + /* If CONFIG_PM_SLEEP_WAKEUP is defined, then ifndefCONFIG_PM_SLEEP_WAKEUP_SEC + * and ifndefCONFIG_PM_SLEEP_WAKEUP_NSEC define the delay until the STM32 + * awakens from PM_SLEEP mode. + */ + +# ifndefCONFIG_PM_SLEEP_WAKEUP_SEC +# defineCONFIG_PM_SLEEP_WAKEUP_SEC 10 +# endif + +# ifndefCONFIG_PM_SLEEP_WAKEUP_NSEC +# defineCONFIG_PM_SLEEP_WAKEUP_NSEC 0 +# endif +#endif + /**************************************************************************** * Private Data ****************************************************************************/ @@ -112,7 +146,6 @@ static void up_idlepm(void) #endif static enum pm_state_e oldstate = PM_NORMAL; enum pm_state_e newstate; - irqstate_t flags; int ret; /* Decide, which power saving level can be obtained */ @@ -125,7 +158,7 @@ static void up_idlepm(void) { lldbg("newstate= %d oldstate=%d\n", newstate, oldstate); - flags = irqsave(); + sched_lock(); /* Force the global state change */ @@ -138,7 +171,7 @@ static void up_idlepm(void) /* No state change... */ - goto errout; + return; } /* Then perform board-specific, state-dependent logic here */ @@ -147,6 +180,14 @@ static void up_idlepm(void) { case PM_NORMAL: { + /* If we just awakened from PM_STANDBY mode, then reconfigure + * clocking. + */ + + if (oldstate == PM_STANDBY) + { + stm32_clockconfig(); + } } break; @@ -189,9 +230,9 @@ static void up_idlepm(void) lldbg("Warning: The alarm is already set\n"); } #endif - /* Call the STM32 stop mode */ + /* Enter the STM32 stop mode */ - stm32_pmstop(true); + (void)stm32_pmstop(false); /* We have been re-awakened by some even: A button press? * An alarm? Cancel any pending alarm and resume the normal @@ -208,7 +249,6 @@ static void up_idlepm(void) /* Resume normal operation */ pm_changestate(PM_NORMAL); - newstate = PM_NORMAL; } break; @@ -218,6 +258,37 @@ static void up_idlepm(void) * of standby is via the reset path. */ +#ifdef CONFIG_PM_SLEEP_WAKEUP + /* Configure the RTC alarm to Auto Reset the system */ + + (void)up_rtc_gettime(&alarmtime); + + alarmtime.tv_sec +=CONFIG_PM_SLEEP_WAKEUP_SEC; + alarmtime.tv_nsec +=CONFIG_PM_SLEEP_WAKEUP_NSEC; + + /* The tv_nsec value must not exceed 1,000,000,000. That + * would be an invalid time. + */ + + if (alarmtime.tv_nsec >= NSEC_PER_SEC) + { + /* Carry to the seconds */ + + alarmtime.tv_sec++; + alarmtime.tv_nsec -= NSEC_PER_SEC; + } + + /* Set the alarm */ + + ret = up_rtc_setalarm(&alarmtime, &up_alarmcb); + if (ret < 0) + { + lldbg("Warning: The alarm is already set\n"); + } +#endif + /* Enter the STM32 standby mode */ + + up_mdelay(10); (void)stm32_pmstandby(); } break; @@ -230,8 +301,7 @@ static void up_idlepm(void) oldstate = newstate; -errout: - irqrestore(flags); + sched_unlock(); } } #else diff --git a/configs/stm3210e-eval/src/up_lcd.c b/configs/stm3210e-eval/src/up_lcd.c index 42da4864a8..045f564c34 100644 --- a/configs/stm3210e-eval/src/up_lcd.c +++ b/configs/stm3210e-eval/src/up_lcd.c @@ -2,9 +2,13 @@ * configs/stm3210e-eval/src/up_lcd.c * arch/arm/src/board/up_lcd.c * - * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * + * With power management enhancements by: + * + * Author: Diego Sanchez + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -1187,7 +1191,7 @@ static void stm3210e_pm_notify(struct pm_callback_s *cb , enum pm_state_e pmstat duty--; } - /* Reduce the LCD light to 50% of the MAXPOWER */ + /* Reduce the LCD backlight to 50% of the MAXPOWER */ duty >>= 1; putreg16((uint16_t)duty, STM32_TIM1_CCR1); @@ -1197,7 +1201,7 @@ static void stm3210e_pm_notify(struct pm_callback_s *cb , enum pm_state_e pmstat case(PM_STANDBY): { - /* Entering STANDBY mode - Turn display off */ + /* Entering STANDBY mode - Turn display backlight off */ #ifdef CONFIG_LCD_PWM putreg16(0, STM32_TIM1_CCR1); @@ -1207,8 +1211,9 @@ static void stm3210e_pm_notify(struct pm_callback_s *cb , enum pm_state_e pmstat case(PM_SLEEP): { - /* Entering SLEEP mode - Logic for PM_SLEEP goes here */ + /* Entering SLEEP mode - Turn off LCD */ + (void)stm3210e_poweroff(); } break; diff --git a/drivers/power/pm_changestate.c b/drivers/power/pm_changestate.c index 27d17ce889..f64760f55b 100644 --- a/drivers/power/pm_changestate.c +++ b/drivers/power/pm_changestate.c @@ -217,6 +217,10 @@ int pm_changestate(enum pm_state_e newstate) pm_changeall(newstate); g_pmglobals.state = newstate; + + /* Restore the interrupt state */ + + irqrestore(flags); return ret; }