# MSP430F5529: Unable to write to FLASH

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....

• Perhaps not the issue, but your flash_ptr in FlashCtl_eraseSegment should be volatile. – Eugene Sh. Dec 10 '18 at 21:48
• @EugeneSh. Interesting that they got that wrong in the sample code then.... – DerStrom8 Dec 10 '18 at 21:49
• There is so much wrong TI provided code... Probably because it is written by EEs who just don't care :) – Eugene Sh. Dec 10 '18 at 21:51
• 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. – GAttuso Dec 10 '18 at 22:55
• @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. – GAttuso Dec 11 '18 at 8:02

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)

• 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 – DerStrom8 Dec 11 '18 at 14:40
• I just updated my question with the current (modified) code. – DerStrom8 Dec 11 '18 at 14:47

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!