This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Flash Memory Issue

Hi,
I have written these 3 functions to erase/read and write.

/////////////////////////////////////////////////////////////////////////////// SNV

const uint32_t f_addr = 0x000FF000; // Last page start address 255

// Create a pointer to that address
uint32_t * p_addr = (uint32_t *)f_addr; //cast f_addr to a pointer

uint32_t erase_SNV()
{
    NRF_LOG_INFO("Memory Erased");
    return sd_flash_page_erase(255);
}


uint32_t write_SNV(int address,uint8_t value)
{
    uint32_t val;
    val=value;
    NRF_LOG_INFO("Data Write in Flash");
    ret_code_t err_code;
    err_code = sd_flash_write(p_addr+address, &val, sizeof(val));
    APP_ERROR_CHECK(err_code);
    return err_code;
}

uint32_t read_SNV(int address)
{
     NRF_LOG_INFO("The Data read from flash is: %d", *(p_addr)+address);
     return *(p_addr)+address;
}


When I write any value from address 1 it gives following wrong output(0 1 2 3).
    write_SNV(1,11);
    read_SNV(1);
    write_SNV(2,12);
    read_SNV(2);
    write_SNV(3,13);
    read_SNV(3);

  //  read_SNV(0);
    read_SNV(1);
    read_SNV(2);
    read_SNV(3);
 



But When I start address from 0 it gives the right values.

    write_SNV(0,10);
    read_SNV(0);
    write_SNV(1,11);
    read_SNV(1);
    write_SNV(2,12);
    read_SNV(2);
    write_SNV(3,13);
    read_SNV(3);

    read_SNV(0);
    read_SNV(1);
    read_SNV(2);
    read_SNV(3);




How can I save values in rondom addresses?
Thanks!

Parents
  • Hello,

    I think you should read up on flash handling before doing this. I suggest that you check out the flash_fds or the flash_fs example, but I can try to explain why this is not working.

    And by the way, if you upload the examples that you use to test it is faster for us to browse your code, and find the references to the SDK\softdevice functions you are using.

    Are you sure that you have pasted the implementation you are using? I suspect you have removed at least one APP_ERROR_CHECK(err_code)?

    Flash operations are fairly slow, compared to the runtime of your application. If I try to run your application implementation, the first write_SNV() is working fine, but the next is generating an error because APP_ERROR_CHECK(err_code) is called with err_code = 17, returned from sd_flash_write(). This is because there is already a flash operation ongoing. 

    If the first flash write is not yet done, it is not possible to read out the flash that you are not yet finished writing in between.

    This is why I recommend you looking into the flash_fs example. When you set up a proper flash handler, you can wait for the flash callback before you try to read it back. Try to search for the flash tickets here on devzone. There are probably hundreds of flash related tickets related to this kind of issue. 

    Best regards,

    Edvin

  • Hi ,

    Sorry for the late reply.Can I add a handler in my current code?

    I am trying this. Is this the correct way?
    Or any suggestion to fix the issue in this code?

    uint32_t write_SNV(int address,uint8_t value)
    {
        uint32_t val;
        val=value;
        ret_code_t         err_code;
        err_code=NRF_ERROR_BUSY;
       // NRF_LOG_INFO("Data Write in Flash");
    
       // err_code = sd_flash_write(p_addr+address, &val, sizeof(val));
        
    
        while(err_code!=NRF_SUCCESS)
        {
        err_code = sd_flash_write(p_addr+address, &val, sizeof(val));
        }
        
    //    APP_ERROR_CHECK(err_code);
    
    
      if(err_code==NRF_ERROR_INTERNAL)
      {
       NRF_LOG_INFO("NRF_ERROR_INTERNAL");
      }
      else if(err_code==NRF_ERROR_INVALID_ADDR)
      {
       NRF_LOG_INFO("NRF_ERROR_INVALID_ADDR");
      } 
      else if(err_code==NRF_ERROR_BUSY)
      {
       NRF_LOG_INFO("NRF_ERROR_BUSY");
      }
      else if(err_code==NRF_ERROR_FORBIDDEN)
      {
       NRF_LOG_INFO("NRF_ERROR_FORBIDDEN");
      }
      else if(err_code==NRF_SUCCESS)
      {
       NRF_LOG_INFO("NRF_SUCCESS");
      }
    
        return err_code;
    }
    

  • I suggest you look into the example SDK\examples\peripheral\flash_fstorage\pca10056\s140\<your IDE>

    Note how there is a layer above sd_flash_write(), namely nrf_fstorage_write().

    In this example the fstorage is initialized with an event handler, fstorage_evt_handler (which is set inside the parameter NRF_FSTORAGE_DEF(nrf_fstorage_t fstorage))

    To answer your question directly, yes. You can have an event handler. Look at how it is done in that example. If you are interrested in a deep dive into how this works, you can see that sd_flash_write() is used in the flash_fstorage example. Search for it in that project. This also has a handler, called nrf_fstorage_sys_evt_handler(), which is set using NRF_SDH_OBSERVER();

    Please note that when you call sd_flash_write() the return value (err_code) will not reflect whether the data was written or not, but whether the operation has been queued or not. The event will be generated when the flash was either written or failed to be written. Please refer to the example. 

     

    Muqarrab said:
    I am trying this. Is this the correct way?
    Or any suggestion to fix the issue in this code?

     What is the issue?

  • Thanks  I am working on it.
    1-How can I read form flash in this case?
    2-Which memory addresses I can directly use in this case? I need 20 bytes simply.
    Thanks

  • Muqarrab said:
    How can I read form flash in this case?

     Look at the header file (.h file) that declares (not defines, declares) the function that writes to flash. Do you find anything there that you can use to read?

     

    Muqarrab said:
    Which memory addresses I can directly use in this case? I need 20 bytes simply.

     Any address that is not in use really. The common way to do it is to use the top of the flash, but you need to consider a few things:

    Do you intend to ever update these values? Or do you write them once, and never update them?

    Do you have any other flash dependent components in your application? Peer manager, for example, for storing bonding information? If so, this will take the top 3 pages of your flash (3*4096 bytes). 

    Do you plan to have a bootloader? If so, that will also use some space in the top of your flash, where the size depends on what bootloader you are using. 

    If you are not experienced with this, I still recommend FDS (at least look it up). It will handle all this for you. What address it uses will be dependent on these questions. It will handle updating the flash whenever you need to. 

    If the answer to all of the questions above is no, then you can use for example 0x000FF000.




  • Look at the header file (.h file) that declares (not defines, declares) the function that writes to flash. Do you find anything there that you can use to read?

    Yes, I have found this function.

    ret_code_t nrf_fstorage_read(nrf_fstorage_t const * p_fs,
                                 uint32_t               src,
                                 void                 * p_dest,
                                 uint32_t               len)
    {
        NRF_FSTORAGE_PARAM_CHECK(p_fs,        NRF_ERROR_NULL);
        NRF_FSTORAGE_PARAM_CHECK(p_dest,      NRF_ERROR_NULL);
        NRF_FSTORAGE_PARAM_CHECK(p_fs->p_api, NRF_ERROR_INVALID_STATE);
        NRF_FSTORAGE_PARAM_CHECK(len,         NRF_ERROR_INVALID_LENGTH);
    
        /* Source addres must be word-aligned. */
        NRF_FSTORAGE_PARAM_CHECK(addr_is_aligned32(src),                NRF_ERROR_INVALID_ADDR);
        NRF_FSTORAGE_PARAM_CHECK(addr_is_within_bounds(p_fs, src, len), NRF_ERROR_INVALID_ADDR);
    
        return (p_fs->p_api)->read(p_fs, src, p_dest, len);
    }

    Do you intend to ever update these values? Or do you write them once, and never update them?

    Yes, I have to update values again and again. 

    Do you have any other flash dependent components in your application? Peer manager, for example, for storing bonding information? If so, this will take the top 3 pages of your flash (3*4096 bytes). 

    Yes, I have enabled bonding.


    Do you plan to have a bootloader? If so, that will also use some space in the top of your flash, where the size depends on what bootloader you are using. 

    Yes, I have to add a secure bootloader in the future.


    If the answer to all of the questions above is no, then you can use for example 0x000FF000.

    Now from what address I should start save values? Nerd

  • I could tell you an address. You should use the page below the FDS pages that the peer manager uses. The peer manager uses the pages directly below the bootloader, so you should use the address of the page below the that again. E.g:

    IF your bootloader starts at 0x000F8000, then you will have the FDS pages (used by the peer manager) at:

    0x000F7000 -> 0x000F7FFF,
    0x000F6000 -> 0x000F6FFF, and
    0x000F5000 -> 0x000F5FFF

    So you can for example use the page 

    0x000F4000 -> 0x000F4FFF for your flash data.

    Remember to set aside an extra page of reserved data in your bootloader. Let me know when you start on that what SDK version you are using and I can tell you the variable you need to change.

    Also let me know if you have changed the number of flash pages used by FDS. By default it is 3 in our examples. 

    How do you intend to update the flash data? Perhaps you can explain how you intend to do it. Hint: Before erasing an entire page, you can only change bits in flash from 1's to 0's. 

    BR,

    Edvin

Reply
  • I could tell you an address. You should use the page below the FDS pages that the peer manager uses. The peer manager uses the pages directly below the bootloader, so you should use the address of the page below the that again. E.g:

    IF your bootloader starts at 0x000F8000, then you will have the FDS pages (used by the peer manager) at:

    0x000F7000 -> 0x000F7FFF,
    0x000F6000 -> 0x000F6FFF, and
    0x000F5000 -> 0x000F5FFF

    So you can for example use the page 

    0x000F4000 -> 0x000F4FFF for your flash data.

    Remember to set aside an extra page of reserved data in your bootloader. Let me know when you start on that what SDK version you are using and I can tell you the variable you need to change.

    Also let me know if you have changed the number of flash pages used by FDS. By default it is 3 in our examples. 

    How do you intend to update the flash data? Perhaps you can explain how you intend to do it. Hint: Before erasing an entire page, you can only change bits in flash from 1's to 0's. 

    BR,

    Edvin

Children

  • Hi

    Remember to set aside an extra page of reserved data in your bootloader. Let me know when you start on that what SDK version you are using and I can tell you the variable you need to change.

     I am using nRF5SDK17009d13099 SDK.

    Also let me know if you have changed the number of flash pages used by FDS. By default it is 3 in our examples.

    I think I didn't change any page.


    I am trying to use the example flash_fstorage. I am using the following command to read the value from flash but getting the following values shown in the screenshot.


        NRF_LOG_INFO("Writing \"%s\" to flash.", m_hello_world);
        rc = nrf_fstorage_write(&fstorage, 0x3f000, m_hello_world, sizeof(m_hello_world), NULL);
        APP_ERROR_CHECK(rc);
    
        wait_for_flash_ready(&fstorage);
        NRF_LOG_INFO("Done.");
    
    
    
        rc = nrf_fstorage_read(&fstorage, 0x3f000, m_hello_world_f, sizeof(m_hello_world_f));
        APP_ERROR_CHECK(rc);
    
    
        for(int i=0;i<sizeof(m_hello_world_f);i++)
        {
         NRF_LOG_INFO("Read Data : %c",m_hello_world_f[i]);
        }


    Is there any simple file where I can just call read/write functions to save/read from flash?
    Thanks!

  • I guess there is something in that flash area already. Are you running the unmodified flash_fstorage example, or did you add it to another project?

    Try to comment out the nrf_fstorage_write() and see what it prints if you don't write anything. Also, %c will only print characters if it is an ascii value. Try to print using %02x:

    If it doesn't print FF for all the values, it means that the flash is not empty. Also, you can use NRF_LOG_RAW_INFO(); if you don't want the linefeed after every char:

        NRF_LOG_INFO("Reading from flash hex:");
        for(uint8_t i=0; i<sizeof(m_hello_world); i++)
        {
            NRF_LOG_RAW_INFO("%02x:", m_hello_world[i]);
        }
        NRF_LOG_RAW_INFO("\r\n");
        NRF_LOG_INFO("Reading from flash char:");
        for(uint8_t i=0; i<sizeof(m_hello_world); i++)
        {
            NRF_LOG_RAW_INFO("%c", m_hello_world[i]);
        }
        NRF_LOG_RAW_INFO("\r\n");
        NRF_LOG_INFO("done");

    I suspect that there is some data in that flash area before you try to write to it. As I mentioned, writing to flash can only change 1's to 0's, so you need to erase the page first. Try using "nrfjprog --eraseall" befoe programming the example. Also, if you add things to your project, then the address 0x3F000 may already be used by the application .hex file.

    Regarding everything else: So you are using SDK17, and you use the peer manager. Look at the sdk_config.h file of the project that uses the peer manager, and search for FDS_VIRTUAL_PAGES. This sets the number of FDS pages. By default it is 3.

    The secure_bootloader\pca10056_s140_ble bootloader has a flash start address of 0xf8000. So if you use this one, then it means that the FDS pages are on 0xF7000, 0xF6000 and 0xF5000. You can use 0xF4000->0xF4FFF. 

    In your bootloader project, when you get this far, check it's sdk_config.h file. Look for NRF_DFU_APP_DATA_AREA_SIZE.

    This is the parameter saying how much of the flash beneath the bootloader that is reserved for application flash use, and this area will not be overwritten during a DFU. 

    By default it is set to 12288. This is the number of bytes that are protected. One flash page is 4096 bytes long, so this corresponds to 3 pages (the FDS pages). If you want to add another page for custom data, please increase this number by 4096.

    BR,

    Edvin

  • I guess there is something in that flash area already. Are you running the unmodified flash_fstorage example, or did you add it to another project?

    I am using the unmodified flash_fstorage example.


    Here is the data I have read after implementing your code part.

  • You need to erase your chip before programming it. I guess the content of that area is from another project that you tested once.

     

    Edvin said:
    Try using "nrfjprog --eraseall"
  • You need to erase your chip before programming it. I guess the content of that area is from another project that you tested once.

Related