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,

  • I am calling  fds_delete_file() from main here is below snippet:

    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_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);
        switch (p_evt->params.rx_data.p_data[0]) {
        ...
        case '8': // To detach configured machine info.
          NRF_LOG_INFO("8 cmd received");
          delete_all_reading_process();
          ...
    
    /* This function is used for delete all stored reading availble in flash even if any not available then clean flash for that file number*/
    void delete_all_reading_process() {
      uint16_t file_no;
      ret_code_t ret;
      ret = fds_find_and_delete(FILE_ID_FRONT_REAR_VAL, REC_KEY_FRONT_REAR_VAL);
      if (ret == FDS_SUCCESS) {
        NRF_LOG_INFO("Deleted front & rear value");
      }
      for (file_no = 1; file_no <= READINGS_STORE; file_no++) {
        NRF_LOG_INFO("Deleting File no:%d", file_no);
        ret = fds_delete_file(file_no);
      }
      if (ret != FDS_SUCCESS) {
        ble_nus_data_send(&m_nus, DETACH_MACH_FAILED, &msg_code_len, m_conn_handle); // send message to connected phone
      }
      detached_machine_info();
    }

    If this wrong how I can set flag from the SD interrupt. I am not understand how i can check this is it inside a soft-device interrupt. 

    I am calling this function from nus_data_handler(..);

    Thanks...

  • Ok. You are calling it from the nus_data_handler. This is a softdevice interrupt, so it will not allow the FDS to start before you exit this interrupt.

    You need to exit this function (let it run to the end) before you start your FDS operations. Very simplified, it will look something like this:

    //near top of main.c:
    static volatile bool fds_delete_flag = false;
    
    
    nus_data_handler()
    {
    
    ... 
        case '8':
        fds_delete_flag = true;
        break;
    ...
    }
    
    
    int main(void)
    {
        ret_code_t err_code;
        init_everything();
        ...
        
        for (;;)
        {
            if (fds_delete_flag == true)
            {
                err_code = fds_delete_file();
                if (err_code == NRF_SUCCESS)
                {
                    fds_delete_flag = false;
                }
            }
            power_manage();
        }
    }

    The point is to exit the nus_data_handler() before you call the FDS functions.

  • Hi Edvin,

    As per you suggested above program snippet this is working and we are able to sent response after completion of flash process. 

    Here is my below is this correct shall we go ahead?

      for (;;) {
        if (fds_delete_flag == true) {
          delete_all_reading_process();
        }
        if (sleep_mode_enable == true) {
          sleep_mode_enter();
          sleep_mode_enable = false;
        }
        idle_state_handle();
      }

    I have set fds_delete_flag = false; when last flash operation success.

    Now every thing is working fine.

    Thanks for the your suggestion.

  • Yes. That looks good. 

     

    vishal said:
    I have set fds_delete_flag = false; when last flash operation success.

     If I were to suggest one change, maybe set the fds_delete_flag = false directly after calling delete_all_reading_process(); so that it doesn't attempt to run delete_all_reading_process() several times. You can rather set it back to true if the delete event is called with result != success to try again.

  • Thanks for quick response..!

    I have also set fds_delete_flag = false; after delete_all_reading_process().

    Just one question Is it necessary to call fds_gc(); after each delete record event?

    ret_code_t fds_delete_file(uint16_t file_ID) {
      ret_code_t ret = fds_file_delete(file_ID);
      if (ret != FDS_SUCCESS) {
        return ret;
      }
      wait_for_next_delete(); /* wait for this stored file successfully deleted*/
      /* Call garbage collector to clean dummpy data from flash*/
      ret = fds_gc(); 
      if (ret != FDS_SUCCESS) {
        return ret;
      }
      return NRF_SUCCESS;
    }

    What will happen if not call fds_gc(); after delete event.

    Thanks...

Reply
  • Thanks for quick response..!

    I have also set fds_delete_flag = false; after delete_all_reading_process().

    Just one question Is it necessary to call fds_gc(); after each delete record event?

    ret_code_t fds_delete_file(uint16_t file_ID) {
      ret_code_t ret = fds_file_delete(file_ID);
      if (ret != FDS_SUCCESS) {
        return ret;
      }
      wait_for_next_delete(); /* wait for this stored file successfully deleted*/
      /* Call garbage collector to clean dummpy data from flash*/
      ret = fds_gc(); 
      if (ret != FDS_SUCCESS) {
        return ret;
      }
      return NRF_SUCCESS;
    }

    What will happen if not call fds_gc(); after delete event.

    Thanks...

Children
  • Actually, you shouldn't call fds_gc() after each delete. You should do it as few times as possibly. only when you try to write or update a record, and it returns FDS_ERR_NO_SPACE_IN_FLASH, you should run fds_gc().

    The reason you don't want to do this too often. The reason for this is that fds_gc() will shuffle around the valid record, and delete the entire old flash page. The flash on the nRF has ~10000 write cycles. This means that after you write to the same address in flash 10000 times, it is not guaranteed to work. (However, it will probably work for 40-50 000, but the "guarantee" is 10 000). 

    So the FDS handles flash wear leveling by spreading out the records, and marking them as "deleted" and write it in another address rather than deleting and writing to the same place. Therefore, you should only call fds_gc() when you need to. Calling fds_gc() every time you delete a record will "beat up" the flash, making the lifetime a lot shorter.

Related