Skip to content

Commit 3ea7855

Browse files
committed
Reattempt failed flash operations
1 parent 4dcfa3b commit 3ea7855

File tree

1 file changed

+64
-32
lines changed

1 file changed

+64
-32
lines changed

libraries/InternalFileSytem/src/flash/flash_nrf5x.c

Lines changed: 64 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,46 @@ extern uint32_t __flash_arduino_start[];
4444
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
4545
//--------------------------------------------------------------------+
4646
static SemaphoreHandle_t _sem = NULL;
47+
static bool _flash_op_failed = false;
4748

4849
void flash_nrf5x_event_cb (uint32_t event)
4950
{
50-
// if (event != NRF_EVT_FLASH_OPERATION_SUCCESS) LOG_LV1("IFLASH", "Flash op Failed");
51-
if ( _sem ) xSemaphoreGive(_sem);
51+
if ( _sem ) {
52+
// Record the result, for consumption by fal_erase or fal_program
53+
// Used to reattempt failed operations
54+
_flash_op_failed = (event == NRF_EVT_FLASH_OPERATION_ERROR);
55+
56+
// Signal to fal_erase or fal_program that our async flash op is now complete
57+
xSemaphoreGive(_sem);
58+
}
59+
}
60+
61+
// How many retry attempts when performing flash operations
62+
#define MAX_RETRY 20
63+
64+
// Check whether a flash operation was successful, or should be repeated
65+
static bool retry_flash_op (uint32_t op_result, bool sd_enabled) {
66+
// If busy
67+
if (op_result == NRF_ERROR_BUSY) {
68+
delay(1);
69+
return true; // Retry
70+
}
71+
72+
// If unspecified error
73+
if (op_result != NRF_SUCCESS)
74+
return true; // Retry
75+
76+
// If the soft device is enabled, flash operations run async
77+
// The callback (flash_nrf5x_event_cb) will give semaphore when the flash operation is complete
78+
// The callback also checks for NRF_EVT_FLASH_OPERATION_ERROR, which is not available to us otherwise
79+
if (sd_enabled) {
80+
xSemaphoreTake(_sem, portMAX_DELAY);
81+
if (_flash_op_failed)
82+
return true; // Retry
83+
}
84+
85+
// Success
86+
return false;
5287
}
5388

5489
// Flash Abstraction Layer
@@ -107,30 +142,28 @@ static bool fal_erase (uint32_t addr)
107142
// Init semaphore for first call
108143
if ( _sem == NULL )
109144
{
110-
_sem = xSemaphoreCreateCounting(10, 0);
145+
_sem = xSemaphoreCreateBinary();
111146
VERIFY(_sem);
112147
}
113148

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
149+
// Check if soft device is enabled
150+
// If yes, flash operations are async, so we need to wait for the callback to give the semaphore
123151
uint8_t sd_en = 0;
124152
(void) sd_softdevice_is_enabled(&sd_en);
125153

126-
if ( sd_en ) xSemaphoreTake(_sem, portMAX_DELAY);
127-
128-
return true;
154+
// Make multiple attempts to erase
155+
uint8_t attempt = 0;
156+
while (retry_flash_op(sd_flash_page_erase(addr / FLASH_NRF52_PAGE_SIZE), sd_en)) {
157+
if (++attempt > MAX_RETRY)
158+
return false; // Failure
159+
}
160+
return true; // Success
129161
}
130162

131163
static uint32_t fal_program (uint32_t dst, void const * src, uint32_t len)
132164
{
133-
// wait for async event if SD is enabled
165+
// Check if soft device is enabled
166+
// If yes, flash operations are async, so we need to wait for the callback to give the semaphore
134167
uint8_t sd_en = 0;
135168
(void) sd_softdevice_is_enabled(&sd_en);
136169

@@ -140,27 +173,26 @@ static uint32_t fal_program (uint32_t dst, void const * src, uint32_t len)
140173
// https://devzone.nordicsemi.com/f/nordic-q-a/40088/sd_flash_write-cause-nrf_fault_id_sd_assert
141174
// Workaround: write half page at a time.
142175
#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);
176+
uint8_t attempt = 0;
177+
while (retry_flash_op(sd_flash_write((uint32_t*) dst, (uint32_t const *) src, len/4), sd_en)) {
178+
if (++attempt > MAX_RETRY)
179+
return 0; // Failure
146180
}
147-
VERIFY_STATUS(err, 0);
148-
149-
if ( sd_en ) xSemaphoreTake(_sem, portMAX_DELAY);
150181
#else
151-
while ( NRF_ERROR_BUSY == (err = sd_flash_write((uint32_t*) dst, (uint32_t const *) src, len/8)) )
152-
{
153-
delay(1);
182+
183+
// First part of block
184+
uint8_t attempt = 0;
185+
while (retry_flash_op(sd_flash_write((uint32_t*) dst, (uint32_t const *) src, len/8), sd_en)) {
186+
if (++attempt > MAX_RETRY)
187+
return 0; // Failure
154188
}
155-
VERIFY_STATUS(err, 0);
156-
if ( sd_en ) xSemaphoreTake(_sem, portMAX_DELAY);
157189

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);
190+
// Second part of block
191+
attempt = 0;
192+
while (retry_flash_op(sd_flash_write((uint32_t*) (dst+ len/2), (uint32_t const *) (src + len/2), len/8), sd_en)) {
193+
if (++attempt > MAX_RETRY)
194+
return 0; // Failure
161195
}
162-
VERIFY_STATUS(err, 0);
163-
if ( sd_en ) xSemaphoreTake(_sem, portMAX_DELAY);
164196
#endif
165197

166198
return len;

0 commit comments

Comments
 (0)