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,56 @@ extern uint32_t __flash_arduino_start[];
4445// MACRO TYPEDEF CONSTANT ENUM DECLARATION
4546//--------------------------------------------------------------------+
4647static SemaphoreHandle_t _sem = NULL ;
48+ static uint32_t _flash_op_result = NRF_EVT_FLASH_OPERATION_SUCCESS ;
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_result = event ;
56+
57+ // Signal to fal_erase or fal_program that our async flash op is now complete
58+ xSemaphoreGive (_sem );
59+ }
60+ }
61+
62+ // How many retry attempts when performing flash operations
63+ #define MAX_RETRY 20
64+
65+ // When soft device is enabled, flash ops are async
66+ // Eventual success is reported via callback, which we await
67+ static uint32_t wait_for_async_flash_op_completion (uint32_t initial_result )
68+ {
69+ // If initial result not NRF_SUCCESS, no need to await callback
70+ // We will pass the initial result (failure) straight through
71+ int32_t result = initial_result ;
72+
73+ // Operation was queued successfully
74+ if (initial_result == NRF_SUCCESS ) {
75+
76+ // Wait for result via callback
77+ xSemaphoreTake (_sem , portMAX_DELAY );
78+
79+ // If completed successfully
80+ if (_flash_op_result == NRF_EVT_FLASH_OPERATION_SUCCESS ) {
81+ result = NRF_SUCCESS ;
82+ }
83+
84+ // If general failure.
85+ // The comment on NRF_EVT_FLASH_OPERATION_ERROR describes it as a timeout,
86+ // so we're using a similar error when translating from NRF_SOC_EVTS type to the global NRF52 error defines
87+ else if (_flash_op_result == NRF_EVT_FLASH_OPERATION_ERROR ) {
88+ result = NRF_ERROR_TIMEOUT ;
89+ }
90+
91+ // If this assert triggers, we need to implement a new NRF_SOC_EVTS value
92+ else {
93+ assert (false);
94+ }
95+ }
96+
97+ return result ;
5298}
5399
54100// Flash Abstraction Layer
@@ -105,27 +151,35 @@ bool flash_nrf5x_erase(uint32_t addr)
105151static bool fal_erase (uint32_t addr )
106152{
107153 // Init semaphore for first call
108- if ( _sem == NULL )
109- {
110- _sem = xSemaphoreCreateCounting (10 , 0 );
154+ if ( _sem == NULL ) {
155+ _sem = xSemaphoreCreateBinary ();
111156 VERIFY (_sem );
112157 }
113158
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
159+ // Check if soft device is enabled
160+ // If yes, flash operations are async, so we need to wait for the callback to give the semaphore
123161 uint8_t sd_en = 0 ;
124162 (void ) sd_softdevice_is_enabled (& sd_en );
125163
126- if ( sd_en ) xSemaphoreTake (_sem , portMAX_DELAY );
164+ // Erase the page
165+ // Multiple attempts if needed
166+ uint32_t err ;
167+ for (uint8_t attempt = 0 ; attempt < MAX_RETRY ; ++ attempt ) {
168+ err = sd_flash_page_erase (addr / FLASH_NRF52_PAGE_SIZE );
127169
128- return true;
170+ if (sd_en ) {
171+ err = wait_for_async_flash_op_completion (err ); // Only async if soft device enabled
172+ }
173+ if (err == NRF_SUCCESS ) {
174+ break ;
175+ }
176+ if (err == NRF_ERROR_BUSY ) {
177+ delay (1 );
178+ }
179+ }
180+ VERIFY_STATUS (err , false); // Return false if all retries fail
181+
182+ return true; // Successfully erased
129183}
130184
131185static uint32_t fal_program (uint32_t dst , void const * src , uint32_t len )
@@ -140,27 +194,57 @@ static uint32_t fal_program (uint32_t dst, void const * src, uint32_t len)
140194 // https://devzone.nordicsemi.com/f/nordic-q-a/40088/sd_flash_write-cause-nrf_fault_id_sd_assert
141195 // Workaround: write half page at a time.
142196#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 );
197+ // Write the page
198+ // Multiple attempts, if needed
199+ for (uint8_t attempt = 0 ; attempt < MAX_RETRY ; ++ attempt ) {
200+ err = sd_flash_write ((uint32_t * ) dst , (uint32_t const * ) src , len /4 );
201+
202+ if (sd_en ) {
203+ err = wait_for_async_flash_op_completion (err ); // Only async if soft device enabled
204+ }
205+ if (err == NRF_SUCCESS ) {
206+ break ;
207+ }
208+ if (err == NRF_ERROR_BUSY ) {
209+ delay (1 );
210+ }
146211 }
147- VERIFY_STATUS (err , 0 );
212+ VERIFY_STATUS (err , 0 ); // Return 0 if all retries fail
148213
149- if ( sd_en ) xSemaphoreTake (_sem , portMAX_DELAY );
150214#else
151- while ( NRF_ERROR_BUSY == (err = sd_flash_write ((uint32_t * ) dst , (uint32_t const * ) src , len /8 )) )
152- {
153- delay (1 );
215+ // Write first part of page
216+ // Multiple attempts, if needed
217+ for (uint8_t attempt = 0 ; attempt < MAX_RETRY ; ++ attempt ) {
218+ err = sd_flash_write ((uint32_t * ) dst , (uint32_t const * ) src , len /8 );
219+
220+ if (sd_en ) {
221+ err = wait_for_async_flash_op_completion (err ); // Only async if soft device enabled
222+ }
223+ if (err == NRF_SUCCESS ) {
224+ break ;
225+ }
226+ if (err == NRF_ERROR_BUSY ) {
227+ delay (1 );
228+ }
154229 }
155- VERIFY_STATUS (err , 0 );
156- if ( sd_en ) xSemaphoreTake (_sem , portMAX_DELAY );
230+ VERIFY_STATUS (err , 0 ); // Return 0 if all retries fail
231+
232+ // Write second part of page
233+ // Multiple attempts, if needed
234+ for (uint8_t attempt = 0 ; attempt < MAX_RETRY ; ++ attempt ) {
235+ err = sd_flash_write ((uint32_t * ) (dst + len /2 ), (uint32_t const * ) (src + len /2 ), len /8 );
157236
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 );
237+ if (sd_en ) {
238+ err = wait_for_async_flash_op_completion (err ); // Only async if soft device enabled
239+ }
240+ if (err == NRF_SUCCESS ) {
241+ break ;
242+ }
243+ if (err == NRF_ERROR_BUSY ) {
244+ delay (1 );
245+ }
161246 }
162- VERIFY_STATUS (err , 0 );
163- if ( sd_en ) xSemaphoreTake (_sem , portMAX_DELAY );
247+ VERIFY_STATUS (err , 0 ); // Return 0 if all retries fail
164248#endif
165249
166250 return len ;
0 commit comments