Skip to content

Commit 92e936c

Browse files
committed
Align with pending upstream PR
adafruit#838
1 parent ed2d1f5 commit 92e936c

File tree

1 file changed

+101
-48
lines changed

1 file changed

+101
-48
lines changed

libraries/InternalFileSytem/src/flash/flash_nrf5x.c

Lines changed: 101 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#include "nrf_soc.h"
2929
#include "delay.h"
3030
#include "rtos.h"
31+
#include "assert.h"
32+
3133

3234
#ifdef NRF52840_XXAA
3335
#define BOOTLOADER_ADDR 0xF4000
@@ -43,46 +45,56 @@ extern uint32_t __flash_arduino_start[];
4345
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
4446
//--------------------------------------------------------------------+
4547
static SemaphoreHandle_t _sem = NULL;
46-
static bool _flash_op_failed = false;
48+
static uint32_t _flash_op_result = NRF_EVT_FLASH_OPERATION_SUCCESS;
4749

4850
void flash_nrf5x_event_cb (uint32_t event)
4951
{
5052
if ( _sem ) {
5153
// Record the result, for consumption by fal_erase or fal_program
5254
// Used to reattempt failed operations
53-
_flash_op_failed = (event == NRF_EVT_FLASH_OPERATION_ERROR);
55+
_flash_op_result = event;
5456

5557
// Signal to fal_erase or fal_program that our async flash op is now complete
5658
xSemaphoreGive(_sem);
5759
}
5860
}
5961

60-
// How many retry attempts when performing flash write operations
62+
// How many retry attempts when performing flash operations
6163
#define MAX_RETRY 20
6264

63-
// Check whether a flash operation was successful, or should be repeated
64-
static bool retry_flash_op (uint32_t op_result, bool sd_enabled) {
65-
// If busy
66-
if (op_result == NRF_ERROR_BUSY) {
67-
delay(1);
68-
return true; // Retry
69-
}
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;
7072

71-
// Unspecified error
72-
if (op_result != NRF_SUCCESS)
73-
return true; // Retry
73+
// Operation was queued successfully
74+
if (initial_result == NRF_SUCCESS) {
7475

75-
// If the soft device is enabled, flash operations run async
76-
// The callback (flash_nrf5x_event_cb) will give semaphore when the flash operation is complete
77-
// The callback also checks for NRF_EVT_FLASH_OPERATION_ERROR, which is not available to us otherwise
78-
if (sd_enabled) {
76+
// Wait for result via callback
7977
xSemaphoreTake(_sem, portMAX_DELAY);
80-
if (_flash_op_failed)
81-
return true; // Retry
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+
}
8295
}
83-
84-
// Success
85-
return false;
96+
97+
return result;
8698
}
8799

88100
// Flash Abstraction Layer
@@ -139,8 +151,7 @@ bool flash_nrf5x_erase(uint32_t addr)
139151
static bool fal_erase (uint32_t addr)
140152
{
141153
// Init semaphore for first call
142-
if ( _sem == NULL )
143-
{
154+
if ( _sem == NULL ) {
144155
_sem = xSemaphoreCreateBinary();
145156
VERIFY(_sem);
146157
}
@@ -150,19 +161,30 @@ static bool fal_erase (uint32_t addr)
150161
uint8_t sd_en = 0;
151162
(void) sd_softdevice_is_enabled(&sd_en);
152163

153-
// Make multiple attempts to erase
154-
uint8_t attempt = 0;
155-
while (retry_flash_op(sd_flash_page_erase(addr / FLASH_NRF52_PAGE_SIZE), sd_en)) {
156-
if (++attempt > MAX_RETRY)
157-
return false; // Failure
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);
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);
178+
}
158179
}
159-
return true; // Success
180+
VERIFY_STATUS(err, false); // Return false if all retries fail
181+
182+
return true; // Successfully erased
160183
}
161184

162185
static uint32_t fal_program (uint32_t dst, void const * src, uint32_t len)
163186
{
164-
// Check if soft device is enabled
165-
// If yes, flash operations are async, so we need to wait for the callback to give the semaphore
187+
// wait for async event if SD is enabled
166188
uint8_t sd_en = 0;
167189
(void) sd_softdevice_is_enabled(&sd_en);
168190

@@ -172,26 +194,57 @@ static uint32_t fal_program (uint32_t dst, void const * src, uint32_t len)
172194
// https://devzone.nordicsemi.com/f/nordic-q-a/40088/sd_flash_write-cause-nrf_fault_id_sd_assert
173195
// Workaround: write half page at a time.
174196
#if NRF52832_XXAA
175-
uint8_t attempt = 0;
176-
while (retry_flash_op(sd_flash_write((uint32_t*) dst, (uint32_t const *) src, len/4), sd_en)) {
177-
if (++attempt > MAX_RETRY)
178-
return 0; // Failure
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+
}
179211
}
180-
#else
212+
VERIFY_STATUS(err, 0); // Return 0 if all retries fail
181213

182-
// First part of block
183-
uint8_t attempt = 0;
184-
while (retry_flash_op(sd_flash_write((uint32_t*) dst, (uint32_t const *) src, len/8), sd_en)) {
185-
if (++attempt > MAX_RETRY)
186-
return 0; // Failure
214+
#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+
}
187229
}
188-
189-
// Second part of block
190-
attempt = 0;
191-
while (retry_flash_op(sd_flash_write((uint32_t*) (dst+ len/2), (uint32_t const *) (src + len/2), len/8), sd_en)) {
192-
if (++attempt > MAX_RETRY)
193-
return 0; // Failure
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);
236+
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+
}
194246
}
247+
VERIFY_STATUS(err, 0); // Return 0 if all retries fail
195248
#endif
196249

197250
return len;

0 commit comments

Comments
 (0)