greeeg 460 Posted October 5, 2011 Share Posted October 5, 2011 All modern MSP chips to my knowledge feature a small area of "information memory". To my knowledge this is the equivalent to internal EEPROM on a PIC or AVR. Using mspgcc we can easily store an array of constant data into infomem. all that is required is a single attribute tag. For example in my current project I have an array of font data. by moving it to infomem I saved 192 bytes of flash. (Strictly speaking infomem is flash :think: So don't be worried about wearing it out anymore than flash ) Anyway here is the code /* "Compressed" font data, in form 0b ABCD EFGH IJKL MNOP {A-P} represent segment bits in each character __J_ _A__ |\ | /| | K H B | L \ | / C | \|/ | >-M--*--D-< | /|\ | N / | \ E | O I F | |/ | \| ~~P~ ~G~~ */ const unsigned int font_data[] __attribute__((section(".infomem"))) = { 0x0000,0xC101,0x0110,0x3B89,0x9BD9,0x5BDA,0x0F6D,0x4000, 0x4400,0x0022,0x55AA,0x1188,0x0002,0x1008,0x0001,0x4002, 0xEA57,0x6800,0xB24D,0xDA41,0x3818,0x8659,0x9A5D,0xA840, 0xBA5D,0xBA59,0x0041,0x0042,0x4203,0x1209,0x0621,0xB0C0, 0xAACD,0xB85C,0xBBC1,0x8255,0xABC1,0x825D,0x805C,0x9A55, 0x381C,0x83C1,0x81C5,0x441C,0x0215,0x6834,0x2C34,0xAA55, 0xB05C,0xAE55,0xB45C,0x9A59,0x81C0,0x2A15,0x4016,0x2C16, 0x4422,0x40A0,0xC243,0x0055,0x0420,0xAA00,0x0402,0x0201, 0x0020,0x028D,0x009D,0x000D,0x018D,0x000F,0x9188,0x1E01, 0x009C,0x0080,0x0081,0x1580,0x03C0,0x188C,0x008C,0x008D, 0x015C,0x03D8,0x000C,0x1081,0x1388,0x0085,0x0006,0x0A85, 0x4182,0x0E01,0x000B,0x8388,0x0180,0x11C1,0x3150,0x0000, }; This one line of code is what does all the magic. This tells the linker to move this block of data into the infomem region. __attribute__((section(".infomem"))) Be warned the infomem region often contains calibration data for the DCO, it would be wise to make a note of what these values are. In case you accidentally store data over them. This can easily be done using this command mspdebug rf2500 'md 0x10FE 0x2' *The address 0x10FE applicable for the the value line devices. This command will open mspdebug, connect to the device and dump 2 bytes from address 0x10FE, on the value line devices these 2 bytes are the DCO calibration values. An interesting side note about the attribute command. is that it could be used to position a function into infomem. However Some MSP430 devices are unable to execute commands from infomem. (or maybe it's just the MSP430f5438 ) Rickta59, xpg, PentiumPC and 2 others 5 Quote Link to post Share on other sites
nobody 47 Posted October 5, 2011 Share Posted October 5, 2011 In IAR workbench use this way: #pragma constseg = INFOB LUT_TABLE Lut_adc[2] = { -67, 10730, 0, 0, 0, // Input from U ADC 0L, 19476L, 0L, 0L, 0L, // Real measured U -59, 30680, 0, 0, 0, // Input from I ADC 0L, 39080L, 0L, 0L, 0L // Real measured I }; #pragma constseg = default #pragma constseg = INFOC const int Lut_pwm[2][LUT_PWM_SIZE + 1] = { 0, 907, 1814, 2721, 3628, 4535, 5442, 6349, 7256, 8163, 9070, 9977, 10884, 11791, 12698, 13605, // U to PWM 0, 986, 1972, 2958, 3944, 4930, 5917, 6903, 7889, 8875, 9861, 10848, 11834, 12820, 13806, 14792 // I to PWM }; #pragma constseg = default #pragma constseg = INFOD const int Factory_max_pwm_U = 8000; const int Factory_max_pwm_I = 3000; const int User_min_pwm_U = 0; const int User_max_pwm_U = 8000; const int User_min_pwm_I = 0; const int User_max_pwm_I = 3000; const int User_stored_pwm_U = 0; const int User_stored_pwm_I = 1; #pragma constseg = default You be able to select concrete segment of info memory. oPossum and cde 2 Quote Link to post Share on other sites
greeeg 460 Posted October 5, 2011 Author Share Posted October 5, 2011 Thanks for that. I didn't mention it but my way, I think, is only for gcc. I can't use IAR or CCS. due to the fact I'm on a mac. Quote Link to post Share on other sites
zborgerd 62 Posted October 6, 2011 Share Posted October 6, 2011 Bonus points for it being GCC, and even more bonus points for all of the other great info. Thanks for this post! Quote Link to post Share on other sites
PentiumPC 119 Posted October 6, 2011 Share Posted October 6, 2011 Thanks for the info, from what I understand, infomem A is protected, so if we need to write something to it, am I right to say we have to read everything out, add on or data and write the whole block back in? Regards, Terence Quote Link to post Share on other sites
Rickta59 589 Posted October 23, 2011 Share Posted October 23, 2011 This one line of code is what does all the magic. This tells the linker to move this block of data into the infomem region. __attribute__((section(".infomem"))) You can avoid overwriting the infoa segment, which is where most of the precalibrated values are stored by using: __attribute__((section(".infob"))) __attribute__((section(".infoc"))) __attribute__((section(".infod"))) each .infox section is 64 bytes. If you avoid .infoa you don't have to worry about what might be stored there. [EDIT] -rick zeke and shabble 2 Quote Link to post Share on other sites
pabigot 355 Posted October 23, 2011 Share Posted October 23, 2011 Not all information segments are 64 bytes; some are 128, and one odd line has 96 byte segments. Not all chips have four segments, either; some only have A and B. Accessing sections individually was not supported in the GNU toolchain until late August, and has not yet been incorporated into a versioned release (you or your packager would need to be running off the git branches). With the next release, not only will you be able to place things in specific segments using the section attribute, you will also be able to reference the address of the specific segment and the size of any segment using linker symbols like __infoa and __info_segment_size. This makes using these sections a lot nicer. See https://sourceforge.net/tracker/?func=d ... tid=432701 for details; one day this might make it into a manual. You can't mix .infomem and specific .info segments in the same program. .infomem starts with the lowest addressed segment, which is normally info D; info A is the highest, so you're generally safe from overwriting info A if you don't fill up the other ones. Quote Link to post Share on other sites
Rickta59 589 Posted October 23, 2011 Share Posted October 23, 2011 @Peter Thanks for the clarification from the source! I have been avoiding all the older gcc releases as I'm only using the newly added value line chips and the FRAM chips. Are there any other nice features on the table for the next release of msp430-gcc? -rick gordon 1 Quote Link to post Share on other sites
pabigot 355 Posted October 23, 2011 Share Posted October 23, 2011 You're welcome. I have been avoiding all the older gcc releases as I'm only using the newly added value line chips and the FRAM chips. Are there any other nice features on the table for the next release of msp430-gcc? Improved information segment management is one. I've added a couple more intrinsics to match CCS/IAR, and increased the span of legal values for __delay_cycles. Improved stack code for chips with the CPUX extensions (pushm/popm). I'll try to create a human readable summary before the next release, but in general the best option is to look at the tickets on SF for what's been done and what's currently pending. Generally nothing goes in that doesn't have a ticket backing it up, since I use the ticket numbers in the internal test suite. Quote Link to post Share on other sites
zeke 693 Posted January 8, 2015 Share Posted January 8, 2015 While reading this thread, I noticed that the answers did not comment on a solution for CCS. So here are my observations and code samples to make that work in CCS. First, I trimmed down the font sample code from @@greeeg just to see if it will work. #pragma DATA_SECTION(font_data, ".infoB") const unsigned int font_data[] = { 0x0000,0xC101,0x0110,0x3B89,0x9BD9,0x5BDA,0x0F6D,0x4000, 0x4400,0x0022,0x55AA,0x1188,0x0002,0x1008,0x0001,0x4002, 0xEA57,0x6800,0xB24D,0xDA41,0x3818,0x8659,0x9A5D,0xA840, 0xBA5D,0xBA59,0x0041,0x0042,0x4203,0x1209,0x0621,0xB0C0, }; Good! This is just the right size to fill up 64 bytes - the size of INFOB. Any bigger and the compiler fails out with an error message about memory size is over filled or something. Next, figure out what special names you can use in the DATA_SECTION declaration. Open up the linker file for your project. In my case, it's called lnk_msp430g2553.cmd. You will see this inside of it: .infoA : {} > INFOA /* MSP430 INFO FLASH MEMORY SEGMENTS */ .infoB : {} > INFOB .infoC : {} > INFOC .infoD : {} > INFOD so, use the lowercase name in your declaration. And here is my test program that I used to test drive the flash on an MSP43G2553: #include <msp430.h> /* "Compressed" font data, in form 0b ABCD EFGH IJKL MNOP {A-P} represent segment bits in each character __J_ _A__ |\ | /| | K H B | L \ | / C | \|/ | >-M--*--D-< | /|\ | N / | \ E | O I F | |/ | \| ~~P~ ~G~~ */ #pragma DATA_SECTION(font_data, ".infoB") const unsigned int font_data[] = { 0x0000,0xC101,0x0110,0x3B89,0x9BD9,0x5BDA,0x0F6D,0x4000, 0x4400,0x0022,0x55AA,0x1188,0x0002,0x1008,0x0001,0x4002, 0xEA57,0x6800,0xB24D,0xDA41,0x3818,0x8659,0x9A5D,0xA840, 0xBA5D,0xBA59,0x0041,0x0042,0x4203,0x1209,0x0621,0xB0C0, }; //const unsigned int font_data[] //__attribute__((section(".infob"))) = //{ //0x0000,0xC101,0x0110,0x3B89,0x9BD9,0x5BDA,0x0F6D,0x4000, //0x4400,0x0022,0x55AA,0x1188,0x0002,0x1008,0x0001,0x4002, //0xEA57,0x6800,0xB24D,0xDA41,0x3818,0x8659,0x9A5D,0xA840, //0xBA5D,0xBA59,0x0041,0x0042,0x4203,0x1209,0x0621,0xB0C0, //0xAACD,0xB85C,0xBBC1,0x8255,0xABC1,0x825D,0x805C,0x9A55, //0x381C,0x83C1,0x81C5,0x441C,0x0215,0x6834,0x2C34,0xAA55, //0xB05C,0xAE55,0xB45C,0x9A59,0x81C0,0x2A15,0x4016,0x2C16, //0x4422,0x40A0,0xC243,0x0055,0x0420,0xAA00,0x0402,0x0201, //0x0020,0x028D,0x009D,0x000D,0x018D,0x000F,0x9188,0x1E01, //0x009C,0x0080,0x0081,0x1580,0x03C0,0x188C,0x008C,0x008D, //0x015C,0x03D8,0x000C,0x1081,0x1388,0x0085,0x0006,0x0A85, //0x4182,0x0E01,0x000B,0x8388,0x0180,0x11C1,0x3150,0x0000, //}; char value; // 8-bit value to write to segment A // Function prototypes void write_SegC (char value); void copy_C2D (void); int main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer if (CALBC1_1MHZ==0xFF) // If calibration constant erased { while(1); // do not load, trap CPU!! } DCOCTL = 0; // Select lowest DCOx and MODx settings BCSCTL1 = CALBC1_1MHZ; // Set DCO to 1MHz DCOCTL = CALDCO_1MHZ; FCTL2 = FWKEY + FSSEL0 + FN1; // MCLK/3 for Flash Timing Generator value = 0; // initialize value while(1) // Repeat forever { write_SegC(value++); // Write segment C, increment value copy_C2D(); // Copy segment C to D __no_operation(); // SET BREAKPOINT HERE } } void write_SegC (char value) { char *Flash_ptr; // Flash pointer unsigned int i; Flash_ptr = (char *) 0x1040; // Initialize Flash pointer FCTL1 = FWKEY + ERASE; // Set Erase bit FCTL3 = FWKEY; // Clear Lock bit *Flash_ptr = 0; // Dummy write to erase Flash segment FCTL1 = FWKEY + WRT; // Set WRT bit for write operation for (i=0; i<64; i++) { *Flash_ptr++ = value; // Write value to flash } FCTL1 = FWKEY; // Clear WRT bit FCTL3 = FWKEY + LOCK; // Set LOCK bit } void copy_C2D (void) { char *Flash_ptrC; // Segment C pointer char *Flash_ptrD; // Segment D pointer unsigned int i; Flash_ptrC = (char *) 0x1040; // Initialize Flash segment C pointer Flash_ptrD = (char *) 0x1000; // Initialize Flash segment D pointer FCTL1 = FWKEY + ERASE; // Set Erase bit FCTL3 = FWKEY; // Clear Lock bit *Flash_ptrD = 0; // Dummy write to erase Flash segment D FCTL1 = FWKEY + WRT; // Set WRT bit for write operation for (i=0; i<64; i++) { *Flash_ptrD++ = *Flash_ptrC++; // copy value segment C to segment D } FCTL1 = FWKEY; // Clear WRT bit FCTL3 = FWKEY + LOCK; // Set LOCK bit } Here is a screen shot of CCS as I inspected the information memory section. The way I have the screen stretched out causes each memory section to be all on one line ie: INFOD (0x1000), INFOC (0x1040), INFOB (0x1080) and INFOA (0x10C0). Footnote: For reference, here's TI's take on this topic: greeeg, veryalive and cde 3 Quote Link to post Share on other sites
zeke 693 Posted February 4, 2015 Share Posted February 4, 2015 I know that I'm going to forget how I did this so here's my mind dump on figuring out the flash timing generator settings: /******************************************************************************* * Divide Flash clock by 1 to 64 using FN0 to FN5 according to: * 32*FN5 + 16*FN4 + 8*FN3 + 4*FN2 + 2*FN1 + FN0 + 1 * * #define FN0 (0x0001) * #define FN1 (0x0002) * #define FN2 (0x0004) * #define FN3 (0x0008) * #define FN4 (0x0010) * #define FN5 (0x0020) * * Select the clock source for the Flash Timing Generator * * #define FSSEL0 (0x0040) // Flash clock select 0 * #define FSSEL1 (0x0080) // Flash clock select 1 * * #define FSSEL_0 (0x0000) // Flash clock select: 0 - ACLK * #define FSSEL_1 (0x0040) // Flash clock select: 1 - MCLK * #define FSSEL_2 (0x0080) // Flash clock select: 2 - SMCLK * #define FSSEL_3 (0x00C0) // Flash clock select: 3 - SMCLK * * What is the frequency of these various clock sources? * ACLK = 32768 kHz if you're using an external crystal * MCLK = * SMCLK= * * The target value for the FTG frequency is 514 kHz < SMCLK < 952 kHz (this is device specific). * * Calculate if you can set the FTG up in this range: * (952 - 514) + 514 = 733 <-- Suggested target value to achieve with above formula * * 32768 kHz / 733 = 44.704 * * What FNn value will produce a result close to 733? * 733 / 44.703 = 16.396 * * Let's round that to an even 16. * * What FNn value is equal to 16? * FN4 = 0x0010 or 0d16 * * but that's not what we want. We want a result of 0d16. Choosing FN2, putting * it into the formula gives us: * 4*0x0004 + 1 = 17 * * Let's recompute the resultant FTG frequency with that value: * 32768 / 733 = 44.704 * 733 / 44.704 = 16.396 * * Now compare by refactoring: * 733 / 17 = 43.118 * * 43.118 * 17 = 733 Hz * * Now we can give this a try. * * Setup FCTL2 with the following values: * FCTL2 = FWKEY + FSSEL0 + FN2; * * Observe the Memory Rendering of the CPU to observe and verify that reliable * values are programmed into INFOD, INFOC and, INFOB information memory segments. * * When the MSP430 is configured to operate at 16 MHz, all 128 memory cells * appear to program properly. There are no stuck or inverted bits as the program * flows. * ******************************************************************************/ // FCTL2 = FWKEY + FSSEL0 + FN1; // MCLK/3 for Flash Timing Generator FCTL2 = FWKEY + FSSEL0 + FN2; Note: These calculations depend upon this: // Configure MSP430 for 16MHz operation BCSCTL1 = CALBC1_16MHZ; DCOCTL = CALDCO_16MHZ; 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.