msp430的DCO校准值被清除后该如何处理

来源:互联网 发布:单片机花贲浇花 编辑:程序博客网 时间:2024/06/03 17:41

起因

在调试MSP430G系列的单片机的过程,发现不怎么的,时钟频率发生了变化,时间一下都对不上了。查收些资料说,DCO的值有可能被擦除了导致时钟不对的。细想一下,好像是在调试的过程中,出现调试不了的现象就在IAR里点击的“Erase memory”。把查找的资料记录下来,所以就有这篇文章。

问题描述

因为DCO校准值在MCU出厂时保存于信息段A,一般是不允许清除信息段A的。

且示例代码中,有如下语句:

if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF)     {     while(1);// If calibration constants erased    // do not load, trap CPU!!}BCSCTL1 = CALBC1_1MHZ; // Set rangeDCOCTL = CALDCO_1MHZ; // Set DCO step + modulation 

可以看出在启动时都先检查DCO1MHZ的校准值是否为0xFF,是则进入while(1)死循环。
正常情况下因为信息段A不清除没问题的,但是我测试BSL下载时,故意给错误的BSL密码,导致FLASH都被擦除,发现转载DCO校准值的信息段A也被清掉了,于是程序运行到上面的代码时即进入死循环。

解决办法

针对于这种DCO数据被擦除的情况,一般的解决办法是,通过利用Timer捕捉外部的32.768K晶振或是时钟源,然后得到1M,8M或是12Mhz之类的DCO的数值,然后在直接写入segment flashA里面。
有两个解决方案供选择:

  • 1、外接晶体,用晶体配合timer校正DCO,TI的msp4300ware有源代码。如下:
 /******************************************************************************* *  *                       MSP430 CODE EXAMPLE DISCLAIMER * * MSP430 code examples are self-contained low-level programs that typically * demonstrate a single peripheral function or device feature in a highly * concise manner. For this the code may rely on the device's power-on default * register values and settings such as the clock configuration and care must * be taken when combining code from several examples to avoid potential side * effects. Also see www.ti.com/grace for a GUI- and www.ti.com/msp430ware * for an API functional library-approach to peripheral configuration. * * --/COPYRIGHT--//******************************************************************************///  MSP430G2xx1 Demo - DCO Calibration Constants Programmer////  NOTE: THIS CODE REPLACES THE TI FACTORY-PROGRAMMED DCO CALIBRATION//  CONSTANTS LOCATED IN INFOA WITH NEW VALUES. USE ONLY IF THE ORIGINAL//  CONSTANTS ACCIDENTALLY GOT CORRUPTED OR ERASED.////  Description: This code re-programs the G2xx1 DCO calibration constants.//  A software FLL mechanism is used to set the DCO based on an external//  32kHz reference clock. After each calibration, the values from the//  clock system are read out and stored in a temporary variable. The final//  frequency the DCO is set to is 1MHz, and this frequency is also used//  during Flash programming of the constants. The program end is indicated//  by the blinking LED.//  ACLK = LFXT1/8 = 32768/8, MCLK = SMCLK = target DCO//  //* External watch crystal installed on XIN XOUT is required for ACLK *//////           MSP430G2xx1//         ---------------//     /|\|            XIN|-//      | |               | 32kHz//      --|RST        XOUT|-//        |               |//        |           P1.0|--> LED//        |           P1.4|--> SMLCK = target DCO////  A. Dannenberg//  Texas Instruments Inc.//  May 2010//  Built with CCS Version 4.2.0 and IAR Embedded Workbench Version: 3.42A//******************************************************************************#include <msp430.h>#define DELTA_1MHZ    244                   // 244 x 4096Hz = 999.4Hz#define DELTA_8MHZ    1953                  // 1953 x 4096Hz = 7.99MHz#define DELTA_12MHZ   2930                  // 2930 x 4096Hz = 12.00MHz#define DELTA_16MHZ   3906                  // 3906 x 4096Hz = 15.99MHzunsigned char CAL_DATA[8];                  // Temp. storage for constantsvolatile unsigned int i;int j;char *Flash_ptrA;                           // Segment A pointervoid Set_DCO(unsigned int Delta);int main(void){  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT  for (i = 0; i < 0xfffe; i++);             // Delay for XTAL stabilization  P1OUT = 0x00;                             // Clear P1 output latches  P1SEL = 0x10;                             // P1.4 SMCLK output  P1DIR = 0x11;                             // P1.0,4 output  j = 0;                                    // Reset pointer  Set_DCO(DELTA_16MHZ);                     // Set DCO and obtain constants  CAL_DATA[j++] = DCOCTL;  CAL_DATA[j++] = BCSCTL1;  Set_DCO(DELTA_12MHZ);                     // Set DCO and obtain constants  CAL_DATA[j++] = DCOCTL;  CAL_DATA[j++] = BCSCTL1;  Set_DCO(DELTA_8MHZ);                      // Set DCO and obtain constants  CAL_DATA[j++] = DCOCTL;  CAL_DATA[j++] = BCSCTL1;  Set_DCO(DELTA_1MHZ);                      // Set DCO and obtain constants  CAL_DATA[j++] = DCOCTL;  CAL_DATA[j++] = BCSCTL1;  Flash_ptrA = (char *)0x10C0;              // Point to beginning of seg A  FCTL2 = FWKEY + FSSEL0 + FN1;             // MCLK/3 for Flash Timing Generator  FCTL1 = FWKEY + ERASE;                    // Set Erase bit  FCTL3 = FWKEY + LOCKA;                    // Clear LOCK & LOCKA bits  *Flash_ptrA = 0x00;                       // Dummy write to erase Flash seg A  FCTL1 = FWKEY + WRT;                      // Set WRT bit for write operation  Flash_ptrA = (char *)0x10F8;              // Point to beginning of cal consts  for (j = 0; j < 8; j++)    *Flash_ptrA++ = CAL_DATA[j];            // re-flash DCO calibration data  FCTL1 = FWKEY;                            // Clear WRT bit  FCTL3 = FWKEY + LOCKA + LOCK;             // Set LOCK & LOCKA bit  while (1)  {    P1OUT ^= 0x01;                          // Toggle LED    for (i = 0; i < 0x4000; i++);           // SW Delay  }}void Set_DCO(unsigned int Delta)            // Set DCO to selected frequency{  unsigned int Compare, Oldcapture = 0;  BCSCTL1 |= DIVA_3;                        // ACLK = LFXT1CLK/8  TACCTL0 = CM_1 + CCIS_1 + CAP;            // CAP, ACLK  TACTL = TASSEL_2 + MC_2 + TACLR;          // SMCLK, cont-mode, clear  while (1)  {    while (!(CCIFG & TACCTL0));             // Wait until capture occured    TACCTL0 &= ~CCIFG;                      // Capture occured, clear flag    Compare = TACCR0;                       // Get current captured SMCLK    Compare = Compare - Oldcapture;         // SMCLK difference    Oldcapture = TACCR0;                    // Save current captured SMCLK    if (Delta == Compare)      break;                                // If equal, leave "while(1)"    else if (Delta < Compare)    {      DCOCTL--;                             // DCO is too fast, slow it down      if (DCOCTL == 0xFF)                   // Did DCO roll under?        if (BCSCTL1 & 0x0f)          BCSCTL1--;                        // Select lower RSEL    }    else    {      DCOCTL++;                             // DCO is too slow, speed it up      if (DCOCTL == 0x00)                   // Did DCO roll over?        if ((BCSCTL1 & 0x0f) != 0x0f)          BCSCTL1++;                        // Sel higher RSEL    }  }  TACCTL0 = 0;                              // Stop TACCR0  TACTL = 0;                                // Stop Timer_A  BCSCTL1 &= ~DIVA_3;                       // ACLK = LFXT1CLK}
  • 第二个办法是,http://www.elprotronic.com/ , Elprotronic新版MSP430下载工具带有DCO校正功能。也可以使用MSP-GANG烧录工具来恢复,该工具支持重新效验DCO校准数据,然后写入information memory。

    这里写图片描述

下次也记得个教训,在做BSL的时候,事先把DCO数据读出,做好备份工作。

参考

  • http://www.deyisupport.com/question_answer/microcontrollers/msp430/f/55/t/62646.aspx

  • http://download.csdn.net/download/xumiaofeng1982/5699199