2 * -------------------------------------------
3 * MSP432 DriverLib - v01_04_00_18
4 * -------------------------------------------
6 * --COPYRIGHT--,BSD,BSD
7 * Copyright (c) 2015, 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>
46 bool PCM_setCoreVoltageLevel(uint_fast8_t voltageLevel)
48 return PCM_setCoreVoltageLevelWithTimeout(voltageLevel, 0);
51 bool PCM_setCoreVoltageLevelWithTimeout(uint_fast8_t voltageLevel,
54 uint8_t powerMode, bCurrentVoltageLevel;
58 ASSERT(voltageLevel == PCM_VCORE0 || voltageLevel == PCM_VCORE1);
60 /* Getting current power mode and level */
61 powerMode = PCM_getPowerMode();
62 bCurrentVoltageLevel = PCM_getCoreVoltageLevel();
64 boolTimeout = timeOut > 0 ? true : false;
66 /* If we are already at the power mode they requested, return */
67 if (bCurrentVoltageLevel == voltageLevel)
70 while (bCurrentVoltageLevel != voltageLevel)
72 regValue = PCM->rCTL0.r;
74 switch (PCM_getPowerState())
76 case PCM_AM_LF_VCORE1:
77 case PCM_AM_DCDC_VCORE1:
78 case PCM_AM_LDO_VCORE0:
79 PCM->rCTL0.r = (PCM_KEY | (PCM_AM_LDO_VCORE1)
80 | (regValue & ~(PCMKEY_M | AMR_M)));
82 case PCM_AM_LF_VCORE0:
83 case PCM_AM_DCDC_VCORE0:
84 case PCM_AM_LDO_VCORE1:
85 PCM->rCTL0.r = (PCM_KEY | (PCM_AM_LDO_VCORE0)
86 | (regValue & ~(PCMKEY_M | AMR_M)));
92 while (BITBAND_PERI(PCM->rCTL1.r, PMR_BUSY_OFS))
94 if (boolTimeout && !(--timeOut))
99 bCurrentVoltageLevel = PCM_getCoreVoltageLevel();
102 /* Changing the power mode if we are stuck in LDO mode */
103 if (powerMode != PCM_getPowerMode())
105 if (powerMode == PCM_DCDC_MODE)
106 return PCM_setPowerMode(PCM_DCDC_MODE);
108 return PCM_setPowerMode(PCM_LF_MODE);
115 bool PCM_setPowerMode(uint_fast8_t powerMode)
117 return PCM_setPowerModeWithTimeout(powerMode, 0);
120 uint8_t PCM_getPowerMode(void)
122 uint8_t currentPowerState;
124 currentPowerState = PCM_getPowerState();
126 switch (currentPowerState)
128 case PCM_AM_LDO_VCORE0:
129 case PCM_AM_LDO_VCORE1:
130 case PCM_LPM0_LDO_VCORE0:
131 case PCM_LPM0_LDO_VCORE1:
133 case PCM_AM_DCDC_VCORE0:
134 case PCM_AM_DCDC_VCORE1:
135 case PCM_LPM0_DCDC_VCORE0:
136 case PCM_LPM0_DCDC_VCORE1:
137 return PCM_DCDC_MODE;
138 case PCM_LPM0_LF_VCORE0:
139 case PCM_LPM0_LF_VCORE1:
140 case PCM_AM_LF_VCORE1:
141 case PCM_AM_LF_VCORE0:
150 uint8_t PCM_getCoreVoltageLevel(void)
152 uint8_t currentPowerState = PCM_getPowerState();
154 switch (currentPowerState)
156 case PCM_AM_LDO_VCORE0:
157 case PCM_AM_DCDC_VCORE0:
158 case PCM_AM_LF_VCORE0:
159 case PCM_LPM0_LDO_VCORE0:
160 case PCM_LPM0_DCDC_VCORE0:
161 case PCM_LPM0_LF_VCORE0:
163 case PCM_AM_LDO_VCORE1:
164 case PCM_AM_DCDC_VCORE1:
165 case PCM_AM_LF_VCORE1:
166 case PCM_LPM0_LDO_VCORE1:
167 case PCM_LPM0_DCDC_VCORE1:
168 case PCM_LPM0_LF_VCORE1:
171 return PCM_VCORELPM3;
179 bool PCM_setPowerModeWithTimeout(uint_fast8_t powerMode, uint32_t timeOut)
181 uint8_t bCurrentPowerMode, bCurrentPowerState;
186 powerMode == PCM_LDO_MODE || powerMode == PCM_DCDC_MODE
187 || powerMode == PCM_LF_MODE);
189 /* Getting Current Power Mode */
190 bCurrentPowerMode = PCM_getPowerMode();
192 /* If the power mode being set it the same as the current mode, return */
193 if (powerMode == bCurrentPowerMode)
196 bCurrentPowerState = PCM_getPowerState();
198 boolTimeout = timeOut > 0 ? true : false;
200 /* Go through the while loop while we haven't achieved the power mode */
201 while (bCurrentPowerMode != powerMode)
203 regValue = PCM->rCTL0.r;
205 switch (bCurrentPowerState)
207 case PCM_AM_DCDC_VCORE0:
208 case PCM_AM_LF_VCORE0:
209 PCM->rCTL0.r = (PCM_KEY | PCM_AM_LDO_VCORE0
210 | (regValue & ~(PCMKEY_M | AMR_M)));
212 case PCM_AM_LF_VCORE1:
213 case PCM_AM_DCDC_VCORE1:
214 PCM->rCTL0.r = (PCM_KEY | PCM_AM_LDO_VCORE1
215 | (regValue & ~(PCMKEY_M | AMR_M)));
217 case PCM_AM_LDO_VCORE1:
219 if (powerMode == PCM_DCDC_MODE)
221 PCM->rCTL0.r = (PCM_KEY | PCM_AM_DCDC_VCORE1
222 | (regValue & ~(PCMKEY_M | AMR_M)));
223 } else if (powerMode == PCM_LF_MODE)
225 PCM->rCTL0.r = (PCM_KEY | PCM_AM_LF_VCORE1
226 | (regValue & ~(PCMKEY_M | AMR_M)));
232 case PCM_AM_LDO_VCORE0:
234 if (powerMode == PCM_DCDC_MODE)
236 PCM->rCTL0.r = (PCM_KEY | PCM_AM_DCDC_VCORE0
237 | (regValue & ~(PCMKEY_M | AMR_M)));
238 } else if (powerMode == PCM_LF_MODE)
240 PCM->rCTL0.r = (PCM_KEY | PCM_AM_LF_VCORE0
241 | (regValue & ~(PCMKEY_M | AMR_M)));
251 while (BITBAND_PERI(PCM->rCTL1.r, PMR_BUSY_OFS))
253 if (boolTimeout && !(--timeOut))
258 bCurrentPowerMode = PCM_getPowerMode();
259 bCurrentPowerState = PCM_getPowerState();
266 bool PCM_setPowerState(uint_fast8_t powerState)
268 return PCM_setPowerStateWithTimeout(powerState, 0);
271 bool PCM_setPowerStateWithTimeout(uint_fast8_t powerState, uint32_t timeout)
273 uint8_t bCurrentPowerState;
274 bCurrentPowerState = PCM_getPowerState();
277 powerState == PCM_AM_LDO_VCORE0 || powerState == PCM_AM_LDO_VCORE1
278 || powerState == PCM_AM_DCDC_VCORE0 || powerState == PCM_AM_DCDC_VCORE1
279 || powerState == PCM_AM_LF_VCORE0 || powerState == PCM_AM_LF_VCORE1
280 || powerState == PCM_LPM0_LDO_VCORE0 || powerState == PCM_LPM0_LDO_VCORE1
281 || powerState == PCM_LPM0_DCDC_VCORE0 || powerState == PCM_LPM0_DCDC_VCORE1
282 || powerState == PCM_LPM3 || powerState == PCM_LPM35_VCORE0
283 || powerState == PCM_LPM45);
285 if (bCurrentPowerState == powerState)
290 case PCM_AM_LDO_VCORE0:
291 return (PCM_setCoreVoltageLevelWithTimeout(PCM_VCORE0, timeout)
292 && PCM_setPowerModeWithTimeout(PCM_LDO_MODE, timeout));
293 case PCM_AM_LDO_VCORE1:
294 return (PCM_setCoreVoltageLevelWithTimeout(PCM_VCORE1, timeout)
295 && PCM_setPowerModeWithTimeout(PCM_LDO_MODE, timeout));
296 case PCM_AM_DCDC_VCORE0:
297 return (PCM_setCoreVoltageLevelWithTimeout(PCM_VCORE0, timeout)
298 && PCM_setPowerModeWithTimeout(PCM_DCDC_MODE, timeout));
299 case PCM_AM_DCDC_VCORE1:
300 return (PCM_setCoreVoltageLevelWithTimeout(PCM_VCORE1, timeout)
301 && PCM_setPowerModeWithTimeout(PCM_DCDC_MODE, timeout));
302 case PCM_AM_LF_VCORE0:
303 return (PCM_setCoreVoltageLevelWithTimeout(PCM_VCORE0, timeout)
304 && PCM_setPowerModeWithTimeout(PCM_LF_MODE, timeout));
305 case PCM_AM_LF_VCORE1:
306 return (PCM_setCoreVoltageLevelWithTimeout(PCM_VCORE1, timeout)
307 && PCM_setPowerModeWithTimeout(PCM_LF_MODE, timeout));
308 case PCM_LPM0_LDO_VCORE0:
309 if (!PCM_setCoreVoltageLevelWithTimeout(PCM_VCORE0, timeout)
310 || !PCM_setPowerModeWithTimeout(PCM_LDO_MODE, timeout))
312 return PCM_gotoLPM0();
313 case PCM_LPM0_LDO_VCORE1:
314 if (!PCM_setCoreVoltageLevelWithTimeout(PCM_VCORE1, timeout)
315 || !PCM_setPowerModeWithTimeout(PCM_LDO_MODE, timeout))
317 return PCM_gotoLPM0();
318 case PCM_LPM0_DCDC_VCORE0:
319 if (!PCM_setCoreVoltageLevelWithTimeout(PCM_VCORE0, timeout)
320 || !PCM_setPowerModeWithTimeout(PCM_DCDC_MODE, timeout))
322 return PCM_gotoLPM0();
323 case PCM_LPM0_DCDC_VCORE1:
324 if (!PCM_setCoreVoltageLevelWithTimeout(PCM_VCORE1, timeout)
325 || !PCM_setPowerModeWithTimeout(PCM_DCDC_MODE, timeout))
327 return PCM_gotoLPM0();
328 case PCM_LPM0_LF_VCORE0:
329 if (!PCM_setCoreVoltageLevelWithTimeout(PCM_VCORE0, timeout)
330 || !PCM_setPowerModeWithTimeout(PCM_LF_MODE, timeout))
332 return PCM_gotoLPM0();
333 case PCM_LPM0_LF_VCORE1:
334 if (!PCM_setCoreVoltageLevelWithTimeout(PCM_VCORE1, timeout)
335 || !PCM_setPowerModeWithTimeout(PCM_LF_MODE, timeout))
337 return PCM_gotoLPM0();
339 return PCM_gotoLPM3();
341 return PCM_shutdownDevice(PCM_LPM45);
342 case PCM_LPM35_VCORE0:
343 return PCM_shutdownDevice(PCM_LPM35_VCORE0);
353 bool PCM_shutdownDevice(uint32_t shutdownMode)
355 uint32_t shutdownModeBits = (shutdownMode == PCM_LPM45) ? LPMR_12 : LPMR_10;
358 shutdownMode == PCM_SHUTDOWN_PARTIAL
359 || shutdownMode == PCM_SHUTDOWN_COMPLETE);
361 /* If a power transition is occuring, return false */
362 if (BITBAND_PERI(PCM->rCTL1.r, PMR_BUSY_OFS))
365 /* Initiating the shutdown */
366 HWREG32(SCS_BASE + OFS_SCB_SCR) |= (SCB_SCR_SLEEPDEEP);
367 PCM->rCTL0.r = (PCM_KEY | shutdownModeBits
368 | (PCM->rCTL0.r & ~(PCMKEY_M | LPMR_M)));
375 bool PCM_gotoLPM0(void)
378 /* If we are in the middle of a state transition, return false */
379 if (BITBAND_PERI(PCM->rCTL1.r, PMR_BUSY_OFS))
382 HWREG32(SCS_BASE + OFS_SCB_SCR) &= ~(SCB_SCR_SLEEPDEEP);
389 bool PCM_gotoLPM0InterruptSafe(void)
392 bool slHappenedCorrect;
394 /* Disabling master interrupts. In Cortex M, if an interrupt is enabled but
395 master interrupts are disabled and a WFI happens the WFI will
397 Interrupt_disableMaster();
399 slHappenedCorrect = PCM_gotoLPM0();
401 /* Enabling and Disabling Interrupts very quickly so that the
402 processor catches any pending interrupts */
403 Interrupt_enableMaster();
404 Interrupt_disableMaster();
406 return slHappenedCorrect;
409 bool PCM_gotoLPM3(void)
411 uint_fast8_t bCurrentPowerState;
412 uint_fast8_t currentPowerMode;
414 /* If we are in the middle of a state transition, return false */
415 if (BITBAND_PERI(PCM->rCTL1.r, PMR_BUSY_OFS))
418 /* If we are in the middle of a shutdown, return false */
419 if ((PCM->rCTL0.r & LPMR_M) == LPMR_10 || (PCM->rCTL0.r & LPMR_M) == LPMR_12)
422 currentPowerMode = PCM_getPowerMode();
423 bCurrentPowerState = PCM_getPowerState();
425 if (currentPowerMode == PCM_DCDC_MODE || currentPowerMode == PCM_LF_MODE)
426 PCM_setPowerMode(PCM_LDO_MODE);
428 /* Clearing the SDR */
429 PCM->rCTL0.r = (PCM->rCTL0.r & ~(PCMKEY_M | LPMR_M)) | PCM_KEY;
431 /* Setting the sleep deep bit */
432 HWREG32(SCS_BASE + OFS_SCB_SCR) |= (SCB_SCR_SLEEPDEEP);
436 HWREG32(SCS_BASE + OFS_SCB_SCR) &= ~(SCB_SCR_SLEEPDEEP);
438 return PCM_setPowerState(bCurrentPowerState);
441 bool PCM_gotoLPM3InterruptSafe(void)
443 bool dslHappenedCorrect;
445 /* Disabling master interrupts. In Cortex M, if an interrupt is enabled but
446 master interrupts are disabled and a WFI happens the WFI will
448 Interrupt_disableMaster();
450 dslHappenedCorrect = PCM_gotoLPM3();
452 /* Enabling and Disabling Interrupts very quickly so that the
453 processor catches any pending interrupts */
454 Interrupt_enableMaster();
455 Interrupt_disableMaster();
457 return dslHappenedCorrect;
460 uint8_t PCM_getPowerState(void)
462 return PCM->rCTL0.b.bCPM;
465 void PCM_enableRudeMode(void)
468 PCM->rCTL1.r = (PCM->rCTL1.r & ~(PCMKEY_M)) | PCM_KEY | FORCE_LPM_ENTRY;
471 void PCM_disableRudeMode(void)
473 PCM->rCTL1.r = (PCM->rCTL1.r & ~(PCMKEY_M | FORCE_LPM_ENTRY)) | PCM_KEY;
476 void PCM_enableInterrupt(uint32_t flags)
481 void PCM_disableInterrupt(uint32_t flags)
483 PCM->rIE.r &= ~flags;
486 uint32_t PCM_getInterruptStatus(void)
491 uint32_t PCM_getEnabledInterruptStatus(void)
493 return PCM_getInterruptStatus() & PCM->rIE.r;
496 void PCM_clearInterruptFlag(uint32_t flags)
498 PCM->rCLRIFG.r |= flags;
501 void PCM_registerInterrupt(void (*intHandler)(void))
504 // Register the interrupt handler, returning an error if an error occurs.
506 Interrupt_registerInterrupt(INT_PCM, intHandler);
509 // Enable the system control interrupt.
511 Interrupt_enableInterrupt(INT_PCM);
514 void PCM_unregisterInterrupt(void)
517 // Disable the interrupt.
519 Interrupt_disableInterrupt(INT_PCM);
522 // Unregister the interrupt handler.
524 Interrupt_unregisterInterrupt(INT_PCM);