Skip to content

Commit 583d67b

Browse files
authored
Merge pull request #377 from ejtagle/master
Try to gracefully handle FLASH operations queue becoming full, instead of silently failing and allow OTA DFU process to be recoverable, in case of a communication error in the DUAL_BANK configuration
2 parents 30c7349 + a76d419 commit 583d67b

File tree

13 files changed

+342
-95
lines changed

13 files changed

+342
-95
lines changed

CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ set(MBR_HEX ${SOFTDEVICE_DIR}/mbr/hex/mbr_nrf52_2.4.1_mbr.hex)
2828
set(TINYUSB_DIR ${CMAKE_CURRENT_LIST_DIR}/lib/tinyusb/src)
2929
set(TCRYPT_DIR ${CMAKE_CURRENT_LIST_DIR}/lib/tinycrypt/lib)
3030

31+
option(DEFAULT_TO_OTA_DFU "Default to OTA DFU instead of Serial DFU" OFF)
3132
option(SIGNED_FW "Enable signed firmware verification" OFF)
3233
option(DUALBANK_FW "Enable dual bank DFU support" OFF)
3334
option(FORCE_UF2 "Force UF2 support even with SIGNED_FW" OFF)
@@ -196,6 +197,10 @@ if (FORCE_UF2)
196197
target_compile_definitions(bootloader PUBLIC FORCE_UF2)
197198
endif ()
198199

200+
if (DEFAULT_TO_OTA_DFU)
201+
target_compile_definitions(bootloader PUBLIC DEFAULT_TO_OTA_DFU)
202+
endif ()
203+
199204
if (TRACE_ETM STREQUAL "1")
200205
# ENABLE_TRACE will cause system_nrf5x.c to set up ETM trace
201206
target_compile_definitions(bootloader PUBLIC ENABLE_TRACE)

Makefile

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22
# CONFIGURE
33
# - SDK_PATH : path to SDK directory
44
#
5-
# - SD_NAME : e.g s132, s140
6-
# - SD_VERSION : SoftDevice version e.g 6.0.0
7-
# - SD_HEX : to bootloader hex binary
8-
# - SIGNED_FW : if bootloader will ONLY accept signed firmware
9-
# - SIGNED_FW_QX : Qx for signed firmware verification
10-
# - SIGNED_FW_QY : Qy for signed firmware verification
11-
# - DUALBANK_FW : If bootloader will implement a dual bank feature to allow autorecover from failed
12-
# - FORCE_UF2 : if SIGNED_FW is 1, will force to include UF2 support (UNSECURE, UF2 does NOT validate signature!)
5+
# - SD_NAME : e.g s132, s140
6+
# - SD_VERSION : SoftDevice version e.g 6.0.0
7+
# - SD_HEX : to bootloader hex binary
8+
# - SIGNED_FW : if bootloader will ONLY accept signed firmware
9+
# - SIGNED_FW_QX : Qx for signed firmware verification
10+
# - SIGNED_FW_QY : Qy for signed firmware verification
11+
# - DUALBANK_FW : If bootloader will implement a dual bank feature to allow autorecover from failed
12+
# - FORCE_UF2 : if SIGNED_FW is 1, will force to include UF2 support (UNSECURE, UF2 does NOT validate signature!)
13+
# - DEFAULT_TO_OTA_DFU : if entering DFU, by default enter OTA DFU instead of Serial DFU
1314
#------------------------------------------------------------------------------
1415

1516
PYTHON = python
@@ -371,6 +372,10 @@ ifeq ($(FORCE_UF2), 1)
371372
CFLAGS += -DFORCE_UF2
372373
endif
373374

375+
ifeq ($(DEFAULT_TO_OTA_DFU), 1)
376+
CFLAGS += -DDEFAULT_TO_OTA_DFU
377+
endif
378+
374379
_VER = $(subst ., ,$(word 1, $(subst -, ,$(GIT_VERSION))))
375380
CFLAGS += -DMK_BOOTLOADER_VERSION='($(word 1,$(_VER)) << 16) + ($(word 2,$(_VER)) << 8) + $(word 3,$(_VER))'
376381

lib/sdk11/components/libraries/bootloader_dfu/bootloader.c

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ typedef enum
4444
BOOTLOADER_SETTINGS_SAVING, /**< Bootloader status for indicating that saving of bootloader settings is in progress. */
4545
BOOTLOADER_COMPLETE, /**< Bootloader status for indicating that all operations for the update procedure has completed and it is safe to reset the system. */
4646
BOOTLOADER_TIMEOUT, /**< Bootloader status field for indicating that a timeout has occured and current update process should be aborted. */
47-
BOOTLOADER_RESET, /**< Bootloader status field for indicating that a reset has been requested and current update process should be aborted. */
47+
BOOTLOADER_SYS_RESET, /**< Bootloader status field for indicating that a reset has been requested and current update process should be aborted. */
48+
BOOTLOADER_RESET_TO_SELF, /**< Bootloader status field for indicating that a reset has been requested and current update process should be aborted and the bootloader must be reentered. */
4849
} bootloader_status_t;
4950

5051
static pstorage_handle_t m_bootsettings_handle; /**< Pstorage handle to use for registration and identifying the bootloader module on subsequent calls to the pstorage module for load and store of bootloader setting in flash. */
@@ -136,9 +137,10 @@ static void wait_for_events(void)
136137

137138
if ((m_update_status == BOOTLOADER_COMPLETE) ||
138139
(m_update_status == BOOTLOADER_TIMEOUT) ||
139-
(m_update_status == BOOTLOADER_RESET) )
140+
(m_update_status == BOOTLOADER_SYS_RESET) ||
141+
(m_update_status == BOOTLOADER_RESET_TO_SELF))
140142
{
141-
// When update has completed or a timeout/reset occured we will return.
143+
// When update has completed or a timeout/reset occurred we will return.
142144
return;
143145
}
144146
}
@@ -186,10 +188,36 @@ static void bootloader_settings_save(bootloader_settings_t * p_settings)
186188
{
187189
if ( is_ota() )
188190
{
189-
uint32_t err_code = pstorage_clear(&m_bootsettings_handle, sizeof(bootloader_settings_t));
191+
uint32_t err_code;
192+
while(1) {
193+
err_code = pstorage_clear(&m_bootsettings_handle, sizeof(bootloader_settings_t));
194+
if (err_code != NRF_ERROR_NO_MEM) {
195+
break;
196+
}
197+
// This means the write/erase queue of commands was completely full - Should not
198+
// happen, but better safe than sorry, wait until space becomes available -
199+
// the pstorage event handler is only run from the main loop, and we are also
200+
// running from a BLE event on the main loop: This means if we wait here, the FLASH
201+
// completion events will never be handled (will be queued by app_scheduler, but
202+
// not handled, and that means this wait will never end... So, process SOC events
203+
// from the SD (but NOT BLE events!) - This will free entries on the pstorage queue
204+
// as soon as operations are complete, allowing this op to be queued
205+
while (NRF_ERROR_NOT_FOUND != proc_soc()) {
206+
// nothing
207+
}
208+
}
190209
APP_ERROR_CHECK(err_code);
191210

192-
err_code = pstorage_store(&m_bootsettings_handle, (uint8_t *) p_settings, sizeof(bootloader_settings_t), 0);
211+
while(1) {
212+
err_code = pstorage_store(&m_bootsettings_handle, (uint8_t *) p_settings, sizeof(bootloader_settings_t), 0);
213+
if (err_code != NRF_ERROR_NO_MEM) {
214+
break;
215+
}
216+
// No space, wait until an entry in the queue is freed
217+
while (NRF_ERROR_NOT_FOUND != proc_soc()) {
218+
// nothing
219+
}
220+
}
193221
APP_ERROR_CHECK(err_code);
194222
}
195223
else
@@ -296,14 +324,19 @@ void bootloader_dfu_update_process(dfu_update_status_t update_status)
296324
}
297325
else if (update_status.status_code == DFU_RESET)
298326
{
299-
m_update_status = BOOTLOADER_RESET;
327+
m_update_status =
328+
(update_status.restart_into_bootloader == false ? BOOTLOADER_SYS_RESET : BOOTLOADER_RESET_TO_SELF);
300329
}
301330
else
302331
{
303332
// No implementation needed.
304333
}
305334
}
306335

336+
bool bootloader_must_reset_to_self(void)
337+
{
338+
return m_update_status == BOOTLOADER_RESET_TO_SELF;
339+
}
307340

308341
uint32_t bootloader_init(void)
309342
{

lib/sdk11/components/libraries/bootloader_dfu/bootloader.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@
3232
*/
3333
uint32_t bootloader_init(void);
3434

35+
/**@brief Function to check if bootloader must be reentered after a reset
36+
* @details: This function can only be called after bootloader_dfu_start returns
37+
* @retval true If device must reboot to the bootloader
38+
* @retval false If device must reboot to the application, if possible
39+
*/
40+
bool bootloader_must_reset_to_self(void);
41+
3542
/**@brief Function for validating application region in flash.
3643
* @retval true If Application region is valid.
3744
* @retval false If Application region is not valid.
@@ -92,6 +99,8 @@ uint32_t bootloader_dfu_sd_update_finalize(void);
9299

93100
void bootloader_mbr_addrs_populate(void);
94101

102+
extern uint32_t proc_soc(void);
103+
95104
#endif // BOOTLOADER_H__
96105

97106
/**@} */

lib/sdk11/components/libraries/bootloader_dfu/bootloader_util.c

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@
3232
#if defined ( __CC_ARM )
3333
__asm static void bootloader_util_reset(uint32_t start_addr)
3434
{
35+
MOVS R5, #0x00 ; R5 = 0
36+
MSR CONTROL, R5 ; Clear CONTROL
37+
MSR PRIMASK, R5 ; Clear PRIMASK
38+
MSR BASEPRI, R5 ; Clear BASEPRI
39+
MSR FAULTMASK, R5 ; Clear FAULTMASK
40+
3541
LDR R5, [R0] ; Get App initial MSP for bootloader.
3642
MSR MSP, R5 ; Set the main stack pointer to the applications MSP.
3743
LDR R0, [R0, #0x04] ; Load Reset handler into R0. This will be first argument to branch instruction (BX).
@@ -69,6 +75,12 @@ static inline void bootloader_util_reset (uint32_t start_addr) __attribute__ ((o
6975
static inline void bootloader_util_reset(uint32_t start_addr)
7076
{
7177
__asm volatile(
78+
"movs r5, #0x00\t\n" // R5 = 0
79+
"msr control, r5\t\n" // Clear CONTROL
80+
"msr primask, r5\t\n" // Clear PRIMASK
81+
"msr basepri, r5\t\n" // Clear BASEPRI
82+
"msr faultmask, r5\t\n" // Clear FAULTMASK
83+
7284
"ldr r0, [%0]\t\n" // Get App initial MSP for bootloader.
7385
"msr msp, r0\t\n" // Set the main stack pointer to the applications MSP.
7486
"ldr r0, [%0, #0x04]\t\n" // Load Reset handler into R0.
@@ -108,7 +120,13 @@ static inline void bootloader_util_reset(uint32_t start_addr)
108120
#elif defined ( __ICCARM__ )
109121
static inline void bootloader_util_reset(uint32_t start_addr)
110122
{
111-
asm("ldr r5, [%0]\n" // Get App initial MSP for bootloader.
123+
asm("movs r5, #0x00\n" // R5 = 0
124+
"msr control, r5\n" // Clear CONTROL
125+
"msr primask, r5\n" // Clear PRIMASK
126+
"msr basepri, r5\n" // Clear BASEPRI
127+
"msr faultmask, r5\n" // Clear FAULTMASK
128+
129+
"ldr r5, [%0]\n" // Get App initial MSP for bootloader.
112130
"msr msp, r5\n" // Set the main stack pointer to the applications MSP.
113131
"ldr r0, [%0, #0x04]\n" // Load Reset handler into R0.
114132

0 commit comments

Comments
 (0)