cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L151CB writing variables to flash

kennethf
Associate II
Posted on July 02, 2014 at 11:21

Hi all,

I try to write some variables to the internal flash memory of the STM32L151CB processor, but it apparantly only works with some addresses? When I write to the address 0x0801FE00 it works, but when I write to the address 0x0801F145 (for example) the SIZERR flag is set?? 

I have tried to allocate the memory for user defined variables in the Keil development invironmemt by defining the startup address to 0x0800000 with size 0x1F000, so that the remaining ROM is free. 

Here is my code:

void Flash_Write(uint8_t Data, uint32_t Flash_Address)

{

FLASH_Unlock();

FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPTVERR | FLASH_FLAG_WRPERR );

FLASHStatus = FLASH_ErasePage(Flash_Address);

FLASHStatus = FLASH_FastProgramWord(Flash_Address, Data);

FLASH_Lock();

}

I must have missed something important, so please help me if you have any ideas.

#stm32-flash
7 REPLIES 7
chen
Associate II
Posted on July 02, 2014 at 11:45

Hi

''When I write to the address 0x0801FE00 it works, but when I write to the address 0x0801F145 (for example) the SIZERR flag is set?? ''

The issue must be to do with address alignment.

At a very minimum, the address must be even- hence 0x0801FE00 works but 0x0801F145 does not.

You will have to check the reference manual but I think Flash Write must be at least Word (16bit) aligned.

''I have tried to allocate the memory for user defined variables in the Keil development invironmemt by defining the startup address to 0x0800000 with size 0x1F000, so that the remaining ROM is free. ''

Not sure where 0x800000 is - Flash starts at 0x8000000.

I think SRAM is at 0x2000000 (at least for STM32F4 parts)

You MUST never use the start of flash for your own purposes if the device boots from Flash. The first 8 bytes MUST contain the Stack Pointer address and the start address of the program, this is normally taken care of for you by the vector table.

kennethf
Associate II
Posted on July 02, 2014 at 13:00

Thank you for your reply.

I am kind of a newbe to this whole embedded programming, so thank you for explaining this to me.

Yes, I am booting from the flash memory, but the program should be placed at 0x08000000-0x08003100 (according to Keil, when i download it). My user defined flash should be at 0x0801F000-0x08020000, so they should not interfere. 

I have played a little around and found that it might be because of the flash beeing divided into pages. It looks like I can only write to an intire page at once, and not write individual words to a page on the fly, without erasing the other words?

Again thanks for your reply, and please be patient with me as I am new to this. 

Posted on July 02, 2014 at 13:10

I think he just missed that you were carving out space at the end.

Requiring natural alignment is not uncommon for FLASH memory, so a Word (32-bit) requiring the (Address % 4) ==0 is not surprising. Unless there is a compelling reason to pack structures, it's better not to. If you had a whole structure, or string, you could write it as bytes.

You shouldn't have to write a whole page at once, so you should be able to add incrementally, or journal. What you can't do is over-write stuff you have already written.
Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
chen
Associate II
Posted on July 02, 2014 at 13:12

Hi

''please be patient with me as I am new to this. ''

Not a problem.

''I have played a little around and found that it might be because of the flash beeing divided into pages. It looks like I can only write to an intire page at once, and not write individual words to a page on the fly, without erasing the other words?''

Yes, Flash is divided into 'sectors'

Erase does a whole sector at a time.

FYI

You can write to any location (taking into account write boundaries) in the sector.

You can also overwrite a location that has been written to before BUT you can only change a '1' to a '0'

Flash Erase resets all bits to '1' (in the sector)

You can write (change) '1's to '0' at any time (but with the right programing sequence, boundaries etc)

You CANNOT change a '0' back to a '1' - this can only be done by erasing the sector.

kennethf
Associate II
Posted on July 02, 2014 at 15:40

Hi both,

Thank you so much for your help.

I managed to make it work by changing the Data to a 32 bit word, and then just extract the 4 hidden bytes in the word by shifting them 0, 8, 16 and 24 bits. 

I have to erase the intire page everytime I overwrite a Word though, but as far as I understand there is no easy workaround for that. However it is ok, since I only have 28 bytes to store (so far). 

Here is my code now: 

/*----------------------------------------------------------------------------

  Flash read

 *----------------------------------------------------------------------------*/

uint32_t Flash_Read(uint32_t Flash_Address)

{

uint32_t *FlashData = (uint32_t *)Flash_Address;

return(*FlashData);

}

/*----------------------------------------------------------------------------

  Flash programmer

 *----------------------------------------------------------------------------*/

void Flash_Write(uint32_t Data, uint32_t Flash_Page, uint32_t Flash_Address)

{

uint32_t Data0 = Flash_Read(Flash_Page); // Each Data contains 4 bytes

uint32_t Data1 = Flash_Read(Flash_Page+4);

uint32_t Data2 = Flash_Read(Flash_Page+8);

uint32_t Data3 = Flash_Read(Flash_Page+12);

uint32_t Data4 = Flash_Read(Flash_Page+16);

uint32_t Data5 = Flash_Read(Flash_Page+20);

uint32_t Data6 = Flash_Read(Flash_Page+24);

uint32_t Data7 = Flash_Read(Flash_Page+28);

if (Flash_Address == Flash_Page) {

Data0 = Data;

}

else if (Flash_Address == (Flash_Page+4)) {

Data1 = Data;

}

else if (Flash_Address == (Flash_Page+8)) {

Data2 = Data;

}

else if (Flash_Address == (Flash_Page+12)) {

Data3 = Data;

}

else if (Flash_Address == (Flash_Page+16)) {

Data4 = Data;

}

else if (Flash_Address == (Flash_Page+20)) {

Data5 = Data;

}

else if (Flash_Address == (Flash_Page+24)) {

Data6 = Data;

}

else if (Flash_Address == (Flash_Page+28)) {

Data7 = Data;

}

FLASH_Unlock();

FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPTVERR | FLASH_FLAG_WRPERR );

FLASHStatus = FLASH_ErasePage(Flash_Page);

FLASHStatus = FLASH_FastProgramWord(Flash_Page, Data0);

FLASHStatus = FLASH_FastProgramWord(Flash_Page+4, Data1);

FLASHStatus = FLASH_FastProgramWord(Flash_Page+8, Data2);

FLASHStatus = FLASH_FastProgramWord(Flash_Page+12, Data3);

FLASHStatus = FLASH_FastProgramWord(Flash_Page+16, Data4);

FLASHStatus = FLASH_FastProgramWord(Flash_Page+20, Data5);

FLASHStatus = FLASH_FastProgramWord(Flash_Page+24, Data6);

FLASHStatus = FLASH_FastProgramWord(Flash_Page+28, Data7);

FLASH_Lock();

}

It works fine, so thank you for your help. 

chen
Associate II
Posted on July 02, 2014 at 15:52

Hi

''Thank you so much for your help.''

No problem.

''I have to erase the intire page everytime I overwrite a Word though, but as far as I understand there is no easy workaround for that. However it is ok, since I only have 28 bytes to store (so far).''

Be careful, the Flash has a erase/write cycle limit (it is in the order of  100,000 cycle, sounds like a lot but is not when you think how often a variable may be changed!) .

If you know that the data is updated frequently - then you may want to use the 'journal' technique that Clive1 mentioned.

The 'journal technique' is where you write the changed data to the next location along (you may need to mark the old location as used/invalid).

Keep doing this until you reach the end (eg end of sector) and then go back to the beginning. This reduces the number of times you have to erase the sector.

kennethf
Associate II
Posted on July 02, 2014 at 16:27

Hi,

Ok? Thats unfortunate.

This might be a problem, thanks for letting me know. 

I guess I'd have to take care to limit the changes in the variables then.

I will try to implement this journal technique.

Thanks for your reply. It is much appreciated.