1 /*
2  * @brief PMU example
3  *
4  * @note
5  * Copyright(C) NXP Semiconductors, 2014
6  * All rights reserved.
7  *
8  * @par
9  * Software that is described herein is for illustrative purposes only
10  * which provides customers with programming information regarding the
11  * LPC products.  This software is supplied "AS IS" without any warranties of
12  * any kind, and NXP Semiconductors and its licensor disclaim any and
13  * all warranties, express or implied, including all implied warranties of
14  * merchantability, fitness for a particular purpose and non-infringement of
15  * intellectual property rights.  NXP Semiconductors assumes no responsibility
16  * or liability for the use of the software, conveys no license or rights under any
17  * patent, copyright, mask work right, or any other intellectual property rights in
18  * or to any products. NXP Semiconductors reserves the right to make changes
19  * in the software without notification. NXP Semiconductors also makes no
20  * representation or warranty that such application will be suitable for the
21  * specified use without further testing or modification.
22  *
23  * @par
24  * Permission to use, copy, modify, and distribute this software and its
25  * documentation is hereby granted, under NXP Semiconductors' and its
26  * licensor's relevant copyrights in the software, without fee, provided that it
27  * is used in conjunction with NXP Semiconductors microcontrollers.  This
28  * copyright, permission, and disclaimer notice must appear in all copies of
29  * this code.
30  */
31 
32 #include "board.h"
33 
34 /*****************************************************************************
35  * Private types/enumerations/variables
36  ****************************************************************************/
37 
38 /* Change this value to increase/decrease the time between power state changes */
39 #define POWER_CYCLE_SEC_DELAY 10
40 
41 /* Comment out this #define if you want a power-cycle count */
42 /* #define RESET_POWER_CYCLE_COUNT */
43 
44 /* Index of PMU GP registers */
45 #define PWR_CYCLE_COUNT_REG_INDEX 0
46 
47 /*****************************************************************************
48  * Public types/enumerations/variables
49  ****************************************************************************/
50 
51 /*****************************************************************************
52  * Private functions
53  ****************************************************************************/
54 
55 /* Read or reset the power-cycle counter */
ProcessCycleCounter(void)56 static uint32_t ProcessCycleCounter(void)
57 {
58 	uint32_t returnVal = 0xFFFFFFFF;
59 
60 #ifndef RESET_POWER_CYCLE_COUNT
61 	/* Read current power-cycle count register */
62 	returnVal = Chip_PMU_ReadGPREG(LPC_PMU, PWR_CYCLE_COUNT_REG_INDEX);
63 #endif
64 
65 	/* Write power-cycle count register */
66 	Chip_PMU_WriteGPREG(LPC_PMU, PWR_CYCLE_COUNT_REG_INDEX, returnVal + 1);
67 
68 	/* Return current value of cycle-count */
69 	return returnVal;
70 }
71 
72 /* Delay to allow all serial output to be processed before power state change */
DelayForSerialOutput(void)73 static void DelayForSerialOutput(void)
74 {
75 	volatile uint32_t tempTimeout;
76 
77 	/* Delay until all serial processing complete */
78 	tempTimeout = Chip_RTC_GetCount(LPC_RTC) + 1;
79 	while (Chip_RTC_GetCount(LPC_RTC) < tempTimeout) {}
80 }
81 
82 /* Handle interrupt from GPIO pin or GPIO pin mapped to PININT */
ProcessPowerState(CHIP_PMU_MCUPOWER_T crntPowerSetting)83 static void ProcessPowerState(CHIP_PMU_MCUPOWER_T crntPowerSetting)
84 {
85 	volatile uint32_t tempTimeout;
86 
87 	/* Output power status message, add separating space */
88 	DEBUGSTR("\r\n");
89 
90 	/* Switch on current selected power setting */
91 	switch (crntPowerSetting) {
92 	case PMU_MCU_SLEEP:
93 	default:
94 		DEBUGSTR("-----------------------------------------------------------------\r\n");
95 		DEBUGSTR("     Entering SLEEP power setting\r\n");
96 		DEBUGOUT("       (System will exit SLEEP in %d seconds)\r\n", POWER_CYCLE_SEC_DELAY);
97 		DEBUGSTR("-----------------------------------------------------------------\r\n\r\n");
98 
99 		/* Wait for all serial characters to be output */
100 		DelayForSerialOutput();
101 
102 		/* Enter MCU Sleep mode */
103 		LPC_PWRD_API->power_mode_configure(PMU_SLEEP, (PMU_PD_WDOSC | PMU_PD_BOD | PMU_PD_ACMP0 | PMU_PD_ACMP1 | PMU_PD_ACMP2 |PMU_PD_ACMP3 | PMU_PD_IREF | PMU_PD_TS));
104 		__WFI();
105 
106 		break;
107 
108 	case PMU_MCU_DEEP_SLEEP:
109 		DEBUGSTR("-----------------------------------------------------------------\r\n");
110 		DEBUGSTR("     Entering DEEP SLEEP power setting\r\n");
111 		DEBUGOUT("       (System will exit DEEP SLEEP in %d seconds)\r\n", POWER_CYCLE_SEC_DELAY);
112 		DEBUGSTR("-----------------------------------------------------------------\r\n\r\n");
113 
114 		/* Wait for all serial characters to be output */
115 		DelayForSerialOutput();
116 
117 		/* We should call Chip_SYSCTL_SetWakeup() to setup any peripherals we want
118 		   to power back up on wakeup. For this example, we'll power back up the IRC,
119 		   FLASH, the system oscillator, and the PLL */
120 		Chip_SYSCTL_SetWakeup(~(SYSCTL_SLPWAKE_IRCOUT_PD | SYSCTL_SLPWAKE_IRC_PD |
121 								SYSCTL_SLPWAKE_FLASH_PD | SYSCTL_SLPWAKE_SYSOSC_PD | SYSCTL_SLPWAKE_SYSPLL_PD));
122 		Chip_SYSCTL_EnableERP1PeriphWakeup(SYSCTL_ERP1_WAKEUP_RTCALARMINT);
123 
124 		/* Enter MCU Deep Sleep mode */
125 		LPC_PWRD_API->power_mode_configure(PMU_DEEP_SLEEP, (PMU_PD_WDOSC | PMU_PD_BOD | PMU_PD_ACMP0 | PMU_PD_ACMP1 | PMU_PD_ACMP2 |PMU_PD_ACMP3 | PMU_PD_IREF | PMU_PD_TS));
126 		__WFI();
127 
128 		break;
129 
130 	case PMU_MCU_POWER_DOWN:
131 		DEBUGSTR("-----------------------------------------------------------------\r\n");
132 		DEBUGSTR("     Entering POWER DOWN power setting\r\n");
133 		DEBUGOUT("       (System will exit POWER DOWN in %d seconds)\r\n", POWER_CYCLE_SEC_DELAY);
134 		DEBUGSTR("-----------------------------------------------------------------\r\n\r\n");
135 
136 		/* Wait for all serial characters to be output */
137 		DelayForSerialOutput();
138 
139 		/* We should call Chip_SYSCTL_SetWakeup() to setup any peripherals we want
140 		   to power back up on wakeup. For this example, we'll power back up the IRC,
141 		   FLASH, the system oscillator, and the PLL */
142 		Chip_SYSCTL_SetWakeup(~(SYSCTL_SLPWAKE_IRCOUT_PD | SYSCTL_SLPWAKE_IRC_PD |
143 								SYSCTL_SLPWAKE_FLASH_PD | SYSCTL_SLPWAKE_SYSOSC_PD | SYSCTL_SLPWAKE_SYSPLL_PD));
144 		Chip_SYSCTL_EnableERP1PeriphWakeup(SYSCTL_ERP1_WAKEUP_RTCALARMINT);
145 
146 		/* Enter MCU Power down mode */
147 		LPC_PWRD_API->power_mode_configure(PMU_POWERDOWN, (PMU_PD_WDOSC | PMU_PD_BOD | PMU_PD_ACMP0 | PMU_PD_ACMP1 | PMU_PD_ACMP2 |PMU_PD_ACMP3 | PMU_PD_IREF | PMU_PD_TS));
148 		__WFI();
149 
150 		break;
151 
152 	case PMU_MCU_DEEP_PWRDOWN:
153 		DEBUGSTR("-----------------------------------------------------------------\r\n");
154 		DEBUGSTR("     Entering DEEP POWER DOWN power setting\r\n");
155 		DEBUGOUT("       (System will exit DEEP POWER DOWN in %d seconds)\r\n", POWER_CYCLE_SEC_DELAY);
156 		DEBUGSTR("-----------------------------------------------------------------\r\n\r\n");
157 
158 		/* Wait for all serial characters to be output */
159 		DelayForSerialOutput();
160 		/* Enable wakeup from deep power down mode due to RTC Alarm Match */
161 		Chip_RTC_EnableWakeup(LPC_RTC, RTC_CTRL_ALARMDPD_EN);
162 		/* Enter MCU Deep Power down mode */
163 		LPC_PWRD_API->power_mode_configure(PMU_DEEP_POWERDOWN, (PMU_PD_WDOSC | PMU_PD_BOD | PMU_PD_ACMP0 | PMU_PD_ACMP1 | PMU_PD_ACMP2 |PMU_PD_ACMP3 | PMU_PD_IREF | PMU_PD_TS));
164 		__WFI();
165 
166 		break;
167 	}
168 }
169 
170 /*****************************************************************************
171  * Public functions
172  ****************************************************************************/
173 
174 /**
175  * @brief	RealTimeClock (RTC) Alarm Interrupt Handler
176  * @return	None
177  */
RTC_ALARM_IRQHandler(void)178 void RTC_ALARM_IRQHandler(void)
179 {
180 	uint32_t rtcStatus;
181 
182 	/* Get RTC status register */
183 	rtcStatus = Chip_RTC_GetStatus(LPC_RTC);
184 
185 	/* Clear only latched RTC status */
186 	Chip_RTC_EnableOptions(LPC_RTC,
187 						   (rtcStatus & (RTC_CTRL_WAKE1KHZ | RTC_CTRL_ALARM1HZ)));
188 }
189 
190 /**
191  * @brief	Main program body
192  * @return	int
193  */
main(void)194 int main(void)
195 {
196 	CHIP_PMU_MCUPOWER_T crntPowerSetting;
197 
198 	/* Setup SystemCoreClock and any needed board code */
199 	SystemCoreClockUpdate();
200 	Board_Init();
201 	Board_LED_Set(0, true);
202 
203 	/* Clear any previously set deep power down and sleep flags */
204 	Chip_PMU_ClearSleepFlags(LPC_PMU, PMU_PCON_SLEEPFLAG | PMU_PCON_DPDFLAG);
205 	/* Enable the RTC oscillator, oscillator rate can be determined by
206 	   calling Chip_Clock_GetRTCOscRate() */
207 	Chip_Clock_EnableRTCOsc();
208 
209 	/* Initialize RTC driver (enables RTC clocking) */
210 	Chip_RTC_Init(LPC_RTC);
211 
212 	/* RTC reset */
213 	Chip_RTC_Reset(LPC_RTC);
214 
215 	/* Start RTC at a count of 0 when RTC is disabled. If the RTC is enabled, you
216 	   need to disable it before setting the initial RTC count. */
217 	Chip_RTC_Disable(LPC_RTC);
218 	Chip_RTC_SetCount(LPC_RTC, 0);
219 
220 	/* Set a long alarm time so the interrupt won't trigger */
221 	Chip_RTC_SetAlarm(LPC_RTC, 1000);
222 
223 	/* Enable RTC */
224 	Chip_RTC_Enable(LPC_RTC);
225 
226 	/* Clear latched RTC interrupt statuses */
227 	Chip_RTC_ClearStatus(LPC_RTC, (RTC_CTRL_OFD | RTC_CTRL_ALARM1HZ | RTC_CTRL_WAKE1KHZ));
228 
229 	/* Enable RTC interrupt */
230 	NVIC_EnableIRQ(RTC_ALARM_IRQn);
231 
232 	/* Enable RTC alarm interrupt */
233 	Chip_RTC_EnableWakeup(LPC_RTC, RTC_CTRL_ALARMDPD_EN);
234 
235 	/* Output example's activity banner */
236 	DEBUGSTR("\r\n");
237 	DEBUGSTR("-----------------------------------------------------------------\r\n");
238 #ifdef RESET_POWER_CYCLE_COUNT
239 	ProcessCycleCounter();
240 	DEBUGOUT("Power Control Example\r\n");
241 #else
242 	DEBUGOUT("Power Control Example   Cycle Count: %d\r\n", ProcessCycleCounter());
243 #endif
244 	DEBUGSTR("  System will cycle through SLEEP, DEEP SLEEP, POWER\r\n");
245 	DEBUGSTR("  DOWN, and DEEP POWER DOWN power states\r\n");
246 	DEBUGSTR("-----------------------------------------------------------------\r\n\r\n");
247 
248 	/* Setup alarm, process next power state then wait for alarm to wake-up system */
249 	crntPowerSetting = PMU_MCU_SLEEP;
250 	while (1) {
251 		/* Set alarm to wakeup in POWER_CYCLE_SEC_DELAY seconds */
252 		Chip_RTC_SetAlarm(LPC_RTC, Chip_RTC_GetCount(LPC_RTC) + POWER_CYCLE_SEC_DELAY);
253 
254 		/* Enter first (or next) power state */
255 		ProcessPowerState(crntPowerSetting);
256 
257 		/* Inc current power setting and test for overflow */
258 		if (crntPowerSetting == PMU_MCU_DEEP_PWRDOWN) {
259 			/* Reset to lowest power setting */
260 			crntPowerSetting = PMU_MCU_SLEEP;
261 		}
262 		else {
263 			crntPowerSetting++;
264 		}
265 	}
266 
267 	return 0;
268 }
269