Skip to content

Commit e13f582

Browse files
authored
Merge pull request #1 from todd-herbert/reattempt-flash-ops
Reattempt failed flash operations
2 parents 4f591d0 + 92e936c commit e13f582

File tree

1 file changed

+115
-31
lines changed

1 file changed

+115
-31
lines changed

libraries/InternalFileSytem/src/flash/flash_nrf5x.c

Lines changed: 115 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "nrf_soc.h"
2929
#include "delay.h"
3030
#include "rtos.h"
31+
#include "assert.h"
3132

3233

3334
#ifdef NRF52840_XXAA
@@ -44,11 +45,56 @@ extern uint32_t __flash_arduino_start[];
4445
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
4546
//--------------------------------------------------------------------+
4647
static SemaphoreHandle_t _sem = NULL;
48+
static uint32_t _flash_op_result = NRF_EVT_FLASH_OPERATION_SUCCESS;
4749

4850
void flash_nrf5x_event_cb (uint32_t event)
4951
{
50-
// if (event != NRF_EVT_FLASH_OPERATION_SUCCESS) LOG_LV1("IFLASH", "Flash op Failed");
51-
if ( _sem ) xSemaphoreGive(_sem);
52+
if ( _sem ) {
53+
// Record the result, for consumption by fal_erase or fal_program
54+
// Used to reattempt failed operations
55+
_flash_op_result = event;
56+
57+
// Signal to fal_erase or fal_program that our async flash op is now complete
58+
xSemaphoreGive(_sem);
59+
}
60+
}
61+
62+
// How many retry attempts when performing flash operations
63+
#define MAX_RETRY 20
64+
65+
// When soft device is enabled, flash ops are async
66+
// Eventual success is reported via callback, which we await
67+
static uint32_t wait_for_async_flash_op_completion(uint32_t initial_result)
68+
{
69+
// If initial result not NRF_SUCCESS, no need to await callback
70+
// We will pass the initial result (failure) straight through
71+
int32_t result = initial_result;
72+
73+
// Operation was queued successfully
74+
if (initial_result == NRF_SUCCESS) {
75+
76+
// Wait for result via callback
77+
xSemaphoreTake(_sem, portMAX_DELAY);
78+
79+
// If completed successfully
80+
if (_flash_op_result == NRF_EVT_FLASH_OPERATION_SUCCESS) {
81+
result = NRF_SUCCESS;
82+
}
83+
84+
// If general failure.
85+
// The comment on NRF_EVT_FLASH_OPERATION_ERROR describes it as a timeout,
86+
// so we're using a similar error when translating from NRF_SOC_EVTS type to the global NRF52 error defines
87+
else if (_flash_op_result == NRF_EVT_FLASH_OPERATION_ERROR) {
88+
result = NRF_ERROR_TIMEOUT;
89+
}
90+
91+
// If this assert triggers, we need to implement a new NRF_SOC_EVTS value
92+
else {
93+
assert(false);
94+
}
95+
}
96+
97+
return result;
5298
}
5399

54100
// Flash Abstraction Layer
@@ -105,27 +151,35 @@ bool flash_nrf5x_erase(uint32_t addr)
105151
static bool fal_erase (uint32_t addr)
106152
{
107153
// Init semaphore for first call
108-
if ( _sem == NULL )
109-
{
110-
_sem = xSemaphoreCreateCounting(10, 0);
154+
if ( _sem == NULL ) {
155+
_sem = xSemaphoreCreateBinary();
111156
VERIFY(_sem);
112157
}
113158

114-
// retry if busy
115-
uint32_t err;
116-
while ( NRF_ERROR_BUSY == (err = sd_flash_page_erase(addr / FLASH_NRF52_PAGE_SIZE)) )
117-
{
118-
delay(1);
119-
}
120-
VERIFY_STATUS(err, false);
121-
122-
// wait for async event if SD is enabled
159+
// Check if soft device is enabled
160+
// If yes, flash operations are async, so we need to wait for the callback to give the semaphore
123161
uint8_t sd_en = 0;
124162
(void) sd_softdevice_is_enabled(&sd_en);
125163

126-
if ( sd_en ) xSemaphoreTake(_sem, portMAX_DELAY);
164+
// Erase the page
165+
// Multiple attempts if needed
166+
uint32_t err;
167+
for (uint8_t attempt = 0; attempt < MAX_RETRY; ++attempt) {
168+
err = sd_flash_page_erase(addr / FLASH_NRF52_PAGE_SIZE);
127169

128-
return true;
170+
if (sd_en) {
171+
err = wait_for_async_flash_op_completion(err); // Only async if soft device enabled
172+
}
173+
if (err == NRF_SUCCESS) {
174+
break;
175+
}
176+
if (err == NRF_ERROR_BUSY) {
177+
delay(1);
178+
}
179+
}
180+
VERIFY_STATUS(err, false); // Return false if all retries fail
181+
182+
return true; // Successfully erased
129183
}
130184

131185
static uint32_t fal_program (uint32_t dst, void const * src, uint32_t len)
@@ -140,27 +194,57 @@ static uint32_t fal_program (uint32_t dst, void const * src, uint32_t len)
140194
// https://devzone.nordicsemi.com/f/nordic-q-a/40088/sd_flash_write-cause-nrf_fault_id_sd_assert
141195
// Workaround: write half page at a time.
142196
#if NRF52832_XXAA
143-
while ( NRF_ERROR_BUSY == (err = sd_flash_write((uint32_t*) dst, (uint32_t const *) src, len/4)) )
144-
{
145-
delay(1);
197+
// Write the page
198+
// Multiple attempts, if needed
199+
for (uint8_t attempt = 0; attempt < MAX_RETRY; ++attempt) {
200+
err = sd_flash_write((uint32_t*) dst, (uint32_t const *) src, len/4);
201+
202+
if (sd_en) {
203+
err = wait_for_async_flash_op_completion(err); // Only async if soft device enabled
204+
}
205+
if (err == NRF_SUCCESS) {
206+
break;
207+
}
208+
if (err == NRF_ERROR_BUSY) {
209+
delay(1);
210+
}
146211
}
147-
VERIFY_STATUS(err, 0);
212+
VERIFY_STATUS(err, 0); // Return 0 if all retries fail
148213

149-
if ( sd_en ) xSemaphoreTake(_sem, portMAX_DELAY);
150214
#else
151-
while ( NRF_ERROR_BUSY == (err = sd_flash_write((uint32_t*) dst, (uint32_t const *) src, len/8)) )
152-
{
153-
delay(1);
215+
// Write first part of page
216+
// Multiple attempts, if needed
217+
for (uint8_t attempt = 0; attempt < MAX_RETRY; ++attempt) {
218+
err = sd_flash_write((uint32_t*) dst, (uint32_t const *) src, len/8);
219+
220+
if (sd_en) {
221+
err = wait_for_async_flash_op_completion(err); // Only async if soft device enabled
222+
}
223+
if (err == NRF_SUCCESS) {
224+
break;
225+
}
226+
if (err == NRF_ERROR_BUSY) {
227+
delay(1);
228+
}
154229
}
155-
VERIFY_STATUS(err, 0);
156-
if ( sd_en ) xSemaphoreTake(_sem, portMAX_DELAY);
230+
VERIFY_STATUS(err, 0); // Return 0 if all retries fail
231+
232+
// Write second part of page
233+
// Multiple attempts, if needed
234+
for (uint8_t attempt = 0; attempt < MAX_RETRY; ++attempt) {
235+
err = sd_flash_write((uint32_t*) (dst+ len/2), (uint32_t const *) (src + len/2), len/8);
157236

158-
while ( NRF_ERROR_BUSY == (err = sd_flash_write((uint32_t*) (dst+ len/2), (uint32_t const *) (src + len/2), len/8)) )
159-
{
160-
delay(1);
237+
if (sd_en) {
238+
err = wait_for_async_flash_op_completion(err); // Only async if soft device enabled
239+
}
240+
if (err == NRF_SUCCESS) {
241+
break;
242+
}
243+
if (err == NRF_ERROR_BUSY) {
244+
delay(1);
245+
}
161246
}
162-
VERIFY_STATUS(err, 0);
163-
if ( sd_en ) xSemaphoreTake(_sem, portMAX_DELAY);
247+
VERIFY_STATUS(err, 0); // Return 0 if all retries fail
164248
#endif
165249

166250
return len;

0 commit comments

Comments
 (0)