2 * -------------------------------------------
3 * MSP432 DriverLib - v3_10_00_09
4 * -------------------------------------------
6 * --COPYRIGHT--,BSD,BSD
7 * Copyright (c) 2014, Texas Instruments Incorporated
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
14 * * Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
17 * * Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
21 * * Neither the name of Texas Instruments Incorporated nor the names of
22 * its contributors may be used to endorse or promote products derived
23 * from this software without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
27 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
29 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
32 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
33 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
34 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
35 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 /* Standard Includes */
40 /* DriverLib Includes */
43 #include <interrupt.h>
48 static bool __PCM_setCoreVoltageLevelAdvanced(uint_fast8_t voltageLevel,
49 uint32_t timeOut, bool blocking)
51 uint8_t powerMode, bCurrentVoltageLevel;
55 ASSERT(voltageLevel == PCM_VCORE0 || voltageLevel == PCM_VCORE1);
57 /* Getting current power mode and level */
58 powerMode = PCM_getPowerMode();
59 bCurrentVoltageLevel = PCM_getCoreVoltageLevel();
61 boolTimeout = timeOut > 0 ? true : false;
63 /* If we are already at the power mode they requested, return */
64 if (bCurrentVoltageLevel == voltageLevel)
67 while (bCurrentVoltageLevel != voltageLevel)
71 switch (PCM_getPowerState())
73 case PCM_AM_LF_VCORE1:
74 case PCM_AM_DCDC_VCORE1:
75 case PCM_AM_LDO_VCORE0:
76 PCM->CTL0 = (PCM_KEY | (PCM_AM_LDO_VCORE1)
77 | (regValue & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK)));
79 case PCM_AM_LF_VCORE0:
80 case PCM_AM_DCDC_VCORE0:
81 case PCM_AM_LDO_VCORE1:
82 PCM->CTL0 = (PCM_KEY | (PCM_AM_LDO_VCORE0)
83 | (regValue & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK)));
91 while (BITBAND_PERI(PCM->CTL1, PCM_CTL1_PMR_BUSY_OFS))
93 if (boolTimeout && !(--timeOut))
103 bCurrentVoltageLevel = PCM_getCoreVoltageLevel();
106 /* Changing the power mode if we are stuck in LDO mode */
107 if (powerMode != PCM_getPowerMode())
109 if (powerMode == PCM_DCDC_MODE)
110 return PCM_setPowerMode(PCM_DCDC_MODE);
112 return PCM_setPowerMode(PCM_LF_MODE);
120 bool PCM_setCoreVoltageLevel(uint_fast8_t voltageLevel)
122 return __PCM_setCoreVoltageLevelAdvanced(voltageLevel, 0, true);
125 bool PCM_setCoreVoltageLevelWithTimeout(uint_fast8_t voltageLevel,
128 return __PCM_setCoreVoltageLevelAdvanced(voltageLevel, timeOut, true);
131 bool PCM_setCoreVoltageLevelNonBlocking(uint_fast8_t voltageLevel)
133 return __PCM_setCoreVoltageLevelAdvanced(voltageLevel, 0, false);
136 uint8_t PCM_getPowerMode(void)
138 uint8_t currentPowerState;
140 currentPowerState = PCM_getPowerState();
142 switch (currentPowerState)
144 case PCM_AM_LDO_VCORE0:
145 case PCM_AM_LDO_VCORE1:
146 case PCM_LPM0_LDO_VCORE0:
147 case PCM_LPM0_LDO_VCORE1:
149 case PCM_AM_DCDC_VCORE0:
150 case PCM_AM_DCDC_VCORE1:
151 case PCM_LPM0_DCDC_VCORE0:
152 case PCM_LPM0_DCDC_VCORE1:
153 return PCM_DCDC_MODE;
154 case PCM_LPM0_LF_VCORE0:
155 case PCM_LPM0_LF_VCORE1:
156 case PCM_AM_LF_VCORE1:
157 case PCM_AM_LF_VCORE0:
166 uint8_t PCM_getCoreVoltageLevel(void)
168 uint8_t currentPowerState = PCM_getPowerState();
170 switch (currentPowerState)
172 case PCM_AM_LDO_VCORE0:
173 case PCM_AM_DCDC_VCORE0:
174 case PCM_AM_LF_VCORE0:
175 case PCM_LPM0_LDO_VCORE0:
176 case PCM_LPM0_DCDC_VCORE0:
177 case PCM_LPM0_LF_VCORE0:
179 case PCM_AM_LDO_VCORE1:
180 case PCM_AM_DCDC_VCORE1:
181 case PCM_AM_LF_VCORE1:
182 case PCM_LPM0_LDO_VCORE1:
183 case PCM_LPM0_DCDC_VCORE1:
184 case PCM_LPM0_LF_VCORE1:
187 return PCM_VCORELPM3;
195 static bool __PCM_setPowerModeAdvanced(uint_fast8_t powerMode, uint32_t timeOut,
198 uint8_t bCurrentPowerMode, bCurrentPowerState;
203 powerMode == PCM_LDO_MODE || powerMode == PCM_DCDC_MODE
204 || powerMode == PCM_LF_MODE);
206 /* Getting Current Power Mode */
207 bCurrentPowerMode = PCM_getPowerMode();
209 /* If the power mode being set it the same as the current mode, return */
210 if (powerMode == bCurrentPowerMode)
213 bCurrentPowerState = PCM_getPowerState();
215 boolTimeout = timeOut > 0 ? true : false;
217 /* Go through the while loop while we haven't achieved the power mode */
218 while (bCurrentPowerMode != powerMode)
220 regValue = PCM->CTL0;
222 switch (bCurrentPowerState)
224 case PCM_AM_DCDC_VCORE0:
225 case PCM_AM_LF_VCORE0:
226 PCM->CTL0 = (PCM_KEY | PCM_AM_LDO_VCORE0
227 | (regValue & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK)));
229 case PCM_AM_LF_VCORE1:
230 case PCM_AM_DCDC_VCORE1:
231 PCM->CTL0 = (PCM_KEY | PCM_AM_LDO_VCORE1
232 | (regValue & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK)));
234 case PCM_AM_LDO_VCORE1:
236 if (powerMode == PCM_DCDC_MODE)
238 PCM->CTL0 = (PCM_KEY | PCM_AM_DCDC_VCORE1
239 | (regValue & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK)));
240 } else if (powerMode == PCM_LF_MODE)
242 PCM->CTL0 = (PCM_KEY | PCM_AM_LF_VCORE1
243 | (regValue & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK)));
249 case PCM_AM_LDO_VCORE0:
251 if (powerMode == PCM_DCDC_MODE)
253 PCM->CTL0 = (PCM_KEY | PCM_AM_DCDC_VCORE0
254 | (regValue & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK)));
255 } else if (powerMode == PCM_LF_MODE)
257 PCM->CTL0 = (PCM_KEY | PCM_AM_LF_VCORE0
258 | (regValue & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK)));
270 while (BITBAND_PERI(PCM->CTL1, PCM_CTL1_PMR_BUSY_OFS))
272 if (boolTimeout && !(--timeOut))
279 bCurrentPowerMode = PCM_getPowerMode();
280 bCurrentPowerState = PCM_getPowerState();
287 bool PCM_setPowerMode(uint_fast8_t powerMode)
289 return __PCM_setPowerModeAdvanced(powerMode, 0, true);
292 bool PCM_setPowerModeNonBlocking(uint_fast8_t powerMode)
294 return __PCM_setPowerModeAdvanced(powerMode, 0, false);
297 bool PCM_setPowerModeWithTimeout(uint_fast8_t powerMode, uint32_t timeOut)
299 return __PCM_setPowerModeAdvanced(powerMode, timeOut, true);
302 static bool __PCM_setPowerStateAdvanced(uint_fast8_t powerState,
306 uint8_t bCurrentPowerState;
307 bCurrentPowerState = PCM_getPowerState();
310 powerState == PCM_AM_LDO_VCORE0 || powerState == PCM_AM_LDO_VCORE1
311 || powerState == PCM_AM_DCDC_VCORE0 || powerState == PCM_AM_DCDC_VCORE1
312 || powerState == PCM_AM_LF_VCORE0 || powerState == PCM_AM_LF_VCORE1
313 || powerState == PCM_LPM0_LDO_VCORE0 || powerState == PCM_LPM0_LDO_VCORE1
314 || powerState == PCM_LPM0_DCDC_VCORE0 || powerState == PCM_LPM0_DCDC_VCORE1
315 || powerState == PCM_LPM3 || powerState == PCM_LPM35_VCORE0
316 || powerState == PCM_LPM45 || powerState == PCM_LPM4);
318 if (bCurrentPowerState == powerState)
323 case PCM_AM_LDO_VCORE0:
324 return (__PCM_setCoreVoltageLevelAdvanced(PCM_VCORE0, timeout, blocking)
325 && __PCM_setPowerModeAdvanced(PCM_LDO_MODE, timeout, blocking));
326 case PCM_AM_LDO_VCORE1:
327 return (__PCM_setCoreVoltageLevelAdvanced(PCM_VCORE1, timeout, blocking)
328 && __PCM_setPowerModeAdvanced(PCM_LDO_MODE, timeout, blocking));
329 case PCM_AM_DCDC_VCORE0:
330 return (__PCM_setCoreVoltageLevelAdvanced(PCM_VCORE0, timeout, blocking)
331 && __PCM_setPowerModeAdvanced(PCM_DCDC_MODE, timeout, blocking));
332 case PCM_AM_DCDC_VCORE1:
333 return (__PCM_setCoreVoltageLevelAdvanced(PCM_VCORE1, timeout, blocking)
334 && __PCM_setPowerModeAdvanced(PCM_DCDC_MODE, timeout, blocking));
335 case PCM_AM_LF_VCORE0:
336 return (__PCM_setCoreVoltageLevelAdvanced(PCM_VCORE0, timeout, blocking)
337 && __PCM_setPowerModeAdvanced(PCM_LF_MODE, timeout, blocking));
338 case PCM_AM_LF_VCORE1:
339 return (__PCM_setCoreVoltageLevelAdvanced(PCM_VCORE1, timeout, blocking)
340 && __PCM_setPowerModeAdvanced(PCM_LF_MODE, timeout, blocking));
341 case PCM_LPM0_LDO_VCORE0:
342 if (!__PCM_setCoreVoltageLevelAdvanced(PCM_VCORE0, timeout, blocking)
343 || !__PCM_setPowerModeAdvanced(PCM_LDO_MODE, timeout, blocking))
345 return PCM_gotoLPM0();
346 case PCM_LPM0_LDO_VCORE1:
347 if (!__PCM_setCoreVoltageLevelAdvanced(PCM_VCORE1, timeout, blocking)
348 || !__PCM_setPowerModeAdvanced(PCM_LDO_MODE, timeout, blocking))
350 return PCM_gotoLPM0();
351 case PCM_LPM0_DCDC_VCORE0:
352 if (!__PCM_setCoreVoltageLevelAdvanced(PCM_VCORE0, timeout, blocking)
353 || !__PCM_setPowerModeAdvanced(PCM_DCDC_MODE, timeout,
356 return PCM_gotoLPM0();
357 case PCM_LPM0_DCDC_VCORE1:
358 if (!__PCM_setCoreVoltageLevelAdvanced(PCM_VCORE1, timeout, blocking)
359 || !__PCM_setPowerModeAdvanced(PCM_DCDC_MODE, timeout,
362 return PCM_gotoLPM0();
363 case PCM_LPM0_LF_VCORE0:
364 if (!__PCM_setCoreVoltageLevelAdvanced(PCM_VCORE0, timeout, blocking)
365 || !__PCM_setPowerModeAdvanced(PCM_LF_MODE, timeout, blocking))
367 return PCM_gotoLPM0();
368 case PCM_LPM0_LF_VCORE1:
369 if (!__PCM_setCoreVoltageLevelAdvanced(PCM_VCORE1, timeout, blocking)
370 || !__PCM_setPowerModeAdvanced(PCM_LF_MODE, timeout, blocking))
372 return PCM_gotoLPM0();
374 return PCM_gotoLPM3();
376 return PCM_gotoLPM4();
378 return PCM_shutdownDevice(PCM_LPM45);
379 case PCM_LPM35_VCORE0:
380 return PCM_shutdownDevice(PCM_LPM35_VCORE0);
390 bool PCM_setPowerState(uint_fast8_t powerState)
392 return __PCM_setPowerStateAdvanced(powerState, 0, true);
395 bool PCM_setPowerStateWithTimeout(uint_fast8_t powerState, uint32_t timeout)
397 return __PCM_setPowerStateAdvanced(powerState, timeout, true);
400 bool PCM_setPowerStateNonBlocking(uint_fast8_t powerState)
402 return __PCM_setPowerStateAdvanced(powerState, 0, false);
405 bool PCM_shutdownDevice(uint32_t shutdownMode)
407 uint32_t shutdownModeBits = (shutdownMode == PCM_LPM45) ?
408 PCM_CTL0_LPMR_12 : PCM_CTL0_LPMR_10;
411 shutdownMode == PCM_SHUTDOWN_PARTIAL
412 || shutdownMode == PCM_SHUTDOWN_COMPLETE);
414 /* If a power transition is occuring, return false */
415 if (BITBAND_PERI(PCM->CTL1, PCM_CTL1_PMR_BUSY_OFS))
418 /* Initiating the shutdown */
419 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
421 PCM->CTL0 = (PCM_KEY | shutdownModeBits
422 | (PCM->CTL0 & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_LPMR_MASK)));
429 bool PCM_gotoLPM4(void)
431 /* Disabling RTC_C and WDT_A */
435 /* LPM4 is just LPM3 with WDT_A/RTC_C disabled... */
436 return PCM_gotoLPM3();
439 bool PCM_gotoLPM4InterruptSafe(void)
441 bool slHappenedCorrect;
443 /* Disabling master interrupts. In Cortex M, if an interrupt is enabled but
444 master interrupts are disabled and a WFI happens the WFI will
446 Interrupt_disableMaster();
448 slHappenedCorrect = PCM_gotoLPM4();
450 /* Enabling and Disabling Interrupts very quickly so that the
451 processor catches any pending interrupts */
452 Interrupt_enableMaster();
453 Interrupt_disableMaster();
455 return slHappenedCorrect;
458 bool PCM_gotoLPM0(void)
460 /* If we are in the middle of a state transition, return false */
461 if (BITBAND_PERI(PCM->CTL1, PCM_CTL1_PMR_BUSY_OFS))
464 SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
471 bool PCM_gotoLPM0InterruptSafe(void)
473 bool slHappenedCorrect;
475 /* Disabling master interrupts. In Cortex M, if an interrupt is enabled but
476 master interrupts are disabled and a WFI happens the WFI will
478 Interrupt_disableMaster();
480 slHappenedCorrect = PCM_gotoLPM0();
482 /* Enabling and Disabling Interrupts very quickly so that the
483 processor catches any pending interrupts */
484 Interrupt_enableMaster();
485 Interrupt_disableMaster();
487 return slHappenedCorrect;
490 bool PCM_gotoLPM3(void)
492 uint_fast8_t bCurrentPowerState;
493 uint_fast8_t currentPowerMode;
495 /* If we are in the middle of a state transition, return false */
496 if (BITBAND_PERI(PCM->CTL1, PCM_CTL1_PMR_BUSY_OFS))
499 /* If we are in the middle of a shutdown, return false */
500 if ((PCM->CTL0 & PCM_CTL0_LPMR_MASK) == PCM_CTL0_LPMR_10
501 || (PCM->CTL0 & PCM_CTL0_LPMR_MASK) == PCM_CTL0_LPMR_12)
504 currentPowerMode = PCM_getPowerMode();
505 bCurrentPowerState = PCM_getPowerState();
507 if (currentPowerMode == PCM_DCDC_MODE || currentPowerMode == PCM_LF_MODE)
508 PCM_setPowerMode(PCM_LDO_MODE);
510 /* Clearing the SDR */
511 PCM->CTL0 = (PCM->CTL0 & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_LPMR_MASK)) | PCM_KEY;
513 /* Setting the sleep deep bit */
514 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
518 SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
520 return PCM_setPowerState(bCurrentPowerState);
523 bool PCM_gotoLPM3InterruptSafe(void)
525 bool lpmHappenedCorrect;
527 /* Disabling master interrupts. In Cortex M, if an interrupt is enabled but
528 master interrupts are disabled and a WFI happens the WFI will
530 Interrupt_disableMaster();
532 lpmHappenedCorrect = PCM_gotoLPM3();
534 /* Enabling and Disabling Interrupts very quickly so that the
535 processor catches any pending interrupts */
536 Interrupt_enableMaster();
537 Interrupt_disableMaster();
539 return lpmHappenedCorrect;
542 uint8_t PCM_getPowerState(void)
544 return (PCM->CTL0 | PCM_CTL0_CPM_MASK);
547 void PCM_enableRudeMode(void)
550 PCM->CTL1 = (PCM->CTL1 & ~(PCM_CTL0_KEY_MASK)) | PCM_KEY
551 | PCM_CTL1_FORCE_LPM_ENTRY;
554 void PCM_disableRudeMode(void)
556 PCM->CTL1 = (PCM->CTL1 & ~(PCM_CTL0_KEY_MASK | PCM_CTL1_FORCE_LPM_ENTRY))
560 void PCM_enableInterrupt(uint32_t flags)
565 void PCM_disableInterrupt(uint32_t flags)
570 uint32_t PCM_getInterruptStatus(void)
575 uint32_t PCM_getEnabledInterruptStatus(void)
577 return PCM_getInterruptStatus() & PCM->IE;
580 void PCM_clearInterruptFlag(uint32_t flags)
582 PCM->CLRIFG |= flags;
585 void PCM_registerInterrupt(void (*intHandler)(void))
588 // Register the interrupt handler, returning an error if an error occurs.
590 Interrupt_registerInterrupt(INT_PCM, intHandler);
593 // Enable the system control interrupt.
595 Interrupt_enableInterrupt(INT_PCM);
598 void PCM_unregisterInterrupt(void)
601 // Disable the interrupt.
603 Interrupt_disableInterrupt(INT_PCM);
606 // Unregister the interrupt handler.
608 Interrupt_unregisterInterrupt(INT_PCM);