Odd problem retrieving data written to Flash via CyBle_StoreAppData

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

cross mob
Anonymous
Not applicable

I'm having a pretty odd problem - something I hope is just me being stupid.  I'm writing some short data to flash using the CyBle_StoreAppData method but I've noticed that I can only correctly retrieve the newly written data if I "loop" through the array instead of indexing directly into the array.  I put "loop" in quotes because simply creating a for loop that only does one loop changes the output of my printf method. Here is my code followed by the output of the code:

const uint8 test[1] = {6};

for(int i =0; i<1;i++)

{

        iprintf("Before Loop print: %d\n\n", test);  

    }

   

    iprintf("Before Hardcoded print: %d\n\n", test[0]); 

  

       

   CYBLE_API_RESULT_T apiResult = CYBLE_ERROR_OK;

    unsigned char val[1] = {2};

    do

    {

        apiResult = CyBle_StoreAppData(

            val,             

            test,

            1,                 

            0);                  

    }

    while (apiResult != CYBLE_ERROR_OK);

   

    for(int i = 0; i < 1 ; i++)

        iprintf("Loop print: %d\n\n", test);  

    iprintf("Hardcoded print: %d\n\n", test[0]);

Output:

Before Loop print: 6

Before Hardcoded print: 6

Loop print: 2

Hardcoded print: 6

What is going on here?  What am I missing?  I've tried altering the accessing of the 0th element of the written to array, but nothing outside of wrapping the print in a simple loop seems to have any effect.

0 Likes
1 Solution
Anonymous
Not applicable

Okay, thanks to everyone's helpful replies I have a solution!  I was initially misled a little bit as a result of this post (How to store a byte array to flash memory? ) from jrow:

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

Which simplifies the issue a little bit too much, I think. It is inaccurate to say you can just directly access this written data by using the constant variable since - as I showed in the original post - you can apparently only access it through a for loop.  However, I discovered that this hacky method of accessing the data falls apart when your compiler's optimization level goes any higher than Debug.  So, instead, here is what I'm doing to easily access this data (based on suggestions in this thread):

  1. const uint8 test[1] = {6}; 
  2. volatile uint8 *testVolatile = test;
  3.         
  4.    CYBLE_API_RESULT_T apiResult = CYBLE_ERROR_OK; 
  5.     unsigned char val[1] = {2}; 
  6.     do 
  7.     { 
  8.         apiResult = CyBle_StoreAppData( 
  9.             val,               
  10.             test,  
  11.             1,                   
  12.             0);                    
  13.     } 
  14.     while (apiResult != CYBLE_ERROR_OK); 
  15.      
  16.     for(int i = 0; i < 1 ; i++) 
  17.         iprintf("Loop print: %d\n\n", testVolatile );    
  18.     iprintf("Hardcoded print: %d\n\n", testVolatile [0]); 

Having a separate volatile pointer to the memory that is used exclusively for accessing seems to do the trick!  Hopefully someone else down the line finds this useful.

View solution in original post

4 Replies
Anonymous
Not applicable

Hello,

It is probably the compiler optimizing it out. Because test is a const variable, it won't try to access it, will just print 6.

Try declaring test as a const volatile variable. This will tell the compiler that it still is const so that it goes into flash, but it is volatile so don't optimize it out.

(e.g. const volatile uint8 test[1] = {6};)

Regards,

Anonymous
Not applicable

Looks like the CyBle_StoreAppData doesn't accept volatile variables, as I get a  CYBLE_ERROR_INVALID_PARAMETER error after making that change.

I do find that explanation extremely plausible, though.  I'm a bit surprised that no one seems to have had this issue before though (as far as I can tell). 

0 Likes
Anonymous
Not applicable

Generally, storing data to flash is only used on storing changing values, thus constant values won't be stored to the flash using the API, and thus the issue of constant versus volatile for the variable has probably only come up in testing such as this instance. Try having a variable that changes/is used to force the compiler to keep it, and then try again to see if that will fix the issue.

0 Likes
Anonymous
Not applicable

Okay, thanks to everyone's helpful replies I have a solution!  I was initially misled a little bit as a result of this post (How to store a byte array to flash memory? ) from jrow:

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

Which simplifies the issue a little bit too much, I think. It is inaccurate to say you can just directly access this written data by using the constant variable since - as I showed in the original post - you can apparently only access it through a for loop.  However, I discovered that this hacky method of accessing the data falls apart when your compiler's optimization level goes any higher than Debug.  So, instead, here is what I'm doing to easily access this data (based on suggestions in this thread):

  1. const uint8 test[1] = {6}; 
  2. volatile uint8 *testVolatile = test;
  3.         
  4.    CYBLE_API_RESULT_T apiResult = CYBLE_ERROR_OK; 
  5.     unsigned char val[1] = {2}; 
  6.     do 
  7.     { 
  8.         apiResult = CyBle_StoreAppData( 
  9.             val,               
  10.             test,  
  11.             1,                   
  12.             0);                    
  13.     } 
  14.     while (apiResult != CYBLE_ERROR_OK); 
  15.      
  16.     for(int i = 0; i < 1 ; i++) 
  17.         iprintf("Loop print: %d\n\n", testVolatile );    
  18.     iprintf("Hardcoded print: %d\n\n", testVolatile [0]); 

Having a separate volatile pointer to the memory that is used exclusively for accessing seems to do the trick!  Hopefully someone else down the line finds this useful.