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.

Saving different variables types to flash memory

Other Parts Discussed in Thread: MSP430F5310, TEST2, MSP430F5309, MSP430G2553

Hello,

I am interested in saving long-type variables into flash memory, and retrieving these values at a later time. According to my understanding, the register addresses are 16-bit integers, so pointers to these registers should be of type int. Long type variables are 32-bit. However, I believe most MSP430's can only write to registers 16 bits at a time, and therefore some manipulation must be done in order to save long-type variables to flash as well as to read these variables from flash memory.

Below is my attempt to do so, and I would appreciate any feedback if there is a flaw in my approach/understanding, or if there is a better way to do this.  Thanks in advance.

---------------------------------------
#define DATA_IN_FLASH 120

#include <msp430f5310.h>

/*************************************************************************************************/
/********************** Variables to be saved to / loaded from flash memory **********************/

volatile static unsigned long Test1 = 131071;
volatile static signed long Test2 = -131072;
volatile static signed int Test3 = -1310;
volatile static signed char Test4 = -31;

/********************** Variables to be saved to / loaded from flash memory **********************/
/*************************************************************************************************/


/******** Flash Memory Addresses ********/
int* Data_In_Flash = (int*) 0xf000;
int* Test1_Flash = (int*) 0xf002;
int* Test2_Flash = (int*) 0xf00a;
int* Test3_Flash = (int*) 0xf012;
int* Test4_Flash = (int*) 0xf016;
/******** Flash Memory Addresses ********/


// Functions
void WriteFlashEntry(int* address, int data);
void EraseFlash(int addr);
void Write_Flash(void);
void readFlashSegment(void);

void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
UCSCTL3 = SELREF_2; // Set DCO FLL reference = REFO
UCSCTL4 |= SELA_2; // Set ACLK = REFO
UCSCTL0 = 0x0000; // Set lowest possible DCOx, MODx

// Loop until XT1,XT2 & DCO stabilizes - In this case only DCO has to stabilize
do
{
UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG);
// Clear XT2,XT1,DCO fault flags
SFRIFG1 &= ~OFIFG; // Clear fault flags
}while (SFRIFG1&OFIFG); // Test oscillator fault flag

__bis_SR_register(SCG0); // Disable the FLL control loop
UCSCTL1 = DCORSEL_5; // Select DCO range 16MHz operation
UCSCTL2 |= 249; // Set DCO Multiplier for 8MHz
// (N + 1) * FLLRef = Fdco
// (249 + 1) * 32768 = ~8MHz
__bic_SR_register(SCG0); // Enable the FLL control loop

// Worst-case settling time for the DCO when the DCO range bits have been
// changed is n x 32 x 32 x f_MCLK / f_FLL_reference. See UCS chapter in 5xx
// UG for optimization.
// 32 x 32 x 8 MHz / 32,768 Hz = 250000 = MCLK cycles for DCO to settle
__delay_cycles(250000);

if (*Data_In_Flash == DATA_IN_FLASH) {
EraseFlash(0xf000);
Write_Flash();
}

while (1) {
}

}

void Write_Flash(void) {
WriteFlashEntry(Data_In_Flash, DATA_IN_FLASH);
WriteFlashEntry(Test1_Flash, Test1 & 0x0000FFFF);
WriteFlashEntry(Test1_Flash + 4, (Test1 & 0xFFFF0000) >> 16);
WriteFlashEntry(Test2_Flash, Test2 & 0x0000FFFF);
WriteFlashEntry(Test2_Flash + 4, (Test2 & 0xFFFF0000) >> 16);
WriteFlashEntry(Test3_Flash, Test3);
WriteFlashEntry(Test4_Flash, Test4);
}

void readFlashSegment() { //writes all three channels to their respective flash memory locations
Test1 = (*Test1_Flash) + ( ( (long)(*(Test1_Flash + 4)) ) << 16);
Test2 = (*Test2_Flash) + ( ( (long)(*(Test2_Flash + 4)) ) << 16);
Test3 = *Test3_Flash;
Test4 = *Test4_Flash;
}

void WriteFlashEntry(int* address, int data) // Write the individual (integer) data to the flash address.
{
while ((BUSY & FCTL3)) ;
FCTL3 = FWKEY; // Unlock the flash.
FCTL1 = FWKEY + WRT; // Enable flash write.
*address = data; // Write the data to the flash.
while ((BUSY & FCTL3)) ;
FCTL1 = FWKEY; // Disable flash write.
FCTL3 = FWKEY + LOCK; // Lock the flash.
}

void EraseFlash(int addr) {
int* address = (int *) addr;
while ((BUSY & FCTL3)) ;
FCTL1 = FWKEY + ERASE; // Enable flash write.
FCTL3 = FWKEY; // Unlock the flash.
*address = 0x00; // Write the data to the flash.
while ((BUSY & FCTL3)) ;
FCTL1 = FWKEY; // Disable flash write.
FCTL3 = FWKEY + LOCK; // Lock the flash.
}
---------------------------------------

Sincerely,

Mehdi

  • When you want to write some data to computer's hard drive - what you do? - You put it into buffer and write it using single write() call. Same here. Put those longs into structure which will be "data block", create flash write routine with RAM data source pointer, destination flash area pointer and size of data to write as parameters. Function call in result shall look like:  FlashWrite(&structoflongs, Data_In_Flash, sizeof(structoflongs);

  • Flash memory is usually "binary". But when you have FCTL2 register, you can actually create bits that are neither "one" nor "zero". A horse of an entirely different color, or "variable of a different type", if you like to call it that way.

  • old_cow_yellow said:

    Flash memory is usually "binary". But when you have FCTL2 register, you can actually create bits that are neither "one" nor "zero". A horse of an entirely different color, or "variable of a different type", if you like to call it that way.

    Hopefully this is not a joke :) Please explain what you mean. Better with example.

  • I am sure what I said was true. If the Flash clock is way too high, you end up with Flash bits being neither "0" nor "1".

    I am not sure this is the subject you asked. Thus the color of the horse metaphor.

  • old_cow_yellow said:
    If the Flash clock is way too high, you end up with Flash bits being neither "0" nor "1".

    Another way of thinking of that, is if the flash is erased / programmed outside of the datasheet specifications then the flash contents may not be reliable, i.e. reading the flash contents may not always return the same value.

    While I haven't tried to abuse the flash in MSP430 devices, with other flash devices I have seen that if an erase operation was aborted before it had completed, then repeatidly reading the same address bits could either read as a "0" or "1".

  • ILMARS JARGANS said:

    Function call in result shall look like:  FlashWrite(&structoflongs, Data_In_Flash, sizeof(structoflongs);

    As I understand, you are saying that the function that writes data to the flash memory should take all parameters into account.  I agree with this, as it is more intelligent in terms of code design.  If I understand correctly, based on the sizeof parameter, the function will choose to either save as a long (which will take up 4 address registers), or to save as an int/char (which will take up 2 address registers -- even though a char needs only one register, the MSP430 will still occupy 2 by leaving one blank).  If I am correct so far, was my original approach correct?  That is, writing the first 16 bits, and then the next 16 bits?  Is there a shorter way to do this in C?

    Thanks for the help.

    Sincerely,

    Mehdi

  • Mehdi Rahman said:
    some manipulation must be done in order to save long-type variables to flash as well as to read these variables from flash memory.

    If you pass a reference to the value and not the value itself, a reference to a long variable is the same as a reference to an array of long variables of the size 1, and array of INT variable of size 2 or an array of CHAR with size 4.
    You can cast one into the other.

    So don't pass data as a value to your write function, rather pass a const void * pointer to data and the size of data. Hten teh write funciton can divide the size by two for word writes, cast the const void * to const int * and write the data as word values. In case of an odd number of bytes, the write function may detect this and do the last write in byte write mode.

    BTW: OCY didn't actually make a joke: most flash cells are (cheap) multilevel cells. Each flash cell storing more than one bit. And in theory, you can use flash cells as storage for analog values of almost infinite resolution (with a rather short data retention time then), but the readout electronics then does a simple threshold comparison to turn the stored value into 0 or 1. Nevertheless, for dynamic ram I remember some quasi analog usages (e.g. bucket brigade store)

    I can even imagine an algorithm that could be used to store more than one bit into one MSP flash cell:
    Overclock the flash controller massively, e.g. factor 4. Write the data by writing it once, twice, three or four times, depending on the 'value' to be stored in each bit. The reading result would be rather random now. However, to 'read' the alues back 8desctructively), you scan for 0 bits, then write 0 to all cells once, check again for newly appearing 0 bits and so on. The more often you have to write 0 to a cell before it reads a s0, the less often it hasbeen writte 0 when programming. However, after 'reading' the ocntent, it is gone from flash (all 0 then) and has to be programmed anew.

  • After reading the datasheet for the MSP430F5309, I realize there is a method to write a long to flash memory by setting the BLKWRT bit of the FCTL1 register.  I have attempted to implement this in addition to the technique mentioned on this forum.  I will admit, as I have implemented it, I do not see the benefit of passing the address of the data to be written to flash, versus passing the data itself.  I would appreciate feedback on this.  Thanks in advance.

    ----------------------------------------------------------------------------------------------------------------

    #define DATA_IN_FLASH 120
    #define LONG_TYPE 2
    #define INT_TYPE 1
    #define CHAR_TYPE 0

    #include <msp430f5310.h>

    /*************************************************************************************************/
    /********************** Variables to be saved to / loaded from flash memory **********************/
    volatile static signed char Flash_Indicator = 120;
    volatile static unsigned long Test1 = 131071;
    volatile static signed long Test2 = -131072;
    volatile static signed int Test3 = -1310;
    volatile static signed char Test4 = -31;

    /********************** Variables to be saved to / loaded from flash memory **********************/
    /*************************************************************************************************/


    /******** Flash Memory Addresses ********/
    char* Data_In_Flash = (char*) 0xf000;
    long* Test1_Flash = (long*) 0xf002;
    long* Test2_Flash = (long*) 0xf00a;
    int* Test3_Flash = (int*) 0xf012;
    char* Test4_Flash = (char*) 0xf016;
    /******** Flash Memory Addresses ********/


    void* Reg_Ptr; // RAM register pointer

    // Functions
    void WriteFlashEntry(void* flash_address, void* data_address, char data_type);
    void EraseFlash(int addr);
    void Write_Flash(void);
    void readFlashSegment(void);

    void main(void)
    {
    WDTCTL = WDTPW + WDTHOLD; // Stop WDT
    UCSCTL3 = SELREF_2; // Set DCO FLL reference = REFO
    UCSCTL4 |= SELA_2; // Set ACLK = REFO
    UCSCTL0 = 0x0000; // Set lowest possible DCOx, MODx

    // Loop until XT1,XT2 & DCO stabilizes - In this case only DCO has to stabilize
    do
    {
    UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG);
    // Clear XT2,XT1,DCO fault flags
    SFRIFG1 &= ~OFIFG; // Clear fault flags
    }while (SFRIFG1&OFIFG); // Test oscillator fault flag

    __bis_SR_register(SCG0); // Disable the FLL control loop
    UCSCTL1 = DCORSEL_5; // Select DCO range 16MHz operation
    UCSCTL2 |= 249; // Set DCO Multiplier for 8MHz
    // (N + 1) * FLLRef = Fdco
    // (249 + 1) * 32768 = ~8MHz
    __bic_SR_register(SCG0); // Enable the FLL control loop

    // Worst-case settling time for the DCO when the DCO range bits have been
    // changed is n x 32 x 32 x f_MCLK / f_FLL_reference. See UCS chapter in 5xx
    // UG for optimization.
    // 32 x 32 x 8 MHz / 32,768 Hz = 250000 = MCLK cycles for DCO to settle
    __delay_cycles(250000);

    if (*Data_In_Flash == DATA_IN_FLASH) {
    EraseFlash(0xf000);
    Write_Flash();
    }

    while (1) {
    }

    }

    void Write_Flash(void) {

    Reg_Ptr = (char *)&Flash_Indicator;
    WriteFlashEntry(Data_In_Flash, Reg_Ptr, CHAR_TYPE);

    Reg_Ptr = (long *)&Test1_Flash;
    WriteFlashEntry(Test1_Flash, Reg_Ptr, LONG_TYPE);

    Reg_Ptr = (long *)&Test2_Flash;
    WriteFlashEntry(Test2_Flash, Reg_Ptr, LONG_TYPE);

    Reg_Ptr = (int *)&Test3_Flash;
    WriteFlashEntry(Test3_Flash, Reg_Ptr, INT_TYPE);

    Reg_Ptr = (char *)&Test4_Flash;
    WriteFlashEntry(Test4_Flash, Reg_Ptr, CHAR_TYPE);
    }

    void readFlashSegment() { //writes all three channels to their respective flash memory locations
    Test1 = (*Test1_Flash) + ( ( (long)(*(Test1_Flash + 4)) ) << 16);
    Test2 = (*Test2_Flash) + ( ( (long)(*(Test2_Flash + 4)) ) << 16);
    Test3 = *Test3_Flash;
    Test4 = *Test4_Flash;
    }

    void WriteFlashEntry(void* flash_address, void* data_address, char data_type) // Write the individual (integer) data to the flash address.
    {
    // Writing 32-bit value?
    if (data_type == LONG_TYPE) {
    long *ptr = (long *)data_address;
    while ((BUSY & FCTL3)) ;
    FCTL3 = FWKEY; // Unlock the flash.
    FCTL1 = FWKEY+BLKWRT; // Enable flash write.
    long *addr = (long *)flash_address;
    *addr = *ptr; // Write the data to the flash.
    while ((BUSY & FCTL3)) ;
    FCTL1 = FWKEY; // Disable flash write.
    FCTL3 = FWKEY + LOCK; // Lock the flash.
    }

    // Writing 16-bit value
    else if (data_type == INT_TYPE) {
    int *ptr = (int *)data_address;
    while ((BUSY & FCTL3)) ;
    FCTL3 = FWKEY; // Unlock the flash.
    FCTL1 = FWKEY + WRT; // Enable flash write.
    int *addr = (int *)flash_address;
    *addr = *ptr; // Write the data to the flash.
    while ((BUSY & FCTL3)) ;
    FCTL1 = FWKEY; // Disable flash write.
    FCTL3 = FWKEY + LOCK; // Lock the flash.
    }

    // Writing 8-bit value
    else {
    char *ptr = (char *)data_address;
    while ((BUSY & FCTL3)) ;
    FCTL3 = FWKEY; // Unlock the flash.
    FCTL1 = FWKEY + WRT; // Enable flash write.
    char *addr = (char *)flash_address;
    *addr = *ptr; // Write the data to the flash.
    while ((BUSY & FCTL3)) ;
    FCTL1 = FWKEY; // Disable flash write.
    FCTL3 = FWKEY + LOCK; // Lock the flash.
    }
    }

    void EraseFlash(int addr) {
    int* address = (int *) addr;
    while ((BUSY & FCTL3)) ;
    FCTL1 = FWKEY + ERASE; // Enable flash write.
    FCTL3 = FWKEY; // Unlock the flash.
    *address = 0x00; // Write the data to the flash.
    while ((BUSY & FCTL3)) ;
    FCTL1 = FWKEY; // Disable flash write.
    FCTL3 = FWKEY + LOCK; // Lock the flash.
    }

    ----------------------------------------------------------------------------------------------------------------

    Sincerely,

    Mehdi

  • Mehdi Rahman said:
    I will admit, as I have implemented it, I do not see the benefit of passing the address of the data to be written to flash, versus passing the data itself.

    Inefficiency of your approch is clearly visible in your code - lot of redundant code, waste of program memory. Function with pointer and data size as arguments will be suitable for ANY data type, it will be universal.

  • Hi Ilmars,

    I believe I understand the basic concept of your approach: The write routine takes the size of the data to be written, the initial flash address to start writing to, and the RAM variable address to  start reading from.  Inside the write routine, one can use a for loop that writes the value of the current RAM address to to the current flash address, then increments both the RAM and flash addresses by 2 before the next iteration.

    There is one aspect I am having trouble with.  As I understand it, you can only read/write to even addresses: http://mspgcc.sourceforge.net/manual/x987.html

    So let's say we have a 12x1 char array, a 6x1 int array, and a 3x1 long array.  I believe the sizeof parameter would be 12 for all cases.  For now let's focus on the char and int.  In one case you would like to write to the flash 12 times whereas in the other case you would like to write to the flash 6 times.  Passing only these three parameters into the function, how would we know what to do?  It seems to me we might need a fourth parameter that describes the data type (char, int, long), but I may be wrong.  Perhaps my approach is still incorrect?

    Sincerely,

    Mehdi

  • Mehdi Rahman said:
    As I understand it, you can only read/write to even addresses: http://mspgcc.sourceforge.net/manual/x987.html

    Read carefully (excerpt): The MSP430 can read and write 8 bit data at any address. Flash write function can and shall handle every data as array of bytes.

    Mehdi Rahman said:
    It seems to me we might need a fourth parameter that describes the data type (char, int, long), but I may be wrong.

    You are wrong indeed. For write function it does not really matter - you are writing 4 bytes or one 32bit long, it can write both as 4 bytes. So why make it complicated? Actually size of variable more or less describes it's type, especially from data storage point of view ;)

  • Hi Ilmars,

    As I understand it, your method is to treat everything as blocks of bytes (i.e. char = 1 byte, int = 2 bytes, long = 4 bytes).  I believe this would mean have all pointers be of type char*.  The flash write function will have a for loop that will run for sizeof iterations.  Inside the loop, the microcontroller will write the contents of the current data address to the current flash address.  Since the current data address will point to a byte, both the data and flash pointers will be of type char.  At the end of the loop, the pointers will be incremented by 1.  Is this the correct approach?

    I have made an attempt to do this below.  Note that I put some temp variables to double check the output of "sizeof" for different variables.

    ---------------------------------------

    #define DATA_IN_FLASH 120
    #include <msp430f5310.h>

    /*************************************************************************************************/
    /********************** Variables to be saved to / loaded from flash memory **********************/
    volatile static signed char Flash_Indicator = 120;
    volatile static unsigned long Test1 = 131071;
    volatile static signed long Test2 = -131072;
    volatile static signed int Test3 = -1310;
    volatile static signed char Test4 = -31;
    volatile static signed char Test5[12] = {10, 20, 30, 40, 50, 60, -60, -50, -40, -30, -20, -10};
    volatile static signed int Test6[6] = {-100, -200, -300, 300, 200, 100};
    volatile static signed long Test7[3] = {-100, -200, -300};

    /********************** Variables to be saved to / loaded from flash memory **********************/
    /*************************************************************************************************/


    /******** Flash Memory Addresses ********/
    char* Data_In_Flash = (char*) 0xf000; // 1 char
    char* Test1_Flash = (char*) 0xf001; // 1 long
    char* Test2_Flash = (char*) 0xf005; // 1 long
    char* Test3_Flash = (char*) 0xf009; // 1 int
    char* Test4_Flash = (char*) 0xf00b; // 1 char
    char* Test5_Flash = (char*) 0xf00c; // 12 chars
    char* Test6_Flash = (char*) 0xf018; // 6 ints
    char* Test7_Flash = (char*) 0xf024; // 3 longs
    /******** Flash Memory Addresses ********/


    volatile static signed char a = 0;
    volatile static signed char b = 0;
    volatile static signed char c = 0;
    volatile static signed char d = 0;
    volatile static signed char e = 0;
    volatile static signed char f = 0;
    volatile static signed char g = 0;
    volatile static signed char h = 0;

    char* Reg_Ptr; // RAM register pointer

    // Functions
    void WriteFlashEntry(char* flash_address, char* data_address, char countmax);
    void EraseFlash(int addr);
    void Write_Flash(void);

    void main(void)
    {
    WDTCTL = WDTPW + WDTHOLD; // Stop WDT
    UCSCTL3 = SELREF_2; // Set DCO FLL reference = REFO
    UCSCTL4 |= SELA_2; // Set ACLK = REFO
    UCSCTL0 = 0x0000; // Set lowest possible DCOx, MODx

    // Loop until XT1,XT2 & DCO stabilizes - In this case only DCO has to stabilize
    do
    {
    UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG);
    // Clear XT2,XT1,DCO fault flags
    SFRIFG1 &= ~OFIFG; // Clear fault flags
    }while (SFRIFG1&OFIFG); // Test oscillator fault flag

    __bis_SR_register(SCG0); // Disable the FLL control loop
    UCSCTL1 = DCORSEL_5; // Select DCO range 16MHz operation
    UCSCTL2 |= 249; // Set DCO Multiplier for 8MHz
    // (N + 1) * FLLRef = Fdco
    // (249 + 1) * 32768 = ~8MHz
    __bic_SR_register(SCG0); // Enable the FLL control loop

    // Worst-case settling time for the DCO when the DCO range bits have been
    // changed is n x 32 x 32 x f_MCLK / f_FLL_reference. See UCS chapter in 5xx
    // UG for optimization.
    // 32 x 32 x 8 MHz / 32,768 Hz = 250000 = MCLK cycles for DCO to settle
    __delay_cycles(250000);

    a = sizeof(Flash_Indicator);
    b = sizeof(Test1);
    c = sizeof(Test2);
    d = sizeof(Test3);
    e = sizeof(Test4);
    f = sizeof(Test5);
    g = sizeof(Test6);
    h = sizeof(Test7);

    if (*Data_In_Flash == DATA_IN_FLASH) {
    EraseFlash(0xf000);
    Write_Flash();
    }

    while (1) {
    }

    }

    void Write_Flash(void) {

    Reg_Ptr = (char *)&Flash_Indicator;
    WriteFlashEntry(Data_In_Flash, Reg_Ptr, sizeof(Data_In_Flash));

    Reg_Ptr = (char *)&Test1;
    WriteFlashEntry(Test1_Flash, Reg_Ptr, sizeof(Test1));

    Reg_Ptr = (char *)&Test2;
    WriteFlashEntry(Test2_Flash, Reg_Ptr, sizeof(Test2));

    Reg_Ptr = (char *)&Test3;
    WriteFlashEntry(Test3_Flash, Reg_Ptr, sizeof(Test3));

    Reg_Ptr = (char *)&Test4;
    WriteFlashEntry(Test4_Flash, Reg_Ptr, sizeof(Test4));

    Reg_Ptr = (char *)&Test5;
    WriteFlashEntry(Test5_Flash, Reg_Ptr, sizeof(Test5));

    Reg_Ptr = (char *)&Test6;
    WriteFlashEntry(Test6_Flash, Reg_Ptr, sizeof(Test6));

    Reg_Ptr = (char *)&Test7;
    WriteFlashEntry(Test7_Flash, Reg_Ptr, sizeof(Test7));
    }

    void WriteFlashEntry(char* flash_address, char* data_address, char countmax) // Write the individual (integer) data to the flash address.
    {
    char *ptr = (char *)data_address;
    char *addr = (char *)flash_address;
    for (int i = 0; i < countmax; i++) {
    while ((BUSY & FCTL3)) ;
    FCTL3 = FWKEY; // Unlock the flash.
    FCTL1 = FWKEY + WRT; // Enable flash write.
    *addr = *ptr; // Write the data to the flash.
    while ((BUSY & FCTL3)) ;
    FCTL1 = FWKEY; // Disable flash write.
    FCTL3 = FWKEY + LOCK; // Lock the flash.
    ptr = ptr + 1;
    addr = addr + 1;
    }
    }

    void EraseFlash(int addr) {
    int* address = (int *) addr;
    while ((BUSY & FCTL3)) ;
    FCTL1 = FWKEY + ERASE; // Enable flash write.
    FCTL3 = FWKEY; // Unlock the flash.
    *address = 0x00; // Write the data to the flash.
    while ((BUSY & FCTL3)) ;
    FCTL1 = FWKEY; // Disable flash write.
    FCTL3 = FWKEY + LOCK; // Lock the flash.
    }

    ---------------------------------------

    Sincerely,

    Mehdi

  • Mehdi Rahman said:
    As I understand it, your method is to treat everything as blocks of bytes (i.e. char = 1 byte, int = 2 bytes, long = 4 bytes).  I believe this would mean have all pointers be of type char*.

    Mainly yes.
    You can cast all types of pointers to void*. And void* to any type of pointer, including char*. And I would make the data pointer const.
    However, I would treat them as INTs. Just because writing INTs to flash is twice as fast as writing bytes :)
    Define the pointers in your function as void* (then you can pass any pointer). 
    Cast the passed void* to int* for the loop (of course, loop only size>>1 times). If the size was odd, add a single byte write at the end (this time cast the pointers to byte*)

    This ensures fastest and most flexible write.

    However, if you must disable interrupts while writing to flash.

  • "However, I would treat them as INTs. Just because writing INTs to flash is twice as fast as writing bytes :)"

    What would the difference be about? Twice as fast?

    Also, what about the case when one variable is of type char. Won't writing it as an int use up a byte of flash memory? For example, if the value to be saved is 0x96, then I believe treating it as an int would write 0x00 and 0x96, thereby wasting an extra byte. On the other hand, writing as a char would write only 0x96 to one address of flash. If I am wrong, please correct me.
  • In byte/word write mode, the flash controller applies programming voltage, writes the value, remoes the programming voltage for each individual write access. So writing two bytes takes two write cycles, writing them together as one word takes one. Twice as fast.
    Even faster (again twice) is the long word write mode on 5x family. However, in this mode you must ensure that always a complete set of 4 bytes is written because only if all four bytes are written by te CPU (as bytes, words or a mixture) the actual flash write process starts. If you writ eto 0x00, 0x01, 0x02 but not to 0x03, nothing is written and all three writes are discarded if you then proceed to a different location (e.g. 0x04, skipping 0x03)
    The reason is that flash is internally organized as 16 bit (older MSPs) or 32 bit (5x family, and perhaps parts of 2x family with >64k flash)
    In your example, yes, you'r eright, if writing only one single byte, then of course writing it as INT would waste space, as it would overwrite the adjacent byte.
    However, if you write to bytes, you should assemble them to a word and write them as word. And when writing an area, write it with word writes (jsu tensure that it is eithe rword-aligned, or do the first and/or last non-aligned write as byte write). This signiicantly speeds up the write operation.
    Also, in older MSPs (1x family for sure, but I think, 2x and 4x as well) there was no way to write a 64byte flash write block (not to be confused with a flash erase segment) could be written with 64 byte writes without exceeding the maximum allowed cumulative write time. (unless block write mode was used, in which the setup and finish time for the programming voltage is only applied once for mutiple bytes).
    Here you had to either use word writes or leave part of a 64byte block unused.
  • I'm not sure about "too high" here. This means the function WriteFlashEntry(...) was called too quickly (without any delay)? Or FCTL2 was set too high (I read Flash example for MSP430G2553 from TI, it sets FCTL2 = MCLK/3 )
  • For 2xx devices, such as G2553, fFTG (Flash timing generator frequency) must be between 257 and 476 kHz. Improper setting of FCTL2 may violate this specification.

  • If a flashwrite example shows a 1/3 smclk, it assumes a 1mhz smclk. so if your smclk is faster you need to divide accordingly so the value still ends up as ~330KHz

    re-Writing a few longs to flash:
    Use infoD.
    Don't erase and write the block more than once a day.
    Use __no_init to reserve a few variable space in flash without using const. ( IAR allows using @ 0x1800 or @"INFOD")
    if declaring it a const the compiler will not allow you to write to it, but as pointers is a runtime parameter it can still be done on const.

    If it is just a few long array, just do
    enable flashwrite;
    flasharray[0| = ramarray[0];
    flasharray[1] = ramarray[1];
    flasharray[2] = ramarray[2];
    closeflashwrite;

    if a struct with a mix of int and longs, just copy each member as above.
    If a single struct from a struct_array/many of same type, function should allow pointer and each member offset is then used by "mypnt->membername".

    Union can be used if struct members memory locations should also be referenced to as a int array
    union{
    struct name{
    ......
    .....
    };
    int rawarray[16];
    } @0x1800;

  • Could you please show me how to use @ 0x1800?
    I saw some code have this symbol "@" but I don't know what it means.

  • @ is a IAR compiler thing, it means: at (as in at absolute memory location)

    CCS don't have it, but by casting an absolute address to a pointer you could overcome it.

    example:
    void flashwite( int *ramsrc, int *flashdest, int len) { // function to write 16bit words
    enableflashwrite;
    while(len--)
    *flashdest++ = *ramsrc++;  // as pointer is of int type, it will +2 when doing ++
    closeflashwrite;

    And you could call it by: flashwrite( &myarray[0], (int *) 0x1800, 8) // casting an absolute address to a pointer
    If array is not of the int type and compiler complains, cast it too: (int *) &myarray 
    Pointing to first field or member is no longer required when you do casting, useful when pointing to structs

    I have not tested it so there could be some typo.

**Attention** This is a public forum