29
29
#include "delay.h"
30
30
#include "rtos.h"
31
31
32
-
33
32
#ifdef NRF52840_XXAA
34
33
#define BOOTLOADER_ADDR 0xF4000
35
34
#else
36
35
#define BOOTLOADER_ADDR 0x74000
37
36
#endif
38
37
38
+ // How many retry attempts when performing flash operations
39
+ #define MAX_RETRY 20
40
+
39
41
// defined in linker script
40
42
extern uint32_t __flash_arduino_start [];
41
43
//extern uint32_t __flash_arduino_end[];
@@ -44,12 +46,7 @@ extern uint32_t __flash_arduino_start[];
44
46
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
45
47
//--------------------------------------------------------------------+
46
48
static 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 ;
53
50
54
51
// Flash Abstraction Layer
55
52
static bool fal_erase (uint32_t addr );
@@ -70,6 +67,31 @@ static flash_cache_t _cache =
70
67
.cache_buf = _cache_buffer
71
68
};
72
69
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
+
73
95
//--------------------------------------------------------------------+
74
96
// Application API
75
97
//--------------------------------------------------------------------+
@@ -105,62 +127,48 @@ bool flash_nrf5x_erase(uint32_t addr)
105
127
static bool fal_erase (uint32_t addr )
106
128
{
107
129
// Init semaphore for first call
108
- if ( _sem == NULL )
109
- {
110
- _sem = xSemaphoreCreateCounting (10 , 0 );
130
+ if ( _sem == NULL ) {
131
+ _sem = xSemaphoreCreateBinary ();
111
132
VERIFY (_sem );
112
133
}
113
134
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
+ }
118
142
delay (1 );
119
143
}
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;
129
145
}
130
146
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
+ }
145
155
delay (1 );
146
156
}
147
- VERIFY_STATUS (err , 0 );
157
+ return false;
158
+ }
148
159
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 );
150
163
#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
157
168
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
164
172
#endif
165
173
166
174
return len ;
0 commit comments