2929#include "delay.h"
3030#include "rtos.h"
3131
32-
3332#ifdef NRF52840_XXAA
3433 #define BOOTLOADER_ADDR 0xF4000
3534#else
3635 #define BOOTLOADER_ADDR 0x74000
3736#endif
3837
38+ // How many retry attempts when performing flash operations
39+ #define MAX_RETRY 20
40+
3941// defined in linker script
4042extern uint32_t __flash_arduino_start [];
4143//extern uint32_t __flash_arduino_end[];
@@ -44,12 +46,7 @@ extern uint32_t __flash_arduino_start[];
4446// MACRO TYPEDEF CONSTANT ENUM DECLARATION
4547//--------------------------------------------------------------------+
4648static SemaphoreHandle_t _sem = NULL ;
47-
48- void flash_nrf5x_event_cb (uint32_t event )
49- {
50- // if (event != NRF_EVT_FLASH_OPERATION_SUCCESS) LOG_LV1("IFLASH", "Flash op Failed");
51- if ( _sem ) xSemaphoreGive (_sem );
52- }
49+ static uint32_t _flash_op_result = NRF_EVT_FLASH_OPERATION_SUCCESS ;
5350
5451// Flash Abstraction Layer
5552static bool fal_erase (uint32_t addr );
@@ -70,6 +67,31 @@ static flash_cache_t _cache =
7067 .cache_buf = _cache_buffer
7168};
7269
70+ void flash_nrf5x_event_cb (uint32_t event ) {
71+ if ( _sem ) {
72+ // Record the result, for consumption by fal_erase or fal_program
73+ // Used to reattempt failed operations
74+ _flash_op_result = event ;
75+
76+ // Signal to fal_erase or fal_program that our async flash op is now complete
77+ xSemaphoreGive (_sem );
78+ }
79+ }
80+
81+ // When soft device is enabled, flash ops are async
82+ // Eventual success is reported via callback, which we await
83+ static uint32_t wait_for_async_flash_op_completion (void ) {
84+ uint8_t sd_en = 0 ;
85+ (void ) sd_softdevice_is_enabled (& sd_en );
86+
87+ if (sd_en ) {
88+ xSemaphoreTake (_sem , portMAX_DELAY );
89+ return (_flash_op_result == NRF_EVT_FLASH_OPERATION_SUCCESS ) ? NRF_SUCCESS : NRF_ERROR_TIMEOUT ;
90+ } else {
91+ return NRF_SUCCESS ;
92+ }
93+ }
94+
7395//--------------------------------------------------------------------+
7496// Application API
7597//--------------------------------------------------------------------+
@@ -105,62 +127,48 @@ bool flash_nrf5x_erase(uint32_t addr)
105127static bool fal_erase (uint32_t addr )
106128{
107129 // Init semaphore for first call
108- if ( _sem == NULL )
109- {
110- _sem = xSemaphoreCreateCounting (10 , 0 );
130+ if ( _sem == NULL ) {
131+ _sem = xSemaphoreCreateBinary ();
111132 VERIFY (_sem );
112133 }
113134
114- // retry if busy
115- uint32_t err ;
116- while ( NRF_ERROR_BUSY == (err = sd_flash_page_erase (addr / FLASH_NRF52_PAGE_SIZE )) )
117- {
135+ // Erase the page: Multiple attempts if needed
136+ for (uint8_t attempt = 0 ; attempt < MAX_RETRY ; ++ attempt ) {
137+ if (NRF_SUCCESS == sd_flash_page_erase (addr / FLASH_NRF52_PAGE_SIZE )) {
138+ if (NRF_SUCCESS == wait_for_async_flash_op_completion ()) {
139+ return true;
140+ }
141+ }
118142 delay (1 );
119143 }
120- VERIFY_STATUS (err , false);
121-
122- // wait for async event if SD is enabled
123- uint8_t sd_en = 0 ;
124- (void ) sd_softdevice_is_enabled (& sd_en );
125-
126- if ( sd_en ) xSemaphoreTake (_sem , portMAX_DELAY );
127-
128- return true;
144+ return false;
129145}
130146
131- static uint32_t fal_program (uint32_t dst , void const * src , uint32_t len )
132- {
133- // wait for async event if SD is enabled
134- uint8_t sd_en = 0 ;
135- (void ) sd_softdevice_is_enabled (& sd_en );
136-
137- uint32_t err ;
138-
139- // Somehow S140 v6.1.1 assert an error when writing a whole page
140- // https://devzone.nordicsemi.com/f/nordic-q-a/40088/sd_flash_write-cause-nrf_fault_id_sd_assert
141- // Workaround: write half page at a time.
142- #if NRF52832_XXAA
143- while ( NRF_ERROR_BUSY == (err = sd_flash_write ((uint32_t * ) dst , (uint32_t const * ) src , len /4 )) )
144- {
147+ // helper for fal_program()
148+ static bool fal_sub_program (uint32_t dst , void const * src , uint32_t len ) {
149+ for (uint8_t attempt = 0 ; attempt < MAX_RETRY ; ++ attempt ) {
150+ if (NRF_SUCCESS == sd_flash_write ((uint32_t * ) dst , (uint32_t const * ) src , len /4 )) {
151+ if (NRF_SUCCESS == wait_for_async_flash_op_completion ()) {
152+ return true;
153+ }
154+ }
145155 delay (1 );
146156 }
147- VERIFY_STATUS (err , 0 );
157+ return false;
158+ }
148159
149- if ( sd_en ) xSemaphoreTake (_sem , portMAX_DELAY );
160+ static uint32_t fal_program (uint32_t dst , void const * src , uint32_t len ) {
161+ #if NRF52832_XXAA
162+ VERIFY (fal_sub_program (dst , src , len ), 0 );
150163#else
151- while ( NRF_ERROR_BUSY == (err = sd_flash_write ((uint32_t * ) dst , (uint32_t const * ) src , len /8 )) )
152- {
153- delay (1 );
154- }
155- VERIFY_STATUS (err , 0 );
156- if ( sd_en ) xSemaphoreTake (_sem , portMAX_DELAY );
164+ // Somehow S140 v6.1.1 assert an error when writing a whole page
165+ // https://devzone.nordicsemi.com/f/nordic-q-a/40088/sd_flash_write-cause-nrf_fault_id_sd_assert
166+ // Workaround: write half page at a time.
167+ VERIFY (fal_sub_program (dst , src , len /2 ), 0 ); // 1st half
157168
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 );
161- }
162- VERIFY_STATUS (err , 0 );
163- if ( sd_en ) xSemaphoreTake (_sem , portMAX_DELAY );
169+ dst += len /2 ;
170+ src += len /2 ;
171+ VERIFY (fal_sub_program (dst , src , len /2 ), 0 ); // 2nd half
164172#endif
165173
166174 return len ;
0 commit comments