I am running my application on nRF SDK 16.0 and SoftDevice 7.2.0 but had this problem since 15.2 and 6.1.1 respectively. I thought it was resolved in an update since this issue is somewhat old and known, see: Data not updated to fds with GATT & FDS: Updating existing records with fds_record_update.
My application is somewhat similar to the first link, I have two GATT characteristics being initialized with pre-processor macros and which can be updated from a mobile phone via nRFConnect. The values need to be stored in NVM and thus I am using FDS to write and update them. However, when any of the two methods are called, nothing happens; it doesn't enter my FDS event handler to even give a NRF error message. Reading works fine.
Here is how I initialize my SoftDevice:
bool softdevice_initialize()
{
ret_code_t err_code;
err_code = nrf_sdh_enable_request();
APP_ERROR_CHECK(err_code);
// Configure the BLE stack using the default settings.
// Fetch the start address of the application RAM.
uint32_t ram_start = 0;
err_code = nrf_sdh_ble_default_cfg_set(1, &ram_start);
APP_ERROR_CHECK(err_code);
err_code = nrf_sdh_ble_enable(&ram_start);
APP_ERROR_CHECK(err_code);
/**/
ble_dfu_buttonless_init_t dfus_init =
{
.evt_handler = ble_dfu_evt_handler
};
err_code = ble_dfu_buttonless_async_svci_init();
APP_ERROR_CHECK(err_code);
err_code = ble_dfu_buttonless_init(&dfus_init);
APP_ERROR_CHECK(err_code);
// Register a handler for BLE events.
NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, handle_gap_event, NULL);
return err_code == NRF_SUCCESS;
}
Here is how I initialize my FDS:
bool fds_initialize(void)
{
//Initialize FDS
ret_code_t ret = fds_register(fds_event_handler);
VERIFY_SUCCESS(ret);
ret = fds_init();
VERIFY_SUCCESS(ret);
while (!m_fds_ready) ;
fds_record_t record;
fds_record_desc_t record_desc;
record.file_id = NET_ID_FILE; // 0x0002 if not defined
record.key = RECORD_KEY; // 0x1112 if not defined
u_int32_t value_of_net_id_addr = get_netId(); // FDS read, should get 0xFFFF=-1 if not initialized
if (value_of_net_id_addr == -1)
{
ret = fds_gc();
u_int32_t m_net_id = NET_ID; // small integer defined in pre-processor macro
// Set up record
record.data.p_data = &m_net_id;
record.data.length_words = 1; /* one word is four bytes */
write_flag = 0;
ret_code_t rc;
rc = fds_record_write(&record_desc, &record);
if (rc != NRF_SUCCESS)
{
/* Handle error. */
printf("Failed to flash write\r\n");
}
while (write_flag == 0) ;
}
memset(&record, 0, sizeof(record));
memset(&record_desc, 0, sizeof(record_desc));
record.file_id = NET_ID_FILE;
record.key = OP_ID_RECORD_KEY;
/* Initialize Operational ID */
u_int32_t value_of_op_id = get_opId(); // FDS read, should get 0xFFFF=-1 if not initialized
if (value_of_op_id == -1)
{
ret = fds_gc();
u_int32_t m_op_id = OP_ID; // small integer defined in pre-processor macro
record.data.p_data = &m_op_id;
record.data.length_words = 1;
write_flag = 0;
ret = fds_record_write(&record_desc, &record);
APP_ERROR_CHECK(ret);
while (write_flag == 0) ;
}
return ret == NRF_SUCCESS;
}
Execution is stuck at line 35 which is supposed to be cleared in the event handler. write_flag and m_fds_ready are a values that are cleared in the event handler. I put error checks and breakpoints in my event handler but no events are being fired.
static void fds_event_handler(fds_evt_t const * p_fds_evt)
{
switch (p_fds_evt->id)
{
case FDS_EVT_INIT:
APP_ERROR_CHECK(p_fds_evt->result);
m_fds_ready = true;
break;
case FDS_EVT_WRITE:
if (p_fds_evt->result == NRF_SUCCESS)
{
write_flag = 1;
}
break;
case FDS_EVT_UPDATE:
if (p_fds_evt->result == NRF_SUCCESS)
{
write_flag = 1;
}
break;
default:
NRF_LOG_INFO("%d", p_fds_evt->id);
break;
}
}
I eventually got it to work by doing the FDS initialization first, then the SoftDevice's. In the update function below, I have to disable the SoftDevice, writing or updating and then re-enable it. Events then fire correctly.
ret_code_t fds_update(uint16_t file_id, uint16_t key, u_int32_t data, uint32_t data_length)
{
fds_record_t record;
fds_record_desc_t record_desc;
fds_find_token_t ftok;
ret_code_t rc;
// Fill in the record
record.file_id = file_id;
record.key = key;
record.data.p_data = &data;
record.data.length_words = data_length;
write_flag = 0;
// Find the record desc and update
ftok.page = 0;
ftok.p_addr = NULL;
APP_ERROR_CHECK(nrf_sdh_disable_request()); // FIXME SoftDevice has to be disabled and re-enabled for write events during code execution
while(fds_record_find(file_id, key, &record_desc, &ftok) == NRF_SUCCESS)
{
rc = fds_record_update(&record_desc, &record);
if (rc == FDS_ERR_NO_SPACE_IN_FLASH)
{
NRF_LOG_INFO("FDS has no space left, garbage collector triggered.\n");
rc = fds_gc();
APP_ERROR_CHECK(rc);
rc = fds_record_update(&record_desc, &record);
APP_ERROR_CHECK(rc);
}
while (write_flag == 0) ;
}
rc = fds_gc();
if (rc != NRF_SUCCESS)
{
APP_ERROR_CHECK(rc);
/* Handle Error */
}
APP_ERROR_CHECK(nrf_sdh_enable_request());
return rc;
}
I have read that the peer manager stores data in flash using FDS also but it seems to work fine without tinkering with the SoftDevice unlike what I have to do so it makes me think the problem is with my implementation. Another potential pointer to the issue could be that FDS_ERR_NO_SPACE_IN_FLASH is always triggered in the above code.
These workarounds are okay for me but is against documentation in the nRF SDK which says FDS can work with the SoftDevice enabled. I'd like to have some peace of mind at least before production.