Skip to content

Commit 0ebb9e9

Browse files
committed
Reattempt flash operations if failed
1 parent 4f591d0 commit 0ebb9e9

File tree

1 file changed

+85
-24
lines changed

1 file changed

+85
-24
lines changed

libraries/InternalFileSytem/src/flash/flash_nrf5x.c

Lines changed: 85 additions & 24 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,18 @@ extern uint32_t __flash_arduino_start[];
4445
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
4546
//--------------------------------------------------------------------+
4647
static SemaphoreHandle_t _sem = NULL;
48+
static bool _flash_op_failed = false;
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_failed = (event == NRF_EVT_FLASH_OPERATION_ERROR);
56+
57+
// Signal to fal_erase or fal_program that our async flash op is now complete
58+
xSemaphoreGive(_sem);
59+
}
5260
}
5361

5462
// Flash Abstraction Layer
@@ -107,30 +115,46 @@ static bool fal_erase (uint32_t addr)
107115
// Init semaphore for first call
108116
if ( _sem == NULL )
109117
{
110-
_sem = xSemaphoreCreateCounting(10, 0);
118+
_sem = xSemaphoreCreateBinary();
111119
VERIFY(_sem);
112120
}
113121

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

126-
if ( sd_en ) xSemaphoreTake(_sem, portMAX_DELAY);
127+
// Make multiple attempts
128+
for (uint8_t attempt = 0;;) {
129+
// Attempt to erase
130+
uint32_t err = sd_flash_page_erase(addr / FLASH_NRF52_PAGE_SIZE);
131+
// Retry if busy
132+
if (err == NRF_ERROR_BUSY) {
133+
delay(1);
134+
continue;
135+
}
136+
// Count genuine attempts
137+
attempt++;
138+
// If using softdevice, erase is async, so we wait here
139+
if (sd_en) xSemaphoreTake(_sem, portMAX_DELAY);
140+
// If erase failed
141+
if (_flash_op_failed) {
142+
assert(attempt < 10); // Something went horribly wrong.. protect the flash
143+
continue; // Try again
144+
}
145+
// Catch any other odd results
146+
VERIFY_STATUS(err, 0);
147+
// Success
148+
break;
149+
}
127150

128151
return true;
129152
}
130153

131154
static uint32_t fal_program (uint32_t dst, void const * src, uint32_t len)
132155
{
133-
// wait for async event if SD is enabled
156+
// Check if soft device is enabled
157+
// If yes, flash operations are async, so we need to wait for the callback to give the semaphore
134158
uint8_t sd_en = 0;
135159
(void) sd_softdevice_is_enabled(&sd_en);
136160

@@ -148,19 +172,56 @@ static uint32_t fal_program (uint32_t dst, void const * src, uint32_t len)
148172

149173
if ( sd_en ) xSemaphoreTake(_sem, portMAX_DELAY);
150174
#else
151-
while ( NRF_ERROR_BUSY == (err = sd_flash_write((uint32_t*) dst, (uint32_t const *) src, len/8)) )
152-
{
153-
delay(1);
175+
176+
// First part of block
177+
// ------------------
178+
for (uint8_t attempt = 0;;) {
179+
// Attempt to write
180+
uint32_t err = sd_flash_write((uint32_t*) dst, (uint32_t const *) src, len/8);
181+
// Retry if busy
182+
if (err == NRF_ERROR_BUSY) {
183+
delay(1);
184+
continue;
185+
}
186+
// Count genuine attempts
187+
attempt++;
188+
// If using softdevice, write is async, so we wait here
189+
if (sd_en) xSemaphoreTake(_sem, portMAX_DELAY);
190+
// If write failed
191+
if (_flash_op_failed) {
192+
assert(attempt < 10); // Something went horribly wrong.. protect the flash
193+
continue; // Try again
194+
}
195+
// Catch any other odd results
196+
VERIFY_STATUS(err, 0);
197+
// Success
198+
break;
154199
}
155-
VERIFY_STATUS(err, 0);
156-
if ( sd_en ) xSemaphoreTake(_sem, portMAX_DELAY);
157200

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);
201+
// Second part of block
202+
// --------------------
203+
for (uint8_t attempt = 0;;) {
204+
// Attempt to write
205+
uint32_t err = sd_flash_write((uint32_t*) (dst+ len/2), (uint32_t const *) (src + len/2), len/8);
206+
// Retry if busy
207+
if (err == NRF_ERROR_BUSY) {
208+
delay(1);
209+
continue;
210+
}
211+
// Count genuine attempts
212+
attempt++;
213+
// If using softdevice, write is async, so we wait here
214+
if (sd_en) xSemaphoreTake(_sem, portMAX_DELAY);
215+
// If write failed
216+
if (_flash_op_failed) {
217+
assert(attempt < 10); // Something went horribly wrong.. protect the flash
218+
continue; // Try again
219+
}
220+
// Catch any other odd results
221+
VERIFY_STATUS(err, 0);
222+
// Success
223+
break;
161224
}
162-
VERIFY_STATUS(err, 0);
163-
if ( sd_en ) xSemaphoreTake(_sem, portMAX_DELAY);
164225
#endif
165226

166227
return len;

0 commit comments

Comments
 (0)