This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Keep variable after the shutdown with a MSP-EXP430G2

Other Parts Discussed in Thread: MSP430F2274

Hello everybody !

I am a happy owner of a MSP EXP430G2, and i have a question about it.


I would like to keep my variables even after a shutdown of the msp. How to do that ? I heard that we have to use a EEPROM memory, is it true ? Which one ?


Many thanks for your help, and sorry about my approximative English !

  • You can do this without needing an external EEPROM by using the Flash Memory Controller to write to the flash memory inside the MSP430. The "information flash" segments are set aside specifically for this purpose.

    You can get more information on this in the Flash Memory Controller chapter of the MSP430x2xx Family User's Guide. There's also sample code demonstrating how to use the information flash memory (msp430g2xx2_flashwrite_01.c).

  • Thank you for your fast answer ! I will try it !

  • I don't understand the "Initialize Flash Pointer" lane. If we initialize the flash Pointer, all the variables would be at the same address in the Flash memory, isn't it ?

    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
    }


    And how to read our variable from the flash memory ? I have found this topic :
    http://e2e.ti.com/support/microcontrollers/msp430/f/166/t/224545.aspx
    But I don't find the lane where it does read the variable. Can someone explain this to me ? :)


    Many thanks !

  • How many variables do you need to save?

    If it is less than 64, you could "ping-pong" between two INFO segments, like A and B. Besides the variables, you could also store an "index" that gets incremented prior to storing. When waking up, look at the index in INFO A and compare to the index in INFO B to see which was newer (high value is newer value). You could then pick the older segment to be updated.

    This could be expanded to use all 4 segments if you want...

    Hopefully that helps.

  • I would like to keep two integer variables ! I don't understand how i will distinguish the two variables, because both of them would have the same pointers, so the same location, isn't it ?
    I would put my two variables in Segment A, but why do I have to transfer them into the Segment B ?



    It's my very first time that I'm coding on microcontrollers, many thanks for your help !

  • You are right, you do not need to use 2 segments.

    After reset, in main(), I would call a function to load a subset of segment 1 into RAM.

    When you are ready to shutdown, call another function that copies the RAM variables into flash.

    Do you know when you are going to shut down, or is it a random occurrence?

  • I don't know when the MSP430 will shutdown ! It can happen anytime. When I loose the DC, a Capacitor gives me about 3 seconds to save my variables. During this period, I save all the variables. But I think that I will save the variables every 30 minutes, just to be sure to have the variables correctly saved.

    Can you give an example of a write into a Segment, and how to read a value from it please ? Unfortunately,  I did not find that in the User's Guide.

    Many Thanks !


    EDIT: I have found this very interesting link:
    http://cyroforge.wordpress.com/2013/01/01/using-flash-memory-in-msp430/
    I will try this, I will tell you if it works !

    Thank you !

  • Hi !
    After some works, following your instruction to use the flash memory. I did this program :

    #include <msp430.h>
    #include<intrinsics.h>
    
    int hHeures;
    int hMinutes;
    
    int hSecondes;
    int *addr = (int *)0x0E000 ; // Address of the flash memory segment starting
    int *addr2 = (int *)0x0E000 +64;
    
    
    int main(void) {
    	P1DIR = 0x41;
    	// Port P1.2 (entrée 3v dispo) entrée  Port P1.3(reset) Entrée   //POUR TESTER ON MET la led 1 en sortie
    	P2DIR = 0x0F;			;					//Ports P2.0 (vert)P2.1(orange) et P2.2(rouge) P2.3 sortie 3v Sorties
    	P1OUT=0x00;
    	hHeures=0;
    	hMinutes=0;
    	//CONSTANTES
    	int xHeures1=0;  //limite LED VERTE
    	int xMinutes1=1;
    	int xHeures2=0;  //limite LED ORANGE
    	int xMinutes2=2;
    	int xHeures3=0;  //limite LED ROUGE
    	int xMinutes3=3;
    	//
    	//
    	hHeures=*addr2;
    	hMinutes=*addr;
    	hSecondes=0;
    	// Stop watchdog timer
    	WDTCTL = WDTPW + WDTHOLD ; //Stop watchdog
    	BCSCTL2 = SELS; // SMCLK = LFXT1CLK (quartz)
    	TA0CTL = MC_1 + TASSEL_2 + TACLR; // Up_mode / SMCLK
    	CCTL0 = CCIE; // CCR0 interrupt enabled
    	CCR0 = 32768;
    	_BIS_SR(GIE); // Active les interruptions globales
    	while(1){
    		if ((P1IN & 0x80) == 0) {
    			P1OUT = 0x40;
    			if (hHeures<=xHeures1 && hMinutes<xMinutes1){
    				P2OUT=0x01;
    			}
    			else if (hHeures<=xHeures2 & hMinutes<xMinutes2){
    				P2OUT=0x02;
    			}
    			else if(hHeures<=xHeures3 & hMinutes<xMinutes3){
    				P2OUT=0x04;
    			}
    			else {
    				P2OUT=0x0C;
    			}
    		}
    		else {
    			hMinutes=0;
    			hHeures=0;
    			hSecondes=0;
    			*addr=2;
    			*addr2=0;
    			P1OUT = 0x01;
    		}
    	}
    }
    
    #pragma vector = TIMER0_A0_VECTOR
    __interrupt void Timer_A(void){
    	hSecondes=hSecondes+1;
    	if (hSecondes==10){
    		hMinutes=hMinutes+1;
    		if(hMinutes==1){
    			*addr=hMinutes;
    			*addr2=hHeures;
    		}
    		hSecondes=0;
    		if (hMinutes==60){
    			hMinutes=0;
    			hHeures=hHeures+1;
    		}
    	}
    	return;
    }
    

    The idea is that the variables hHeures and hMinutes are saved in addr and addr2. addr and addr2 are supposed to be kept even if the MSP430 is shutdown. (line 71 - 72)

    When the MSP430 is ON, it sets variables hHeures and hMinutes from addr and addr2. (line 28 - 29)

    And i tried to design something to reset those variables.( line 58 - 59 )

    I create a pointer to do that, but it doesn't work...

    Can you explain where I did wrong please? I think that I'm not so far from the result ! (I hope)

    Many Thanks !

  • Hey,

    If u want to retain  information after shutdown, you to execute flash write. I mean, you have to write to a address of  flash memory. Not just to a address. Flash writing is a simple but you have some limitations. any way here is my code to write to flash. I have written it log back u can use it.

    Also read Flash segment of user guide for the family of micro controller u are using.

    #include "ToFlash.h"
    
    void init_Flash( void );
    void Data_Erase_Main(void);
    void write_Flash1(int n, int m,uint8_t wr_index);
    
    //Declaring pointer to point to a location in Flash
    int *P_int;
    
    //Initializing Flash writing Machine with required settings. Note: Settings vary with family of MSP
    void init_Flash(void)
      {
    		    BCSCTL1 = CALBC1_1MHZ;                    // Set DCO to 1MHz
    		    DCOCTL = CALDCO_1MHZ;
    		    FCTL2 = FWKEY + FSSEL0 + FN1;             // MCLK/3 for Flash Timing Generator
      }
    //Before writing to Flash you should earase flash. Flash earase happens only in segments.
    //Info segments are of 64bit size
    //data/code segments are 512 byte size void Data_Erase_Main(void) { //int *P_int1; FCTL2 = FWKEY + FSSEL0 + FN1; FCTL3 = FWKEY; // clr LOCK bit FCTL1 = FWKEY + ERASE; // activate segment erase mode P_int = (int*)0xC000; // Initializing pointer to 0xc000 address of Flash memory *P_int = 0; // Dummy write to erase. This will earase entire segment
    // from c000 to c200 512 bytes.
    } //Writing to flash
    //@parameter n --> data to be written to flash
    m --> location of slot in memory segments where data to be written to
    wr_index-> which memory segment is to be selected.
     void write_Flash1(int n, int m, uint8_t wr_index)
        {
     	       	//char *P_int;
    	 switch(wr_index)
    	 {
    	 	 case 1:{	P_int = (int*)0xC000; break;}                     // Intiate pointer to selected location
    	 	 case 2:{	P_int = (int*)0xC200; break;}                    // Intiate pointer to selected location
    	 	 case 3:{	P_int = (int*)0xC400; break;}                    // Intiate pointer to selected location
    	 	 case 4:{	P_int = (int*)0xC600; break;}                    // Intiate pointer to selected location
    	 	 case 5:{	P_int = (int*)0xC800; break;}                    // Intiate pointer to selected location
    	 	 case 6:{	P_int = (int*)0xCA00; break;}                    // Intiate pointer to selected location
    	 }
    				FCTL2 = FWKEY + FSSEL0 + FN1;
    				FCTL3 = FWKEY;                         // CLR LOCK Bit
    
    				P_int = P_int + m;                         // moving memory pointer m slots with in segment.
    
    
    				FCTL1 = FWKEY + WRT;            // Set WRT bit to enable WRT mode
    
    				*P_int = n;
    
    				FCTL1 = FWKEY;
    				FCTL3 = FWKEY + LOCK;
    
        }
    
    

  • Hi ! I have updated my program, following your instructions, and it hasn't any error !

    But It doesn't work: when I try to loss the power, I can't recover the saved variables !

    #include <msp430.h>
    #include<intrinsics.h>
    int test; int maj;
    int hHeures;
    int hMinutes;
                         // Flash pointer
    int hSecondes;
    
    char *Flash_ptr1;
    char *Flash_ptr2;
    void write_SegC (char value);
    void write_SegD (char value);
    int main(void) {
    	Flash_ptr1 = (char *) 0x1040;
    	Flash_ptr2 = (char *) 0x512;
    	P1DIR = 0x41;
    	// Port P1.2 (entrée 3v dispo) entrée  Port P1.3(reset) Entrée   //POUR TESTER ON MET la led 1 en sortie
    	P2DIR = 0x0F;							//Ports P2.0 (vert)P2.1(orange) et P2.2(rouge) P2.3 sortie 3v Sorties
    	P1OUT=0x00;
    	hHeures=0;
    	hMinutes=0;
    	//CONSTANTES
    	int xHeures1=0;  //limite LED VERTE
    	int xMinutes1=1;
    	int xHeures2=0;  //limite LED ORANGE
    	int xMinutes2=30;
    	int xHeures3=0;  //limite LED ROUGE
    	int xMinutes3=40;
     hMinutes=*Flash_ptr1;
     hHeures=*Flash_ptr2;
    
    	hSecondes=0;
    	// Stop watchdog timer
    	WDTCTL = WDTPW + WDTHOLD ; //Stop watchdog
    	BCSCTL2 = SELS; // SMCLK = LFXT1CLK (quartz)
    	TA0CTL = MC_1 + TASSEL_2 + TACLR; // Up_mode / SMCLK
    	CCTL0 = CCIE; // CCR0 interrupt enabled
    	CCR0 = 32768;
    	_BIS_SR(GIE); // Active les interruptions globales
    	maj=0;
    	while(1){
    		if (maj==1){
    			write_SegC(hMinutes);
    			write_SegD(hHeures);
    			maj=0;
    		}
    		if ((P1IN & 0x80) == 0) {
    			P1OUT = 0x40;
    			if (hHeures<=xHeures1 && hMinutes<xMinutes1){
    				P2OUT=0x01;
    				test=1;
    			}
    			else if (hHeures<=xHeures2 && hMinutes<xMinutes2){
    				P2OUT=0x02;
    				test=2;
    			}
    			else if(hHeures<=xHeures3 && hMinutes<xMinutes3){
    				P2OUT=0x04;
    				test=3;
    			}
    			else {
    				P2OUT=0x0C;
    				test=4;
    			}
    		}
    		else {
    			hMinutes=0;
    			hHeures=0;
    			hSecondes=0;
    			write_SegC(0);
    			write_SegD(0);
    			P1OUT = 0x01;
    		}
    	}
    }
    
    #pragma vector = TIMER0_A0_VECTOR
    __interrupt void Timer_A(void){
    	hSecondes=hSecondes+1;
    	if (hSecondes==10){
    		hMinutes=hMinutes+1;
    		if(hMinutes==1){
    			maj=1;
    		}
    		hSecondes=0;
    		if (hMinutes==60){
    			hMinutes=0;
    			hHeures=hHeures+1;
    			maj=1;
    		}
    	}
    	return;
    }
    void write_SegC (char value)
    {
                                // Flash pointer
    
    
      //Flash_ptr1 = (char *) 0x1040;              // Initialize Flash pointer
      FCTL1 = FWKEY + ERASE;                    // Set Erase bit
      FCTL3 = FWKEY;                            // Clear Lock bit
      *Flash_ptr1 = 0;                           // Dummy write to erase Flash segment
    
      FCTL1 = FWKEY + WRT;                      // Set WRT bit for write operation
    
     // for (i=0; i<64; i++)
      //{
        *Flash_ptr1 = value;                   // Write value to flash
      //}
    
      FCTL1 = FWKEY;                            // Clear WRT bit
      FCTL3 = FWKEY + LOCK;                     // Set LOCK bit
    }
    void write_SegD (char value)
    {
                                // Flash pointer
    
    
      //Flash_ptr2 = (char *) 0x512;              // Initialize Flash pointer
      FCTL1 = FWKEY + ERASE;                    // Set Erase bit
      FCTL3 = FWKEY;                            // Clear Lock bit
      *Flash_ptr2 = 0;                           // Dummy write to erase Flash segment
    
      FCTL1 = FWKEY + WRT;                      // Set WRT bit for write operation
    
     // for (i=0; i<64; i++)
      //{
        *Flash_ptr2 = value;                   // Write value to flash
      //}
    
      FCTL1 = FWKEY;                            // Clear WRT bit
      FCTL3 = FWKEY + LOCK;                     // Set LOCK bit
    }
    
    

    I think that the mistake come from the initialization on the beginning of the code.... (lines 14 and 29)
    Many thanks for your help guys ! It is very nice from you !

  • sri-sri said:
    FCTL2 = FWKEY + FSSEL0 + FN1; FCTL3 = FWKEY;

    1.Flash timing generator is not initiated in your code. This necessary to start flash writing.

    2. After the addition of above line, I think you can definitely retain information in 0x1040 InfoC.

    3. You may not retain in fo from ox510. thats a different but try with above line. rest looks fine for me.

  • Hi again ! Thank you for your answer ! I tried what you explained, and it didn't work unfortunately.. But I think that is because I put those lines at the wrong location. I inserted your lines in the function write_SegC just after the dummy write. Is it right ?

    #include <msp430.h>
    #include<intrinsics.h>
    int test; int maj;
    int hHeures;
    int hMinutes;
                         // Flash pointer
    int hSecondes;
    
    char *Flash_ptr1;
    char *Flash_ptr2;
    void write_SegC (char value);
    void write_SegD (char value);
    int main(void) {
    
    	//Flash_ptr1 = (char *) 0x1040;
    	//Flash_ptr2 = (char *) 0x512;
    	P1DIR = 0x41;
    	// Port P1.2 (entrée 3v dispo) entrée  Port P1.3(reset) Entrée   //POUR TESTER ON MET la led 1 en sortie
    	P2DIR = 0x0F;							//Ports P2.0 (vert)P2.1(orange) et P2.2(rouge) P2.3 sortie 3v Sorties
    	P1OUT=0x00;
    	hHeures=0;
    	hMinutes=0;
    	//CONSTANTES
    	int xHeures1=0;  //limite LED VERTE
    	int xMinutes1=1;
    	int xHeures2=0;  //limite LED ORANGE
    	int xMinutes2=30;
    	int xHeures3=0;  //limite LED ROUGE
    	int xMinutes3=40;
     hMinutes=*Flash_ptr1;
     //hHeures=*Flash_ptr2;
    
    	hSecondes=0;
    	// Stop watchdog timer
    	WDTCTL = WDTPW + WDTHOLD ; //Stop watchdog
    	BCSCTL2 = SELS; // SMCLK = LFXT1CLK (quartz)
    	TA0CTL = MC_1 + TASSEL_2 + TACLR; // Up_mode / SMCLK
    	CCTL0 = CCIE; // CCR0 interrupt enabled
    	CCR0 = 32768;
    	_BIS_SR(GIE); // Active les interruptions globales
    	maj=0;
    	while(1){
    		if (maj==1){
    			write_SegC(hMinutes);
    			//write_SegD(hHeures);
    			maj=0;
    		}
    		if ((P1IN & 0x80) == 0) {
    			P1OUT = 0x40;
    			if (hHeures<=xHeures1 && hMinutes<xMinutes1){
    				P2OUT=0x01;
    				test=1;
    			}
    			else if (hHeures<=xHeures2 && hMinutes<xMinutes2){
    				P2OUT=0x02;
    				test=2;
    			}
    			else if(hHeures<=xHeures3 && hMinutes<xMinutes3){
    				P2OUT=0x04;
    				test=3;
    			}
    			else {
    				P2OUT=0x0C;
    				test=4;
    			}
    		}
    		else {
    			hMinutes=0;
    			hHeures=0;
    			hSecondes=0;
    			write_SegC(5);
    			//write_SegD(0);
    			P1OUT = 0x01;
    		}
    	}
    }
    
    #pragma vector = TIMER0_A0_VECTOR
    __interrupt void Timer_A(void){
    	hSecondes=hSecondes+1;
    	if (hSecondes==10){
    		hMinutes=hMinutes+1;
    		if(hMinutes==1){
    			maj=1;
    		}
    		hSecondes=0;
    		if (hMinutes==60){
    			hMinutes=0;
    			hHeures=hHeures+1;
    			maj=1;
    		}
    	}
    	return;
    }
    void write_SegC (char value)
    {
                                // Flash pointer
    
    
      Flash_ptr1 = (char *) 0x1040;              // Initialize Flash pointer
      FCTL1 = FWKEY + ERASE;                    // Set Erase bit
      FCTL3 = FWKEY;                            // Clear Lock bit
      *Flash_ptr1 = 0;                           // Dummy write to erase Flash segment
    
      FCTL1 = FWKEY + WRT;                      // Set WRT bit for write operation
      FCTL2 = FWKEY + FSSEL0 + FN1; FCTL3 = FWKEY;
     // for (i=0; i<64; i++)
      //{
        *Flash_ptr1 = value;                   // Write value to flash
      //}
    
      FCTL1 = FWKEY;                            // Clear WRT bit
      FCTL3 = FWKEY + LOCK;                     // Set LOCK bit
    
    }
    
    
    

    Thank you for your fast answer ! :)


  • Try this function

    void write_SegC (char value)
    {
      //Step 1: Start Flash timming generator          
      FCTL2 = FWKEY + FSSEL0 + FN1;
      FCTL3 = FWKEY;                    // clr LOCK bit
      //Step 2: activate segment erase mode
      FCTL1 = FWKEY + ERASE;            
      //Step 3: Initialize Flash pointer
      Flash_ptr1 = (char *) 0x1040;              
      //Step 4: Dummy write to erase Flash segment
      *Flash_ptr1 = 0; 
    //-----------------Segment Earase Complete---------------------------                          
      //Step 5: Set WRT bit for write operation
      FCTL1 = FWKEY + WRT;                      
     // for (i=0; i<64; i++)
      //{
        *Flash_ptr1 = value;                   // Write value to flash
      //}
    
      FCTL1 = FWKEY;                            // Clear WRT bit
      FCTL3 = FWKEY + LOCK;                     // Set LOCK bit
    
    }

  • Some news! With your function (thank you), the variable *Flash_ptr1 has the right value after the save: the variable is correctly saved ! But, when I loose the power, the variable is set to decimal 255 instead of the value saved. I don't understand why....

    I think that we are really close to the result !

    Cordially,
    Doan Khai HO

  • its because, you are assigning a char type pointer to integer type variable.

    int hHeures; 
    int hMinutes; 
    int hSecondes; 
    // Flash pointer int
    char *Flash_ptr1; 
    char *Flash_ptr2;

    and in the main body

    hMinutes=*Flash_ptr1;

    so change "char2 pointer to "int" pointer and you will see what you need.

    or 

    "int"ariable to "char" variable.

  • Same situation ! If the power is kept, the *Flash_ptr1 has the right value (it means that the save is correctly done I think) but when the power is lost, the *Flash_ptr1 seems to be set at 0...

    May be the initialization is bad ?

    Thank you for your help, it is very nice !

    Cordially

    Doan Khai HO

  • if the data is lost after power down, therer is no sense in using flash then.
    Can you ppost complete code here. I will check it for you and see if there is any thing to be doen.

    mean while if u find answer for your self. Will you please close this thread by checking verify answer please.Thats helps other threads.

    :)

  • Here is the complete code !

    #include <msp430.h>
    #include<intrinsics.h>
    int test; int maj;
    int hHeures;
    int hMinutes;
                         // Flash pointer
    int hSecondes;
    
    int *Flash_ptr1;
    int *Flash_ptr2;
    void write_SegC (char value);
    void write_SegD (char value);
    int main(void) {
    
    //	Flash_ptr1 = (char *) 0x1040;
    	//Flash_ptr2 = (char *) 0x512;
    	P1DIR = 0x41;
    	// Port P1.2 (entrée 3v dispo) entrée  Port P1.3(reset) Entrée   //POUR TESTER ON MET la led 1 en sortie
    	P2DIR = 0x0F;							//Ports P2.0 (vert)P2.1(orange) et P2.2(rouge) P2.3 sortie 3v Sorties
    	P1OUT=0x00;
    	hHeures=0;
    	hMinutes=0;
    	//CONSTANTES
    	int xHeures1=0;  //limite LED VERTE
    	int xMinutes1=1;
    	int xHeures2=0;  //limite LED ORANGE
    	int xMinutes2=30;
    	int xHeures3=0;  //limite LED ROUGE
    	int xMinutes3=40;
     hMinutes=*Flash_ptr1; // here, i am supposed to read the flash memory when the power is back !
     //hHeures=*Flash_ptr2;
    
    	hSecondes=0;
    	// Stop watchdog timer
    	WDTCTL = WDTPW + WDTHOLD ; //Stop watchdog
    	BCSCTL2 = SELS; // SMCLK = LFXT1CLK (quartz)
    	TA0CTL = MC_1 + TASSEL_2 + TACLR; // Up_mode / SMCLK
    	CCTL0 = CCIE; // CCR0 interrupt enabled
    	CCR0 = 32768;
    	_BIS_SR(GIE); // Active les interruptions globales
    	maj=0;
    	while(1){
    		//hMinutes=*Flash_ptr1;
    		if (maj==1){
    			write_SegC(hMinutes);
    			//write_SegD(hHeures);
    			maj=0;
    		}
    		if ((P1IN & 0x80) == 0) {
    			P1OUT = 0x40;
    			if (hHeures<=xHeures1 && hMinutes<xMinutes1){
    				P2OUT=0x01;
    				test=1;
    			}
    			else if (hHeures<=xHeures2 && hMinutes<xMinutes2){
    				P2OUT=0x02;
    				test=2;
    			}
    			else if(hHeures<=xHeures3 && hMinutes<xMinutes3){
    				P2OUT=0x04;
    				test=3;
    			}
    			else {
    				P2OUT=0x0C;
    				test=4;
    			}
    		}
    		else {
    			hMinutes=0;
    			hHeures=0;
    			hSecondes=0;
    			write_SegC(5);
    			//write_SegD(0);
    			P1OUT = 0x01;
    		}
    	}
    }
    
    #pragma vector = TIMER0_A0_VECTOR
    __interrupt void Timer_A(void){
    	hSecondes=hSecondes+1;
    	if (hSecondes==10){
    		hMinutes=hMinutes+1;
    		if(hMinutes==1){
    			//maj=1;
    		}
    		hSecondes=0;
    		if (hMinutes==60){
    			hMinutes=0;
    			hHeures=hHeures+1;
    			//maj=1;
    		}
    	}
    	return;
    }
    void write_SegC (char value)
    {
      //Step 1: Start Flash timming generator
      FCTL2 = FWKEY + FSSEL0 + FN1;
      FCTL3 = FWKEY;                    // clr LOCK bit
      //Step 2: activate segment erase mode
      FCTL1 = FWKEY + ERASE;
      //Step 3: Initialize Flash pointer
      Flash_ptr1 = (int *) 0x1040;
      //Step 4: Dummy write to erase Flash segment
      *Flash_ptr1 = 0;
    //-----------------Segment Earase Complete---------------------------
      //Step 5: Set WRT bit for write operation
      FCTL1 = FWKEY + WRT;
     // for (i=0; i<64; i++)
      //{
        *Flash_ptr1 = value;                   // Write value to flash
      //}
      FCTL1 = FWKEY;                            // Clear WRT bit
      FCTL3 = FWKEY + LOCK;                     // Set LOCK bit
    }
    
    
    Of course when it will work, I will be happy to give my code, if it helps people who wants to do the same thing , it would make me happy! :)
    
    Cordially
    Doan Khai HO

  • Did you find something ? I really have to solve this problem in a very short time. 

    Thanks. 

  • At start of main, Flash_ptr1 is initialized to 0, so it points to 0x0000. Then you read from 0x0000, which is an SFR adn initialized at power-on. Only when you call write_SegC, the pointer is set to the address 0x1040, where it writes to. So the value is probably properly saved, you are just unable to read it because your read pointer is uninitialized when you try to read.

    In your previous version, Flash_ptr2 is initialized to address 0x512, which is vacant memory and not flash (at least on the G2553 - you don't write which MSP you actually use on the Gs LaunchPad.)

  • You only want to save two 16bit variables,
    saving every 30 minutes could wear out the flash in a few years so not recommended
    or if your vars are never 0xffff you could find the first empty spot so you only have to erase every 32nd times

    at boot-up, copy &0x1000 to var1 and copy &0x1002 to var2

    Clear the 64byte infoD segment right away to have that part over with
    mov.w   #FWKEY+FSSEL_1+FN1,&FCTL2 ; Timing generator = MCLK/3 (257 kHz to 476 kHz range)
    mov.w   #FWKEY,&FCTL3                         ; Unlock flash for erase
    mov.w   #FWKEY+ERASE,&FCTL1           ; Choose erase mode
    mov.w   #0,&0x1000                                   ; Erase segment
    mov.w   #FWKEY+LOCK,&FCTL3            ; Lock flash memory

    At power failure, copy var1 to &0x1000  and copy var2 to &0x1002 
    mov.w  #FWKEY+FSSEL_1+FN1,&FCTL2 ; Timing generator = MCLK/3
    mov.w  #FWKEY+WRT,&FCTL1                ; Write bit = 1
    mov.w  #FWKEY,&FCTL3                          ; Lock = 0  allow flash writes 
    mov.w  &myvar1,&0x1000
    mov.w  &myvar2,&0x1002
    mov.w  #FWKEY+LOCK,&FCTL3             ; Lock = 1 (stop flash writing)

  • I did those modifications but it s still not working : 

    #include <msp430g2453.h>
    #include<intrinsics.h>
    //Variables globales: portée maximale
    int test; int maj;
    int hHeures;
    int hMinutes;
                         // Flash pointer
    int hSecondes;
    
    int *Flash_ptr1;	// pointeur vers la variable rangée dans la mémoire permanante  (Minutes)
    int *Flash_ptr2; //(HEures)
    void write_SegC (char value); // fonction pour écrire les mintues dans la mémoire
    void write_SegD (char value);  // fonction pour écrire les heures dans la mémoire
    int main(void) {
    
    
    	P1DIR = 0x41;
    	// Port P1.2 (entrée 3v dispo) entrée  Port P1.7(reset) Entrée   //POUR TESTER ON MET la led 1 en sortie
    	P2DIR = 0x0F;							//Ports P2.0 (vert)P2.1(orange) et P2.2(rouge) P2.3 sortie 3v Sorties
    	P1OUT=0x00;
    	hHeures=0; //initialisation
    	hMinutes=0;
    	//CONSTANTES
    	int xHeures1=0;  //limite fin LED VERTE
    	int xMinutes1=1;
    	int xHeures2=0;  //limite LED ORANGE
    	int xMinutes2=30;
    	int xHeures3=0;  //limite LED ROUGE
    	int xMinutes3=40;
     hMinutes=*Flash_ptr1; //donner à la valeur des minutes la valeur sauvegardée dans le flash. Pour l'instant, les heures ne sont pas codés.
     //hHeures=*Flash_ptr2;
    
    	hSecondes=0;
    	// Stop watchdog timer
    	WDTCTL = WDTPW + WDTHOLD ; //Stop watchdog
    	BCSCTL2 = SELS; // SMCLK = LFXT1CLK (quartz)
    	TA0CTL = MC_1 + TASSEL_2 + TACLR; // Up_mode / SMCLK
    	CCTL0 = CCIE; // CCR0 interrupt enabled
    	CCR0 = 32768;
    	_BIS_SR(GIE); // Active les interruptions globales
    	maj=0; //maj = sauvegarder
    	while(1){
    		//hMinutes=*Flash_ptr1;
    		if (maj==1){ //on sauvegarde quand maj=1
    			write_SegC(hMinutes); //écriture dans la mémoire des minutes
    			//write_SegD(hHeures);
    			maj=0;
    		}
    		if ((P1IN & 0x80) == 0) {//si le reset n'est pas activé
    			P1OUT = 0x40;
    			if (hHeures<=xHeures1 && hMinutes<xMinutes1){ //LED VERTE
    				P2OUT=0x01;
    				test=1;
    			}
    			else if (hHeures<=xHeures2 && hMinutes<xMinutes2){ //LED ORANGE
    				P2OUT=0x02;
    				test=2;
    			}
    			else if(hHeures<=xHeures3 && hMinutes<xMinutes3){ //LED VERTE
    				P2OUT=0x04;
    				test=3;
    			}
    			else {//LED ROUGE + sortie 12v
    				P2OUT=0x0C;
    				test=4;
    			}
    		}
    		else {//Si reset activé, on met tout à zéro, et on sauvegarde
    			hMinutes=0;
    			hHeures=0;
    			hSecondes=0;
    			write_SegC(5); // mettre 0 au lieu de 5. Le 5 permet de vérifier si la sauvegarde a été faite. après la perte de courant, la LED orange doit s'allumer (5 minutes => LED ORANGE)
    			//write_SegD(0);
    			P1OUT = 0x01;
    		}
    		if ((P1IN & 0x04)==!0) {// Si perte de courant.
    						P2OUT=0x00; // on coupe les LEDS pour économiser les piles
    						maj=1; //ordre pour sauvegarder.
    					}
    	}
    }
    
    #pragma vector = TIMER0_A0_VECTOR //chaque seconde, le programme va là pour incrémenter les variables
    __interrupt void Timer_A(void){
    	hSecondes=hSecondes+1;
    	if (hSecondes==10){
    		hMinutes=hMinutes+1;
    		if(hMinutes==1){//quand la sauvegarde fonctionnera, enlever les commentaires pour les maj
    			//maj=1;
    		}
    		hSecondes=0;
    		if (hMinutes==60){
    			hMinutes=0;
    			hHeures=hHeures+1;
    			//maj=1;
    		}
    	}
    	return;
    }
    void write_SegC (char value) // ici c'est le bordel, demander au mec sur internet.
    {
      //Step 1: Start Flash timming generator
      FCTL2 = FWKEY + FSSEL0 + FN1;
      FCTL3 = FWKEY;                    // clr LOCK bit
      //Step 2: activate segment erase mode
      FCTL1 = FWKEY + ERASE;
      //Step 3: Initialize Flash pointer
      Flash_ptr1 = (int *) 0x1040;
      //Step 4: Dummy write to erase Flash segment
      *Flash_ptr1 = 0;
    //-----------------Segment Earase Complete---------------------------
      //Step 5: Set WRT bit for write operation
      FCTL1 = FWKEY + WRT;
     // for (i=0; i<64; i++)
      //{
        *Flash_ptr1 = value;                   // Write value to flash
      //}
      FCTL1 = FWKEY;                            // Clear WRT bit
      FCTL3 = FWKEY + LOCK;                     // Set LOCK bit
    }
    void write_SegD (char value)
    {
                                // Flash pointer
    
    
      //Flash_ptr2 = (char *) 0x512;              // Initialize Flash pointer
      FCTL1 = FWKEY + ERASE;                    // Set Erase bit
      FCTL3 = FWKEY;                            // Clear Lock bit
      *Flash_ptr2 = 0;                           // Dummy write to erase Flash segment
    
      FCTL1 = FWKEY + WRT;                      // Set WRT bit for write operation
    
     // for (i=0; i<64; i++)
      //{
        *Flash_ptr2 = value;                   // Write value to flash
      //}
    
      FCTL1 = FWKEY;                            // Clear WRT bit
      FCTL3 = FWKEY + LOCK;
      // Set LOCK bit
    
    }

  • Have you found the reason that this code is not working. I have the same problem where FLASH is not retaining the values written before system reset. I checked the memory places before and after writing to FLASH and the FLASH content changes after writing but after system reset there are just 0xFF values. The code is in development phase but it should be functional at this stage according to datasheets and testing (before system reset). I am using MSP430F2274 MCU.

           

    static uint8_t sega1;
            static uint8_t sega2;
            static uint8_t segb1;
            static uint8_t segb2;
            static uint8_t segc1;
            static uint8_t segc2;
            static uint8_t segd1;
            static uint8_t segd2;
            memcpy(&sega1, (uint8_t*) 0x10C0, 1);
            memcpy(&sega2, (uint8_t*) 0x10C1, 1);
            memcpy(&segb1, (uint8_t*) 0x1080, 1);
            memcpy(&segb2, (uint8_t*) 0x1081, 1);
            memcpy(&segc1, (uint8_t*) 0x1040, 1);
            memcpy(&segc2, (uint8_t*) 0x1041, 1);
            memcpy(&segd1, (uint8_t*) 0x1000, 1);
            memcpy(&segd2, (uint8_t*) 0x1001, 1);
            /* modify segB */
            if(FLASH_OK != hal_flash_erase_segment((uint16_t*) 0x1080)){
                /* error */
            }
            hal_flash_write_byte((uint8_t *) 0x1080, 0x00);
            hal_flash_write_byte((uint8_t *) 0x1081, 0x00);
            /* modify segC */
            if(FLASH_OK != hal_flash_erase_segment((uint16_t*) 0x1040)){
                /* error */
            }
            hal_flash_write_byte((uint8_t *) 0x1040, 0x00);
            hal_flash_write_byte((uint8_t *) 0x1041, 0x00);
            /* modify segD */
            if(FLASH_OK != hal_flash_erase_segment((uint16_t*) 0x1000)){
                /* error */
            }
            hal_flash_write_byte((uint8_t *) 0x1000, 0x00);
            hal_flash_write_byte((uint8_t *) 0x1001, 0x00);
            //        lib_sega_writesega(seg);
            memcpy(&sega1, (uint8_t*) 0x10C0, 1);
            memcpy(&sega2, (uint8_t*) 0x10C1, 1);
            memcpy(&segb1, (uint8_t*) 0x1080, 1);
            memcpy(&segb2, (uint8_t*) 0x1081, 1);
            memcpy(&segc1, (uint8_t*) 0x1040, 1);
            memcpy(&segc2, (uint8_t*) 0x1041, 1);
            memcpy(&segd1, (uint8_t*) 0x1000, 1);
            memcpy(&segd2, (uint8_t*) 0x1001, 1);
    
    
    hal_flash_status_t hal_flash_erase_segment(uint16_t* addr){
        /* disable watchdog */
        uint8_t wdt_set = 0;
        if(!(WDTCTL & WDTHOLD)){
            WDTCTL |= WDTPW | WDTHOLD;
            wdt_set = 1;
        }
        /* wait for flash to be free (not busy) */
        while(FCTL3 & BUSY){
        }
        /* set flash controller clock to ~300kHz */
        uint8_t prescaler = (uint8_t) ((1000) / 300);//((CPU_CLK * 1000) / 300);
        /* select MCLK for clock source */
        FCTL2 = FWKEY | FSSEL_1 | (0x003F & prescaler);
        /* clear LOCK */
        FCTL3 = FWKEY;
        /* enable erase */
        FCTL1 = FWKEY | ERASE;
        /* dummy write to initiate erase */
        addr = 0;
        /* wait for flash to be free (not busy) */
        while(FCTL3 & BUSY){
        }
        /* set lock */
        FCTL3 = FWKEY | LOCK;
        /* enable wdt if it was enabled before */
        if(wdt_set){
            WDTCTL = WDTPW;
        }
    
        return FLASH_OK;
    }
    
    
    hal_flash_status_t hal_flash_write_byte(uint8_t* addr, uint8_t data){
        /* disable watchdog */
        uint8_t wdt_set = 0;
        if(!(WDTCTL & WDTHOLD)){
            WDTCTL |= WDTPW | WDTHOLD;
            wdt_set = 1;
        }
        /* wait for flash to be free (not busy) */
        while(FCTL3 & BUSY){
        }
        /* set flash controller clock to ~300kHz */
        uint8_t prescaler = (uint8_t) ((1000) / 300);//((CPU_CLK * 1000) / 300);
        /* select MCLK for clock source */
        FCTL2 = FWKEY | FSSEL_1 | (0x003F & prescaler);
        /* clear LOCK */
        FCTL3 = FWKEY;
        /* enable write */
        FCTL1 = FWKEY | WRT;
        /* dummy write to initiate erase */
        *addr = data;
        /* wait for flash to be free (not busy) */
        while(FCTL3 & BUSY){
        }
        /* set lock */
        FCTL3 = FWKEY | LOCK;
        /* enable wdt if it was enabled before */
        if(wdt_set){
            WDTCTL = WDTPW;
        }
    
        return FLASH_OK;
    }

    Best regards,

    --

    Klemen

  • Found the problem in my setup! I was performing system reset with debugger and reprogramming the chip. Before loading flash I was without knowing performing complete erase including the infomem, so I just changed the erase call in programming script and the problem was solved. I need to check the segmentA functioning (some problems).

    Best regards,
    --
    Klemen
  • I have also found a mistake in function hal_flash_erase_segment at the point, where the dummy byte should be written to memory

    Wrong use of pointers:
    /* dummy write to initiate erase */
    addr = 0;
    
    Fixed problem:
    /* dummy write to initiate erase */
    *addr = 0;

  • /* disable watchdog */
    uint8_t wdt_set = 0;
    if(!(WDTCTL & WDTHOLD)){
    WDTCTL |= WDTPW | WDTHOLD;

    What is up with that?
    Just set it as HOLD and get over with it, no need to check it first.
    Don't use |= with password protected registers, always use =
    Though there is a different xor-password for those rare use of toggle (^=)

    Why use memcopy for single bytes?, Why use 3 different infoblocks for 2 bytes each?
    I would set up a typedef struct, then put one in in ram and one bckup in info, and then struct copy. (IAR is easier to set forced memory location)

    addr = 0;
    The compiler did not error/warn about that?

    As the only way to override the error/warning of you trying to change the pointer-address would be to cast the value zero as a pointer: 
    addr = (char*)0;
    That is why C forces you to declare var as pointers so they can only be changed/passed to functions by other pointers.

  • Tony, I think the compiler won't give you a warning if you assign a numeric constant to a pointer variable.
    If you want to assign a variable to a pointer, it would.

**Attention** This is a public forum