Skip to content

Commit 53058a7

Browse files
authored
Merge pull request #838 from todd-herbert/ble-flash-corruption
Avoid InternalFileSystem corruption caused by simultaneous BLE operation
2 parents 4dcfa3b + 275da60 commit 53058a7

File tree

1 file changed

+59
-51
lines changed

1 file changed

+59
-51
lines changed

libraries/InternalFileSytem/src/flash/flash_nrf5x.c

Lines changed: 59 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,15 @@
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
4042
extern 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
//--------------------------------------------------------------------+
4648
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;
5350

5451
// Flash Abstraction Layer
5552
static 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)
105127
static 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

Comments
 (0)