Other Parts Discussed in Thread: MSP430G2553
I have several msp430g2553 attached to TI launchpads to play with, some of them with a 32.768Hz crystal attached.
By chance, I was playing with a 60-multiplus long time timer to put the system in sleeping mode (LPM3 to keep ACLK clock alive) for a long time. I wrote a code thinking in one of the MCUs with the crystal attached.
As I understood from the various sources I read (e.g., datasheet, slacXXXX) and according to my knowledge, to get the longest time, the main things to look at are frequency and CCRx (counter) size.
On the one hand, CCRx is 16bits, so 2^16=65.536 (well, one less, 65535 or 0xFFFF should be the biggest stored number.
On teh other hand, being the external crystal the one providing the lowest frequency (DCO provides 16MHz), I used for my ACLK:
32.768 = 2^15 using the ACLK /8 (=2^3) divider, we get 2^12=4.096Hz for the ACLK
Using TimerAx (Timer A0 in my case) /8 divider, we get 512Hz for the TimerA0 clock signal. Until here, everything fine. I got my code working and sleeping for 1 second (CCR0=511) and for 2 minutes ( CRR0=(512*120)-1 ). I was using MC_1 (counting up to CCR0) and everything was ok.
After that I tried to use the MC_3 (Up/Down) to double this time to 4 minutes, but I used one of the lauchpads without crystal by error. The result is that the system is sleeping for 5:50 minutes aprox. until the first wake up and after that every 14:18 minutes aprox.
I can not explain this issue, maybe someone here could do it, but this could be "exploited" to get very long time sleep times (that with the configuration explained, could not go further to 2 minutes or 4 minutes in Up/Down if I make it works.
#include <msp430.h>
void clock_init(void){
/*
* SELM_0 -- DCOCLK
* DIVM_0 -- Divide by 1
* DIVS_0 -- Divide by 1
*/
BCSCTL2 = SELM_0 | DIVM_0 | DIVS_0;
if (CALBC1_16MHZ != 0xFF) {
/* Adjust this accordingly to your VCC rise time */
// __delay_cycles(100000);
/* Follow recommended flow. First, clear all DCOx and MODx bits. Then
* apply new RSELx values. Finally, apply new DCOx and MODx bit values.
*/
DCOCTL = 0x00;
BCSCTL1 = CALBC1_16MHZ; /* Set DCO to 16MHz */
DCOCTL = CALDCO_16MHZ;
}
/*
* XT2OFF -- Disable XT2CLK
* DIVA_3 -- Divide by 8
*/
BCSCTL1 |= XT2OFF | DIVA_3;
/*
* XT2S_0 -- 0.4 - 1 MHz
* LFXT1S_0 -- If XTS = 0, XT1 = 32768kHz Crystal
* XCAP_3 -- ~12.5 pF
*/
BCSCTL3 = XT2S_0 | LFXT1S_0 | XCAP_3;
}
void timer0_a0_init(void)
{
/*
* TA0CCTL0, Capture/Compare Control Register 0
*
* CM_0 -- No Capture
* CCIS_0 -- CCIxA
* ~SCS -- Asynchronous Capture
* ~SCCI -- Latched capture signal (read)
* ~CAP -- Compare mode
* OUTMOD_0 -- PWM output mode: 0 - OUT bit value
* TAIE -- Timer A counter interrupt enable
*/
TA0CCTL0 = CM_0 | CCIS_0 | OUTMOD_0 | CCIE | TAIE;
/* TA0CCR0, Timer_A Capture/Compare Register 0 */
TA0CCR0 = 61439;
/*
* TA0CTL, Timer_A3 Control Register
*
* TASSEL_1 -- ACLK
* ID_3 -- Divider - /8
* MC_1 -- Up Mode
*/
TA0CTL = TASSEL_1 | ID_3 | MC_1;
}
#pragma vector=TIMER0_A0_VECTOR
__interrupt void TIMER0_A0_ISR_HOOK(void)
{
P1OUT^=0x01;
}
void main(void){
int a;
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
P1DIR=0x01;
clock_init();
timer0_a0_init();
while(1){
__bis_SR_register(LPM3_bits +GIE);
}
}