Jump to content
NatureTM

Flashing the missing DCO calibration constants

Recommended Posts

EDIT: Here's another really nice DCO calibration program. It's part of TinyOS-msp430. http://code.google.com/p/tinyos-msp430/ It's the file called calibrate-dco. As gordon, who discovered it said, "[it] appears to be a quite beefed-up DCO calibration app, with goodies on the side (taking silicon errata into account for various devices when calibrating)." It looks like it's built to be solid and reliable. I skimmed over the code and didn't see anything for calculating SegA checksum, but that usually isn't an issue for most non-critical applications.

 

EDIT: maxpenna shared another version of the DCO calibration program. This is the one to use if you need a correct SegmentA checksum. It uses the C calibration function. You can get it here http://www.43oh.com/forum/download/file.php?id=292

 

WARNING: Some of the programs in this thread will erase Segment A and only put back the DCO calibrations. They should not be used with chips that have an ADC12, as this process will destroy the ADC12 calibrations. Some of the programs do not calculate the Segment A checksum, so the integrity of Segment A cannot be verified during runtime after calibration. Still, I've been using it without any problems.

 

 

There's been a bit of a discussion in another thread about an idea simpleavr had for adding the dco calibration constants to flash for the Value Line series. I've cobbled together some pieces of TI code and have it working. It seems to work great. Here's how I did it with CCS. I think the people on linux should be able to reproduce the result with a little adaptation.

 

This requires the TI DCO library I modified in another thread and an external LF crystal like the one with Launchpad.

http://naturetm.com/files/Launchpad%20setDCO%20lib.rar

 

First, run this to calibrate the constants and write them to flash:

EDIT: 43oh member zeke has made some changes to the code for finer tuning. Check page 2 for his code.

//******************************************************************************
//  MSP430F20xx 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 F2xx 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 *//
//
//           MSP430F20xx
//         ---------------
//     /|\|            XIN|-
//      | |               | 32kHz
//      --|RST        XOUT|-
//        |               |
//        |           P1.0|--> LED
//        |           P1.4|--> SMLCK = target DCO
//
//  A. Dannenberg
//  Texas Instruments Inc.
//  May 2007
//  Built with CCE Version: 3.2.0 and IAR Embedded Workbench Version: 3.42A
//******************************************************************************
#include "msp430x20x1.h"
#include "DCO_Library.h"

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 setting);

void main(void)
{
 WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
 for (i = 0; i < 0xfffe; i++);             // Delay for XTAL stabilization
 P1OUT = 0x01;                             // Red LED on
 P1SEL = 0x10;                             // P1.4 SMCLK output
 P1DIR = 0x51;                             // P1.0,4,6 output

 j = 0;                                    // Reset pointer

 Set_DCO(TI_DCO_16MHZ);                     // Set DCO and obtain constants
 CAL_DATA[j++] = DCOCTL;
 CAL_DATA[j++] = BCSCTL1;

 Set_DCO(TI_DCO_12MHZ);                     // Set DCO and obtain constants
 CAL_DATA[j++] = DCOCTL;
 CAL_DATA[j++] = BCSCTL1;

 Set_DCO(TI_DCO_8MHZ);                      // Set DCO and obtain constants
 CAL_DATA[j++] = DCOCTL;
 CAL_DATA[j++] = BCSCTL1;

 Set_DCO(TI_DCO_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

 P1OUT = 0;
 while (1)
 {
   P1OUT ^= BIT6;                          // Toggle green LED
   for (i = 0; i < 0x4000; i++);           // SW Delay
 }
}

void Set_DCO(unsigned int setting){
volatile unsigned int I;
//	P1DIR |= BIT0; 									// P1.0 output
BCSCTL1 &= ~XTS;								// external source is LF;
BCSCTL3 &= ~(LFXT1S0 + LFXT1S1);  				// watch crystal mode
BCSCTL3 |= XCAP0 + XCAP1; 						// ~12.5 pf cap on the watch crystal as recommended

for( I = 0; I < 0xFFFF; I++){} 					// delay for ACLK startup
if(TI_SetDCO(setting) == TI_DCO_NO_ERROR)	// if setting the clock was successful,
	P1OUT |= BIT0; 								// bring P1.0 high (Launchpad red LED)
else
	while(1);									// trap if setting the clock isn't successful
}

 

The green light should start blinking in a few seconds, indicating success. Now we need to modify some linker and header files so CCS knows about the new calibrations.

 

I'm using the MSP430G2231, so I duplicated the file C:\Program Files (x86)\Texas Instruments\ccsv4\msp430\include\msp430g2231.cmd in that directory, and renamed the duplicate as msp430g2231_mod.cmd. Now I can edit it without affecting the original. Edit msp430g2231_mod.cmd and change the calibration section at the bottom to this:

 

/************************************************************
* Calibration Data in Info Mem
************************************************************/
CALDCO_16MHZ       = 0x10F8;
CALBC1_16MHZ       = 0x10F9;
CALDCO_12MHZ       = 0x10FA;
CALBC1_12MHZ       = 0x10FB;
CALDCO_8MHZ        = 0x10FC;
CALBC1_8MHZ        = 0x10FD;
CALDCO_1MHZ        = 0x10FE;
CALBC1_1MHZ        = 0x10FF;

 

Now the linker knows we have calibration data in that section when we use the modified file.

 

When we create a new project in CCS or modify an existing one, CCS will want to use the default linking file, and the default header. Here's an example about how to configure a project to use the new constants.

First create a new project. Within the project, there should be a file called something like lnk_msp430g2231.cmd. The last line of that file should be something like -l msp430g2231.cmd. Open it, and change the last line to reflect the new linker file so it reads -l msp430g2231_mod.cmd.

Next, add the appropriate header file to the project. Right-click the project folder in the left pane of CCS and click "Add files to project..." In this example, I'm using C:\Program Files (x86)\Texas Instruments\ccsv4\msp430\include\msp430g2231.h. Now we have a copy of the file in the project we can safely edit. Edit the file so the calibration section looks like this:

/************************************************************
* Calibration Data in Info Mem
************************************************************/

#ifndef __DisableCalData

SFR_8BIT(CALDCO_16MHZ);                       /* DCOCTL  Calibration Data for 16MHz */
SFR_8BIT(CALBC1_16MHZ);                       /* BCSCTL1 Calibration Data for 16MHz */
SFR_8BIT(CALDCO_12MHZ);                       /* DCOCTL  Calibration Data for 12MHz */
SFR_8BIT(CALBC1_12MHZ);                       /* BCSCTL1 Calibration Data for 12MHz */
SFR_8BIT(CALDCO_8MHZ);                        /* DCOCTL  Calibration Data for 8MHz */
SFR_8BIT(CALBC1_8MHZ);                        /* BCSCTL1 Calibration Data for 8MHz */
SFR_8BIT(CALDCO_1MHZ);                        /* DCOCTL  Calibration Data for 1MHz */
SFR_8BIT(CALBC1_1MHZ);                        /* BCSCTL1 Calibration Data for 1MHz */

#endif /* #ifndef __DisableCalData */

 

Now you can begin using the new calibration data in your program. When you #include the msp430g2231.h file, put it in quotes instead of <> to ensure it's loading the modified header local to the project directory.

 

I tested the constants with a cheap oscilloscope and they seemed correct. My scope doesn't have great accuracy at high frequencies so they might be a little off, but nothing I can detect. It works with my composite video prog, so that's a pretty good sign.

 

EDIT: Oops! I had an incorrectly named file in these instructions. Corrected.

Share this post


Link to post
Share on other sites
There's been a bit of a discussion in another thread about an idea simpleavr had for adding the dco calibration constants to flash for the Value Line series. I've cobbled together some pieces of TI code and have it working. It seems to work great. Here's how I did it with CCS. I think the people on linux should be able to reproduce the result with a little adaptation.

 

it's not really my idea though, i was trying to run all the ti examples in slau80 which was intent for F2xxx series and the fact that since the G series is new, we have to "pretend" they are F series devices for development under linux. the G2231 is close to the F2012 in my view but there are also some minor differences, the pre-calibrated values is one of them. i was like jbremnant trying to use a 8Mhz pre-calibrated clock setting and found that it was not set. so i spent some time reading the header files and understand the why and how.

 

i played w/ the 'c' calibration example and it was not working, so i hand calibrated my project and had forgot about it when NatureTM's thread had success w/ the assembly calibration code. so i make some effort and get it work as is at this stage.

 

i guess it would be a handy thing (calibration) for a lot of people using the launchpad and NatureTM is nice enough to organize it into an user friend thread.

 

i would doubt HaD would use it though, it's really something tiny and specific to a smaller crowd. NatureTM's TVOut will have a lot better chance. People will "wow" on a 14pin mcu driving a 50inch TV (i did, :) ), but it's hard to explain the benefit a pre-calibrated clock setting to the general audience.

Share this post


Link to post
Share on other sites
i would doubt HaD would use it though, it's really something tiny and specific to a smaller crowd. NatureTM's TVOut will have a lot better chance. People will "wow" on a 14pin mcu driving a 50inch TV (i did, ), but it's hard to explain the benefit a pre-calibrated clock setting to the general audience.

 

Never hurts to submit. In any case, it will be featured here at the Blog.

Share this post


Link to post
Share on other sites

IMHO it's not good idea, erase full segment A. There is probably stored more device-depended constants, not only DCO calibration. (Look at page 644 in slau144.pdf - "SegmentA structure"). Better idea is simply write those 3 missing constants (for 8, 12 and 16MHz) into the empty space (empty space contains 0xFFFF, is writable...).

 

And more important info: You thinking about data integrity in segment A? Write the correct info into 0x10F6 (TAG_DCO_30 and length of DCO table)? Recalculate (and write) new checksum for segment A?

 

For those, who want correctly change DCO constants:

- Save full contents from segment A into RAM.

- Change (in RAM) what You want, compute new checksum, etc...

- And then write full block into erased segment A.

 

I suggest You: look at page 649 and 650 in slau144.pdf.

 

btw: the last version is slau144f.pdf

Share this post


Link to post
Share on other sites
IMHO it's not good idea, erase full segment A. There is probably stored more device-depended constants, not only DCO calibration. (Look at page 644 in slau144.pdf - "SegmentA structure"). Better idea is simply write those 3 missing constants (for 8, 12 and 16MHz) into the empty space (empty space contains 0xFFFF, is writable...).

 

And more important info: You thinking about data integrity in segment A? Write the correct info into 0x10F6 (TAG_DCO_30 and length of DCO table)? Recalculate (and write) new checksum for segment A?

 

For those, who want correctly change DCO constants:

- Save full contents from segment A into RAM.

- Change (in RAM) what You want, compute new checksum, etc...

- And then write full block into erased segment A.

 

thanks nobody, i agree it is safer to transfer seg A to ram before writing back w/ calibrated values (and re-calc checksum). i did messed up dco values when trying this initially. but i would prefer to write it to seg A instead of other segments just to be in-line w/ the TI conventions (i.e. common header files for msp430f2xxxx).

 

there is probably no need to mess w/ seg A if u got everything calibrated at factory. unfortunately the G series only come up w/ 1Mhz calibrated and it will be convenience to have the other values. in my experience it's safe for the G devices as there's no 12bitADC (or thereof calibrate values of that) and i can't think of other applications that may use the checksum and other device tags (i don't think G series supports BSL).

 

this is good advice to all those want to do calibration and understand the potential risks and decide. it's also probably good to always save the original seg A content in a file.

Share this post


Link to post
Share on other sites

Hi Guys,

 

I wanted to tack on my calibration code that I successfully used to calibrate my G2231 device.

 

It's almost exactly like naturetm's code. The only difference is the setDCO() function has a little more fine tuning in it.

 

Take a look and notice that the setDCO() function is slightly different. I stole the idea from a post aBUGSworstnightmare made on the ti.com website. Here's the link.

 

//******************************************************************************
//  MSP430F20xx 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 F2xx 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 *//
//
//           MSP430F20xx
//         ---------------
//     /|\|            XIN|-
//      | |               | 32kHz
//      --|RST        XOUT|-
//        |               |
//        |           P1.0|--> LED
//        |           P1.4|--> SMLCK = target DCO
//
//  A. Dannenberg
//  Texas Instruments Inc.
//  May 2007
//  Built with CCE Version: 3.2.0 and IAR Embedded Workbench Version: 3.42A
//******************************************************************************
//#include "msp430x20x1.h" // do not forget to change this according to the device you're using
#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);

void main(void)
{
 WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT

 BCSCTL3 |= XCAP_3; // Launchpad watch crystals need ~12.5 pF

 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
}

 

Concerning the mods that were made to the cmd file, I just threw them into the default files because I know that I'm going to forget to made the project edits that are suggested in the first post above.

 

Just calibrate the g2231 first then use the code after.

Share this post


Link to post
Share on other sites
Concerning the mods that were made to the cmd file, I just threw them into the default files because I know that I'm going to forget to made the project edits that are suggested in the first post above.

 

Just calibrate the g2231 first then use the code after.

I agree. I think calibration should be the first thing I do with new chips. That way, I always have the same platform.

 

NatureTM and zeke, your contributions have expanded possibilities for all of us. Thank you. :D

Share this post


Link to post
Share on other sites

Hey guys, has anyone checked to see if the calibration data are already in the MSP430G2231 flash? Perhaps the only problem is the missing entries in the support files? I admit I know very little at this stage but I'm eager to learn.

 

Cheerful regards, Mike

Share this post


Link to post
Share on other sites
Hey guys, has anyone checked to see if the calibration data are already in the MSP430G2231 flash?

 

I thought someone did, but you made me a little nervous there for a second. I checked back over to this thread: http://www.43oh.com/forum/viewtopic.php?f=10&t=234 and sure enough, simpleavr had dumped the flash and confirmed that they were missing.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×