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

Problem with fds: Flash read, write, delete calling that function using android phone.

Hello to all,

I am using nRF52832 DK with sd132, v6.0.0 and sdk 15.0.0, segger embedded studio. We want to achieve change application timer time (APP_TIMER_TICKS(update_time)) using android phone. We have a sensor devices it will wake up as per app timer time defined, we want to change this wake up time using Noridc UART tool box app. For that we are using fds example as referred in given sdk 15.0 and other nRF5-flash-storage-examples .

We are able to flash write read and delete but problem is:

  1.  When i call fds_test_find_and_delete(), fds_test_write(), fds_read() whenever received command from nordic UART app it not able to read and write at this time.
  2. I want to change update_time variable of app timer ticks using android phone and store this time in flash. Whenever want to user need to change this time first delete previous and update latest send time. 
  3. Will you please provide me program snippet for How i call flash fds API through android phone and store received time in that app_timer ticks. Confused regarding this.

I am currently using this following functions for FDS read, write, and delete:

static ret_code_t fds_test_write(void)
{
		
    //static uint32_t const m_deadbeef[2] = {0xDEADBEEF,0xBAADF00D};
    static uint8_t const m_deadbeef[1] = {0x14};
//    memcpy(m_deadbeef, write_data, sizeof(m_deadbeef));
    fds_record_t        record;
    fds_record_desc_t   record_desc;

    // Set up data.
    
    // Set up record.
    record.file_id        = FILE_ID_FDS_TEST;
    record.key            = REC_KEY_FDS_TEST;
    record.data.p_data    = &m_deadbeef;
    //record.data.length_words   = sizeof(m_deadbeef)/sizeof(uint32_t);
    record.data.length_words   = sizeof(m_deadbeef)/sizeof(uint8_t);
                    
    ret_code_t ret = fds_record_write(&record_desc, &record);
    if (ret != FDS_SUCCESS)
    {
                    return ret;
    }
     NRF_LOG_INFO("Writing Record ID = %d \r\n",record_desc.record_id);
    return NRF_SUCCESS;
}

static ret_code_t fds_read(void)
{

    fds_flash_record_t  flash_record;
    fds_record_desc_t   record_desc;
    fds_find_token_t    ftok ={0};//Important, make sure you zero init the ftok token
    //uint32_t *data;
    uint8_t *data;
    uint32_t err_code;
    
    NRF_LOG_INFO("Start searching... \r\n");
    // Loop until all records with the given key and file ID have been found.
    while (fds_record_find(FILE_ID_FDS_TEST, REC_KEY_FDS_TEST, &record_desc, &ftok) == FDS_SUCCESS)
    {
                    err_code = fds_record_open(&record_desc, &flash_record);
                    if ( err_code != FDS_SUCCESS)
                    {
                            return err_code;		
                    }
                    
                    NRF_LOG_INFO("Found Record ID = %d\r\n",record_desc.record_id);
                    NRF_LOG_INFO("Data = ");
                    //data = (uint32_t *) flash_record.p_data;
                    data = (uint8_t *) flash_record.p_data;
                    for (uint8_t i=0;i<flash_record.p_header->length_words;i++)
                    {
                            NRF_LOG_INFO("0x%8x ",data[i]);
                    }
                    NRF_LOG_INFO("\r\n");
                    // Access the record through the flash_record structure.
                    // Close the record when done.
                    err_code = fds_record_close(&record_desc);
                    if (err_code != FDS_SUCCESS)
                    {
                            return err_code;	
                    }
    }
    return NRF_SUCCESS;
		
}


static ret_code_t fds_test_find_and_delete (void)
{
    fds_record_desc_t   record_desc;
    fds_find_token_t    ftok;

    ftok.page=0;
    ftok.p_addr=NULL;
    // Loop and find records with same ID and rec key and mark them as deleted. 
    while (fds_record_find(FILE_ID_FDS_TEST, REC_KEY_FDS_TEST, &record_desc, &ftok) == FDS_SUCCESS)
    {
        fds_record_delete(&record_desc);
        NRF_LOG_INFO("Deleted record ID: %d \r\n",record_desc.record_id);
    }
    // call the garbage collector to empty them, don't need to do this all the time, this is just for demonstration
    ret_code_t ret = fds_gc();
    if (ret != FDS_SUCCESS)
    {
        return ret;
    }
    return NRF_SUCCESS;
}

Parents
  • You cannot call the fds API through an android phone!

    What you will need to do is to devise some sort of command that your app will send to instruct your nRF code to update the parameters, and store in Flash

    please provide me program snippet for How i call flash fds

    That is exactly what the example project does - but it does it for an interactive human user at a terminal.

    So you just need to get rid of the interactive CLI stuff, and implement a command over the BLE link ...

  • Thanks for fast response,

    So you just need to get rid of the interactive CLI stuff, and implement a command over the BLE link ...

    But as you said above how i can implement CLI stuff over BLE link will you please provide me tutorial or example.

    If i call flash write function like this is it have any restriction:

    When Nordic UART tool box connected to device then we send 3 commnd-->

    static void nus_data_handler(ble_nus_evt_t * p_evt)
    {
    
    if (p_evt->type == BLE_NUS_EVT_RX_DATA)
    {
    uint32_t err_code;
    NRF_LOG_INFO("nus_data_handler call");
    // send_to_central();
    NRF_LOG_DEBUG("Received data from BLE NUS. Writing data on UART.");
    NRF_LOG_HEXDUMP_DEBUG(p_evt->params.rx_data.p_data, p_evt->params.rx_data.length);
    
    for (uint32_t i = 0; i < p_evt->params.rx_data.length; i++)
    {
    do
    {
    err_code = app_uart_put(p_evt->params.rx_data.p_data[i]);
    if(p_evt->params.rx_data.p_data[i] == '3')
    {
    NRF_LOG_INFO("Start flashing....");
    err_code = fds_test_find_and_delete();
    APP_ERROR_CHECK(err_code);
    nrf_delay_ms(1000);
    fds_test_write();
    nrf_delay_ms(1000);
    // fds_read();
    break;
    }

    Thanks,

  • Hi,

    If got server error due to any connection problem, so that time sensor device is not able to transmit data to server, since we want to store that time  sensor readings in flash. Once readings stored in flash and whenever sensor wkae up want to read stored data from flash and sent it to server.

    For achieving this i am confused & struggling how i can write this logic and i set file ID, record_key for each reading and also once reading transmitted to server after that delete specific reading.

    Will you please help me how i can achieved this and also can you provide tutorial or any other useful data for understanding flash api use in detail like what is record_key, file_id, data write address location etc.

    Thank you......!!

  • Hello,

    There is a user guide for the fds library on infocenter:

    http://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk5.v15.2.0%2Flib_fds_usage.html

    Alternatively, there is also a user guide for fstorage:

    http://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk5.v15.2.0%2Flib_fstorage.html

    The advantage of using the FDS library is that it will handle the flash storage for you, ensuring an even "wear and tear" for the flash.

    A thing that isn't mentioned specifically in the fds guide is that when you e.g. write a record, you should wait for a write and a delete event after using the suggested write or delete functions before you do another fds function. These events are described here.

    So if you call your write function fds_write_test() (which is doing what is described in the "writing a record" snippet), you should wait for the event before writing a new record:

    volatile bool m_fds_init_success = false;
    volatile bool m_fds_write_success = false;
    
    static void fds_evt_handler(fds_evt_t const * p_fds_evt)
    {
        switch (p_fds_evt->id)
        {
            case FDS_EVT_INIT:
                if (p_fds_evt->result != FDS_SUCCESS)
                {
                    //initialization failed.
                }
                else
                {
                    m_fds_init_succeess = true;
                }
                break;
            case FDS_EVT_WRITE:
                if (p_fds_evt->result == FDS_SUCCESS)
                {
                    m_fds_write_success = true;
                }
        }
    }
    
    int main(void)
    {
        fds_init();
        while (!m_fds_init_succes){};
        fds_test_write();
        while (!m_fds_init_success){};
        m_fds_init_success = false;
        
    }

    Best regards,

    Edvin

  • Hello,

    Thanks for providing links and tutorial...

    I am able to write some data into flash using fds as per call write function like this:

    fds_write(0x0001, 0x1111);

    But still confused for update this already stored data on same address(file ID and rec_key)

    Can you please tell me how i can do that?

    Another ques:

    1. What is maximum size of File ID & record key?
    2. We want to store near about 24KB data which is one sensor reading data, So if define specific file ID and record key for that. Is it stored in single file ID OR i need to add next file ID once memory NO memory error got.
    3. Will you please explain Or provide program snippet for update flash data & store large amount of data in single operation.

    Thanks for great supporting...!!

  • Hello,

    You can't re-write to the same address. The bits in the flash can only be changed from '1's to '0's. To rewrite to the same address, you need to erase the entire flash page (only one page, not the entire flash).

    The advantage of FDS is that it uses records, so you can update a record using fds_record_update(). When you do this, the FDS module will write this record to a new place in flash, and mark the old one for deletion. Note that it is not yet deleted. If you get an error message at some point saying that the flash is full, you must do an FDS Garbage Collection (fds_gc()). This function will go through all the records. If the record is still valid, it will copy it to a new flash page, and invalidate the old copy. When it has gone through the entire page, and everything that is still valid is copied, it will delete the old page, so that you can use it again. 

    Note that records that you delete with fds_record_delete() are also not completely deleted. They are marked for deletion, and will be deleted on the next fds_gc().

    1: The maxiumum size is 1018. That is one page size (1024) minus some headers. You can read about it here.

    2: You can read about the IDs and record keys on infocenter (link to fds_record_write())

    3: See the first part of this post. You can update records, and run fds_gc() to delete old copies.

    Best regards,

    Edvin

  • Thanks for this providing this information..!!

    We got one issue which is When i select debug configuration in seeger embedded St.(SES) the flash write operation is success. But When i select release config. in SES the flash write operation is failed and getting error code 3 in NRF_LOG.

    Why this error coming what is the meaning of error 3 only when select release config. build?

    Is any other configuration do i need in SES or in program to work for release build please let me know..!!

    Thanks..!!!

Reply
  • Thanks for this providing this information..!!

    We got one issue which is When i select debug configuration in seeger embedded St.(SES) the flash write operation is success. But When i select release config. in SES the flash write operation is failed and getting error code 3 in NRF_LOG.

    Why this error coming what is the meaning of error 3 only when select release config. build?

    Is any other configuration do i need in SES or in program to work for release build please let me know..!!

    Thanks..!!!

Children
  • Where do you get the error 3? 

    The only difference between Release and Debug is your project settings. 

    Try to define "DEBUG" in your preprocessor defines while you use the "Release" build, and see if the log prints any info on where error_code 3 is coming from.

  • While using release config. I defined DEBUG in preprocessor, it worked now able successfully flash data. But problem getting is When i flash first time it successfully flash and also read properly. But when i flash other data on other FileID and rec key got successful flash event gen But when i turn OFF dev board and again check second time flash data get empty record first flash data read properly.

    I am more struggling to work properly for flash read write and update data?

    Here is my update read and write program snippet:

    void fds_read(uint16_t file_ID, uint16_t rec_key)
    {
        ret_code_t err_code = FDS_SUCCESS;
        fds_flash_record_t  flash_record;
        fds_record_desc_t   record_desc;
        fds_find_token_t    ftok;
        memset(&ftok, 0x00, sizeof(fds_find_token_t));
        memset(fdsRead_buff, 0, sizeof(fdsRead_buff));
        
        while (fds_record_find(file_ID, rec_key, &record_desc, &ftok) == FDS_SUCCESS)
        {
            err_code = fds_record_open(&record_desc, &flash_record);
            if (err_code != FDS_SUCCESS)
            {
                // Handle error
                NRF_LOG_INFO("fds_record_open error %d\r\n", err_code);
            }
            uint8_t *data = (uint8_t *) (flash_record.p_data);
            NRF_LOG_INFO("record found:%s\r\n", (uint32_t *)data);
            for (int i=0;i<flash_record.p_header->length_words;i++)
            {
                fdsRead_buff[i] = data[i];
            }
    //        NRF_LOG_INFO("fdsRead_buff:%s\r\n", (uint32_t *)fdsRead_buff);
            // Access the record through the flash_record structure
            // Close the record when done.
            err_code = fds_record_close(&record_desc);
            if(err_code != FDS_SUCCESS)
            {
                // Handle error
                NRF_LOG_INFO("fds_record_close err_code %d\r\n", err_code);
            }       
        }
    }
    
    static ret_code_t fds_write(uint16_t file_ID, uint16_t rec_key)  //char *flashData[]
    {
    		
        NRF_LOG_INFO("In flashing: %s",(uint32_t)fdsWrite_buff);
    
        fds_record_t        record;
        fds_record_desc_t   record_desc;
        fds_find_token_t    ftok;
        ftok.page=0;
        ftok.p_addr=NULL;    
        // Set up record.
        record.file_id        = file_ID;
        record.key            = rec_key;
        record.data.p_data    = &fdsWrite_buff;
        //record.data.length_words   = sizeof(m_deadbeef)/sizeof(uint32_t);
        record.data.length_words   = (sizeof(fdsWrite_buff) + 3) / 4; //sizeof(m_deadbeef)/sizeof(uint8_t);
                        
        while (fds_record_find(file_ID, rec_key, &record_desc, &ftok) == FDS_SUCCESS)
        {
            fds_record_delete(&record_desc);
            NRF_LOG_INFO("Deleted record ID: %d \r\n",record_desc.record_id);
        }
        ret_code_t ret = fds_record_write(&record_desc, &record);
        if (ret != FDS_SUCCESS)
        {
           return ret;
        }
    //     NRF_LOG_INFO("Writing Record ID = %d \r\n",record_desc.record_id);
        return NRF_SUCCESS;
    }
    
    

    For first data file ID= 0x0001 & rec_key= 0x1111

    For second data file ID= 0x0002 & rec_key= 0x2222

    Will you please check my code for where should i am getting wrong What is the other best way or program function for flash read, write, update data.

    Thanks...!!!!!

  • Hello,

    Can you describe what you see?

    Do you get any "fds_record_open error..." in your log?

    Do you get any "Delete record ID:..."?

    I see that you may not actually delete all your records, even though you try. You don't wait for the delete event to finish.

    What does your fds_evt_handler look like?

    I could send you a project, but it would look like the SDK\examples\peripheral\flash_fds example. You can look at this.

    Alternatively, upload your entire project, and I can take a look.

    BR,

    Edvin

  • I am trying to save WiFi configuration in flash for that i am doing Send specific cmd from nordic uart app with included SSID name & password. It successfully stored in flash here is bellow log:

    But now problem getting when reading this stored config in flash getting empty buffer each time:

    As like log bellow:

    The delete record ID is getting correct and increase each write event occur.

    But why getting empty when turn OFF board and call read command.

    I am calling simple fds write and read function once specific command received from nordic uart app.

    as like bellow:

    fds_write(FILE_ID_SSID, REC_KEY_SSID); // when 9 cmd send

    fds_read(FILE_ID_SSID, REC_KEY_SSID); // when 1 cmd send

    my fds_event Handler function is bellow:

    static void fds_evt_handler(fds_evt_t const * const p_fds_evt)
    {
        switch (p_fds_evt->id)
        {
            case FDS_EVT_INIT:
                if (p_fds_evt->result != FDS_SUCCESS)
                {
                    // Initialization failed.
                }
                break;
    	case FDS_EVT_WRITE:
                if (p_fds_evt->result == FDS_SUCCESS)
                {
                   m_fds_write_success = true;
                   NRF_LOG_INFO("Flash Write event generated");
                }
                break;
            case FDS_EVT_DEL_RECORD:
                if (p_fds_evt->result == FDS_SUCCESS)
                {
                    NRF_LOG_INFO("Flash data record deleted");
                    m_fds_delete_success = true;
                }
                 break;
            default:
                break;
        }
    }

    Will you please help me whats going wrong in above functions and procedure.

    If you create this case as private then i can share my project to you.

    Thanks...!!!!

  • First, can you try to wait for the FDS_EVT_DEL_RECORD event before you start writing your next record? It doesn't seem like you do this from your snippet in the previous reply.

        while (fds_record_find(file_ID, rec_key, &record_desc, &ftok) == FDS_SUCCESS)
        {
            m_fds_delete_success = false;
            fds_record_delete(&record_desc);
            while(!m_fds_delete_success)
            {
                //wait
            }
            
            NRF_LOG_INFO("Deleted record ID: %d \r\n",record_desc.record_id);
        }

Related