Skip to content

Commit 630668a

Browse files
committed
Refactor for maintainability
1 parent 3ea7855 commit 630668a

File tree

1 file changed

+69
-44
lines changed

1 file changed

+69
-44
lines changed

libraries/InternalFileSytem/src/flash/flash_nrf5x.c

Lines changed: 69 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
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
//--------------------------------------------------------------------+
4647
static SemaphoreHandle_t _sem = NULL;
47-
static bool _flash_op_failed = false;
48+
static uint32_t _flash_op_result = NRF_EVT_FLASH_OPERATION_SUCCESS;
4849

4950
void 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

163176
static 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

Comments
 (0)