Jump to content
43oh

Value Line series easy DCO setting library


Recommended Posts

Here's an existing TI lib I modified to work with the Value Line series and CCS.

 

Since the G series doesn't come with factory-calibrated DCO settings, I wanted an easy way to set the MCLK to 16MHz or some other arbitrary frequency. A TI library existed for setting the DCO using an external watch crystal as a reference, however it didn't work with the G series. It just took some minor editing.

I think this should be nice for Launchpad owners especially, since the kit comes with an external crystal and a 16MHz rated chip.

 

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

Link to post
Share on other sites
  • Replies 48
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

Popular Posts

Here's an existing TI lib I modified to work with the Value Line series and CCS.   Since the G series doesn't come with factory-calibrated DCO settings, I wanted an easy way to set the MCLK to 16MHz

if u dump out the stock flash portion where the calibrated values are defined.   (mspdebug) dis 0x10f0 010f0: ff ff ff ff AND.B @R15+, 0xffff(R15) 010f4: ff ff ff ff

it was the crystal all along.   the c example msp430x20xx_dco_flashcal.c (from slau80) has been working all right.   i finally solder a 32khz crystal onto my launchpad, result became better but st

Just browsed through the code. Good stuff.

I'll certainly make a good use of it.

 

Question:

 

can't you simply do?

 

BCSCTL1 = CALBC1_16MHZ;

DCOCTL = CALDCO_16MHZ;

 

Apologize in advance for my ignorance, I may have overlooked apparent benefit of the api.

 

The valueline chips only have 1 calibrated clock setting, 1mhz. Unlike other families of msp430 chips, you have to do some work for other speeds.

Link to post
Share on other sites
Just browsed through the code. Good stuff.

I'll certainly make a good use of it.

 

Question:

 

can't you simply do?

 

BCSCTL1 = CALBC1_16MHZ;

DCOCTL = CALDCO_16MHZ;

 

Apologize in advance for my ignorance, I may have overlooked apparent benefit of the api.

 

if u dump out the stock flash portion where the calibrated values are defined.

 

(mspdebug) dis 0x10f0
   010f0: ff ff ff ff               AND.B   @R15+,   0xffff(R15)
   010f4: ff ff ff ff               AND.B   @R15+,   0xffff(R15)
   010f8: ff ff ff ff               AND.B   @R15+,   0xffff(R15)
   010fc: 01 02                     MOVA    #0x4,    SP
   010fe: 6b 87                     SUB.B   @R7,     R11

 

the double word from 0x10fc (0x0102, 0x6b87) are the calibrated 1Mhz values from factory.

the other 3 sets (8, 12, 16Mhz) are pre-allocated but blank for the value line (cheaper, so no calibration).

 

[EDIT] correction, the 4 calibrated values should be double bytes, not double words according to header files.

0x10ff, 0x10fe are 1Mhz BCSCTL1+DCOCTL values
0x10fd, 0x10fc are 8Mhz
0x10fb, 0x10fa are 12Mhz
0x10f9, 0x10f8 are 16Mhz

value shown from my mspdebug session has been messed up (i guess) when i was trying the calibration code.

too early to give "thank you"s to me, :)

[END EDIT]

 

typically u can modify NatureTMs example and "write" the calibrated values to those memory locations, after that u can use

 

   if (CALBC1_16MHZ != 0xff && CALDCO_16MHZ != 0xff) {  
       BCSCTL1 = CALBC1_16MHZ;      // Set DCO to 16MHz
       DCOCTL = CALDCO_16MHZ;
   }//if 

 

additional check for 0xff will ensure u only use it if it's set.

 

there is also a c example msp430x20xx_dco_flashcal.c in the slau80 examples that also writes to the flash constant locations, but i never got it to work.

 

this way u don't have to carry the library on all of your projects and u only need the crystal when doing calibration.

Link to post
Share on other sites

Well I think I got that flashcal program working and managed to write the calibrations. I was hoping to not have to use a crystal with my TV output prog. I used my setDCO lib instead of their function and it wrote values to flash that looked correct. I then edited the msp430g2231.h and msp430g2231.cmd files to include the definitions for the calibrations, but when I tried to compile, i still got "error: identifier "CALDCO_16MHZ" is undefined." I'm not sure what else to edit.

Link to post
Share on other sites

Oh here's the code that I used for adding the calibrations if anyone else wants to try.

 

#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
}

Link to post
Share on other sites

well, i tried again the 'c' based msp430x20xx_dco_flashcal.c (inside slau80 examples) and managed to get it to work after tweaking it a bit. here are some findings for anyone who is interested.

 

 

i look at the code and see that for each frequency it is not giving the dco any initial value, i thought it will take forever for the timer to reach the require clock ticks one step at a time. so i add some "guess" values so the calibration start at a close clock rate.

 

and it didn't help, i still did not see the end of calibration when the led should blink.

 

i look at the code again and it struck me that the set_dco() function can go on forever if each timing iteration swings back and forth (i.e. this time slow, next time too fast, etc, etc), it won't exit the function if the timing is not exactly the value it wants.

 

so i comment out the calibration block for 16,12,8 Mhz and just try 1Mhz, and after may be 1 minute i can get it to finish. but sometimes it never finishes. but for the other clock rates, it might take many hours to have it struck the exact value (if it ever does).

 

to validate this theory, i add a counter to count the "swinging" condition and if it reaches 100 swings (too slow, too fast, too slow..) i will call it quit and use the last calibrated value.

 

i am able to calibrate the 4 set of frequencies like so.

 

but.... they look incorrect to me, the values looks too high, and i can't get consistent results.

 

i am sure something is still wrong, may be whoever had tried this example before can give some input. it would be nice to have this working correctly.

 

 

here is the code portion i changed in function Set_DCO(...) to get the calibration going and finish.

 

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

 unsigned char backnforth = 0;  // added by me
 unsigned char dir = 0;  // added by me
 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 || backnforth > 100)  // changed by me, added backnforth check
     break;                                // If equal, leave "while(1)"
   else if (Delta < Compare)
   {
     if (dir == 1) backnforth++;  // add by me
     dir = 0;  // add by me
     DCOCTL--;                             // DCO is too fast, slow it down
     if (DCOCTL == 0xFF)                   // Did DCO roll under?
       if (BCSCTL1 & 0x0f)
         BCSCTL1--;                        // Select lower RSEL
   }
   else
   {
     if (dir == 0) backnforth++;  // add by me
     dir = 1;  // add by me
     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
}

Link to post
Share on other sites
i look at the code again and it struck me that the set_dco() function can go on forever if each timing iteration swings back and forth (i.e. this time slow, next time too fast, etc, etc), it won't exit the function if the timing is not exactly the value it wants.

 

so i comment out the calibration block for 16,12,8 Mhz and just try 1Mhz, and after may be 1 minute i can get it to finish. but sometimes it never finishes. but for the other clock rates, it might take many hours to have it struck the exact value (if it ever does).

Try leaving it overnight and see if it calibrates. Maybe 100 is not enough.

 

Do they really do this when they manufacture the chips? individually calibrate each chip. Wow!

 

SimpleAVR, I have a TI Rep office close to my place. I can forward your questions to him.

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...