mirror of
https://github.com/travisgoodspeed/goodwatch
synced 2024-11-23 01:08:35 +00:00
182 lines
5.2 KiB
C
182 lines
5.2 KiB
C
/*! \file power.c
|
|
\brief Power management library for the CC430F6137.
|
|
|
|
These library functions are responsible for powering up the CC430
|
|
when necessary for the radio, and for dropping power at all other
|
|
times.
|
|
*/
|
|
|
|
#include<stdio.h>
|
|
#include<msp430.h>
|
|
|
|
//! Returns non-zero if in anything but the lowest power mode.
|
|
int power_ishigh(){
|
|
return
|
|
( PMMCTL0_L & PMMHPMRE_L) //High power mode.
|
|
|| (PMMCTL0 & PMMCOREV_3) //VCore in anything but 0 mode.
|
|
;
|
|
}
|
|
|
|
//! Step the core voltage up
|
|
static unsigned int power_vcoreup (unsigned char level) {
|
|
unsigned int PMMRIE_backup,SVSMHCTL_backup;
|
|
|
|
// Open PMM registers for write access
|
|
PMMCTL0_H = 0xA5;
|
|
|
|
// Disable dedicated Interrupts to prevent that needed flags will be
|
|
// cleared
|
|
PMMRIE_backup = PMMRIE;
|
|
PMMRIE &= ~(SVSMHDLYIE | SVSMLDLYIE | SVMLVLRIE | SVMHVLRIE | SVMHVLRPE);
|
|
// Set SVM highside to new level and check if a VCore increase is
|
|
// possible
|
|
SVSMHCTL_backup = SVSMHCTL;
|
|
PMMIFG &= ~(SVMHIFG | SVSMHDLYIFG);
|
|
SVSMHCTL = SVMHE | SVMHFP | (SVSMHRRL0 * level);
|
|
// Wait until SVM highside is settled
|
|
while ((PMMIFG & SVSMHDLYIFG) == 0);
|
|
// Disable full-performance mode to save energy
|
|
SVSMHCTL &= ~SVSLFP ;
|
|
|
|
// Check if a VCore increase is possible
|
|
if ((PMMIFG & SVMHIFG) == SVMHIFG){
|
|
// Vcc is too low for a Vcore increase, so recover the previous
|
|
// settings.
|
|
|
|
printf("VCC too low to raise core.\n");
|
|
|
|
PMMIFG &= ~SVSMHDLYIFG;
|
|
SVSMHCTL = SVSMHCTL_backup;
|
|
// Wait until SVM highside is settled
|
|
while ((PMMIFG & SVSMHDLYIFG) == 0);
|
|
// Clear all Flags
|
|
PMMIFG &= ~(SVMHVLRIFG | SVMHIFG | SVSMHDLYIFG
|
|
| SVMLVLRIFG | SVMLIFG | SVSMLDLYIFG);
|
|
// backup PMM-Interrupt-Register
|
|
PMMRIE = PMMRIE_backup;
|
|
|
|
// Lock PMM registers for write access
|
|
PMMCTL0_H = 0x00;
|
|
return 0;//Not set.
|
|
}
|
|
|
|
// Set also SVS highside to new level
|
|
//-> Vcc is high enough for a Vcore increase
|
|
SVSMHCTL |= SVSHE | (SVSHRVL0 * level);
|
|
// Set SVM low side to new level
|
|
SVSMLCTL = SVMLE | SVMLFP | (SVSMLRRL0 * level);
|
|
// Wait until SVM low side is settled
|
|
while ((PMMIFG & SVSMLDLYIFG) == 0);
|
|
// Clear already set flags
|
|
PMMIFG &= ~(SVMLVLRIFG | SVMLIFG);
|
|
// Set VCore to new level
|
|
PMMCTL0_L = PMMCOREV0 * level;
|
|
// Wait until new level reached
|
|
if (PMMIFG & SVMLIFG)
|
|
while ((PMMIFG & SVMLVLRIFG) == 0);
|
|
// Set also SVS/SVM low side to new level
|
|
PMMIFG &= ~SVSMLDLYIFG;
|
|
SVSMLCTL |= SVSLE | (SVSLRVL0 * level);
|
|
// wait for lowside delay flags
|
|
while ((PMMIFG & SVSMLDLYIFG) == 0);
|
|
|
|
// Disable SVS/SVM Low
|
|
// Disable full-performance mode to save energy
|
|
SVSMLCTL &= ~(SVSLE+SVMLE+SVSLFP );
|
|
|
|
// Clear all Flags
|
|
PMMIFG &= ~(SVMHVLRIFG | SVMHIFG | SVSMHDLYIFG
|
|
| SVMLVLRIFG | SVMLIFG | SVSMLDLYIFG);
|
|
// backup PMM-Interrupt-Register
|
|
PMMRIE = PMMRIE_backup;
|
|
|
|
// Lock PMM registers for write access
|
|
PMMCTL0_H = 0x00;
|
|
return 1;//okay
|
|
}
|
|
|
|
//! Step the voltage core down.
|
|
static unsigned int power_vcoredown (unsigned char level) {
|
|
unsigned int PMMRIE_backup;
|
|
|
|
// Open PMM registers for write access
|
|
PMMCTL0_H = 0xA5;
|
|
|
|
// Disable dedicated Interrupts to prevent that needed flags will be cleared
|
|
PMMRIE_backup = PMMRIE;
|
|
PMMRIE &= ~(SVSMHDLYIE | SVSMLDLYIE | SVMLVLRIE | SVMHVLRIE | SVMHVLRPE);
|
|
|
|
// Set SVM high side and SVM low side to new level
|
|
PMMIFG &= ~(SVMHIFG | SVSMHDLYIFG | SVMLIFG | SVSMLDLYIFG);
|
|
SVSMHCTL = SVMHE | SVMHFP | (SVSMHRRL0 * level);
|
|
SVSMLCTL = SVMLE | SVMLFP | (SVSMLRRL0 * level);
|
|
// Wait until levels are settled.
|
|
while ((PMMIFG & SVSMHDLYIFG) == 0 || (PMMIFG & SVSMLDLYIFG) == 0);
|
|
|
|
|
|
// Set VCore to new level
|
|
PMMCTL0_L = PMMCOREV0 * level;
|
|
|
|
/*
|
|
printf("Changing high and low sides.\n");
|
|
// Set also SVS highside and SVS low side to new level
|
|
PMMIFG &= ~(SVSHIFG | SVSMHDLYIFG | SVSLIFG | SVSMLDLYIFG);
|
|
|
|
printf("a\n");
|
|
SVSMHCTL |= SVSHE | SVSHFP | (SVSHRVL0 * level);
|
|
printf("b\n");
|
|
SVSMLCTL |= SVSLE | SVSLFP | (SVSLRVL0 * level);
|
|
*/
|
|
|
|
|
|
// Wait until SVS high side and SVS low side is settled
|
|
//while ((PMMIFG & SVSMHDLYIFG) == 0 || (PMMIFG & SVSMLDLYIFG) == 0);
|
|
|
|
// Disable full-performance mode to save energy
|
|
SVSMHCTL &= ~SVSLFP;
|
|
// Disable SVS/SVM Low
|
|
// Disable full-performance mode to save energy
|
|
SVSMLCTL &= ~(SVSLE+SVMLE+SVSLFP);
|
|
|
|
|
|
// Clear all Flags
|
|
PMMIFG &= ~(SVMHVLRIFG | SVMHIFG | SVSMHDLYIFG
|
|
| SVMLVLRIFG | SVMLIFG | SVSMLDLYIFG);
|
|
// backup PMM-Interrupt-Register
|
|
PMMRIE = PMMRIE_backup;
|
|
// Lock PMM registers for write access
|
|
PMMCTL0_H = 0x00;
|
|
|
|
if ((PMMIFG & SVMHIFG) == SVMHIFG)
|
|
// Highside is still too low for the adjusted VCore Level
|
|
return 0;
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
|
|
//! Sets the core core voltage.
|
|
int power_setvcore (int level) {
|
|
int oldlevel, origlevel;
|
|
int status = 1;
|
|
|
|
//Mask off the level.
|
|
level &= PMMCOREV_3;
|
|
//Current core voltage.
|
|
origlevel = oldlevel = (PMMCTL0 & PMMCOREV_3);
|
|
|
|
// step by step increase or decrease
|
|
while (((level != oldlevel) && (status)) || (level < oldlevel)) {
|
|
if (level > oldlevel)
|
|
status = power_vcoreup(++oldlevel);
|
|
else
|
|
status = power_vcoredown(--oldlevel);
|
|
__delay_cycles(850);
|
|
}
|
|
|
|
printf("Power %d->%d.\n",
|
|
origlevel,
|
|
PMMCTL0 & PMMCOREV_3);
|
|
return status;
|
|
}
|