]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_M4F_MSP432_LaunchPad_IAR_CCS_Keil/driverlib/pcm.c
Final V8.2.1 release ready for tagging:
[freertos] / FreeRTOS / Demo / CORTEX_M4F_MSP432_LaunchPad_IAR_CCS_Keil / driverlib / pcm.c
1 /*
2  * -------------------------------------------
3  *    MSP432 DriverLib - v01_04_00_18 
4  * -------------------------------------------
5  *
6  * --COPYRIGHT--,BSD,BSD
7  * Copyright (c) 2015, Texas Instruments Incorporated
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * *  Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  *
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.
20  *
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.
24  *
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.
36  * --/COPYRIGHT--*/
37 /* Standard Includes */
38 #include <stdint.h>
39
40 /* DriverLib Includes */
41 #include <pcm.h>
42 #include <debug.h>
43 #include <interrupt.h>
44 #include <cpu.h>
45
46 bool PCM_setCoreVoltageLevel(uint_fast8_t voltageLevel)
47 {
48     return PCM_setCoreVoltageLevelWithTimeout(voltageLevel, 0);
49 }
50
51 bool PCM_setCoreVoltageLevelWithTimeout(uint_fast8_t voltageLevel,
52         uint32_t timeOut)
53 {
54     uint8_t powerMode, bCurrentVoltageLevel;
55     uint32_t regValue;
56     bool boolTimeout;
57
58     ASSERT(voltageLevel == PCM_VCORE0 || voltageLevel == PCM_VCORE1);
59
60     /* Getting current power mode and level */
61     powerMode = PCM_getPowerMode();
62     bCurrentVoltageLevel = PCM_getCoreVoltageLevel();
63
64     boolTimeout = timeOut > 0 ? true : false;
65
66     /* If we are already at the power mode they requested, return */
67     if (bCurrentVoltageLevel == voltageLevel)
68         return true;
69
70     while (bCurrentVoltageLevel != voltageLevel)
71     {
72         regValue = PCM->rCTL0.r;
73
74         switch (PCM_getPowerState())
75         {
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)));
81             break;
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)));
87             break;
88         default:
89             ASSERT(false);
90         }
91
92         while (BITBAND_PERI(PCM->rCTL1.r, PMR_BUSY_OFS))
93         {
94             if (boolTimeout && !(--timeOut))
95                 return false;
96
97         }
98
99         bCurrentVoltageLevel = PCM_getCoreVoltageLevel();
100     }
101
102     /* Changing the power mode if we are stuck in LDO mode */
103     if (powerMode != PCM_getPowerMode())
104     {
105         if (powerMode == PCM_DCDC_MODE)
106             return PCM_setPowerMode(PCM_DCDC_MODE);
107         else
108             return PCM_setPowerMode(PCM_LF_MODE);
109     }
110
111     return true;
112
113 }
114
115 bool PCM_setPowerMode(uint_fast8_t powerMode)
116 {
117     return PCM_setPowerModeWithTimeout(powerMode, 0);
118 }
119
120 uint8_t PCM_getPowerMode(void)
121 {
122     uint8_t currentPowerState;
123
124     currentPowerState = PCM_getPowerState();
125
126     switch (currentPowerState)
127     {
128     case PCM_AM_LDO_VCORE0:
129     case PCM_AM_LDO_VCORE1:
130     case PCM_LPM0_LDO_VCORE0:
131     case PCM_LPM0_LDO_VCORE1:
132         return PCM_LDO_MODE;
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:
142         return PCM_LF_MODE;
143     default:
144         ASSERT(false);
145         return false;
146
147     }
148 }
149
150 uint8_t PCM_getCoreVoltageLevel(void)
151 {
152     uint8_t currentPowerState = PCM_getPowerState();
153
154     switch (currentPowerState)
155     {
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:
162         return PCM_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:
169         return PCM_VCORE1;
170     case PCM_LPM3:
171         return PCM_VCORELPM3;
172     default:
173         ASSERT(false);
174         return false;
175
176     }
177 }
178
179 bool PCM_setPowerModeWithTimeout(uint_fast8_t powerMode, uint32_t timeOut)
180 {
181     uint8_t bCurrentPowerMode, bCurrentPowerState;
182     uint32_t regValue;
183     bool boolTimeout;
184
185     ASSERT(
186             powerMode == PCM_LDO_MODE || powerMode == PCM_DCDC_MODE
187             || powerMode == PCM_LF_MODE);
188
189     /* Getting Current Power Mode */
190     bCurrentPowerMode = PCM_getPowerMode();
191
192     /* If the power mode being set it the same as the current mode, return */
193     if (powerMode == bCurrentPowerMode)
194         return true;
195
196     bCurrentPowerState = PCM_getPowerState();
197
198     boolTimeout = timeOut > 0 ? true : false;
199
200     /* Go through the while loop while we haven't achieved the power mode */
201     while (bCurrentPowerMode != powerMode)
202     {
203         regValue = PCM->rCTL0.r;
204
205         switch (bCurrentPowerState)
206         {
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)));
211             break;
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)));
216             break;
217         case PCM_AM_LDO_VCORE1:
218         {
219             if (powerMode == PCM_DCDC_MODE)
220             {
221                 PCM->rCTL0.r = (PCM_KEY | PCM_AM_DCDC_VCORE1
222                         | (regValue & ~(PCMKEY_M | AMR_M)));
223             } else if (powerMode == PCM_LF_MODE)
224             {
225                 PCM->rCTL0.r = (PCM_KEY | PCM_AM_LF_VCORE1
226                         | (regValue & ~(PCMKEY_M | AMR_M)));
227             } else
228                 ASSERT(false);
229
230             break;
231         }
232         case PCM_AM_LDO_VCORE0:
233         {
234             if (powerMode == PCM_DCDC_MODE)
235             {
236                 PCM->rCTL0.r = (PCM_KEY | PCM_AM_DCDC_VCORE0
237                         | (regValue & ~(PCMKEY_M | AMR_M)));
238             } else if (powerMode == PCM_LF_MODE)
239             {
240                 PCM->rCTL0.r = (PCM_KEY | PCM_AM_LF_VCORE0
241                         | (regValue & ~(PCMKEY_M | AMR_M)));
242             } else
243                 ASSERT(false);
244
245             break;
246         }
247         default:
248             ASSERT(false);
249         }
250
251         while (BITBAND_PERI(PCM->rCTL1.r, PMR_BUSY_OFS))
252         {
253             if (boolTimeout && !(--timeOut))
254                 return false;
255
256         }
257
258         bCurrentPowerMode = PCM_getPowerMode();
259         bCurrentPowerState = PCM_getPowerState();
260     }
261
262     return true;
263
264 }
265
266 bool PCM_setPowerState(uint_fast8_t powerState)
267 {
268     return PCM_setPowerStateWithTimeout(powerState, 0);
269 }
270
271 bool PCM_setPowerStateWithTimeout(uint_fast8_t powerState, uint32_t timeout)
272 {
273     uint8_t bCurrentPowerState;
274     bCurrentPowerState = PCM_getPowerState();
275
276     ASSERT(
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);
284
285     if (bCurrentPowerState == powerState)
286         return true;
287
288     switch (powerState)
289     {
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))
311             break;
312         return PCM_gotoLPM0();
313     case PCM_LPM0_LDO_VCORE1:
314         if (!PCM_setCoreVoltageLevelWithTimeout(PCM_VCORE1, timeout)
315                 || !PCM_setPowerModeWithTimeout(PCM_LDO_MODE, timeout))
316             break;
317         return PCM_gotoLPM0();
318     case PCM_LPM0_DCDC_VCORE0:
319         if (!PCM_setCoreVoltageLevelWithTimeout(PCM_VCORE0, timeout)
320                 || !PCM_setPowerModeWithTimeout(PCM_DCDC_MODE, timeout))
321             break;
322         return PCM_gotoLPM0();
323     case PCM_LPM0_DCDC_VCORE1:
324         if (!PCM_setCoreVoltageLevelWithTimeout(PCM_VCORE1, timeout)
325                 || !PCM_setPowerModeWithTimeout(PCM_DCDC_MODE, timeout))
326             break;
327         return PCM_gotoLPM0();
328     case PCM_LPM0_LF_VCORE0:
329         if (!PCM_setCoreVoltageLevelWithTimeout(PCM_VCORE0, timeout)
330                 || !PCM_setPowerModeWithTimeout(PCM_LF_MODE, timeout))
331             break;
332         return PCM_gotoLPM0();
333     case PCM_LPM0_LF_VCORE1:
334         if (!PCM_setCoreVoltageLevelWithTimeout(PCM_VCORE1, timeout)
335                 || !PCM_setPowerModeWithTimeout(PCM_LF_MODE, timeout))
336             break;
337         return PCM_gotoLPM0();
338     case PCM_LPM3:
339         return PCM_gotoLPM3();
340     case PCM_LPM45:
341         return PCM_shutdownDevice(PCM_LPM45);
342     case PCM_LPM35_VCORE0:
343         return PCM_shutdownDevice(PCM_LPM35_VCORE0);
344     default:
345         ASSERT(false);
346         return false;
347     }
348
349     return false;
350
351 }
352
353 bool PCM_shutdownDevice(uint32_t shutdownMode)
354 {
355     uint32_t shutdownModeBits = (shutdownMode == PCM_LPM45) ? LPMR_12 : LPMR_10;
356
357     ASSERT(
358             shutdownMode == PCM_SHUTDOWN_PARTIAL
359             || shutdownMode == PCM_SHUTDOWN_COMPLETE);
360
361     /* If a power transition is occuring, return false */
362     if (BITBAND_PERI(PCM->rCTL1.r, PMR_BUSY_OFS))
363         return false;
364
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)));
369
370     CPU_wfi();
371
372     return true;
373 }
374
375 bool PCM_gotoLPM0(void)
376 {
377
378     /* If we are in the middle of a state transition, return false */
379     if (BITBAND_PERI(PCM->rCTL1.r, PMR_BUSY_OFS))
380         return false;
381
382     HWREG32(SCS_BASE + OFS_SCB_SCR) &= ~(SCB_SCR_SLEEPDEEP);
383
384     CPU_wfi();
385
386     return true;
387 }
388
389 bool PCM_gotoLPM0InterruptSafe(void)
390 {
391
392     bool slHappenedCorrect;
393
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
396      immediately exit. */
397     Interrupt_disableMaster();
398
399     slHappenedCorrect = PCM_gotoLPM0();
400
401     /* Enabling and Disabling Interrupts very quickly so that the
402      processor catches any pending interrupts */
403     Interrupt_enableMaster();
404     Interrupt_disableMaster();
405
406     return slHappenedCorrect;
407 }
408
409 bool PCM_gotoLPM3(void)
410 {
411     uint_fast8_t bCurrentPowerState;
412     uint_fast8_t currentPowerMode;
413
414     /* If we are in the middle of a state transition, return false */
415     if (BITBAND_PERI(PCM->rCTL1.r, PMR_BUSY_OFS))
416         return false;
417
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)
420         return false;
421
422     currentPowerMode = PCM_getPowerMode();
423     bCurrentPowerState = PCM_getPowerState();
424
425     if (currentPowerMode == PCM_DCDC_MODE || currentPowerMode == PCM_LF_MODE)
426         PCM_setPowerMode(PCM_LDO_MODE);
427
428     /* Clearing the SDR */
429     PCM->rCTL0.r = (PCM->rCTL0.r & ~(PCMKEY_M | LPMR_M)) | PCM_KEY;
430
431     /* Setting the sleep deep bit */
432     HWREG32(SCS_BASE + OFS_SCB_SCR) |= (SCB_SCR_SLEEPDEEP);
433
434     CPU_wfi();
435
436     HWREG32(SCS_BASE + OFS_SCB_SCR) &= ~(SCB_SCR_SLEEPDEEP);
437
438     return PCM_setPowerState(bCurrentPowerState);
439 }
440
441 bool PCM_gotoLPM3InterruptSafe(void)
442 {
443     bool dslHappenedCorrect;
444
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
447      immediately exit. */
448     Interrupt_disableMaster();
449
450     dslHappenedCorrect = PCM_gotoLPM3();
451
452     /* Enabling and Disabling Interrupts very quickly so that the
453      processor catches any pending interrupts */
454     Interrupt_enableMaster();
455     Interrupt_disableMaster();
456
457     return dslHappenedCorrect;
458 }
459
460 uint8_t PCM_getPowerState(void)
461 {
462     return PCM->rCTL0.b.bCPM;
463 }
464
465 void PCM_enableRudeMode(void)
466 {
467
468     PCM->rCTL1.r = (PCM->rCTL1.r & ~(PCMKEY_M)) | PCM_KEY | FORCE_LPM_ENTRY;
469 }
470
471 void PCM_disableRudeMode(void)
472 {
473     PCM->rCTL1.r = (PCM->rCTL1.r & ~(PCMKEY_M | FORCE_LPM_ENTRY)) | PCM_KEY;
474 }
475
476 void PCM_enableInterrupt(uint32_t flags)
477 {
478     PCM->rIE.r |= flags;
479 }
480
481 void PCM_disableInterrupt(uint32_t flags)
482 {
483     PCM->rIE.r &= ~flags;
484 }
485
486 uint32_t PCM_getInterruptStatus(void)
487 {
488     return PCM->rIFG.r;
489 }
490
491 uint32_t PCM_getEnabledInterruptStatus(void)
492 {
493     return PCM_getInterruptStatus() & PCM->rIE.r;
494 }
495
496 void PCM_clearInterruptFlag(uint32_t flags)
497 {
498     PCM->rCLRIFG.r |= flags;
499 }
500
501 void PCM_registerInterrupt(void (*intHandler)(void))
502 {
503     //
504     // Register the interrupt handler, returning an error if an error occurs.
505     //
506     Interrupt_registerInterrupt(INT_PCM, intHandler);
507
508     //
509     // Enable the system control interrupt.
510     //
511     Interrupt_enableInterrupt(INT_PCM);
512 }
513
514 void PCM_unregisterInterrupt(void)
515 {
516     //
517     // Disable the interrupt.
518     //
519     Interrupt_disableInterrupt(INT_PCM);
520
521     //
522     // Unregister the interrupt handler.
523     //
524     Interrupt_unregisterInterrupt(INT_PCM);
525 }