silkz_classic.lv erstellt
[hackover2013-badge-firmware.git] / core / pmu / pmu.c
1 /**************************************************************************/
2 /*!
3 @file pmu.c
4 @author K. Townsend (microBuilder.eu)
5 @date 22 March 2010
6 @version 0.10
7
8 @section DESCRIPTION
9
10 Controls the power management features of the LPC1343, allowing you
11 to enter sleep/deep-sleep or deep power-down mode.
12
13 For examples of how to enter either mode, see the comments for the
14 functions pmuSleep(), pmuDeepSleep() and pmuPowerDown().
15
16 @section LICENSE
17
18 Software License Agreement (BSD License)
19
20 Copyright (c) 2010, microBuilder SARL
21 All rights reserved.
22
23 Redistribution and use in source and binary forms, with or without
24 modification, are permitted provided that the following conditions are met:
25 1. Redistributions of source code must retain the above copyright
26 notice, this list of conditions and the following disclaimer.
27 2. Redistributions in binary form must reproduce the above copyright
28 notice, this list of conditions and the following disclaimer in the
29 documentation and/or other materials provided with the distribution.
30 3. Neither the name of the copyright holders nor the
31 names of its contributors may be used to endorse or promote products
32 derived from this software without specific prior written permission.
33
34 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
35 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
36 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
37 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
38 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
39 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
40 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
42 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
43 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44 */
45 /**************************************************************************/
46
47 #include "core/gpio/gpio.h"
48 #include "core/cpu/cpu.h"
49 #include "core/timer32/timer32.h"
50 #include "pmu.h"
51
52 #ifdef CFG_CHIBI
53 #include "drivers/rf/chibi/chb_drvr.h"
54 #endif
55 #define PMU_WDTCLOCKSPEED_HZ 7812
56
57 void pmuSetupHW(void);
58 void pmuRestoreHW(void);
59
60
61 /**************************************************************************/
62 /*!
63 Wakeup interrupt handler
64 */
65 /**************************************************************************/
66
67 void WAKEUP_IRQHandler(void)
68 {
69 uint32_t regVal;
70
71 // Reconfigure system clock/PLL
72 cpuPllSetup(CPU_MULTIPLIER_6);
73
74 // Clear match bit on timer
75 TMR_TMR32B0EMR = 0;
76
77 // Clear pending bits
78 SCB_STARTRSRP0CLR = SCB_STARTRSRP0CLR_MASK;
79
80 // Clear SLEEPDEEP bit
81 SCB_SCR &= ~SCB_SCR_SLEEPDEEP;
82
83 // Disable the deep sleep timer
84 TMR_TMR32B0TCR = TMR_TMR32B0TCR_COUNTERENABLE_DISABLED;
85
86 /* This handler takes care of all the port pins if they
87 are configured as wakeup source. */
88 regVal = SCB_STARTSRP0;
89 if (regVal != 0)
90 {
91 SCB_STARTRSRP0CLR = regVal;
92 }
93
94 // Reconfigure CT32B0
95 timer32Init(0, TIMER32_DEFAULTINTERVAL);
96 timer32Enable(0);
97
98 // Perform peripheral specific and custom wakeup tasks
99 pmuRestoreHW();
100
101 /* See tracker for bug report. */
102 __asm volatile ("NOP");
103
104 return;
105 }
106
107 /**************************************************************************/
108 /*!
109 Setup the clock for the watchdog timer. The default is 7.8125kHz.
110 */
111 /**************************************************************************/
112 static void pmuWDTClockInit (void)
113 {
114 /* Enable WDT clock */
115 SCB_PDRUNCFG &= ~(SCB_PDRUNCFG_WDTOSC);
116
117 /* Configure watchdog clock */
118 /* Freq. = 0.5MHz, div = 64: WDT_OSC = 7.8125kHz */
119 SCB_WDTOSCCTRL = SCB_WDTOSCCTRL_FREQSEL_0_5MHZ |
120 SCB_WDTOSCCTRL_DIVSEL_DIV64;
121
122 // Switch main clock to WDT output
123 SCB_MAINCLKSEL = SCB_MAINCLKSEL_SOURCE_WDTOSC;
124 SCB_MAINCLKUEN = SCB_MAINCLKUEN_UPDATE; // Update clock source
125 SCB_MAINCLKUEN = SCB_MAINCLKUEN_DISABLE; // Toggle update register once
126 SCB_MAINCLKUEN = SCB_MAINCLKUEN_UPDATE;
127
128 // Wait until the clock is updated
129 while (!(SCB_MAINCLKUEN & SCB_MAINCLKUEN_UPDATE));
130 }
131
132 /**************************************************************************/
133 /*!
134 @brief Initialises the power management unit
135 */
136 /**************************************************************************/
137 void pmuInit( void )
138 {
139 /* Enable all clocks, even those turned off at power up. */
140 SCB_PDRUNCFG &= ~(SCB_PDRUNCFG_WDTOSC_MASK |
141 SCB_PDRUNCFG_SYSOSC_MASK |
142 SCB_PDRUNCFG_ADC_MASK);
143
144 return;
145 }
146
147 /**************************************************************************/
148 /*!
149 @brief Puts select peripherals in sleep mode.
150
151 This function will put the device into sleep mode. Most gpio pins
152 can be used to wake the device up, but the pins must first be
153 configured for this in pmuInit.
154
155 @section Example
156
157 @code
158 // Configure wakeup sources before going into sleep/deep-sleep.
159 // By default, pin 0.1 is configured as wakeup source (falling edge)
160 pmuInit();
161
162 // Enter sleep mode
163 pmuSleep();
164 @endcode
165 */
166 /**************************************************************************/
167 void pmuSleep()
168 {
169 SCB_PDAWAKECFG = SCB_PDRUNCFG;
170 __asm volatile ("WFI");
171 return;
172 }
173
174 /**************************************************************************/
175 /*!
176 @brief Turns off select peripherals and puts the device in deep-sleep
177 mode.
178
179 The device can be configured to wakeup from deep-sleep mode after a
180 specified delay by supplying a non-zero value to the wakeupSeconds
181 parameter. This will configure CT32B0 to toggle pin 0.1 (CT32B0_MAT2)
182 after x seconds, waking the device up. The timer will be configured
183 to run off the WDT OSC while in deep-sleep mode, meaning that WDTOSC
184 should not be powered off (using the sleepCtrl parameter) when a
185 wakeup delay is specified.
186
187 The sleepCtrl parameter is used to indicate which peripherals should
188 be put in sleep mode (see the SCB_PDSLEEPCFG register for details).
189
190 @param[in] sleepCtrl
191 The bits to set in the SCB_PDSLEEPCFG register. This
192 controls which peripherals will be put in sleep mode.
193 @param[in] wakeupSeconds
194 The number of seconds to wait until the device will
195 wakeup. If you do not wish to wakeup after a specific
196 delay, enter a value of 0.
197
198 @code
199 uint32_t pmuRegVal;
200
201 // Initialise power management unit
202 pmuInit();
203
204 // Put peripherals into sleep mode
205 pmuRegVal = SCB_PDSLEEPCFG_IRCOUT_PD |
206 SCB_PDSLEEPCFG_IRC_PD |
207 SCB_PDSLEEPCFG_FLASH_PD |
208 SCB_PDSLEEPCFG_USBPLL_PD |
209 SCB_PDSLEEPCFG_SYSPLL_PD |
210 SCB_PDSLEEPCFG_SYSOSC_PD |
211 SCB_PDSLEEPCFG_ADC_PD |
212 SCB_PDSLEEPCFG_BOD_PD;
213
214 // Enter deep sleep mode (wakeup after 5 seconds)
215 // By default, pin 0.1 is configured as wakeup source
216 pmuDeepSleep(pmuRegVal, 5);
217 @endcode
218 */
219 /**************************************************************************/
220 void pmuDeepSleep(uint32_t sleepCtrl, uint32_t wakeupSeconds)
221 {
222 // Setup the board for deep sleep mode, shutting down certain
223 // peripherals and remapping pins for lower power
224 pmuSetupHW();
225 SCB_PDAWAKECFG = SCB_PDRUNCFG;
226 sleepCtrl |= (1 << 9) | (1 << 11);
227 SCB_PDSLEEPCFG = sleepCtrl;
228 SCB_SCR |= SCB_SCR_SLEEPDEEP;
229
230 /* Configure system to run from WDT and set TMR32B0 for wakeup */
231 if (wakeupSeconds > 0)
232 {
233 // Make sure WDTOSC isn't disabled in PDSLEEPCFG
234 SCB_PDSLEEPCFG &= ~(SCB_PDSLEEPCFG_WDTOSC_PD);
235
236 // Disable 32-bit timer 0 if currently in use
237 TMR_TMR32B0TCR = TMR_TMR32B0TCR_COUNTERENABLE_DISABLED;
238
239 // Disable internal pullup on 0.1
240 gpioSetPullup(&IOCON_PIO0_1, gpioPullupMode_Inactive);
241
242 /* Enable the clock for CT32B0 */
243 SCB_SYSAHBCLKCTRL |= (SCB_SYSAHBCLKCTRL_CT32B0);
244
245 /* Configure 0.1 as Timer0_32 MAT2 */
246 IOCON_PIO0_1 &= ~IOCON_PIO0_1_FUNC_MASK;
247 IOCON_PIO0_1 |= IOCON_PIO0_1_FUNC_CT32B0_MAT2;
248
249 /* Set appropriate timer delay */
250 TMR_TMR32B0MR0 = PMU_WDTCLOCKSPEED_HZ * wakeupSeconds;
251
252 /* Configure match control register to raise an interrupt and reset on MR0 */
253 TMR_TMR32B0MCR |= (TMR_TMR32B0MCR_MR0_INT_ENABLED | TMR_TMR32B0MCR_MR0_RESET_ENABLED);
254
255 /* Configure external match register to set 0.1 high on match */
256 TMR_TMR32B0EMR &= ~(0xFF<<4); // Clear EMR config bits
257 TMR_TMR32B0EMR |= TMR_TMR32B0EMR_EMC2_HIGH; // Set MAT2 (0.1) high on match
258
259 /* Enable wakeup interrupts (any I/O pin can be used as a wakeup source) */
260 //NVIC_EnableIRQ(WAKEUP0_IRQn); // P0.0
261 NVIC_EnableIRQ(WAKEUP1_IRQn); // P0.1 (CT32B0_MAT2)
262 //NVIC_EnableIRQ(WAKEUP2_IRQn); // P0.2
263 //NVIC_EnableIRQ(WAKEUP3_IRQn); // P0.3
264 //NVIC_EnableIRQ(WAKEUP4_IRQn); // P0.4
265 //NVIC_EnableIRQ(WAKEUP5_IRQn); // P0.5
266 //NVIC_EnableIRQ(WAKEUP6_IRQn); // P0.6
267 //NVIC_EnableIRQ(WAKEUP7_IRQn); // P0.7
268 //NVIC_EnableIRQ(WAKEUP8_IRQn); // P0.8
269 //NVIC_EnableIRQ(WAKEUP9_IRQn); // P0.9
270 //NVIC_EnableIRQ(WAKEUP10_IRQn); // P0.10
271 //NVIC_EnableIRQ(WAKEUP11_IRQn); // P0.11
272 //NVIC_EnableIRQ(WAKEUP12_IRQn); // P1.0
273 //NVIC_EnableIRQ(WAKEUP13_IRQn); // P1.1
274 //NVIC_EnableIRQ(WAKEUP14_IRQn); // P1.2
275 //NVIC_EnableIRQ(WAKEUP15_IRQn); // P1.3
276 //NVIC_EnableIRQ(WAKEUP16_IRQn); // P1.4
277 //NVIC_EnableIRQ(WAKEUP17_IRQn); // P1.5
278 //NVIC_EnableIRQ(WAKEUP18_IRQn); // P1.6
279 //NVIC_EnableIRQ(WAKEUP19_IRQn); // P1.7
280 //NVIC_EnableIRQ(WAKEUP20_IRQn); // P1.8
281 //NVIC_EnableIRQ(WAKEUP21_IRQn); // P1.9
282 //NVIC_EnableIRQ(WAKEUP22_IRQn); // P1.10
283 //NVIC_EnableIRQ(WAKEUP23_IRQn); // P1.11
284 //NVIC_EnableIRQ(WAKEUP24_IRQn); // P2.0
285 //NVIC_EnableIRQ(WAKEUP25_IRQn); // P2.1
286 //NVIC_EnableIRQ(WAKEUP26_IRQn); // P2.2
287 //NVIC_EnableIRQ(WAKEUP27_IRQn); // P2.3
288 //NVIC_EnableIRQ(WAKEUP28_IRQn); // P2.4
289 //NVIC_EnableIRQ(WAKEUP29_IRQn); // P2.5
290 //NVIC_EnableIRQ(WAKEUP30_IRQn); // P2.6
291 //NVIC_EnableIRQ(WAKEUP31_IRQn); // P2.7
292 //NVIC_EnableIRQ(WAKEUP32_IRQn); // P2.8
293 //NVIC_EnableIRQ(WAKEUP33_IRQn); // P2.9
294 //NVIC_EnableIRQ(WAKEUP34_IRQn); // P2.10
295 //NVIC_EnableIRQ(WAKEUP35_IRQn); // P2.11
296 //NVIC_EnableIRQ(WAKEUP36_IRQn); // P3.0
297 //NVIC_EnableIRQ(WAKEUP37_IRQn); // P3.1
298 //NVIC_EnableIRQ(WAKEUP38_IRQn); // P3.2
299 //NVIC_EnableIRQ(WAKEUP39_IRQn); // P3.3
300
301 /* Use RISING EDGE for wakeup detection. */
302 SCB_STARTAPRP0 |= SCB_STARTAPRP0_APRPIO0_1;
303
304 /* Clear all wakeup sources */
305 SCB_STARTRSRP0CLR = SCB_STARTRSRP0CLR_MASK;
306
307 /* Enable Port 0.1 as wakeup source. */
308 SCB_STARTERP0 |= SCB_STARTERP0_ERPIO0_1;
309
310 // Reconfigure clock to run from WDTOSC
311 pmuWDTClockInit();
312
313 /* Start the timer */
314 TMR_TMR32B0TCR = TMR_TMR32B0TCR_COUNTERENABLE_ENABLED;
315 }
316
317 __asm volatile ("WFI");
318 return;
319 }
320
321 /**************************************************************************/
322 /*!
323 @brief Puts the device in deep power-down mode.
324
325 This function will configure the PMU control register and enter
326 deep power-down mode. Pre-determined values are stored in the four
327 general-purpose registers (PMU_GPREG0..3), which can be used to persist
328 any essential system settings while the device is in deep power-down
329 mode, so long as 3.3V is still available.
330
331 @warning The only way to wake a device up from deep power-down mode
332 is to set a low-level on P1.4. If 3.3V power is lost, the
333 values stored in the four general-purpose registers will
334 also be lost.
335
336 @section Example
337
338 @code
339 #include "core/cpu/cpu.h"
340 #include "core/pmu/pmu.h"
341
342 int main(void)
343 {
344 cpuInit();
345 pmuInit();
346
347 // Enter power-down mode
348 pmuPowerDown();
349
350 while(1)
351 {
352 // Device was woken up by WAKEUP pin
353 }
354 }
355 @endcode
356 */
357 /**************************************************************************/
358 void pmuPowerDown( void )
359 {
360 uint32_t regVal;
361
362 // Make sure HW and external devices are in low power mode
363 pmuSetupHW();
364
365 if ( (PMU_PMUCTRL & ((0x1<<8) | (PMU_PMUCTRL_DPDFLAG))) != 0x0 )
366 {
367 /* Check sleep and deep power down bits. If sleep and/or
368 deep power down mode are entered, clear the PCON bits. */
369 regVal = PMU_PMUCTRL;
370 regVal |= ((0x1<<8) |
371 (PMU_PMUCTRL_DPDEN_SLEEP) |
372 (PMU_PMUCTRL_DPDFLAG));
373 PMU_PMUCTRL = regVal;
374
375 if ( (PMU_GPREG0 != 0x12345678)||(PMU_GPREG1 != 0x87654321)
376 ||(PMU_GPREG2 != 0x56781234)||(PMU_GPREG3 != 0x43218765) )
377 {
378 while (1);
379 }
380 }
381 else
382 {
383 /* If in neither sleep nor deep-sleep mode, enter deep power down mode. */
384 PMU_GPREG0 = 0x12345678;
385 PMU_GPREG1 = 0x87654321;
386 PMU_GPREG2 = 0x56781234;
387 PMU_GPREG3 = 0x43218765;
388 SCB_SCR |= SCB_SCR_SLEEPDEEP;
389 PMU_PMUCTRL = PMU_PMUCTRL_DPDEN_DEEPPOWERDOWN;
390 __asm volatile ("WFI");
391 }
392 return;
393 }
394
395 /**************************************************************************/
396 /*!
397 @brief Configures parts and system peripherals to use lower power
398 before entering sleep mode
399 */
400 /**************************************************************************/
401 void pmuSetupHW(void)
402 {
403 #ifdef CFG_CHIBI
404 chb_sleep(TRUE);
405 #endif
406 }
407
408 /**************************************************************************/
409 /*!
410 @brief Restores parts and system peripherals to an appropriate
411 state after waking up from deep-sleep mode
412 */
413 /**************************************************************************/
414 void pmuRestoreHW(void)
415 {
416 #ifdef CFG_CHIBI
417 // Wakeup Chibi/Transceiver
418 chb_sleep(FALSE);
419 #endif
420 }
This page took 0.092338 seconds and 5 git commands to generate.