//******************************************************************************
// MSP430x21x1 Demo - Basic Clock, Implement Auto RSEL SW FLL
//
// Deion: Set DCO clock to (Delta)*(4096) using software FLL. DCO clock
// is output on P1.4 as SMCLK. DCO clock, which is the selected SMCLK source
// for Timer_A is integrated over LFXT1/8 (4096) until SMCLK is is equal
// to Delta. CCR2 captures ACLK. To use, Set_DCO Timer_A must be
// operating in continuous mode. Watch crystal for ACLK is required for
// this example. Delta must be kept in a range that allows possible
// DCO speeds. Minimum Delta must ensure that Set_DCO loop can complete
// within capture interval. Maximum delta can be calculated be
// f(DCOx7) / 4096. f(DCOx7) can be found in device specific datasheet.
// ACLK = LFXT1/8 = 32768/8, MCLK = SMCLK = target DCO
// [] To measure SMCLK on P1.4 with the FET, use "Release JTAG on Go"
// in the debugger to have access to the port. Then run the code.
// //* External watch crystal installed on XIN XOUT is required for ACLK *//
// H. Grewal / A. Dannenberg
// Texas Instruments Inc.
// June 2005
// Built with IAR Embedded Workbench Version: 3.30A
//******************************************************************************
//******************************************************************************
// 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;
}