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

FDS: Updating existing records with fds_record_update

I have been debugging this problem for a few days and have exhausted all of my options. I am relatively new to embedded development so user error is not out of the question.

To start, I am using SDK 11 and leveraging the experimental Flash Data Storage library on an nRF51422. I am able to read, write, and update records in a file but there is a catch. Updating a record only seems to work after I remove/reload the soft device(clear flash) through nRFgo Studio. In other words, if I start with a clean slate it all works fine and values are updated as expected, however, if I reset the device through the debugger, or re run the program, the updates never apply. It always remembers the very last write and won’t overwrite that value. The relevant code can be found below:

Flow:

First Run

  1. First write = fds_record_write

  2. All Subsequent writes go through fds_record_update

Result: All updates are performed as expected

Second Run

  1. Re run program:

  2. All writes, including the first, are handled through fds_record_update

Result: All updates succeed with FDS_SUCCESS, but value does not change. It always remembers the last value written from step 2.

Code:

void writeToFDSManager(void *dataToWrite, uint64_t byteCount) {

fds_record_t record;
fds_record_chunk_t record_chunk;
static fds_record_desc_t recordDesc;

record_chunk.p_data = dataToWrite;
/* See app_util for BYTES_TO_WORDS macro: (((n_bytes) + 3) >> 2 */
record_chunk.length_words = BYTES_TO_WORDS(byteCount);
record.file_id = fileDescriptor;
record.key = recordKey;
record.data.p_chunks = &record_chunk;
record.data.num_chunks = MAX_NUM_CHUNKS;

if (hasExistingRecord(recordDesc, fileDescriptor)) {
    fds_record_update(&recordDesc, &record);
} else {
    fds_record_write(&recordDesc, &record);
 }
}


void const *readFromFDSManager(void) {

fds_flash_record_t flash_record;
/* Per docs, always zero initialize */
fds_find_token_t ftok = {0};
fds_record_desc_t recordDesc;
	
	/* recordKey is hardcoded at the top of this file. If the user does not specify a fileId && recordKey, the
	   defaults are used. Currently set to 250 and 251 respectively */
	fds_descriptor_from_rec_id(&recordDesc, recordKey);
while (fds_record_find_by_key(recordKey, &recordDesc, &ftok) == FDS_SUCCESS) {
			/* Assignment of p_data via flash_record pointer */
    if (fds_record_open(&recordDesc, &flash_record) == FDS_SUCCESS) {
        fds_record_close(&recordDesc);
    }
}
return flash_record.p_data;
}

void fds_evt_handler(fds_evt_t const *const p_fds_evt) {
	
	switch(p_fds_evt->id) {
		case FDS_EVT_WRITE: {
			Foo *foo = (Foo *)readFromFDSManager();
			LOG("\n Write finished, new value is %u \n", foo->someId);
			break;
		}
		case FDS_EVT_UPDATE:{
			Foo *foo = (Foo *)readFromFDSManager();
			LOG("\n Update finished, new value is %u \n", foo->someId);
			break;
		}
		default:
			break;
	}
}

I will skip the initialization code, but the calls to read/update/write from main look like this:

    /* The docs state that we should hold onto the data until the write event is complete */
	static Foo foo;
for (int i = 0; i < 10; i++) {
	foo.someId = i;
	nrf_delay_ms(1000);
	writeToFDSManager((void *)&foo, sizeof(foo));
	nrf_delay_ms(2000);
}

Actual output log:

First run(After clearing flash via goStudio then reloading softDevice and application):

Write finished,  new value is 0 
Update finished, new value is 1
Update finished, new value is 2
Update finished, new value is 3
Update finished, new value is 4
Update finished, new value is 5
Update finished, new value is 6
Update finished, new value is 7
Update finished, new value is 8
Update finished, new value is 9

Second run(Restart debugger or restart program)

Update finished, new value is 9
Update finished, new value is 9
Update finished, new value is 9
Update finished, new value is 9
Update finished, new value is 9
Update finished, new value is 9
Update finished, new value is 9
Update finished, new value is 9
Update finished, new value is 9
Update finished, new value is 9

I am leaving the majority of the methods,ret_code_t handling out for brevity but rest assured this works on a fresh softdevice/application stack on the first run. I have a theory as to why this fails on subsequent runs, but I might be off:

During a read/write record_chunk.p_data points to whatever address it is given. When the program is run a second time, that address has probably changed in which case maybe it can't find the correct address that points to the data to be updated?

Any help would be greatly appreciated.

Thanks!

  • I have an open ticket 29065 about this; and I also have github repo that reproduces this issue. Currently I'm Delete, Run GC, and Write to perform an update. github.com/.../nordic-flash-data-storage I also have this issue in the SDK 10 known issues: devzone.nordicsemi.com/.../

  • Hi,

    I think that you are close with your suspicion that there is something going on with record_chunk.p_data.

    From the FDS documentation, Retrieving data:

    the data pointed to by the fds_flash_record_t structure might change at any time after the record is closed. So if you need to access the data after closing the record, you must open it again.

    If you change the code so that instead of returning a pointer you copy the contents to a separate instance of Foo, do you still get the same behaviour?

    Regards, Terje

  • Hi,

    My guess is that by the time fds attempts to write 'foo' to flash, the loop has already finished, and 'foo.'someId' has value 9. Therefore, all the update operations will go through, but the data being written will be the same because at the time the records are updated (which happens asynchronously), the static data that you fed to fds does not change anymore. It is in fact the same. This is why fds is updating the record with someId=9 several times.

    Remember, fds will not buffer your data. This is why it has to be 'alive' at the time the write/update happens.

    I would suggest to write the records one by one, changing 'someId' in the static 'foo' variable after you have received the callback from fds which notifies that the update has taken place.

    Hope this helps. Regards,

    E

  • I see now that there is considerable delay in the loop. This might not be the case then, but I hope it gives you more insight into the problem.

  • I think I see the problem now and it's what Terje was onto as well:

    Upon receiving the event, you actually iterate ALL the records with a given key and then return a pointer to the data of the LAST record you iterated over. So each time you are printing the same item (the last record). When you have no records and write them for the fist time, it works. Then, when you boot with 9 records, each time you update you print the data of the last record with that key, which has 9 as the value of the field you are printing.

Related