2
\$\begingroup\$

Background:

I am trying to write an 8-bit value to Info C block of FLASH on the MSP430F5529. Info C starts at address 0x1880, so I use a #define to keep this value:

#define     INFOC_REGISTER       0x1880

In my main function I make a call to a method which is intended to write this 8-bit value (let's just say 0x01 for the sake of argument) to the lowest byte of address 0x1880:

writeValueToFlash(data);

This function has two calls to functions declared in flashctl.c, which I got from MSP430Ware_3_80_05_04. My writeValueToFlash() function is as follows:

/*********************************************************************
 * @fn      bool writeValueToFlash(uint8_t data)
 * @brief   Write 8-bit value to FLASH
 * @param   data - 8-bit value
 * @return  bool - Returns true
 */
bool writeValueToFlash(uint8_t data) {

    FlashCtl_eraseSegment((uint8_t*)INFOC_REGISTER);

    FlashCtl_write8((uint8_t*)data, (uint8_t*)INFOC_REGISTER, 1);

    return true;                                // Baud rate changed
}

Below are the two functions from the MSP430Ware package. I have not made any changes to these functions, except for adding the header commentary from the flashctl.h file:

//*******************************************************************
//
//! \brief Erase a single segment of the flash memory.
//!
//! For devices like MSP430i204x, if the specified segment is the information
//! flash segment, the FLASH_unlockInfo API must be called prior to calling
//! this API.
//!
//! \param flash_ptr is the pointer into the flash segment to be erased
//!
//! \return None
//
//********************************************************************

void FlashCtl_eraseSegment(uint8_t *flash_ptr){
    //Clear Lock bit
    HWREG16(FLASH_BASE + OFS_FCTL3) = FWKEY;

    //Set Erase bit
    HWREG16(FLASH_BASE + OFS_FCTL1) = FWKEY + ERASE;

    //Dummy write to erase Flash seg
    *flash_ptr = 0;

    //test busy
    while(HWREG8(FLASH_BASE + OFS_FCTL3) & BUSY)
    {
        ;
    }

    //Clear ERASE bit
    HWREG16(FLASH_BASE + OFS_FCTL1) = FWKEY;

    //Set LOCK bit
    HWREG16(FLASH_BASE + OFS_FCTL3) = FWKEY + LOCK;
}



//********************************************************************
//
//! \brief Write data into the flash memory in byte format, pass by reference
//!
//! This function writes a byte array of size count into flash memory. Assumes
//! the flash memory is already erased and unlocked. FlashCtl_eraseSegment can
//! be used to erase a segment.
//!
//! \param data_ptr is the pointer to the data to be written
//! \param flash_ptr is the pointer into which to write the data
//! \param count number of times to write the value
//!
//! \return None
//
//********************************************************************

void FlashCtl_write8(uint8_t *data_ptr,
                 uint8_t *flash_ptr,
                 uint16_t count)
{
    //Clear Lock bit
    HWREG16(FLASH_BASE + OFS_FCTL3) = FWKEY;

    //Enable byte/word write mode
    HWREG16(FLASH_BASE + OFS_FCTL1) = FWKEY + WRT;

    while(count > 0)
    {
        //test busy
        while(HWREG8(FLASH_BASE + OFS_FCTL3) & BUSY)
        {
            ;
        }

        //Write to Flash
        *flash_ptr++ = *data_ptr++;
        count--;
    }

    //Clear WRT bit
    HWREG16(FLASH_BASE + OFS_FCTL1) = FWKEY;

    //Set LOCK bit
    HWREG16(FLASH_BASE + OFS_FCTL3) = FWKEY + LOCK;
}

The Problem:

The issue I am facing is that when I try to write "data" (or 0x01 in this case) to the INFOC_REGISTER (address 0x1880), it does not work properly. When I attempt to erase the block, I end up with something along the lines of FF7E in that memory location (this fluctuates somewhat - it is not always FF7E, it changes every time I restart the micro and try the erase again), and when I attempt to write 0x01 I end up with something similar like FF50 in that memory location. This value also fluctuates. I am expecting FF01.

Are there any obvious mistakes in the way I am erasing or writing to FLASH? I know I had it working at one point quite some time ago but I am not sure what I would have changed that could cause this issue.


Update:

Per CL's answer, I have modified the code as follows, but still seem to have similar issues.

#define     INFOC_REGISTER       ((uint8_t*)0x1880)

bool writeValueToFlash(uint8_t data) {

    FlashCtl_eraseSegment(INFOC_REGISTER);

    FlashCtl_write8(&data, INFOC_REGISTER, 1);
}

It appeared to work the first time (I wrote 0x08 and it worked correctly), but then when I went back and tried to change it to 0x01 or 0x0A it did not. After stepping over the FlashCtl_eraseSegment() function call it changed to FF0C, and when I stepped over the FlashCtl_write8() function (with data = 0x0A) it just went back to FF08.

Further Update:

Sometimes it seems to work, other times not. It is very flaky....

\$\endgroup\$
  • \$\begingroup\$ Perhaps not the issue, but your flash_ptr in FlashCtl_eraseSegment should be volatile. \$\endgroup\$ – Eugene Sh. Dec 10 '18 at 21:48
  • \$\begingroup\$ @EugeneSh. Interesting that they got that wrong in the sample code then.... \$\endgroup\$ – DerStrom8 Dec 10 '18 at 21:49
  • \$\begingroup\$ There is so much wrong TI provided code... Probably because it is written by EEs who just don't care :) \$\endgroup\$ – Eugene Sh. Dec 10 '18 at 21:51
  • 1
    \$\begingroup\$ Although I agree about TI code quality, but here it's pretty obvious that the author doesn't understand well how vlaues/pointers/addresses work and specifically how to pass them into functions. The (uint8_t*)data in the first function is already a nonsense. \$\endgroup\$ – GAttuso Dec 10 '18 at 22:55
  • 1
    \$\begingroup\$ @DerStrom8 Sorry if I sounded rude. Just to add 2 cents to @CL. answer, about what happening in your current code: Assuming uint8_t data = 1, then cast (uint8_t *)data is casting data's value to an address and, for instance, *(uint8_t *)data will now access the memory (read or write) with the address 0x0001 which is obviously not what you wanted. \$\endgroup\$ – GAttuso Dec 11 '18 at 8:02
2
\$\begingroup\$

This is not how pointers work in C.

The FlashCtl_write8() function expects a pointer to the data to be written. Normally, you would have multiple bytes in an array, and writing the array name without an index results in a pointer to the (first element of the) array:

uint8_t data[3] = { 11, 22, 33 };

FlashCtl_write8(data, (uint8_t *)INFOC, 3);

You could do the same with an array of size 1. However, if you do not have an array, you must use the & operator to get the pointer to that data:

uint8_t data;

FlashCtl_write8(&data, (uint8_t *)INFOC, 1);

Without the address-of operator, the function would take the value of data as the address, and write the value found at that address to the flash.


Please note that the information memory is not a register. And you need a pointer whenever you access it (especially when you want to read it), so you should define the symbol so that it already is a pointer:

#define INFO_MEM_C ((uint8_t *)0x1880)
\$\endgroup\$
  • \$\begingroup\$ Thank you very much for this. When I first wrote this I had the & before data in the call to FlashCtl_write8() but I second-guessed myself. That being said I am still having an issue. It seemed to work once - I wrote a value of 0x08 to the INFOC register (which I defined the way you suggested and removed the cast in the later code) and I got FF08 (great!). But when I tried writing a 0x01 or a 0x0A it stayed at FF08 (it went to FF0C when I erased the segment, and went back to FF08 when I tried writing 0x0A). Seems I am still having the problem \$\endgroup\$ – DerStrom8 Dec 11 '18 at 14:40
  • \$\begingroup\$ I just updated my question with the current (modified) code. \$\endgroup\$ – DerStrom8 Dec 11 '18 at 14:47
2
\$\begingroup\$

Well I did not see that coming.

While CL's answer is definitely accurate and my code was incorrect (and I have fixed my code, +1 for the help!), it was not actually the root of this exact problem. The biggest clue is this:

When I attempt to erase the block, I end up with something along the lines of FF7E in that memory location (this fluctuates somewhat - it is not always FF7E, it changes every time I restart the micro and try the erase again)

When I was erasing the byte in FLASH, it was not erasing properly. It turns out I have a couple of bad cells. To be fair I have been developing this project for quite some time and in that time I have re-written to that FLASH address (0x1880) many, many times. I may have just reached the point where it couldn't be written to properly anymore. In actual operation I do not expect to write to that location more than maybe a dozen times (realistically it will only be on or two) over a 20-year lifetime, so this should not be an issue moving forward.

Anyway, to fix it for the time being I have changed the FLASH address to 0x1882 and it is working perfectly every time. Thank you all for the help!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.