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 		Chip_PMU_SleepState(LPC_PMU);
104 
105 		break;
106 
107 	case PMU_MCU_DEEP_SLEEP:
108 		DEBUGSTR("-----------------------------------------------------------------\r\n");
109 		DEBUGSTR("     Entering DEEP SLEEP power setting\r\n");
110 		DEBUGOUT("       (System will exit DEEP SLEEP in %d seconds)\r\n", POWER_CYCLE_SEC_DELAY);
111 		DEBUGSTR("-----------------------------------------------------------------\r\n\r\n");
112 
113 		/* Wait for all serial characters to be output */
114 		DelayForSerialOutput();
115 
116 		/* We should call Chip_SYSCTL_SetWakeup() to setup any peripherals we want
117 		   to power back up on wakeup. For this example, we'll power back up the IRC,
118 		   FLASH, the system oscillator, and the PLL */
119 		Chip_SYSCTL_SetWakeup(~(SYSCTL_SLPWAKE_IRCOUT_PD | SYSCTL_SLPWAKE_IRC_PD |
120 								SYSCTL_SLPWAKE_FLASH_PD | SYSCTL_SLPWAKE_SYSOSC_PD | SYSCTL_SLPWAKE_SYSPLL_PD));
121 		Chip_SYSCTL_EnableERP1PeriphWakeup(SYSCTL_ERP1_WAKEUP_RTCALARMINT);
122 
123 		/* Enter MCU Deep Sleep mode */
124 		Chip_PMU_DeepSleepState(LPC_PMU);
125 
126 		break;
127 
128 	case PMU_MCU_POWER_DOWN:
129 		DEBUGSTR("-----------------------------------------------------------------\r\n");
130 		DEBUGSTR("     Entering POWER DOWN power setting\r\n");
131 		DEBUGOUT("       (System will exit POWER DOWN in %d seconds)\r\n", POWER_CYCLE_SEC_DELAY);
132 		DEBUGSTR("-----------------------------------------------------------------\r\n\r\n");
133 
134 		/* Wait for all serial characters to be output */
135 		DelayForSerialOutput();
136 
137 		/* We should call Chip_SYSCTL_SetWakeup() to setup any peripherals we want
138 		   to power back up on wakeup. For this example, we'll power back up the IRC,
139 		   FLASH, the system oscillator, and the PLL */
140 		Chip_SYSCTL_SetWakeup(~(SYSCTL_SLPWAKE_IRCOUT_PD | SYSCTL_SLPWAKE_IRC_PD |
141 								SYSCTL_SLPWAKE_FLASH_PD | SYSCTL_SLPWAKE_SYSOSC_PD | SYSCTL_SLPWAKE_SYSPLL_PD));
142 		Chip_SYSCTL_EnableERP1PeriphWakeup(SYSCTL_ERP1_WAKEUP_RTCALARMINT);
143 
144 		/* Enter MCU Power down mode */
145 		Chip_PMU_PowerDownState(LPC_PMU);
146 
147 		break;
148 
149 	case PMU_MCU_DEEP_PWRDOWN:
150 		DEBUGSTR("-----------------------------------------------------------------\r\n");
151 		DEBUGSTR("     Entering DEEP POWER DOWN power setting\r\n");
152 		DEBUGOUT("       (System will exit DEEP POWER DOWN in %d seconds)\r\n", POWER_CYCLE_SEC_DELAY);
153 		DEBUGSTR("-----------------------------------------------------------------\r\n\r\n");
154 
155 		/* Wait for all serial characters to be output */
156 		DelayForSerialOutput();
157 		/* Enable wakeup from deep power down mode due to RTC Alarm Match */
158 		Chip_RTC_EnableWakeup(LPC_RTC, RTC_CTRL_ALARMDPD_EN);
159 		/* Enter MCU Deep Power down mode */
160 		Chip_PMU_DeepPowerDownState(LPC_PMU);
161 
162 		break;
163 	}
164 }
165 
166 /*****************************************************************************
167  * Public functions
168  ****************************************************************************/
169 
170 /**
171  * @brief	RealTimeClock (RTC) Alarm Interrupt Handler
172  * @return	None
173  */
RTC_ALARM_IRQHandler(void)174 void RTC_ALARM_IRQHandler(void)
175 {
176 	uint32_t rtcStatus;
177 
178 	/* Get RTC status register */
179 	rtcStatus = Chip_RTC_GetStatus(LPC_RTC);
180 
181 	/* Clear only latched RTC status */
182 	Chip_RTC_EnableOptions(LPC_RTC,
183 						   (rtcStatus & (RTC_CTRL_WAKE1KHZ | RTC_CTRL_ALARM1HZ)));
184 }
185 
186 /**
187  * @brief	Main program body
188  * @return	int
189  */
main(void)190 int main(void)
191 {
192 	CHIP_PMU_MCUPOWER_T crntPowerSetting;
193 
194 	/* Setup SystemCoreClock and any needed board code */
195 	SystemCoreClockUpdate();
196 	Board_Init();
197 	Board_LED_Set(0, true);
198 
199 	/* Clear any previously set deep power down and sleep flags */
200 	Chip_PMU_ClearSleepFlags(LPC_PMU, PMU_PCON_SLEEPFLAG | PMU_PCON_DPDFLAG);
201 	/* Enable the RTC oscillator, oscillator rate can be determined by
202 	   calling Chip_Clock_GetRTCOscRate() */
203 	Chip_Clock_EnableRTCOsc();
204 
205 	/* Initialize RTC driver (enables RTC clocking) */
206 	Chip_RTC_Init(LPC_RTC);
207 
208 	/* RTC reset */
209 	Chip_RTC_Reset(LPC_RTC);
210 
211 	/* Start RTC at a count of 0 when RTC is disabled. If the RTC is enabled, you
212 	   need to disable it before setting the initial RTC count. */
213 	Chip_RTC_Disable(LPC_RTC);
214 	Chip_RTC_SetCount(LPC_RTC, 0);
215 
216 	/* Set a long alarm time so the interrupt won't trigger */
217 	Chip_RTC_SetAlarm(LPC_RTC, 1000);
218 
219 	/* Enable RTC */
220 	Chip_RTC_Enable(LPC_RTC);
221 
222 	/* Clear latched RTC interrupt statuses */
223 	Chip_RTC_ClearStatus(LPC_RTC, (RTC_CTRL_OFD | RTC_CTRL_ALARM1HZ | RTC_CTRL_WAKE1KHZ));
224 
225 	/* Enable RTC interrupt */
226 	NVIC_EnableIRQ(RTC_ALARM_IRQn);
227 
228 	/* Enable RTC alarm interrupt */
229 	Chip_RTC_EnableWakeup(LPC_RTC, RTC_CTRL_ALARMDPD_EN);
230 
231 	/* Output example's activity banner */
232 	DEBUGSTR("\r\n");
233 	DEBUGSTR("-----------------------------------------------------------------\r\n");
234 #ifdef RESET_POWER_CYCLE_COUNT
235 	ProcessCycleCounter();
236 	DEBUGOUT("Power Control Example\r\n");
237 #else
238 	DEBUGOUT("Power Control Example   Cycle Count: %d\r\n", ProcessCycleCounter());
239 #endif
240 	DEBUGSTR("  System will cycle through SLEEP, DEEP SLEEP, POWER\r\n");
241 	DEBUGSTR("  DOWN, and DEEP POWER DOWN power states\r\n");
242 	DEBUGSTR("-----------------------------------------------------------------\r\n\r\n");
243 
244 	/* Setup alarm, process next power state then wait for alarm to wake-up system */
245 	crntPowerSetting = PMU_MCU_SLEEP;
246 	while (1) {
247 		/* Set alarm to wakeup in POWER_CYCLE_SEC_DELAY seconds */
248 		Chip_RTC_SetAlarm(LPC_RTC, Chip_RTC_GetCount(LPC_RTC) + POWER_CYCLE_SEC_DELAY);
249 
250 		/* Enter first (or next) power state */
251 		ProcessPowerState(crntPowerSetting);
252 
253 		/* Inc current power setting and test for overflow */
254 		if (crntPowerSetting == PMU_MCU_DEEP_PWRDOWN) {
255 			/* Reset to lowest power setting */
256 			crntPowerSetting = PMU_MCU_SLEEP;
257 		}
258 		else {
259 			crntPowerSetting++;
260 		}
261 	}
262 
263 	return 0;
264 }
265