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.

CCS/MSP430G2553: write/read into information memory - the right way

Part Number: MSP430G2553

Tool/software: Code Composer Studio

Hi Everybody,

about information memory. the memory is byte addressable (i think)

it has 4 segments, each segment has 64 bytes (256 bytes overall).

it starts wth address: 0x1000 (segment D).  so if  i put a char (byte size) into this address. the next address to be available is 0x1001

and if after that i put a short (2 bytes), the next available address is  0x1003

if what i said is right, so why my code below not working correctly?

#include <msp430g2553.h>

#define END_OF_FLASH 0x0FFFF

void WriteCharToFlash(char* Flashptr, char val);
void WriteLongToFlash(long* Flashptr, long val);
void ReadCharFromFlash(char* address, char* val);
void ReadLongFromFlash(long* address, long* val);
void ClearAllFlash();

int main(void) {
	WDTCTL = WDTPW + WDTHOLD;
	BCSCTL1 = CALBC1_1MHZ;                    // Set DCO to 1MHz
	DCOCTL = CALDCO_1MHZ;
	FCTL2 = FWKEY + FSSEL0 + FN1;

	long val;
	char val2;
	ClearAllFlash();
	WriteCharToFlash((char *) 0x01000, '2');
	ReadCharFromFlash((char *) 0x01000, &val2);
	WriteLongToFlash((long *) 0x01001, 1234567);
	ReadLongFromFlash((long *) 0x01001, &val);

	ReadLongFromFlash((long *) 0x01001, &val);
	ReadCharFromFlash((char *) 0x01000, &val2);
	return 0;
}


void WriteLongToFlash(long* address, long val)
{
	long* flash_ptr;
	flash_ptr = address; // Initialize Flash pointer
	FCTL1 = FWKEY + ERASE;                    // Set Erase bit
	FCTL3 = FWKEY;                            // Clear Lock bit
	*flash_ptr = 0;
	while(FCTL3 & BUSY);
	FCTL1 = FWKEY + WRT;
	*flash_ptr = val;
	while(FCTL3 & BUSY);
	FCTL1 = FWKEY;                            // Clear WRT bit
	FCTL3 = FWKEY + LOCK;                     // Set LOCK bit
}

void ReadLongFromFlash(long* address, long* val)
{
	long* flash_ptr;
	flash_ptr = address;
	*val = *flash_ptr;
}

void WriteCharToFlash(char* address, char val)
{
	char* flash_ptr;
	flash_ptr = address; // Initialize Flash pointer
	FCTL1 = FWKEY + ERASE;                    // Set Erase bit
	FCTL3 = FWKEY;                            // Clear Lock bit
	*flash_ptr = 0;
	FCTL1 = FWKEY + WRT;
	*flash_ptr = val;
	FCTL1 = FWKEY;                            // Clear WRT bit
	FCTL3 = FWKEY + LOCK;                     // Set LOCK bit
}

void ReadCharFromFlash(char* address, char* val)
{
	char* flash_ptr;
	flash_ptr = address;
	*val = *flash_ptr;
}

void ClearAllFlash()
{
	char *flash_ptr;                         // Segment D pointer
	flash_ptr = (char *) 0x1000;             // Initialize Flash segment D pointer
	FCTL1 = FWKEY + MERAS;                    // Set Mass Erase bit
	FCTL3 = FWKEY;                            // Clear Lock bit
	*flash_ptr = 0;                          // Dummy write to erase Flash segment D
	FCTL1 = FWKEY + WRT;                      // Set WRT bit for write operation
	FCTL1 = FWKEY;                            // Clear WRT bit
	FCTL3 = FWKEY + LOCK;
}

  • Data writing to flash should be aligned. You can write/read byte to 0x1000, 0x1001, 0x1002... word to 0x1000, 0x1002, 0x1004...
    Of course you can update your function to correctly write/read long to/from 0x1001 by shiftings, but don't see any point/reason for this.
    Your write function will erase all block (0xFFFF values), before write. Function ClearAllFlash will erase all main flash including your program.

  • thank you for your help,

    from what i'm understanding, if i don't want my program (code and data) to be erase, not to use ClearAllFlash

    from what you said i put the data in the right place

    so why i'm getting wrong values?

    in the code, i write char 2 into 0x01000 and read it , it' returns 2 

    after that, i write long 1234567 into 0x01001 and read it, it returns 1234567

    so far, like it should be.

    but, if i read address 0x01000 again i'm not getting 2, getting something else.

    and i don't understand why

  • The MSP430 does not allow unaligned memory accesses. When you try to write a value larger than 8 bits to address 0x1001, something unpredictable happenes. (In your case, the CPU apparently accesses 0x1000 instead.)

    Please note that all your Write functions erase the entire segment, so they also erase any values put into the same segment by any earlier Write call.
  • thank you for the reply,

    on the write part of the char and long i erase the erase lines and set a new main here's part of the code:

    int main(void) {
    	WDTCTL = WDTPW + WDTHOLD;
    	BCSCTL1 = CALBC1_1MHZ;                    // Set DCO to 1MHz
    	DCOCTL = CALDCO_1MHZ;
    	FCTL2 = FWKEY + FSSEL0 + FN1;
    
    	long val;
    	char val2;
    	char val3;
    	ClearAllFlash();
    	WriteCharToFlash((char *) 0x01040, '2');
    	WriteLongToFlash((long *) 0x01039, 1234567);
    	WriteCharToFlash((char *) 0x01035, '5');
    
    	ReadCharFromFlash((char *) 0x01040, &val2);
    	ReadLongFromFlash((long *) 0x01039, &val);
    	ReadCharFromFlash((char *) 0x01035, &val3);
    
    	return 0;
    }
    
    
    void WriteLongToFlash(long* address, long val)
    {
    	long* flash_ptr;
    	flash_ptr = address; // Initialize Flash pointer
    	while(FCTL3 & BUSY);
    	FCTL1 = FWKEY + WRT;
    	*flash_ptr = val;
    	while(FCTL3 & BUSY);
    	FCTL1 = FWKEY;                            // Clear WRT bit
    	FCTL3 = FWKEY + LOCK;                     // Set LOCK bit
    }

    I started with segment C

    putting charon 0x01040 takes the following addresses: 0x01040
    putting long on 0x01039 takes the following addresses: 0x01039, 0x01038, 0x01037, 0x01036
    putting char on 0x01036 takes the following addresses: 0x01035

    but only the last parameter gets the correct value.

    so i don't know what i'm missing

  • What are the values that you read?
  • hex (dec.)
    val2 = 0xFF (255)
    val = 0xFFFFFFFF(-1)
    val3 = 0x35 (5)
  • The other values got erased.
  • i don't understand how? do i write to an unaccessable address?
    maybe because the ClearAllFlash? but it is at the start of the code
  • Show the entire code. Change the values to ensure that you're running the new code.
  • I've changed the values but when i ran the code... the data didn't written or read

    here's the full code, and thank you for your help

    #include <msp430g2553.h>
    
    void WriteCharToFlash(char* Flashptr, char val);
    void WriteLongToFlash(long* Flashptr, long val);
    void ReadCharFromFlash(char* address, char* val);
    void ReadLongFromFlash(long* address, long* val);
    void ClearAllFlash();
    
    int main(void) {
    	WDTCTL = WDTPW + WDTHOLD;
    	BCSCTL1 = CALBC1_1MHZ;                    // Set DCO to 1MHz
    	DCOCTL = CALDCO_1MHZ;
    	FCTL2 = FWKEY + FSSEL_3 + FN1;
    
    	long val;
    	char val2;
    	char val3;
    	//ClearAllFlash();
    	WriteCharToFlash((char *) 0x01040, '4');
    	WriteLongToFlash((long *) 0x01039, 54321);
    	WriteCharToFlash((char *) 0x01035, '7');
    
    	ReadCharFromFlash((char *) 0x01040, &val2);
    	ReadLongFromFlash((long *) 0x01039, &val);
    	ReadCharFromFlash((char *) 0x01035, &val3);
    
    	return 0;
    }
    
    
    void WriteLongToFlash(long* address, long val)
    {
    	long* flash_ptr;
    	flash_ptr = address; // Initialize Flash pointer
    	while(FCTL3 & BUSY);
    	FCTL1 = FWKEY + WRT;
    	*flash_ptr = val;
    	while(FCTL3 & BUSY);
    	FCTL1 = FWKEY;                            // Clear WRT bit
    	FCTL3 = FWKEY + LOCK;                     // Set LOCK bit
    }
    
    void ReadLongFromFlash(long* address, long* val)
    {
    	while(FCTL3 & BUSY);
    	long* flash_ptr;
    	flash_ptr = address;
    	*val = *flash_ptr;
    }
    
    void WriteCharToFlash(char* address, char val)
    {
    	char* flash_ptr;
    	flash_ptr = address; // Initialize Flash pointer
    	while(FCTL3 & BUSY);
    	FCTL1 = FWKEY + WRT;
    	*flash_ptr = val;
    	while(FCTL3 & BUSY);
    	FCTL1 = FWKEY;                            // Clear WRT bit
    	FCTL3 = FWKEY + LOCK;                     // Set LOCK bit
    }
    
    void ReadCharFromFlash(char* address, char* val)
    {
    	while(FCTL3 & BUSY);
    	char* flash_ptr;
    	flash_ptr = address;
    	*val = *flash_ptr;
    }
    
    void ClearAllFlash()
    {
    	char *flash_ptr;                         // Segment D pointer
    	flash_ptr = (char *) 0x1000;             // Initialize Flash segment D pointer
    	FCTL1 = FWKEY + MERAS;                    // Set Mass Erase bit
    	FCTL3 = FWKEY;                            // Clear Lock bit
    	*flash_ptr = 0;                          // Dummy write to erase Flash segment D
    	FCTL1 = FWKEY + WRT;                      // Set WRT bit for write operation
    	FCTL1 = FWKEY;                            // Clear WRT bit
    	FCTL3 = FWKEY + LOCK;
    }
    

  • Erasing sets all bits to 1. Programming (writing) sets some bits to 0. If you do not erase at all, you cannot change any bit to 1.

    The MERAS bit stands for "mass erase" and erases all main memory segments. You probably want to use the ERASE bit instead.

    (See section 7.3.2 of the User's Guide.)
  • Joe Shoshana said:

    I've changed the values but when i ran the code... the data didn't written or read

    here's the full code, and thank you for your help

    	//ClearAllFlash();
    	WriteCharToFlash((char *) 0x01040, '4');
    	WriteLongToFlash((long *) 0x01039, 54321);
    	WriteCharToFlash((char *) 0x01035, '7');
    
    	ReadCharFromFlash((char *) 0x01040, &val2);
    	ReadLongFromFlash((long *) 0x01039, &val);
    	ReadCharFromFlash((char *) 0x01035, &val3);
    


    You can't write long value to 0x1039 (flash or RAM, whatever).
  • I made some changes:

    1. in the write functions i forgot to unlock the FWKEY so i added it.

    2. i added an erase function:

    void EraseSegment(char* flash_ptr)
    {
    	FCTL3 = FWKEY;                            // Clear Lock bit
    	FCTL1 = FWKEY + ERASE;                    // Set Erase bit
    	*flash_ptr = 0;
    	FCTL1 = FWKEY;                            // Clear WRT bit
    	FCTL3 = FWKEY + LOCK;                     // Set LOCK bit
    }

    i change from long to char and rearrange the addreses to be aligned here's the main:

    int main(void) {
    	WDTCTL = WDTPW + WDTHOLD;
    	BCSCTL1 = CALBC1_1MHZ;                    // Set DCO to 1MHz
    	DCOCTL = CALDCO_1MHZ;
    	FCTL2 = FWKEY + FSSEL_3 + FN1;
    
    	char val;
    	char val2;
    	char val3;
    	EraseSegment((char*) 0x1040);
    	WriteCharToFlash((char *) 0x01040, '1');
    	WriteCharToFlash((char *) 0x01039, '3');
    	WriteCharToFlash((char *) 0x01038, '5');
    
    	ReadCharFromFlash((char *) 0x01040, &val2);
    	ReadCharFromFlash((char *) 0x01039, &val);
    	ReadCharFromFlash((char *) 0x01038, &val3);
    
    	return 0;
    }
    

    but still val 3 and val 5 are not saved

    another thing, how do you suggest to save long value? divide into 2 words?

    and what about short? is a 2 byte (word) it can be written?

  • You are erasing the information memory segment that contains the address 0x1040, i.e., the segment from 0x1040 to 0x107F. You are writing the other two values to non-erased flash.
  • Joe Shoshana said:

    another thing, how do you suggest to save long value? divide into 2 words?

    and what about short? is a 2 byte (word) it can be written?

    If you need (because of some special reason) to write word / long to unaligned address, than you can split it in bytes, and use multiple byte write with address increment.
    Standard way is to write word to 0x1040, 0x1042, 0x1044... and to split long to two words and write it with double address increment.
  • … and to split long to two words

    The compiler does this automatically. You need to care about this only if the order of the two writes is important.

  • Thank you for your help,

    In the past week, i tried to write into main memory. i succeded to write into the main memory, but i always needed a 2 byte address to write into (doesn't matter if char or short). but when i tried to change it at runtime it won't change anything. everytime i call saveparameters function i call loadparameters to see if the parameters are saved.

    i tried to do the same in information memory but still failed to change at run time.

    here's the code with the information memory with only one parameter (same code in main memory)

    void LoadParameters()
    {
    	short m1,m2;
    	ReadFromFlash((char*)0x1040,(char*)&cnt_by_idx);// Count_By
    	if( cnt_by_idx < 0 || cnt_by_idx > COUNT_BY_ARR_LEN - 1)
    		cnt_by_idx = 3;
    }
    
    void SaveParameters()
    {
    	WriteToFlash((char*)0x1040,(char)cnt_by_idx);// Count_By
    }
    
    void WriteToFlash(char* address, char val)
    {
    	char* flash_ptr;
    	FCTL3 = FWKEY;
    	flash_ptr = address;              // Initialize Flash pointer
    	while(FCTL3 & BUSY);
    	FCTL1 = FWKEY + WRT;
    	*flash_ptr = val;
    	while(FCTL3 & BUSY);
    	FCTL1 = FWKEY;                            // Clear WRT bit
    	FCTL3 = FWKEY + LOCK;                     // Set LOCK bit
    }
    
    void ReadFromFlash(char* address, char* val)
    {
    	char* flash_ptr;
    	flash_ptr = address;
    	while(FCTL3 & BUSY);
    	*val = *flash_ptr;
    }

  • Here you can find source code for writing only one byte...

    https://www.embeddedrelated.com/showthread/msp430/20061-1.php

    If this is not what you want, search. I am sure that Google will find 100 flash write working examples.

  • please check your memory adresses:
    Segment D goes from 0x1000 to 0x103F
    Segmend C goes from 0x1040 to 0x 107F

    You are erasing Segment D (but commentet out in your code above)

    variable val is in Segment C (0x1040!)
    variable val2 goes over the border between Segment D and Segment D (0x1039..0x1042, the adresses count upwards)
    variable val3 is correct in Segment D (0x1035), therefore this ist the only value you can read.
  • in general, it is not good to work with hard-coded adresses. I found out a better apoach to work with Information memory, because the linker knows were the information memory is located.

    try to do the following (i assume you use CCS):

      #pragma DATA_SECTION(myValue , ".infoD")

      int myValue;

    or if you have more than one value to store:

    #pragma SET_DATA_SECTION(".infoD")
    int myValue_1;
    long myValue_2;
    char myValue_3;
    //... not more than 64 bytes, every datatype is allowed
    #pragma SET_DATA_SECTION("")

    if you want to write to these values, you can use your write-function in this way:

    WriteCharToFlash(&myValue3, char_value_to_write)

    You need a different write-Funktion for each datatype,
    but you don't need any read-function, you can just use that variable.

    I do it a little bit shorter:

    void writeWord(void *Flash_ptr, int value)
    {
    	unsigned int *tmp_ptr; //format to write, only this line you must change for each datatype
    	FCTL3 = FWKEY; // Clear Lock bit
    	FCTL1 = FWKEY + WRT; // Set WRT bit for write operation
    	tmp_ptr = Flash_ptr;  //cast void* to uint*
    	*tmp_ptr = value; // Write value to flash
    	FCTL1 = FWKEY; // Clear WRT bit
    	FCTL3 = FWKEY + LOCK; // Set LOCK bit
    }

    if you want to erase this segment, just pick one of the variable inside:
    eraseSegment(&val_1);

    void eraseSegment (void *pointer)
    {
        char *seg_pointer;

        seg_pointer = pointer;
        FCTL1 = FWKEY + ERASE; // Set Erase bit
        FCTL3 = FWKEY; // Clear Lock bit
        *seg_pointer = 0; // Dummy write to erase Flash segment
        FCTL1 = FWKEY; // Clear Erase bit
        FCTL3 = FWKEY + LOCK; // Set LOCK bit
    }

    the information I used for this comes from
    www.ti.com/.../getliterature.tsp



**Attention** This is a public forum