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
3634#else
3735 #define BOOTLOADER_ADDR 0x74000
3836#endif
3937
38+ // How many retry attempts when performing flash operations
39+ #define MAX_RETRY 20
40+
4041// defined in linker script
4142extern uint32_t __flash_arduino_start [];
4243//extern uint32_t __flash_arduino_end[];
@@ -47,56 +48,6 @@ extern uint32_t __flash_arduino_start[];
4748static SemaphoreHandle_t _sem = NULL ;
4849static uint32_t _flash_op_result = NRF_EVT_FLASH_OPERATION_SUCCESS ;
4950
50- void flash_nrf5x_event_cb (uint32_t event )
51- {
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 ;
98- }
99-
10051// Flash Abstraction Layer
10152static bool fal_erase (uint32_t addr );
10253static uint32_t fal_program (uint32_t dst , void const * src , uint32_t len );
@@ -116,6 +67,31 @@ static flash_cache_t _cache =
11667 .cache_buf = _cache_buffer
11768};
11869
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+
11995//--------------------------------------------------------------------+
12096// Application API
12197//--------------------------------------------------------------------+
@@ -156,95 +132,43 @@ static bool fal_erase (uint32_t addr)
156132 VERIFY (_sem );
157133 }
158134
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
161- uint8_t sd_en = 0 ;
162- (void ) sd_softdevice_is_enabled (& sd_en );
163-
164- // Erase the page
165- // Multiple attempts if needed
166- uint32_t err ;
135+ // Erase the page: Multiple attempts if needed
167136 for (uint8_t attempt = 0 ; attempt < MAX_RETRY ; ++ attempt ) {
168- err = sd_flash_page_erase (addr / FLASH_NRF52_PAGE_SIZE );
169-
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 );
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+ }
178141 }
142+ delay (1 );
179143 }
180- VERIFY_STATUS (err , false); // Return false if all retries fail
181-
182- return true; // Successfully erased
144+ return false;
183145}
184146
185- static uint32_t fal_program (uint32_t dst , void const * src , uint32_t len )
186- {
187- // wait for async event if SD is enabled
188- uint8_t sd_en = 0 ;
189- (void ) sd_softdevice_is_enabled (& sd_en );
190-
191- uint32_t err ;
192-
193- // Somehow S140 v6.1.1 assert an error when writing a whole page
194- // https://devzone.nordicsemi.com/f/nordic-q-a/40088/sd_flash_write-cause-nrf_fault_id_sd_assert
195- // Workaround: write half page at a time.
196- #if NRF52832_XXAA
197- // Write the page
198- // Multiple attempts, if needed
147+ // helper for fal_program()
148+ static bool fal_sub_program (uint32_t dst , void const * src , uint32_t len ) {
199149 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 );
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+ }
210154 }
155+ delay (1 );
211156 }
212- VERIFY_STATUS (err , 0 ); // Return 0 if all retries fail
157+ return false;
158+ }
213159
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 );
214163#else
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- }
229- }
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 );
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
236168
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- }
246- }
247- VERIFY_STATUS (err , 0 ); // Return 0 if all retries fail
169+ dst += len /2 ;
170+ src += len /2 ;
171+ VERIFY (fal_sub_program (dst , src , len /2 ), 0 ); // 2nd half
248172#endif
249173
250174 return len ;
0 commit comments