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//--------------------------------------------------------------------+
4647static SemaphoreHandle_t _sem = NULL ;
48+ static bool _flash_op_failed = false;
4749
4850void 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
131154static 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