How to store a byte array to flash memory?

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Anonymous
Not applicable

My PSoC board connects to an Android app though Bluetooth. The Android app sends a 4 byte array and I want to save this array to flash storage and later retrieve it and assign it to a variable. How can I go about doing this? 

0 Likes
1 Solution
Anonymous
Not applicable

Hi Rabiul,

   

The function you want to look into is CyBle_StoreAppData(). There aren't many examples that show this, but the BLE Component's generated source uses the relevant API call to store client characteristic configuration descriptor data for bonded devices.

   

Basically, you need to declare some global constant data in your code so the compiler/linker assigns it to a predictable location in flash, and then use that API call to write new values (from RAM) whenever you need to update it. You can read the value of the const byte array at any time, but you have to use CyBle_StoreAppData() to change it. Data stored this way will persist across resets and power cycles.

   

Here's a really simple example:

   
/* constant variable container, will be stored in flash */ ​const uint8 flash_storage[16] = {0};  /* simple function to write data void StoreInFlash(uint8 *newData, uint8 length) {     /* make sure the BLE stack is not in low-power mode */     CyBle_ExitLPM();      /* repeat flash write attempt until success */      do     {         /* write segment of configuration structure from RAM into flash */         CYBLE_API_RESULT_T result = CyBle_StoreAppData(             newData,                    /* uint8 pointer to source data */             (uint8_t *)&flash_storage,  /* uint8 pointer to const destination */             length,                     /* number of bytes to write */             0);                         /* don't force write, but loop will keep retrying */     }     while (result != CYBLE_ERROR_OK); }

View solution in original post

0 Likes
27 Replies
Anonymous
Not applicable

Hi Rabiul,

   

The function you want to look into is CyBle_StoreAppData(). There aren't many examples that show this, but the BLE Component's generated source uses the relevant API call to store client characteristic configuration descriptor data for bonded devices.

   

Basically, you need to declare some global constant data in your code so the compiler/linker assigns it to a predictable location in flash, and then use that API call to write new values (from RAM) whenever you need to update it. You can read the value of the const byte array at any time, but you have to use CyBle_StoreAppData() to change it. Data stored this way will persist across resets and power cycles.

   

Here's a really simple example:

   
/* constant variable container, will be stored in flash */ ​const uint8 flash_storage[16] = {0};  /* simple function to write data void StoreInFlash(uint8 *newData, uint8 length) {     /* make sure the BLE stack is not in low-power mode */     CyBle_ExitLPM();      /* repeat flash write attempt until success */      do     {         /* write segment of configuration structure from RAM into flash */         CYBLE_API_RESULT_T result = CyBle_StoreAppData(             newData,                    /* uint8 pointer to source data */             (uint8_t *)&flash_storage,  /* uint8 pointer to const destination */             length,                     /* number of bytes to write */             0);                         /* don't force write, but loop will keep retrying */     }     while (result != CYBLE_ERROR_OK); }
0 Likes
Anonymous
Not applicable

Hi jrow,
Thank you so much for your response. I still have some questions if you don't mind. 

So if I want to retrieve the data I wrote, all I have to do is read the constant variable container? Also, I've read that writing to flash interferes with Bluetooth so it's good to attempt writing to flash when there is no Bluetooth device connected. When exactly should I try to write to flash? Would you recommend doing it after the event CYBLE_EVT_GAP_DEVICE_DISCONNECTED in the event handler?

0 Likes
Anonymous
Not applicable

Hi Rabiul,

   

>> So if I want to retrieve the data I wrote, all I have to do is read the constant variable container?

   

That is correct. In my previous example, you can directly read the flash_storage byte array in exactly the same way you would if it were non-const and stored in RAM. The compiler/CPU takes care of the memory access from flash vs. RAM transparently.

   

>> Also, I've read that writing to flash interferes with Bluetooth so it's good to attempt writing to flash when there is no Bluetooth device connected. When exactly should I try to write to flash?

   

I haven't encountered much trouble with flash writes during a connection, but that likely depends on CPU speed and connection parameters, among other things. If you want to play it extra safe, then yes--you would wait for the CYBLE_EVT_GAP_DEVICE_DISCONNECTED stack event to occur before storing in flash. Of course, this assumes that you can guarantee an execution flow of (1) advertise -> (2) connect -> (3) client writes data -> (4) client disconnects, so that the disconnection will always occur before you need to write new data. If your client needs to stay connected indefinitely or for a long time, and you need to make sure data is stored in flash before this much time elapses, then waiting for a disconnection might not be suitable.

   

You can try performing the flash write while connected anyway and see what the consequences are in your case; it might work fine for you.

jrow,

   

I've been trying to get your code for "a really simple example" of storing data to flash (5 Aug 2016) working on a Pioneer Board with a CYBLE-214009-00 module.  It seems to be writing to flash OK but I have two problems (that I know of):

   

1.  Since it appears that in order to get the compliler to place the flash_storage[16] array in flash instead of RAM it has to be declared a constant and initialized to some value, in this case {0}.  Problem is that everytime the program is re-run, such as after a power cycle, it re-initializes the array to zero again, which sort of defeats the purpose of saving it to flash.  Am I missing something here?

   

2.  After the storage to flash takes placed, and inside the program's for(;;) loop I added the following line to read the first element of the saved data to a variable:

   

readfromflash = flash_storage[0];

   

I'm kind of rusty with C...actually with everything at this point in my life (I've just turned 75)...so I'm not certain how to read it, but I've tried every permutation and combination of pointer stuff I can think of and have been unable to get this to work.

   

I'd be greatful if you could straighten me out on this.

   

Thanks,
Dennis

0 Likes
Anonymous
Not applicable

Hi Dennis,

   

First of all, nice work honing your C skills at 75! I hope I am equally driven with whatever the current tech is at that phase of life.

   

Concerning the project, can you create an archive and attach it to a post here for review? This will be easier for troubleshooting than analyzing only from the description in your post(s).

   

When you declare a const byte array in code, the compiler places the initialization values in the .data (or .text) section of flash, and no further initialization should be done when the code execution starts. Any references in code should point directly to the location in flash rather than some copy in RAM, which means the data is only "reset" so to speak when you actually re-flash the chip with the compiled .hex image. Simply rebooting the module or power-cycling it will not affect the data stored in flash.

   

If you are reading the data and it isn't changing, then I suspect the write operation is actually to blame. However, I can't say for sure until I take a look at your code.

   

Jeff

0 Likes
lock attach
Attachments are accessible only for community members.

Hi jrow,

   

Attached is the archive you asked me to send.

   

RE: staying interested and alive at 75.  I've decided my goal is to live to be 130 so I'm only a little over middle age now!  Besides, I'm too busy to die. 😉

   

Dennis

0 Likes
Anonymous
Not applicable

Good luck reaching your goal! What a great approach to life.

   

I haven't had a chance to try your code with hardware yet (I will tomorrow), but I notice that there is no call in your application to the CyBle_Start() API. I am not sure off-hand whether it is strictly necessary to do this, but in all of the applications I've worked with which also used the CyBle_StoreAppData() API, the stack was initialized and started before performing any flash writes.

   

I know it seems like it shouldn't be necessary, but I'm not sure exactly what internally happens during initalization. As a general rule, the way PSoC Component source files are built, you usually don't want to call any [Component]_xxx() APIs until after the [Component]_Start() or at least [Component]_Init() method is called. Can you try this in your code?

   

Jeff

0 Likes

Jeff,

   

Entirely by accident, I discovered that the examples in PSoC Creator has one for writing to SFlash that is not the same as the one in 100 projects in 100 days.  And it actually works on the EZ-BLE module I'm using.  So I'm all set. No need for you to look over my code.  But thanks for your help anyway. 

   

Dennis

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Welcome in the forum!

   

At first, I hope you are talking about Bluetooth Low Energy (BLE) which is different from standard Bluetooth.

   

For storing small amounts of data there is a BLE Supervisory Flash

   

within the PSoC4 BLE devices. See example.

   

 

   

Bob

Anonymous
Not applicable

Thank you Bob,

   

Yes, I am indeed talking about Bluetooth Low Energy. What is the difference between supervisory flash and what jrow has recommended?

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

@Jrow

   

const uint8 flash_storage[16];
is not enough to guarantee that the variable is put into flash!!! It additionally needs an initialization to perform that.  Care must be taken so that the compiler does not "remember" the initialization values when referred to in the program.

   

 

   

Bob

Anonymous
Not applicable

It does not seem to be working. Bob, how can I initialize the array but not have it remember the initialization values?

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

I used memcpy() to transfer flash data into sram.

   

 

   

Bob

0 Likes
Anonymous
Not applicable

I have the exact same issues/question, so I'm replying to follow.  When you say memcpy(), do you mean, on initializing, to copy the const variable to an application dynamic variable?

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

copy the const variable to an application dynamic variable  Yes, exactly.

   

I frequently use a struct to keep the information. one copy is in flash and a working copy is in sram. So I can initialize my sram struct from flash and when values changed I can update flash. The struct usually holds a "Magic Number" to indicate a valid struct and a "BurnCount" to keep track of how many times it was written to flash.

   

 

   

Bob

Anonymous
Not applicable

Bob,

   

Could you post a bit more of an example? I follow what you are saying, but am unclear on exactly how to do this. I read a value from a sensor and place the single byte in a variable. I write it to a pointer. I print the pointer using the UART so I know what the value is and it is correct. When I write that single byte with the CyBle_StoreAppData as Jrow shows, I get 0x00 when I read it back. My read is immediately after it is written.  I am guessing I do not have it 'initialized' as you state in post #7.

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Can you please post your complete project, so that we all can have a look at all of your settings. To do so, use
Creator->File->Create Workspace Bundle (minimal)
and attach the resulting file.

   

 

   

Bob

0 Likes
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

Bob,

   

This is running with the CYALKIT-E02 beacon. Let me know if you see anything.

   

k

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Sorry, I was not referring to a CyBLE function, I was talking about Cy flash routines you can find in System Reference Guide.

   

 

   

Bob

0 Likes
Anonymous
Not applicable

Bob,

   

the function that jrow posted in post 2 as a response to the original question uses the CyBle_StoreAppData() call. Will this no longer work? I cannot seem to get it to work.

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Of course it will work! Follow jrows explanations.

   

 

   

Bob

0 Likes
KyGr_1968351
Level 2
Level 2
5 sign-ins 10 replies posted 5 replies posted

Where can I find these constants to use with my 256kB PSoC4 device?

   
    

#define USER_SFLASH_ROW_SIZE (128u) /* SFlash row size for 128KB flash BLE device. For other PSoC 4 BLE devices
* with higher flash size, this example project might need some modification.
* Please check the device datasheet and TRM before using this code on non 128KB
* flash devices */
#define SFLASH_STARTING_VALUE (0x00) /* Starting value to be stored in user SFlash to demonstrate SFlash write API */
#define USER_SFLASH_ROWS (4u) /* Total number of user SFlash rows supported by the device */
#define USER_SFLASH_BASE_ADDRESS (0x0FFFF200u) /* Starting address of user SFlash row for 128KB PSoC 4 BLE device */
#define LOAD_FLASH 0x80000004
#define WRITE_USER_SFLASH_ROW 0x80000018
#define USER_SFLASH_WRITE_SUCCESSFUL 0xA0000000

   
0 Likes
Anonymous
Not applicable

They might be the same, since SFlash is more or less unrelated with the flash chip that runs the code 🙂

0 Likes

I found the answer last night. They are different. The rows in 256kB devices are 256B and the address is slightly different. I'll pull request my change to the github repo if I get a chance.

0 Likes
KyGr_1968351
Level 2
Level 2
5 sign-ins 10 replies posted 5 replies posted

Is it possible to write just a partial row? I'm thinking I could preserve the flash lifetime if I'm only updating a few bytes at a time when they need to change rather than the whole row.

   

My guess is "no", but figured it was worth asking.

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Basically not. a row is the smallest unit that can be erased and re-programmed.

   

But with a bit of software around you might read a complete row into ram, change the required byte(s) and write the ram back to the row.

   

 

   

Bob

0 Likes
Anonymous
Not applicable

Hi

   

I am trying to write data on the SFLAH of PROC on CYBLE 02200100 i am successful in wririg to all th four row i have three question here 

   

1)The document tell me that the first row that means row0 of SFLASH will be used to store BLE address ,so does that mean that i cannot use this row for storing any other user data in this row if i am using BLE Component.Although currently i am able to write on all fpur rows and i am not using any BLE component.

   

2)When i do the user protection from FLASH SECURITY  tab in ,cydwr then although i have written protected on these rows still all the new data is written on the lines which i have protected.how to ensure the row protection

   

3)Can please send an example code doing read a complete row into ram, change the required byte(s) and write the ram back to the row.

   

Niti

0 Likes