2828#include "nrf_soc.h"
2929#include "delay.h"
3030#include "rtos.h"
31+ #include "assert.h"
3132
3233
3334#ifdef NRF52840_XXAA
@@ -44,14 +45,14 @@ extern uint32_t __flash_arduino_start[];
4445// MACRO TYPEDEF CONSTANT ENUM DECLARATION
4546//--------------------------------------------------------------------+
4647static SemaphoreHandle_t _sem = NULL ;
47- static bool _flash_op_failed = false ;
48+ static uint32_t _flash_op_result = NRF_EVT_FLASH_OPERATION_SUCCESS ;
4849
4950void flash_nrf5x_event_cb (uint32_t event )
5051{
5152 if ( _sem ) {
5253 // Record the result, for consumption by fal_erase or fal_program
5354 // Used to reattempt failed operations
54- _flash_op_failed = ( event == NRF_EVT_FLASH_OPERATION_ERROR ) ;
55+ _flash_op_result = event ;
5556
5657 // Signal to fal_erase or fal_program that our async flash op is now complete
5758 xSemaphoreGive (_sem );
@@ -61,29 +62,35 @@ void flash_nrf5x_event_cb (uint32_t event)
6162// How many retry attempts when performing flash operations
6263#define MAX_RETRY 20
6364
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- }
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+ // If initial result not NRF_SUCCESS, no need to await callback
69+ // We will pass the initial result (failure) straight through
70+ int32_t result = initial_result ;
7171
72- // If unspecified error
73- if (op_result != NRF_SUCCESS )
74- return true; // Retry
72+ // Operation was queued successfully
73+ if (initial_result == NRF_SUCCESS ) {
7574
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 ) {
75+ // Wait for result via callback
8076 xSemaphoreTake (_sem , portMAX_DELAY );
81- if (_flash_op_failed )
82- return true; // Retry
77+
78+ // If completed successfully
79+ if (_flash_op_result == NRF_EVT_FLASH_OPERATION_SUCCESS )
80+ result = NRF_SUCCESS ;
81+
82+ // If general failure.
83+ // The comment on NRF_EVT_FLASH_OPERATION_ERROR describes it as a timeout,
84+ // so we're using a similar error when translating from NRF_SOC_EVTS type to the global NRF52 error defines
85+ else if (_flash_op_result == NRF_EVT_FLASH_OPERATION_ERROR )
86+ result = NRF_ERROR_TIMEOUT ;
87+
88+ // If this assert triggers, we need to implement a new NRF_SOC_EVTS value
89+ else
90+ assert (false);
8391 }
84-
85- // Success
86- return false;
92+
93+ return result ;
8794}
8895
8996// Flash Abstraction Layer
@@ -151,19 +158,24 @@ static bool fal_erase (uint32_t addr)
151158 uint8_t sd_en = 0 ;
152159 (void ) sd_softdevice_is_enabled (& sd_en );
153160
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
161+ // Erase the page
162+ // Multiple attempts if needed
163+ uint32_t err ;
164+ for (uint8_t attempt = 0 ; attempt < MAX_RETRY ; ++ attempt ) {
165+ err = sd_flash_page_erase (addr / FLASH_NRF52_PAGE_SIZE );
166+
167+ if (sd_en ) err = wait_for_async_flash_op_completion (err ); // Only async if soft device enabled
168+ if (err == NRF_SUCCESS ) break ;
169+ if (err == NRF_ERROR_BUSY ) delay (1 );
159170 }
160- return true; // Success
171+ VERIFY_STATUS (err , false); // Return false if all retries fail
172+
173+ return true; // Successfully erased
161174}
162175
163176static uint32_t fal_program (uint32_t dst , void const * src , uint32_t len )
164177{
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
178+ // wait for async event if SD is enabled
167179 uint8_t sd_en = 0 ;
168180 (void ) sd_softdevice_is_enabled (& sd_en );
169181
@@ -173,26 +185,39 @@ static uint32_t fal_program (uint32_t dst, void const * src, uint32_t len)
173185 // https://devzone.nordicsemi.com/f/nordic-q-a/40088/sd_flash_write-cause-nrf_fault_id_sd_assert
174186 // Workaround: write half page at a time.
175187#if NRF52832_XXAA
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
188+ // Write the page
189+ // Multiple attempts, if needed
190+ for (uint8_t attempt = 0 ; attempt < MAX_RETRY ; ++ attempt ) {
191+ err = sd_flash_write ((uint32_t * ) dst , (uint32_t const * ) src , len /4 );
192+
193+ if (sd_en ) err = wait_for_async_flash_op_completion (err ); // Only async if soft device enabled
194+ if (err == NRF_SUCCESS ) break ;
195+ if (err == NRF_ERROR_BUSY ) delay (1 );
180196 }
181- #else
197+ VERIFY_STATUS ( err , 0 ); // Return 0 if all retries fail
182198
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
199+ #else
200+ // Write first part of page
201+ // Multiple attempts, if needed
202+ for (uint8_t attempt = 0 ; attempt < MAX_RETRY ; ++ attempt ) {
203+ err = sd_flash_write ((uint32_t * ) dst , (uint32_t const * ) src , len /8 );
204+
205+ if (sd_en ) err = wait_for_async_flash_op_completion (err ); // Only async if soft device enabled
206+ if (err == NRF_SUCCESS ) break ;
207+ if (err == NRF_ERROR_BUSY ) delay (1 );
188208 }
209+ VERIFY_STATUS (err , 0 ); // Return 0 if all retries fail
210+
211+ // Write second part of page
212+ // Multiple attempts, if needed
213+ for (uint8_t attempt = 0 ; attempt < MAX_RETRY ; ++ attempt ) {
214+ err = sd_flash_write ((uint32_t * ) (dst + len /2 ), (uint32_t const * ) (src + len /2 ), len /8 );
189215
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
216+ if (sd_en ) err = wait_for_async_flash_op_completion (err ); // Only async if soft device enabled
217+ if (err == NRF_SUCCESS ) break ;
218+ if (err == NRF_ERROR_BUSY ) delay (1 );
195219 }
220+ VERIFY_STATUS (err , 0 ); // Return 0 if all retries fail
196221#endif
197222
198223 return len ;
0 commit comments