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.

MSP430 Information Flash Read, Erase, Write. Am I doing this right?

Other Parts Discussed in Thread: MSP430G2231, MSP430F5637

Before I go and screw something up.  Could anyone look at the code below to see if I am doing this correctly.

I need to:

1. Read two integers from the MSP430 Information Flash and store the values in global variables.

2. Erase flash information segment B,

3. Write two integers to MSP430 flash information segment B.

 

#include  "msp430g2231.h".....

#define info_seg_B 0x1080

unsigned int storedVlvOffPosition;

unsigned int storedVlvOnPosition;

// Declare Flash Subroutines

void read_segment(int address);

void erase_segment(int address);

void write_segment(int address, int valveOff, int valveOn);


void main(void)

{

  WDTCTL = WDTPW + WDTHOLD; 

.....

// Call the flash functions....

read_segment(info_seg_B);   // Read the previously stored valve positions from flash

erase_segment(info_seg_B); // Erase the segment to prepare write new values

write_segment(info_seg_B, vlvOffPosition, vlvOnPosition); // Write the new valve positions to flash

}    // End of main()


//*************************************************************************

// Read stored valve positions from the Information flash segment B

//*************************************************************************

void read_segment(int address)

{

  int *Flash_ptr;                           // Flash pointer

  Flash_ptr = (int *)address;               // Initialize flash pointer

  storedVlvOffPosition = *Flash_ptr;

  Flash_ptr = Flash_ptr + 2; // Increment the flash pointer to next integer

  storedVlvOnPosition = *Flash_ptr;

}

//*************************************************************************

// Erase Information Flash segment B

//*************************************************************************

void erase_segment(int address)

{

  int *Flash_ptr;                           // Flash pointer

  Flash_ptr = (int *)address;               // Initialize Flash pointer to 0x1080

  FCTL1 = FWKEY + ERASE;                    // Set Erase bit

  FCTL3 = FWKEY;                            // Clear Lock bit

  *Flash_ptr = 0;                           // Dummy write to erase Flash segment

  FCTL3 = FWKEY + LOCK;                     // Set LOCK bit

}


//************************************************************************

// Write valve on/off positions to the Information flash Segment B

//************************************************************************


void write_segment(int address, int valveOff, int valveOn)

{

  int *Flash_ptr;                           // Flash pointer

  Flash_ptr = (int *)address;               // Initialize Flash pointer to 0x1080

  FCTL3 = FWKEY;                            // Clear Lock bit

  FCTL1 = FWKEY + WRT;                      // Set WRT bit for write operation 

  *Flash_ptr = valveOff;                    // Write value to flash

  Flash_ptr = Flash_ptr + 2;                // Increment the flash pointer to next even address

  *Flash_ptr = valveOn;                     // Write value to flash

  FCTL1 = FWKEY;                            // Clear WRT bit

  FCTL3 = FWKEY + LOCK;                     // Set LOCK bit

}

  • /*************************************************************************/
    /** OnChip flash memory                                                 **/
    /*************************************************************************/
    static UINT8 *CpuFlash= (UINT8*)0x1040;         //Use Segment C at 0x01040
    static const UINT16 CpuFlashLimit= 64;          //64 bytes of CPU flash
    
    static void DevCpuFlashWrite(int DoErase, UINT16 Addr, const UINT8 *pSrc, UINT16 ByteCt) {
      if(Addr<CpuFlashLimit) {
        ByteCt= min(ByteCt,CpuFlashLimit-Addr);
        FCTL2= FWKEY|FSSEL1|FN1;            //SMCLK/3
        FCTL3= FWKEY;                       //Clear LOCK
        if(DoErase) {
          DevWatchdogReset();               //This may take a while...
          //Do not attempt to single-step through this block...
          FCTL1= FWKEY|ERASE;
          CpuFlash[Addr]= 0xFF;             //Initiate erase
          while(FCTL3 & BUSY);              //Wait until erase is complete
        }
        DevWatchdogReset();                 //This may take a while...
        FCTL3= FWKEY;                       //Clear LOCK
        FCTL1= FWKEY|WRT;                   //Write enable
        //For some reason block writes did not work, triggering an
        //access violation after the first byte. Individual writes
        //work, but are slower (raises and lowers the eeprom voltage
        //for each byte)
        while(ByteCt--) {
          while((FCTL3 & BUSY));            //Wait until previous write completes
          CpuFlash[Addr++]= *pSrc++;
        }
        FCTL1= FWKEY;                       //Disable write, block write
        FCTL3= FWKEY|LOCK;                  //Set LOCK
      }
    }
    
    //Read is provided to keep the actual address hidden from the caller.
    static void DevCpuFlashRead(UINT16 Addr, UINT8 *pDst, UINT16 ByteCt) {
      if(Addr<CpuFlashLimit) {
        ByteCt= min(ByteCt,CpuFlashLimit-Addr);
        while(ByteCt--) {
          *pDst++= CpuFlash[Addr++];
        }
      }
    }
    
    
    Your code looks fine to me, although I would add wait loops after the erase and before each write. Erasing flash may take a while, and writes are slower than execution speed.

    And as a heads-up, you can't single-step through the flash code. Setting the FWKEY bit in FCTL1 puts the cpu into a special mode. See the MSP user guide for details.

    I have attached my own flash code for reference.

    -- Chip

  • Thanks Chip...

    "And as a heads-up, you can't single-step through the flash code. Setting the FWKEY bit in FCTL1 puts the cpu into a special mode. See the MSP user guide for details"

    By this you mean that I can't increment the flash pointer within the write() function, and that I will have write both integers in a single step?

    Regards,

    Ed

  • OK, I think got what you mean by not single stepping through flash.  

    Looking at your code, I'll have to check the flash BUSY bit between integer writes.

  • By "single-stepping" I was referring to single-stepping using the debugger.

    The MSP430 has a bulk-write mode, but I was not able to get that working and once I had the individual writes working I moved on to other problems. If you get the bulk-write working please let me know.

    Also, if my reply was helpful please click the "Verify" button in the forum. It helps my karma count. :)

    -- Chip

     

  • ChipD,

    If your code is in the same bank as what you are trying to erase or re-write, waiting for BUSY is unnecessary. But it does not hurt either.

    -- OCY

  • OCY:

    I'm a bit confused by that statement. By "bank" are you referring to the 64-byte information area that is being written? If so, there is virtually no chance the code will reside there.

    Or does "bank" mean something else?

    -- Chip

     

  • Chip,

    Most MSP430s have only one bank of flash. That is why they do not talk about banks.

    See the F5xx/F6xx User’s Guide. Some of them have 4 banks of 64KB+ flash.

    -- OCY

  • OK, if I understand correctly: 

    Both the 64-byte information blocks (segments) and the program code space reside on the same physical flash memory bank, so the act of fetching the next program instruction from flash performs an implicit wait. This makes the explicit wait loop redundant unless the program code is being executed from SRAM, perhaps as part of a whole firmware update.

    This was not clear, even after rereading the user guides. Thank you!

    -- Chip

     

  • Chip

     

    I just wanted to add that some modifications to my code.  This has to do with the C code function argument for the Flash write operation.  When I pass the integer arguments via the write() function I changed the unsigned integer values to integers and most importantly I passed the address instead of the value use the ANSI C "&" operator when calling the function.  for example 

    // Write the new valve positions to flash

    write_segment(info_seg_B, &vlvOffPosition, &vlvOnPosition); 


    Then in the function, the arguments are declare as integer pointers to the value as shown below. 

    void write_segment(int address, int *valveOff, int *valveOn)

    {

      int *Flash_ptr;                           // Flash pointer

     LSHI_OUT |= LSHI; // Turn ON Hi Limit Switch Output

      Flash_ptr = (int *)address;               // Initialize Flash pointer to 0x1080

      while(FCTL3 & BUSY);              // Wait until erase is complete

      FCTL3 = FWKEY;                            // Clear Lock bit

      FCTL1 = FWKEY + WRT;                      // Set WRT bit for write operation

      

      *Flash_ptr = *valveOff;                    // Write value to flash at 0x1080/81

      while((FCTL3 & BUSY));            //Wait until previous write completes

      Flash_ptr = Flash_ptr + 2;                // Increment the flash pointer to next integer

    *Flash_ptr = *valveOn;                     // Write value to flash at 0x1082/83

      while((FCTL3 & BUSY));            //Wait until previous write completes

      FCTL1 = FWKEY;                            // Clear WRT bit

      FCTL3 = FWKEY + LOCK;                     // Set LOCK bit

    }

    For whatever reason it did not work using a call by "value".

     

  • ChipD said:
    Both the 64-byte information blocks (segments) and the program code space reside on the same physical flash memory bank, so the act of fetching the next program instruction from flash performs an implicit wait.

    Actually this isn't exactly true.

    While erasign a flash segment or writing to flash, ANY flash read on ANY bank will result in a 0x3fff reading. This will let the CPU jump on place if it is an instruction fetch, but will cause havoc if it is an interrupt vector read.

    The only exception is during a block erase operation. This mode is only available on the MSPs with more than 64k flash. (Block borders are not necessarily at 0xXffff, depending on the device).

    If a block erase is done (and maybe a mass erase, but there it wouldn't make sense), data can be fetched from a different block, including code execution. So in theory (and provided theblock borders match), code running in 0x0xxxx could initiate a block erase of 0x10000-0x1ffff and while the erase takes place, the code could continue, as long as it does not try to fetch anything form the other block.
    Unfortunately a bug causes the cpu to crash instead, because the flash controller will not deliver 0x3fff reads not will it return the proper flash content under all circumstances. So a block erase operation can only be performed from ram.

    In my bootstrap code, the following code is copied to RAM and executed there to initiate erasing the block above 0x10000 and wait for completion:

                          "  movx    #0,        &0x10000                       \n"
                          ".WaitForBankErase:                                  \n"
                          "  bit     %[_BUSY],  %[_FCTL3]                      \n"
                          "  jne     .WaitForBankErase                         \n"
                          "  ret                                               \n"

    As this code is static (except for the bank address, but this too is static in this case) one could push the resulting binary bytes onto stack, call he stack, then pop them off again. Or initialize an array of INTs with the values, then make a funciton call to the array's address.

    ChipD said:
    This makes the explicit wait loop redundant unless the program code is being executed from SRAM, perhaps as part of a whole firmware update.

    Yes, for write and segment erase operations. For block erase operations, neither way would work, at least for those devices where the flash controller is  broken (namely the 54xx series, but maybe others too)

  • Ed OReilly said:

    void write_segment(int address, int *valveOff, int *valveOn)

    {

      int *Flash_ptr;                           // Flash pointer

     LSHI_OUT |= LSHI; // Turn ON Hi Limit Switch Output

      Flash_ptr = (int *)address;               // Initialize Flash pointer to 0x1080

    <snip> 

      *Flash_ptr = *valveOff;                    // Write value to flash at 0x1080/81

      while((FCTL3 & BUSY));            //Wait until previous write completes

      Flash_ptr = Flash_ptr + 2;                // Increment the flash pointer to next integer

    <snip>

    }

    Ed -

    I'm sure you caught this long ago, but incrementing Flash_ptr by 2 will not increment it to the next integer, it will go one further.  Welcome to C pointer arithmetic.

    I came across this thread for a completely unrelated reason but I saw this bug & wanted to point it out in case anyone else takes this code & tries to use it without realizing what it's doing.

  • Hi,      have you been able to write and read from flash. If yes can you give me your final function code (read, write erase) I did a lot of test without success. Thank you in advance for your help.

    Alex

  • Hi,

    I am working with msp430x5419A. I want to use the flash for storing data of 200 bytes sampled every minute. There are 2 problems i am facing here.

    1. Addressing of the Bank 1 which starts at 0x10000h. I guess this is regarding 20 bit address.

    2. When i use the sample code given above or this one http://320volt.com/wp-content/uploads/2010/10/msp430x54x_flashwrite_03.c.html there is an access violation and the ACCVIFG is set. Is there any password setting or something that I am missing here?? Any help would be great. thanks

          unsigned char Flash_ptr = (unsigned char *) 0x5C00;     // Initialize Flash pointer
       
          FCTL1 = FWKEY+MERAS;            // Set Erase bit
          FCTL3 = FWKEY;                            // Clear Lock bit
          *Flash_ptr = 0;                                // Dummy write to erase Flash seg
          FCTL3 = FWKEY+LOCK;              // Set LOCK

  • I wanted to give back a little here.  I found this post very very helpful.  I've modified the code so that it works on my MSP430F5637 in the long word mode. I wanted to post it up to help out anyone looking for a quick code fix for that family in this mode.  Below are the read write erase functions.

    //************************************************************************

    // Write to the Information flash

    //************************************************************************
    void Flash_Write(int address, int *config1, int *config2)
    {
    int *Flash_ptr; // Flash pointer

    __disable_interrupt();

    Flash_ptr = (int *)address; // Initialize Flash pointer to 0x1080

    FCTL3 = FWKEY; // Clear Lock bit
    FCTL1 = FWKEY + BLKWRT; // Set WRT bit for write operation

    *Flash_ptr = *config1; // Write value to flash
    Flash_ptr = Flash_ptr + 1; // Increment the flash pointer to next even address

    *Flash_ptr = *config2; // Write value to flash
    while((FCTL3 & BUSY));

    FCTL1 = FWKEY; // Clear WRT bit
    FCTL3 = FWKEY + LOCK; // Set LOCK bit

    __enable_interrupt();
    }


    //*************************************************************************

    // Erase Information Flash

    //*************************************************************************

    void Flash_Erase(int address)

    {
    int *Flash_ptr; // Flash pointer

    __disable_interrupt();

    Flash_ptr = (int *)address; // Initialize Flash pointer to 0x1980

    FCTL1 = FWKEY + ERASE; // Set Erase bit
    //FCTL1 = FWKEY + MERAS;
    FCTL3 = FWKEY; // Clear Lock bit

    *Flash_ptr = 0; // Dummy write to erase Flash segment

    FCTL3 = FWKEY + LOCK; // Set LOCK bit

    __enable_interrupt();
    }

    //*************************************************************************

    // Read stored Information flash

    //*************************************************************************

    int Flash_Read(int address)

    {
    __disable_interrupt();
    int *Flash_ptr; // Flash pointer

    Flash_ptr = (int *)address; // Initialize flash pointer
    /*
    storedVlvOffPosition = *Flash_ptr;

    Flash_ptr = Flash_ptr + 2; // Increment the flash pointer to next integer

    storedVlvOnPosition = *Flash_ptr;
    */
    __enable_interrupt();

    return *Flash_ptr;
    }

    Here is the code I used to check the results using the debugger.

    //Flash_Erase(0x1980);
    Flash_Write(0x1900, &config1, &config2);
    Flash_Write(0x1904, &config1, &config2);

    _NOP();
    _NOP();

    if(Flash_Read(0x1900) == 0x1212)
    P1OUT |= 0xFF;
    _NOP();
    _NOP();

    It just writes 4 integers to segment B basically.  

    I was a bit confused about one aspect though, when I erase It erases something like four or six words. I though flash had to erase a lot more data than that for an erase instruction?  Am I missing something?

    Rob

  • Robbie Valentine said:
    I was a bit confused about one aspect though, when I erase It erases something like four or six words. I though flash had to erase a lot more data than that for an erase instruction?  Am I missing something?

    Flash always reases a whole segment. However, a main memory flash segment is 512 bytes while in info memory, segment sizes vary from 64 to 256 bytes per segment (depending on total info memory size).
    It is unimportant which address you use to start an erase. The flash controlelr will erase the segment in which the target address lies, no matter whether it is at the beginning or the end of the segment.

**Attention** This is a public forum