白沙的香烟盒 https://bbs.21ic.com/?77381 [收藏] [复制] [RSS] MCU,ARM,程序,应用手记

日志

MSP430F2132 DCO校准恢复

已有 969 次阅读2013-3-6 19:35 |个人分类:程序参考|系统分类:单片机

 



//******************************************************************************
// 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;
}


 


路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)