STM32F4 saving data to internal flash (at runtime) - Page 1
Forum section: electronics / general

author: roli
author_rank: Regular Contributor
timestamp: January 07, 2014, 04:23:10 pm
content: I am building an application for this MCU that needs to persistently save some data - two or three string arrays (about 1k or less) at runtime (because the values are not known at compile time). I know that the micro has 11 flash sectors of different sizes. And I've seen the flash header that the STM provides. It has the erase/write functions that I need. And now for the actual question: How do I reserve the needed space (I'm guessing the whole sector?) so the compiler won't save any code there? And how do you actually read that data from memory - or is it as simple as using the actual sector base address? I am guessing that everything depends on the actual toolkit being used - I am using the lite (codesize limited) version of IAR Workbench.

author: andyturk
author_rank: Frequent Contributor
timestamp: January 07, 2014, 04:38:09 pm
content: The compiler doesn't determine the actual location of anything--that's the linker's job. So if you want to reserve space somewhere, you'll need to modify the linker file. I'm not sure how IAR does things, but with a GCC toolchain, you'll have a .ld file somewhere.But since you're using a STM32F4, check out the "Backup SRAM" capability. There's 4K of RAM that's essentially non-volatile as long as the mcu has power on the VBAT pin. Writing to backup SRAM will be much faster and you won't have to worry about write endurance.

author: roli
author_rank: Regular Contributor
timestamp: January 07, 2014, 06:13:31 pm
content: I completely forgot about the linker. That happens when you are used to other (non-C) high-level languages. You completely forget that the linker even exists. I found the linker options file (.icf if I understand this correctly) for the project but I have no idea how to set them - I've never actually dealt with linkers before.As for the backup SRAM option. I've read about that but it really isn't the path I would like to take. It's still volatile and I don't like that. And flash would really be better since I mostly just need to read the data. I need to save/modify some data once a month or so. Not really something problematic.

author: leppie
author_rank: Frequent Contributor
timestamp: January 08, 2014, 05:41:12 am
content: You might want to look at the bootloader examples. I guess the process will be similar.

author: casinada
author_rank: Frequent Contributor
timestamp: January 08, 2014, 06:16:48 am
content: You might want to try the M3 series that comes with EEPROM that is as easy to write as to SRAM but is non volatile and the endurance is better than the Flash counterpart.http://www.st.com/web/en/catalog/tools/PF259096The discovery board is only $8If you want to use your current kit you can buy some serial eeproms and save that data that way.The Flash memory is conventionally used to hold the program and not the data.

author: Kjelt
author_rank: Super Contributor
timestamp: January 08, 2014, 07:53:06 am
content: Quote from: casinada on January 08, 2014, 06:16:48 amIn theory your right and for small prototyping or hobbyist products this is definitely recommended. In mass production however where every cent counts it is normal to use the flash for storing some dynamic data that is not very often updated. If as OP states he only wants to save the data once a month the internal flash is a candidate.If it was a couple of times a minute it would wear out the flash to soon even with a filesystem and wearleveling algorithms.

author: Kjelt
author_rank: Super Contributor
timestamp: January 08, 2014, 08:06:40 am
content: Quote from: roli on January 07, 2014, 04:23:10 pmI have no experience the M4 nor with IAR for this, only saw something like this for M3 and Keil (see code below). It is pretty stupid/straightforward implementation, could be there is some nice linker directives you can use, not sure about that.Make sure you align on a page, use the exact size of a page and make sure that the page is not write protected (option bytes). You simply allocate a buffer at the exact address and assign all 0xFF to the space since this is the empty value. Flash can only make '1' s to '0's not the other way round then you have to erase the whole page. To prevent erasing too many times you might want to use a simple linkedlist algo with status, so you can mark a list as old and search for the latest valid entry and so use the entire page before erasing it again, but that's up to you. Hope this helps a bit with searching and finding an answer to your specific issue.Code:const uint8_t MyFlashPage __attribute__((section(".ARM.__at_0x08008000"))) ={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,// skipped but fill the exact page number of bytes in this case 2048 bytes0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};

author: roli
author_rank: Regular Contributor
timestamp: January 09, 2014, 09:23:57 pm
content: Thanks for the suggestions everyone!I managed to do it. And it actually wasn't hard at all. Here's some of the code - for anyone with the same issue.The actual memory "allocation" (I put it in a separate .c file):Code:#include "stm32f4xx.h"#pragma location=0x800C000volatile const uint8_t flash_data = {0xFF,0xFF,0xFF, ... ,0xFF};And then the actual saving:Code:uint8_t flash_status;void save_data_to_flash() {flash_status = FLASH_COMPLETE;FLASH_Unlock();FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR |FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR |FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);flash_status = FLASH_EraseSector(FLASH_Sector_3, VoltageRange_3);if (flash_status != FLASH_COMPLETE) {FLASH_Lock();return;}uint8_t* address = &flash_data;//program first run status bitflash_status = FLASH_ProgramByte((uint32_t)address, 0x00);address += 4;if (flash_status != FLASH_COMPLETE) {FLASH_Lock();return;}...}The only thing worth mentioning is that you need to save data to the right address or else you get those ARM alignment issues and the flashing fails - that's why I used 4 bytes to save a single byte.

author: Jeroen3
author_rank: Super Contributor
timestamp: January 14, 2014, 06:25:24 pm
content: Those alignment issues are a piece of cake. I recently used word aligned byte-array access for image processing all the time.With Keil uVision ARM MDKCode:uint8_t blockOfData __attribute__((aligned (4))); // Word aligned byte arrayUsing this word based is easy now:Code:uint32_t *dataPointer = (uint32_t)&blockOfData; // Word aligned access to byte 0, 1, 2 and 3*dataPointer++ = 0x12345678; // Write to four bytes at once and increment pointer 4 bytes (next word)One timy detail: a misalignment throws you to one of the fault handlers.Maybe you can consider disabling other interrupts when flashing, to be safe.