If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

# msp430fxxxx low freq oscillator

/*

This project 's goal is to remedy
the inaccuracy of the clock VLO 12k.
To do so exploit the fact that the DCO clock 1Mhz
has a tolerance of about l '1%, when using
calibration constants present in every single uC

Froma datasheet we see that VLO clock can span from 4k to 20k .
So we can not to base on it if we want a predictable timing.
The idea here is to use the 1% tolerance 1Mhz clock in MSP430
to determine a calibration constant for VLO.

Algoritmh:
We clock TA with VLO (unknowed freq) and TB with SMCLK (1Mhz).
Set Isr for TA(VLO), at isr we count the TB clock and so we know the
exact (1%) time interval.
From this , and knowing the number of clock pulse of VLO in this
interval we can calculate the real frequence of VLO.
Knowing this we can set TACCR0 to get a precise (1%) time interval
using VLO.
Of course if we think that in our application the temperature and Vcc
have a variation such to cause significant changes in VLO we could repete the
procedure at different Vcc and Temperature
*/

/* I tested this firmware with some intervals and it seem to go,
if you find incoerence or if you introduce optimimizationi in
this procedure please do it and back to the forum .
Develop some TODO i left in ...........
*/

/* I used IAR for this firmware */

#include "io430.h"
#include "in430.h"
#include <stdlib.h>

#define Led_Red_ON  P2OUT |= 0x08 //P2.3
#define Led_Red_OFF P2OUT &= ~0x08
#define TOGGLE_P45  P4OUT ^=  0x20; // signal to see on the oscilloscope
//#define DT        200  // in ms ,  max = 5400ms

volatile unsigned char     isrA0,isrB0;
unsigned long int     *ptr_gCountB ;
unsigned long int     *ptr_f_TA;
unsigned int          VerifyVLO(unsigned int DT); // DT[ms]

int main( void )
{
WDTCTL = WDTPW + WDTHOLD;

P2DIR |= 0x08;  // Led Red    P2.3
P4DIR |= 0x20;  // See this signal with oscilloscope
P4REN |= 0x20;  // weak  pull up for P4.5

TACCR0 =    VerifyVLO(200);    // Looking for real VLO freq to get 200ms isr
// but you can change it
TACTL = MC_1+TASSEL_1+ID_1;   // Start TA in new mode
// ID_1 to simulate a deviation of 50% , 12k-->6k
//      if your uC have a 12k VLO
free(ptr_f_TA); free(ptr_gCountB);  // free allocated mem

// Testing
while(1)
{
if(isrA0==1)
{
TOGGLE_P45; // to check the test interval  interval [200ms], but you cna change it
isrA0=0;
}
}
}

unsigned int VerifyVLO(unsigned int DT)
{
BCSCTL1 = CALBC1_1MHZ; // Set DCO to 1MHz
DCOCTL = CALDCO_1MHZ;
BCSCTL3 |= LFXT1S_2;   // ACLK = VLO = 4k-12k-20k (great tolerance)

// IMPRECISE CLOCK VLO
// TIMER A      (1/12kHz) x 2^16 = 5.46sec  ; f=1*2^16/( DT)
TACCTL0 = CCIE;              // isr ON for TA
TACCR0=32768;                // 65536/2 //TODO use a smaller range
TACTL = MC_1+TASSEL_1+ID_1;  // MC_1 = up_mode (until to TACCR0)
// MC_2 = until to 0xFFFF
// TASSEL_1 = clock VLO
// ID_1 To simulate a deviation of 50%, 12k --> 6k
//         if you uC have a 12k VLO

// PRECISE (1%) CLOCK SMCLK
// TIMER B      1/Mzh x 2^16 = 65536uS = 65ms
TBCCTL0 = CCIE;              // isr ON for TB
TBCTL = MC_2+TASSEL_2;       // up_mode (until to TBCCR0) , SMCLK = 1Mhz

ptr_gCountB = (unsigned long int *)malloc(1*sizeof(unsigned long int));
*ptr_gCountB=0;
ptr_f_TA =    (unsigned long int *)malloc(1*sizeof(unsigned long int));
*ptr_f_TA=0;

isrA0=isrB0=0;
Led_Red_ON; // start procedure
_BIS_SR(GIE);
while(1)
{
if(isrA0==1)
{
*ptr_gCountB = (*ptr_gCountB+1) * 65536 + TBR;
*ptr_gCountB=*ptr_gCountB/1000;
*ptr_f_TA = 1000 * 32768;
*ptr_f_TA = (*ptr_f_TA) / (*ptr_gCountB); // real VLO freq
isrA0=0;
TAR=TBR=0;
//// I have determinate the real VLO freq
//// Now i want to determine the necessary TACCR0
//// to obtain a time interval DT[ms]
//// Numclok of VLO = f_TA * DT  ;
//TACCR0 =  (*ptr_f_TA * DT)/1000 ;
Led_Red_OFF; // end of procedure
return ( (*ptr_f_TA * DT)/1000 ) ;   // return the value to use for TACCR0
}
if(isrB0==1) //65.536ms
{
(*ptr_gCountB)++; // counting the ovf for TB
isrB0=0;
}
}
}

#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A (void)
{
isrA0=1; // the isr do only isr
}

#pragma vector=TIMERB0_VECTOR
__interrupt void Timer_B (void)
{
isrB0=1; // the isr do only isr
}

### 2 Replies

• Hi Tommaso,

Thank you for sharing this.

Regards,

David