I have the following code to write 0x34 bytes to flash
void saveKeysToFlash(ble_gap_enc_info_t* keys, unsigned char **saveDataBuffer, unsigned short int *saveDataLength, unsigned char* cccdSet, unsigned short* noOfCccds) { int i; unsigned char *keysDataBuffer = NULL; const char utech[8] = {'U', 'T', 'E', 'C', 'H', '_', 'P', 'O'}; uint32_t err_code; uint32_t pg_size = NRF_FICR->CODEPAGESIZE; uint32_t pg_num = NRF_FICR->CODESIZE - 1; // Use last page in flash uint32_t *addr; int size = 8 + // space for key "UTECH_PO" sizeof(ble_gap_enc_info_t) + // encryption info sizeof(unsigned short) + // number of cccds sizeof(unsigned char) * (*noOfCccds) + // the cccds sizeof(unsigned short) + // length of save data buffer ((*saveDataBuffer != NULL) ? *saveDataLength * sizeof(unsigned char) : 0); // the save data buffer // The writes are done in 4-byte hunks so we have to even out the length size = 4 + ((size >> 2) << 2); keysDataBuffer = calloc(1, size); // Now load all the data we want to save into this buffer uint8_t *ptr = keysDataBuffer; memcpy(ptr, utech, 8); // Load identifier ptr = ptr + 8; memcpy(ptr, keys, sizeof(ble_gap_enc_info_t)); // load our encryption info ptr = ptr + sizeof(ble_gap_enc_info_t); memcpy(ptr, noOfCccds, sizeof(unsigned short)); // Load number of CCCDs ptr = ptr + sizeof(unsigned short); memcpy(ptr, cccdSet, sizeof(unsigned char) * (*noOfCccds)); // Load the cccdSet[] ptr = ptr + sizeof(unsigned char) * (*noOfCccds); memcpy(ptr, saveDataLength, sizeof(unsigned short)); // Load saveDataLength ptr = ptr + sizeof(unsigned short); if (*saveDataBuffer != NULL) { memcpy(ptr, saveDataBuffer, *saveDataLength * sizeof(unsigned char)); // Load the saveDataBuffer } // Now we have to write the data in hunks into flash // Each page is 1024 bytes, and a write is in 4-byte hunks // So we will find the number of 1024 byte pages to write, and then the number of 4-byte hunks left over. // Buffer to write to flash. Need to write it in four-byte hunks uint32_t *ptr32 = (uint32_t *)keysDataBuffer; while (true) { // Where to write addr = (uint32_t *)(pg_size * pg_num); // Erase page: while(true) { err_code = sd_flash_page_erase(pg_num); if (err_code == NRF_SUCCESS) { break; } if (err_code != NRF_ERROR_BUSY) { APP_ERROR_CHECK(err_code); // nrf_delay_ms(200); } } // nrf_delay_ms(200); i = (size >= pg_size) ? (pg_size >> 2) : (size >> 2); // four-byte hunks to write; size is evenly divisible by four while(true) { err_code = sd_flash_write(addr, ptr32, i); if (err_code == NRF_SUCCESS) { break; } if (err_code != NRF_ERROR_BUSY) { APP_ERROR_CHECK(err_code); // nrf_delay_ms(200); } } size = size - pg_size; // Subtract a page size from the total size if (size <= 0) // if zero or less, all data has been written { break; } pg_num++; ptr32 = (uint32_t *)(keysDataBuffer + pg_size); } uint8_t *test = (uint8_t *)(pg_size * pg_num) + 8; ble_gap_enc_info_t testKeys; memcpy(&testKeys, test, sizeof(ble_gap_enc_info_t)); free(keysDataBuffer); if(testKeys.ltk_len == keys->ltk_len) { if (testKeys.div == keys->div) { if (testKeys.auth == keys->auth) { if (testKeys.ltk[3] == keys->ltk[3]) { int i = 9; return; } } } } }
If I place a breakpoint in the debugger at the start of the erase/write code and step through it, the flash write works. If, on the other hand, I set a breakpoint at the end of the write loop, the flash write fails. The test loop at the end shows all values are just FF's or whatever it was. They are all the same.
I tried implementing delays but the Keil compiler gives an error on the nrf_delay.h file so I couldn't do that. THe question is what am I missing such that the flash write works when stepping through using the debugger, but fails when I 'run' though the code? Note that in both cases, the debugger is being run. It does fail when used normally (without using the debugger).
I have tried all kinds of combinations, using while loops on sd_evt_get() and looking for the NRF_EVT_FLASH_OPERATION_SUCCESS etc and they all work if one goes step by step in the debugger and they all fail if one lets them run 'freely' only hitting a break point after the writes are completed.
I invoke the write after the device disconnects from the peer. So there should be no radio competition here. What is going on? - nrf51822 apparently ancient s110 ver 5/6.
Even tried calling it from a timer - same result.
I believe the flash write is broken. The previous version of this code used the bonding manager and the pstorage - and it had the same issue - failed encryption every time on a reconnect. The bonding manager is so complex I gave up trying to debug it. But if the basic sd_flash_write is broken it is understandable that the pstorage would be broken. (The bonding manager used flash storage to save the LTKs and other data one needs to support bonding - without LTKs, encryption will fail)