Vor ein paar Tagen habe ich einmal den mitgelieferten Quarz (Launchpad, MS3V-T1R) getestet und ein paar Messungen durchgeführt. Weiterhin wurde ein 32kHz Uhrenquarz von Pollin getestet (CFS-206). Eine kurze Einführung für die Benutzung eines 32kHz Quarz und die Initialisierung für den MSP430.
Wer es sich nicht zutraut den mitgelieferten Quarz auf das Launchpad zu löten, dem empfehle ich den Quarz von Pollin. Dieser lässt sich einfach an die Stiftleiste löten, oder per Buchsen anschließen. Der MSP430(G) hat zwei interene Ladekapazitäten CL1 und CL2, die per Software ausgewählt werden können (BSCTL3 Register -> ~1pF bis 12.5pF, siehe User-Guide). Es können aber auch externe Kondensatoren angeschlossen werden, falls nötig.
Daten mitgelieferter Quarz:
MS3V-T1R (32.768kHz)
Load Capacitance: 12.5pF
Frequency Tolerance:+/-20ppm (ppm=parts per million)
SMD Metal Package
Datasheet
Daten Uhrenquarz von Pollin:
CFS-206 (32.768 kHz)
Load Capacitance: 12,5 pF
Frequency Tolerance: +/-20ppm
Datasheet
(Diese Methode funktioniert zwar, ist aber nicht zu empfehlen, der Quarz muss so nah wie möglich am Controller gelötet werden)
Quarz Initialisierung
Wer sich näher mit der Thematik beschäftigen will, findet im UserGuide ab Seite 273 alle nötigen Informationen.
BCSCTL3|=XCAP_3;
do
{
IFG1&=~OFIFG;
__delay_cycles(1000);
}
while(IFG1&OFIFG);
In der ersten Zeile werden Einstellungen am BCSCTL3 Register (Basic Clock System Control Register 3)
vorgenommen. Hier können die Frequenzen und Ladekapazitäten ausgewählt werden. In diesem Fall reicht es Bit 3-2 -> XCAP_3 (~12.5pF)
zu setzen. XT2Sx (00 = 0.4 bis 1MHz) und LFXT1Sx (00 = 32768Hz LFXT1)
sind standardmäßig nicht gesetzt. Im BCSCTL1 (Basic Clock System Control Register 1)
ist standardmäßig das Bit XTS (0 = Low-frequency mode)
nicht gesetzt. In diesem Register kann noch ein Vorteiler für ACLK
ausgewählt werden (1,2,4,8), in diesem Fall werden die Bits DIVAx
nicht gesetzt (00 = /1).
In der do-while Schleife wird zuerst das OFIFG (Oscillator fault interrupt flag)
Bit im IFG1 Register (Interrupt Flag Register 1)
auf 0 gesetzt (no interrupt pending)
. Danach wird 1000 Zyklen gewartet (Einschwingzeit, sollte vielleicht höher sein ~10ms) und geprüft ob das OFIFG Bit immer noch gesetzt ist. Falls ja, wird nochmal gewartet.
Timer-Initialisierung
Als CLK-Source für den TImer soll der 32kHz Quarz dienen.
TACTL|=TASSEL_1+ID_0; //ACLK, 1x divider
Im TACTL Register
werden die Bits TASSEL_1 (01 = ACLK)
gesetzt und der Vorteiler bleibt auf “/1” (nicht nötig ID_0
zu schreiben). In diesem Fall entsprechen 32768 Zyklen genau eine Sekunde ( (32768Hz*1,0s)/1=32768).
Messung
Im Test-Programm blinkt eine LED mit 2Hz (250ms ON, 250ms OFF => T=500ms => f=2Hz). Benutzt wurde der mitgelieferte Quarz (SMD Metal Package).
Auto-Measurement (P1.6, LED)
Manuell (P1.6, LED)
Auto-Measurement (ACLK, P1.0)
C-Programm
FILE: main.c
/*************************************************
* ___ _ _
* | |_ _ _| |___ ___ _| |___
* | | |_'_| . | -_| _|_| . | -_|
* |___|_,_|___|___|___|_|___|___|
*
* FILE: main.c
* Author: declis (xdec.de)
************************************************/
#include <msp430g2231.h>
#include "timer.h"
void main(void)
{
WDTCTL=WDTPW+WDTHOLD; // stop watchdog timer
BCSCTL1=CALBC1_1MHZ;
DCOCTL=CALDCO_1MHZ;
BCSCTL3|=XCAP_3;
do
{
IFG1&=~OFIFG;
__delay_cycles(1000);
}
while(IFG1&OFIFG);
P1DIR|=BIT6; //P1.6 (LED2) -> output
P1OUT&=~BIT6; //clear P1.6 (LED2 off)
P1SEL|=BIT0; //ACLK on P1.0
P1DIR|=BIT0;
init_TimerA(); //initialize TimerA
_EINT(); //enable interrupt
while(1);
}
FILE: timer.c
/*************************************************
* ___ _ _
* | |_ _ _| |___ ___ _| |___
* | | |_'_| . | -_| _|_| . | -_|
* |___|_,_|___|___|___|_|___|___|
*
* FILE: timer.c
* Author: declis (xdec.de)
************************************************/
#include <msp430g2231.h>
#include "timer.h"
#define cycles 8192 // 250ms ACLK=32kHz Quarz
//#define cycles 31250 // 250ms SMCLK=1MHz
/* cycles=(seconds*Frequency_Hz)/divider */
/* seconds=(divider*cycles)/Frequency_Hz */
void init_TimerA(void)
{
TACTL|=TASSEL_1+ID_0; // ACLK, 1x divider
//TACTL|=TASSEL_2+ID_3; // SMCLK, 8x divider
TACCR0=cycles;
TACCTL0|=CCIE; // enable TimerA interrupt
TACTL|=MC_1; // start timer in up-mode
}
/* Timer_A ISR */
#pragma INTERRUPT (ISR_TimerA);
#pragma vector=TIMERA0_VECTOR
void ISR_TimerA(void)
{
P1OUT^=BIT6; // toggle P1.6
}
FILE: timer.h
/*************************************************
* ___ _ _
* | |_ _ _| |___ ___ _| |___
* | | |_'_| . | -_| _|_| . | -_|
* |___|_,_|___|___|___|_|___|___|
*
* FILE: timer.h
* Author: declis (xdec.de)
************************************************/
#ifndef TIMER_H_
#define TIMER_H_
void init_TimerA(void);
#endif /*TIMER_H_*/