@@ -44,11 +44,46 @@ extern uint32_t __flash_arduino_start[];
4444// MACRO TYPEDEF CONSTANT ENUM DECLARATION
4545//--------------------------------------------------------------------+
4646static SemaphoreHandle_t _sem = NULL ;
47+ static bool _flash_op_failed = false;
4748
4849void 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
131163static 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