//******************************************************************************
//MSP43021x1时钟校准,21x1出厂时,在Info Flash保存了四种时钟的调整参数
// 分别是 1MHz,8MHz,12MHz,16MHz
// 由于用户在下载程序的时候,会将Info Flash擦除,或芯片出厂校准参数不正确
// 就需要用户自己校准时钟。
// 有两种方法可以校准系统时钟,1;在用户程序初始化时校准,
// 2: 单独运行校准程序,将校准参数保存到InfoFlash
// 中,用户程序直接调用。由于21X1系列的内部时钟
// 精度在整个温度范围内已经达到了2.5%,因此可以
// 用这种方法,减少应用程序占用Flash。
// 要保证CPU供电在3。3V以上
//
// 毛武斌
// 杭州冰河奥特使电子有限公司
// 2006.3.23
// 本程序由TI的例子程序修改而来,使用IAREW430 V3。40A
//******************************************************************************
#include <MSP430x21x1.h>
#define DELTA_1M 245
#define DELTA_8M 1954
#define DELTA_12M 2930
#define DELTA_16M 3906
char *pInfoFlash_A;
char AdjBCSCTL1_1M;
char AdjpDCOCTL_1M;
char AdjBCSCTL1_8M;
char AdjpDCOCTL_8M;
char AdjBCSCTL1_12M;
char AdjpDCOCTL_12M;
char AdjBCSCTL1_16M;
char AdjpDCOCTL_16M;
char tmpBCSCTL1;
char tmpDCOCTL;
void Set_DCO (unsigned int delta, char *pBcsctl1_, char *pDcoct_);
void softwareDelay(unsigned int time);
void timeAdelay(unsigned int time);
void main(void)
{
WDTCTL = WDTPW + WDTHOLD;// Stop WDT
// 测试时钟输出
P1OUT = 0;
P1DIR |= BIT3 + BIT4;; // P1.3,4 output
P1SEL |= BIT4; // P1.4 SMCLK output
_DINT();
tmpBCSCTL1 = BCSCTL1;
tmpDCOCTL = DCOCTL;
Set_DCO(DELTA_1M, &AdjBCSCTL1_1M, &AdjpDCOCTL_1M);
Set_DCO(DELTA_8M, &AdjBCSCTL1_8M, &AdjpDCOCTL_8M);
Set_DCO(DELTA_12M, &AdjBCSCTL1_12M, &AdjpDCOCTL_12M);
Set_DCO(DELTA_16M, &AdjBCSCTL1_16M, &AdjpDCOCTL_16M);
BCSCTL1 = tmpBCSCTL1;
DCOCTL = tmpDCOCTL;
FCTL2 = FWKEY + FSSEL0 + FN1;// MCLK/3 for Flash Timing Generator
FCTL1 = FWKEY + ERASE; // Set Erase bit, allow interrupts
if(FCTL3 & LOCKA)
{
FCTL3 = FWKEY + LOCKA; // Clear LOCK & LOCKA bits
}
pInfoFlash_A = (char *) 0x10C0; // Initialize Flash pointer
*pInfoFlash_A = 0; // Dummy write to erase Flash segment A
FCTL1 = FWKEY + WRT; // Set WRT bit for write operation
pInfoFlash_A = (char *) CALDCO_16MHZ_; // Initialize Flash pointer
*pInfoFlash_A++ = AdjpDCOCTL_16M;
*pInfoFlash_A++ = AdjBCSCTL1_16M;
*pInfoFlash_A++ = AdjpDCOCTL_12M;
*pInfoFlash_A++ = AdjBCSCTL1_12M;
*pInfoFlash_A++ = AdjpDCOCTL_8M;
*pInfoFlash_A++ = AdjBCSCTL1_8M;
*pInfoFlash_A++ = AdjpDCOCTL_1M;
*pInfoFlash_A = AdjBCSCTL1_1M;
FCTL1 = FWKEY; // Clear WRT bit
FCTL3 = FWKEY + LOCKA + LOCK; // Set LOCK & LOCKA bit // Set LOCK bit
P1OUT |= BIT3;
for (;;)
{ // 隔四秒钟输出SMCLK
BCSCTL1 = CALBC1_1MHZ;
DCOCTL = CALDCO_1MHZ;
timeAdelay(2);
P1OUT ^= BIT3;
softwareDelay(50000);
P1OUT ^= BIT3;
BCSCTL1 = CALBC1_8MHZ;
DCOCTL = CALDCO_8MHZ;
timeAdelay(2);
P1OUT ^= BIT3;
softwareDelay(50000);
P1OUT ^= BIT3;
BCSCTL1 = CALBC1_12MHZ;
DCOCTL = CALDCO_12MHZ;
timeAdelay(2);
P1OUT ^= BIT3;
softwareDelay(50000);
P1OUT ^= BIT3;
BCSCTL1 = CALBC1_16MHZ;
DCOCTL = CALDCO_16MHZ;
timeAdelay(2);
P1OUT ^= BIT3;
softwareDelay(50000);
P1OUT ^= BIT3;
}
}
//------------------------------------------------------------------------------
void Set_DCO (unsigned int delta, char *pBcsctl1_, char *pDcoct_)// Set DCO to selected frequency
//------------------------------------------------------------------------------
{
unsigned int Compare, Oldcapture = 0;
BCSCTL1 |= DIVA_3;// ACLK= LFXT1CLK/8
BCSCTL3 |= XCAP_3;
CCTL2 = CM_1 + CCIS_1 + CAP;// CAP, ACLK
TACTL = TASSEL_2 + MC_2 + TACLR;// SMCLK, cont-mode, clear
while (1)
{
while (!(CCIFG & CCTL2)); // Wait until capture occured
CCTL2 &= ~CCIFG;// Capture occured, clear flag
Compare = CCR2; // Get current captured SMCLK
Compare = Compare - Oldcapture;// SMCLK difference
Oldcapture = CCR2;// Save current captured SMCLK
if (delta == Compare) break;// If equal, leave "while(1)"
else if (delta < Compare)// DCO is too fast, slow it down
{
DCOCTL--;
if (DCOCTL == 0xFF)
{
if (!(BCSCTL1 == (XT2OFF + DIVA_3)))
BCSCTL1--; // Did DCO roll under?, Sel lower RSEL
}
}
else
{
DCOCTL++;
if (DCOCTL == 0x00)
{
if (!(BCSCTL1 == (XT2OFF + DIVA_3 + 0x0F)))
BCSCTL1++; // Did DCO roll over? Sel higher RSEL
}
}
softwareDelay(20);
}
CCTL2 = 0; // Stop CCR2
TACTL = 0; // Stop Timer_A
*pBcsctl1_ = BCSCTL1 & (~DIVA_3);
*pDcoct_ = DCOCTL;
}
void softwareDelay(unsigned int time)
{
while(--time);
}
void timeAdelay(unsigned int time)
{
TACTL = TASSEL_1 + MC_2 + TACLR;// SMCLK, cont-mode, clear
while(time)
{
while(!(TACTL &TAIFG));
TACTL &= ~TAIFG;
time--;
}
TACTL = 0;
}