2828#include "nrf_soc.h"
2929#include "delay.h"
3030#include "rtos.h"
31- #include "assert.h"
32-
3331
3432#ifdef NRF52840_XXAA
3533 #define BOOTLOADER_ADDR 0xF4000
@@ -59,6 +57,34 @@ void flash_nrf5x_event_cb (uint32_t event)
5957 }
6058}
6159
60+ // How many retry attempts when performing flash write operations
61+ #define MAX_RETRY 20
62+
63+ // Check whether a flash operation was successful, or should be repeated
64+ static bool retry_flash_op (uint32_t op_result , bool sd_enabled ) {
65+ // If busy
66+ if (op_result == NRF_ERROR_BUSY ) {
67+ delay (1 );
68+ return true; // Retry
69+ }
70+
71+ // Unspecified error
72+ if (op_result != NRF_SUCCESS )
73+ return true; // Retry
74+
75+ // If the soft device is enabled, flash operations run async
76+ // The callback (flash_nrf5x_event_cb) will give semaphore when the flash operation is complete
77+ // The callback also checks for NRF_EVT_FLASH_OPERATION_ERROR, which is not available to us otherwise
78+ if (sd_enabled ) {
79+ xSemaphoreTake (_sem , portMAX_DELAY );
80+ if (_flash_op_failed )
81+ return true; // Retry
82+ }
83+
84+ // Success
85+ return false;
86+ }
87+
6288// Flash Abstraction Layer
6389static bool fal_erase (uint32_t addr );
6490static uint32_t fal_program (uint32_t dst , void const * src , uint32_t len );
@@ -124,31 +150,13 @@ static bool fal_erase (uint32_t addr)
124150 uint8_t sd_en = 0 ;
125151 (void ) sd_softdevice_is_enabled (& sd_en );
126152
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 ;
153+ // Make multiple attempts to erase
154+ uint8_t attempt = 0 ;
155+ while (retry_flash_op (sd_flash_page_erase (addr / FLASH_NRF52_PAGE_SIZE ), sd_en )) {
156+ if (++ attempt > MAX_RETRY )
157+ return false; // Failure
149158 }
150-
151- return true;
159+ return true; // Success
152160}
153161
154162static uint32_t fal_program (uint32_t dst , void const * src , uint32_t len )
@@ -164,63 +172,25 @@ static uint32_t fal_program (uint32_t dst, void const * src, uint32_t len)
164172 // https://devzone.nordicsemi.com/f/nordic-q-a/40088/sd_flash_write-cause-nrf_fault_id_sd_assert
165173 // Workaround: write half page at a time.
166174#if NRF52832_XXAA
167- while ( NRF_ERROR_BUSY == (err = sd_flash_write ((uint32_t * ) dst , (uint32_t const * ) src , len /4 )) )
168- {
169- delay (1 );
175+ uint8_t attempt = 0 ;
176+ while (retry_flash_op (sd_flash_write ((uint32_t * ) dst , (uint32_t const * ) src , len /4 ), sd_en )) {
177+ if (++ attempt > MAX_RETRY )
178+ return 0 ; // Failure
170179 }
171- VERIFY_STATUS (err , 0 );
172-
173- if ( sd_en ) xSemaphoreTake (_sem , portMAX_DELAY );
174180#else
175181
176182 // 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 ;
183+ uint8_t attempt = 0 ;
184+ while (retry_flash_op (sd_flash_write ((uint32_t * ) dst , (uint32_t const * ) src , len /8 ), sd_en )) {
185+ if (++ attempt > MAX_RETRY )
186+ return 0 ; // Failure
199187 }
200188
201189 // 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 ;
190+ attempt = 0 ;
191+ while (retry_flash_op (sd_flash_write ((uint32_t * ) (dst + len /2 ), (uint32_t const * ) (src + len /2 ), len /8 ), sd_en )) {
192+ if (++ attempt > MAX_RETRY )
193+ return 0 ; // Failure
224194 }
225195#endif
226196
0 commit comments