NatureTM 100 Posted November 26, 2010 Share Posted November 26, 2010 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 lvagasi, gatesphere, bluehash and 2 others 5 Quote Link to post Share on other sites
gatesphere 45 Posted November 26, 2010 Share Posted November 26, 2010 Nice work! Thanks for sharing Quote Link to post Share on other sites
bluehash 1,581 Posted November 29, 2010 Share Posted November 29, 2010 Blog page material. Thanks for sharing NTM. Quote Link to post Share on other sites
NatureTM 100 Posted November 29, 2010 Author Share Posted November 29, 2010 Awesome! I've actually been sitting on this for awhile. I just got my hands on a cheap oscilloscope so I could directly verify the clock speed, even though it was working with some timing-dependant stuff. Just wanted to be sure! Quote Link to post Share on other sites
jbremnant 17 Posted December 1, 2010 Share Posted December 1, 2010 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. Quote Link to post Share on other sites
cde 334 Posted December 1, 2010 Share Posted December 1, 2010 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. Quote Link to post Share on other sites
simpleavr 399 Posted December 1, 2010 Share Posted December 1, 2010 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. bluehash, GeekDoc, jbremnant and 2 others 5 Quote Link to post Share on other sites
gatesphere 45 Posted December 1, 2010 Share Posted December 1, 2010 simpleavr, you never cease to amaze me. Quote Link to post Share on other sites
GeekDoc 226 Posted December 1, 2010 Share Posted December 1, 2010 This is great! And simpleavr's tip makes it even better! You both rock! Quote Link to post Share on other sites
NatureTM 100 Posted December 2, 2010 Author Share Posted December 2, 2010 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. Quote Link to post Share on other sites
NatureTM 100 Posted December 2, 2010 Author Share Posted December 2, 2010 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 } Quote Link to post Share on other sites
GeekDoc 226 Posted December 2, 2010 Share Posted December 2, 2010 I then edited the msp430g2231.h and msp430g2231.cmd files to include the definitions for the calibrations... I'm thinking you should probably put those definitions in your own headers so they're not defined for units that you have not calibrated. Quote Link to post Share on other sites
NatureTM 100 Posted December 2, 2010 Author Share Posted December 2, 2010 You're right. Maybe doing that will get things working as well. Quote Link to post Share on other sites
simpleavr 399 Posted December 2, 2010 Share Posted December 2, 2010 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 } bluehash 1 Quote Link to post Share on other sites
bluehash 1,581 Posted December 2, 2010 Share Posted December 2, 2010 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. Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.