We use some essential cookies to make our website work.

We use optional cookies, as detailed in our cookie policy, to remember your settings and understand how you use our website.

riozebratubo
Posts: 4
Joined: Fri Apr 30, 2021 6:35 am

The basics of writing/reading user data to the flash memory for long term storage

Fri Apr 30, 2021 7:03 am

Hi, guys.

I feel that the flash examples on the sdk are not so informative as how and why do things to beginners, so I'm gonna try to show the basics of operating with the flash.

Storing data

To store data, you need to choose a flash memory region to do so. I think it's safe to assume you can choose right after your program (it lives at the beginning of the flash), but even with this simple idea you should plan for it to grow over time. I'm trying to leave 512K for the program (which is a lot! even with a lot of libraries) on the example. The raspberry pico has 2MB of flash, so there is plenty of room.

The code is not tested, it should be viewed as a general idea. Please note that the examples assume your user data lives as a global variable to simplify things.

As you're gonna see, we need to erase the whole area we need to write to, and after that we can write the data: it's a flash memory related behaviour. The sdk allows us to erase in flash sectors size multiples and write in flash page size multiples.

Code: Select all

#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/flash.h" // for the flash erasing and writing
#include "hardware/sync.h" // for the interrupts

#define FLASH_TARGET_OFFSET (512 * 1024) // choosing to start at 512K

struct MyData {
  int some_int;
  char some_string[40];
  long some_long_int;
};

MyData myData;

void saveMyData() {
    uint8_t* myDataAsBytes = (uint8_t*) &myData;
    int myDataSize = sizeof(myData);
    
    int writeSize = (myDataSize / FLASH_PAGE_SIZE) + 1; // how many flash pages we're gonna need to write
    int sectorCount = ((writeSize * FLASH_PAGE_SIZE) / FLASH_SECTOR_SIZE) + 1; // how many flash sectors we're gonna need to erase
        
    printf("Programming flash target region...\n");

    uint32_t interrupts = save_and_disable_interrupts();
    flash_range_erase(FLASH_TARGET_OFFSET, FLASH_SECTOR_SIZE * sectorCount);
    flash_range_program(FLASH_TARGET_OFFSET, myDataAsBytes, FLASH_PAGE_SIZE * writeSize);
    restore_interrupts(interrupts);

    printf("Done.\n");
}


Reading back data

This is easy peasy. The data is simply available at a memory region for us to read, even right after writing to the flash. So let's be happy.

Code: Select all

void readBackMyData() {
    const uint8_t* flash_target_contents = (const uint8_t *) (XIP_BASE + FLASH_TARGET_OFFSET);
    memcpy(&myData, flash_target_contents + FLASH_PAGE_SIZE, sizeof(myData));
}

Please feel free to correct or add to it. I hope you enjoy it.

Roberto Buaiz

nikryd
Posts: 8
Joined: Wed May 05, 2021 9:03 pm

Re: The basics of writing/reading user data to the flash memory for long term storage

Fri Jun 04, 2021 6:57 pm

Hi riozebratubo,
I can not get this to work.
I use a oled display to display print out values.
First time I run code I get random data in myData.some_int as I expect.
After saveMyData() I always get myData.some_int = -1 even when I reboot the pico.

display print out

Code: Select all

int old:-1
int new: 5
int after:-1

Do you have any idea what I missing.

//Niklas

My code

Code: Select all


#include <stdio.h>
#include <stdlib.h>
#include "pico/stdlib.h"
#include "hardware/flash.h" // for the flash erasing and writing
#include "hardware/sync.h" // for the interrupts
#include <cstring>

#include <iostream>


#include "oled.h"

using std::string;


#define FLASH_TARGET_OFFSET (512 * 1024) // choosing to start at 512K

struct MyData {
  int some_int; 
};

MyData myData;

void saveMyData() {
    uint8_t* myDataAsBytes = (uint8_t*) &myData;
    int myDataSize = sizeof(myData);
    
    int writeSize = (myDataSize / FLASH_PAGE_SIZE) + 1; // how many flash pages we're gonna need to write
    int sectorCount = ((writeSize * FLASH_PAGE_SIZE) / FLASH_SECTOR_SIZE) + 1; // how many flash sectors we're gonna need to erase    
    uint32_t interrupts = save_and_disable_interrupts();
    flash_range_erase(FLASH_TARGET_OFFSET, FLASH_SECTOR_SIZE * sectorCount);
    flash_range_program(FLASH_TARGET_OFFSET, myDataAsBytes, FLASH_PAGE_SIZE * writeSize);
    restore_interrupts(interrupts);
   
}

void readBackMyData() {
    const uint8_t* flash_target_contents = (const uint8_t *) (XIP_BASE + FLASH_TARGET_OFFSET);
    memcpy(&myData, flash_target_contents + FLASH_PAGE_SIZE, sizeof(myData));
}


int main(){    
    int h = 64;
    init_display(h);    
    readBackMyData();
    setCursorx(0,8);
    setCursory(1,8);
    ssd1306_print("int old:");
    ssd1306_print(intToStr(myData.some_int));
    
    if(myData.some_int=-1){
        myData.some_int = 5; 
        setCursorx(0,8);
        setCursory(2,8);
        ssd1306_print("int new:");
        ssd1306_print(intToStr(myData.some_int));              
        saveMyData();
        readBackMyData();
        setCursorx(0,8);
        setCursory(3,8);
        ssd1306_print("int after:");
        ssd1306_print(intToStr(myData.some_int));
       
    }else {
        myData.some_int= +1;
        setCursorx(0,8);
        setCursory(2,8);
        ssd1306_print("int3:");
        ssd1306_print(intToStr(myData.some_int));
        saveMyData();
        readBackMyData();
        setCursorx(0,8);
        setCursory(3,8);
        ssd1306_print("int after:");
        ssd1306_print(intToStr(myData.some_int));
    }
    show_scr();
    
     while (true) {
     }

}

roadrunner3
Posts: 1
Joined: Sat Oct 28, 2023 9:40 am

Re: The basics of writing/reading user data to the flash memory for long term storage

Sun Nov 12, 2023 10:02 am

The readBackMyData() function of the first post has a mistake. It wrongly calculated the read address. It should be flash_target_contents without adding FLASH_PAGE_SIZE:

Code: Select all

void readBackMyData() {
    const uint8_t* flash_target_contents = (const uint8_t *) (XIP_BASE + FLASH_TARGET_OFFSET);
    memcpy(&myData, flash_target_contents, sizeof(myData));
}

User avatar
kralvarado
Posts: 7
Joined: Sat Feb 04, 2017 3:04 am

Re: The basics of writing/reading user data to the flash memory for long term storage

Sun Dec 10, 2023 11:05 pm

Thanks for posting your code. This seems to be an answer I'm looking for. But now, I'm having trouble including "hardware\flash.h" into my C++ project with Visual Studio Code.

I believe this to be a cmake issue, but I'm not sure how to go about this. When trying to include hardware\flash.h Visual Studio Code, shows the red-wavy line under the include. I can include other hardware libraries, such as hardware\gpio.h and hardware\rtc.h. So I know that the pico-sdk library is available.

I did find within pico-sdk\src\rp2_common\CMakeList.txt the first line is:

Code: Select all

option(PICO_NO_FLASH "Default binaries to not not use flash")
So I'm assuming PICO_NO_FLASH is being set and I'm not sure where I can set that option allowing the flash.h to be included.

Any advice is welcome. Thank you.
- Problems arose, ensued, were over come!

User avatar
adam_green
Posts: 137
Joined: Tue Dec 14, 2021 12:43 am

Re: The basics of writing/reading user data to the flash memory for long term storage

Mon Dec 11, 2023 12:00 am

You probably need to add hardware_flash to your CMakeLists.txt:

Code: Select all

target_link_libraries(your_target_name PRIVATE
    pico_stdlib
    hardware_flash
)

User avatar
kralvarado
Posts: 7
Joined: Sat Feb 04, 2017 3:04 am

Re: The basics of writing/reading user data to the flash memory for long term storage

Tue Dec 12, 2023 11:05 am

Yes, adding hardware_flash to target_link_libraries resolved the issue.

Thank you.
- Problems arose, ensued, were over come!

User avatar
adam_green
Posts: 137
Joined: Tue Dec 14, 2021 12:43 am

Re: The basics of writing/reading user data to the flash memory for long term storage

Tue Dec 12, 2023 11:21 am

Excellent! Happy to hear that you got it to work.

aayush.deo
Posts: 3
Joined: Tue Oct 17, 2023 4:52 am
Location: Ranchi, Jharkhand, India

Re: The basics of writing/reading user data to the flash memory for long term storage

Wed Feb 14, 2024 8:26 am

If the program is multicore then :-

follow: viewtopic.php?t=311709
if the 2nd core is running, you must pick which core is doing the flashing and which is the "victim"
the victim must then run multicore_lockout_victim_init()
the core doing the flashing must then run multicore_lockout_start_blocking() and multicore_lockout_end_blocking() around any erase/write code, to stop the victim core
core 0

Code: Select all

uint8_t* myDataAsBytes = (uint8_t*) buf;
int myDataSize = sizeof(buf);

int writeSize = (myDataSize / FLASH_PAGE_SIZE) + 1; // how many flash pages we're gonna need to write
int sectorCount = ((writeSize * FLASH_PAGE_SIZE) / FLASH_SECTOR_SIZE) + 1; // how many flash sectors we're gonna need to erase
		
//printf("Programming flash target region...\n");

uint32_t interrupts = save_and_disable_interrupts();
		
multicore_lockout_start_blocking();
		
flash_range_erase(FLASH_TARGET_OFFSET, FLASH_SECTOR_SIZE * sectorCount);
flash_range_program(FLASH_TARGET_OFFSET, myDataAsBytes, FLASH_PAGE_SIZE * writeSize);
		
multicore_lockout_end_blocking();
		
restore_interrupts(interrupts);
core 1 - starts with

Code: Select all

multicore_lockout_victim_init()

Return to “General”