×
单片机 > 单片机程序设计 > 详情

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

发布时间:2020-08-25 发布时间:
|

起因

在调试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 range

DCOCTL = 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


#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.99MHz


unsigned char CAL_DATA[8];                  // Temp. storage for constants

volatile unsigned int i;

int j;

char *Flash_ptrA;                           // Segment A pointer

void 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--;



『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
单片机制作超级流水灯