-
Notifications
You must be signed in to change notification settings - Fork 1.3k
samples: mcuboot: Add firmware loader entrance sample #23318
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
5c472ab
f04c408
e4cfe13
9c61cd0
02be92f
832a7e4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# | ||
# Copyright (c) 2025 Nordic Semiconductor | ||
# | ||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause | ||
# | ||
|
||
cmake_minimum_required(VERSION 3.20.0) | ||
|
||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) | ||
project(firmware_loader_entrance) | ||
|
||
target_sources(app PRIVATE src/main.c) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
mcuboot: | ||
address: 0x0 | ||
region: flash_primary | ||
size: 0x8000 | ||
app: | ||
address: 0x8200 | ||
region: flash_primary | ||
size: 0x5fe00 | ||
mcuboot_pad: | ||
address: 0x8000 | ||
region: flash_primary | ||
size: 0x200 | ||
mcuboot_primary: | ||
address: 0x8000 | ||
orig_span: &id001 | ||
- app | ||
- mcuboot_pad | ||
region: flash_primary | ||
size: 0x60000 | ||
span: *id001 | ||
mcuboot_primary_app: | ||
address: 0x8200 | ||
orig_span: &id002 | ||
- app | ||
region: flash_primary | ||
size: 0x5fe00 | ||
span: *id002 | ||
mcuboot_secondary: | ||
address: 0x68000 | ||
orig_span: &id003 | ||
- mcuboot_secondary_pad | ||
- firmware_loader | ||
region: flash_primary | ||
size: 0x60000 | ||
span: *id003 | ||
mcuboot_secondary_pad: | ||
region: flash_primary | ||
address: 0x68000 | ||
size: 0x200 | ||
firmware_loader: | ||
region: flash_primary | ||
address: 0x68200 | ||
size: 0x5fe00 | ||
settings_storage: | ||
address: 0xc8000 | ||
region: flash_primary | ||
size: 0x4000 | ||
unallocated: | ||
address: 0xcc000 | ||
region: flash_primary | ||
size: 0x34000 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
mcuboot: | ||
address: 0x0 | ||
region: flash_primary | ||
size: 0xa000 | ||
app: | ||
address: 0xa800 | ||
region: flash_primary | ||
size: 0x60000 | ||
mcuboot_pad: | ||
address: 0xa000 | ||
region: flash_primary | ||
size: 0x800 | ||
mcuboot_primary: | ||
address: 0xa000 | ||
orig_span: &id001 | ||
- app | ||
- mcuboot_pad | ||
region: flash_primary | ||
size: 0x60800 | ||
span: *id001 | ||
mcuboot_primary_app: | ||
address: 0xa800 | ||
orig_span: &id002 | ||
- app | ||
region: flash_primary | ||
size: 0x60000 | ||
span: *id002 | ||
mcuboot_secondary: | ||
address: 0x6a800 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I might misunderstand the point of the Firmware Loader, but: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. actually it's a very good point. Actually there is only primary and firmware loader partition used as bootable images. |
||
orig_span: &id003 | ||
- mcuboot_secondary_pad | ||
- firmware_loader | ||
region: flash_primary | ||
size: 0x60800 | ||
span: *id003 | ||
mcuboot_secondary_pad: | ||
region: flash_primary | ||
address: 0x6a800 | ||
size: 0x800 | ||
firmware_loader: | ||
region: flash_primary | ||
address: 0x6b000 | ||
size: 0x60000 | ||
settings_storage: | ||
address: 0xcb000 | ||
region: flash_primary | ||
size: 0x4000 | ||
unallocated: | ||
address: 0xcf000 | ||
region: flash_primary | ||
size: 0x96000 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# Enable MCUmgr and dependencies. | ||
tomchy marked this conversation as resolved.
Show resolved
Hide resolved
|
||
CONFIG_NET_BUF=y | ||
CONFIG_ZCBOR=y | ||
CONFIG_MCUMGR=y | ||
CONFIG_BT=y | ||
CONFIG_BT_PERIPHERAL=y | ||
|
||
# Allow for large Bluetooth data packets. | ||
CONFIG_BT_L2CAP_TX_MTU=498 | ||
CONFIG_BT_BUF_ACL_RX_SIZE=502 | ||
CONFIG_BT_BUF_ACL_TX_SIZE=502 | ||
CONFIG_BT_CTLR_DATA_LENGTH_MAX=251 | ||
|
||
# Enable the Bluetooth mcumgr transport (unauthenticated). | ||
CONFIG_MCUMGR_TRANSPORT_BT=y | ||
CONFIG_MCUMGR_TRANSPORT_BT_CONN_PARAM_CONTROL=y | ||
|
||
# Enable the mcumgr Packet Reassembly feature over Bluetooth and its configuration dependencies. | ||
# MCUmgr buffer size is optimized to fit one SMP packet divided into five Bluetooth Write Commands, | ||
# transmitted with the maximum possible MTU value: 498 bytes. | ||
CONFIG_MCUMGR_TRANSPORT_BT_REASSEMBLY=y | ||
CONFIG_MCUMGR_TRANSPORT_NETBUF_SIZE=2475 | ||
CONFIG_MCUMGR_GRP_OS_MCUMGR_PARAMS=y | ||
CONFIG_MCUMGR_TRANSPORT_WORKQUEUE_STACK_SIZE=4608 | ||
|
||
# Enable OS management with bootloader information and boot mode support | ||
CONFIG_MCUMGR_GRP_OS=y | ||
CONFIG_MCUMGR_GRP_OS_RESET_BOOT_MODE=y | ||
CONFIG_MCUMGR_GRP_OS_BOOTLOADER_INFO=y | ||
|
||
# Disable Bluetooth ping support | ||
CONFIG_BT_CTLR_LE_PING=n | ||
|
||
# Enable logging | ||
CONFIG_LOG=y |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
sample: | ||
tomchy marked this conversation as resolved.
Show resolved
Hide resolved
|
||
name: Firmware loader entrance | ||
description: Demo application for entering the firmware loader application | ||
common: | ||
sysbuild: true | ||
build_only: true | ||
gchwier marked this conversation as resolved.
Show resolved
Hide resolved
|
||
tests: | ||
sample.mcuboot.firmware_loader_entrance: | ||
harness: bluetooth | ||
gchwier marked this conversation as resolved.
Show resolved
Hide resolved
|
||
tags: bluetooth | ||
platform_allow: | ||
- nrf52840dk/nrf52840 | ||
- nrf54l15dk/nrf54l15/cpuapp | ||
integration_platforms: | ||
- nrf52840dk/nrf52840 | ||
- nrf54l15dk/nrf54l15/cpuapp |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
/* | ||
* Copyright (c) 2025 Nordic Semiconductor ASA | ||
* | ||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause | ||
*/ | ||
|
||
#include <zephyr/kernel.h> | ||
#include <zephyr/settings/settings.h> | ||
#include <zephyr/bluetooth/bluetooth.h> | ||
#include <zephyr/bluetooth/hci.h> | ||
#include <zephyr/bluetooth/conn.h> | ||
#include <zephyr/bluetooth/uuid.h> | ||
#include <zephyr/bluetooth/gatt.h> | ||
#include <zephyr/mgmt/mcumgr/transport/smp_bt.h> | ||
#include <zephyr/logging/log.h> | ||
|
||
LOG_MODULE_REGISTER(firmware_entrance_loader, LOG_LEVEL_DBG); | ||
|
||
static struct k_work adv_work; | ||
|
||
static const struct bt_data ad[] = { | ||
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), | ||
BT_DATA_BYTES(BT_DATA_UUID128_ALL, SMP_BT_SVC_UUID_VAL), | ||
}; | ||
|
||
static const struct bt_data sd[] = { | ||
BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, (sizeof(CONFIG_BT_DEVICE_NAME) - 1)), | ||
}; | ||
|
||
static void adv_work_handler(struct k_work *work) | ||
{ | ||
int rc = bt_le_adv_start(BT_LE_ADV_CONN_FAST_2, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd)); | ||
|
||
if (rc) { | ||
LOG_ERR("Advertising failed to start: %d", rc); | ||
return; | ||
} | ||
|
||
LOG_INF("Advertising successfully started, device name: %s", CONFIG_BT_DEVICE_NAME); | ||
} | ||
|
||
static void advertising_start(void) | ||
{ | ||
k_work_submit(&adv_work); | ||
} | ||
|
||
static void connected(struct bt_conn *conn, uint8_t err) | ||
{ | ||
if (err) { | ||
LOG_ERR("Connection failed: 0x%02x (%s)", err, bt_hci_err_to_str(err)); | ||
return; | ||
} | ||
|
||
LOG_INF("Connected"); | ||
} | ||
|
||
static void disconnected(struct bt_conn *conn, uint8_t reason) | ||
{ | ||
LOG_INF("Disconnected, reason: 0x%02x (%s)", reason, bt_hci_err_to_str(reason)); | ||
} | ||
|
||
static void recycled_cb(void) | ||
{ | ||
LOG_INF("Connection object available from previous conn. Disconnect is complete!"); | ||
advertising_start(); | ||
} | ||
|
||
#ifdef CONFIG_BT_SMP | ||
static void security_changed(struct bt_conn *conn, bt_security_t level, | ||
enum bt_security_err err) | ||
{ | ||
char addr[BT_ADDR_LE_STR_LEN]; | ||
|
||
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); | ||
|
||
if (!err) { | ||
LOG_INF("Security changed: %s level %u", addr, level); | ||
} else { | ||
LOG_INF("Security failed: %s level %u error: %d (%s)", addr, level, err, | ||
bt_security_err_to_str(err)); | ||
} | ||
} | ||
#endif | ||
|
||
BT_CONN_CB_DEFINE(conn_callbacks) = { | ||
.connected = connected, | ||
.disconnected = disconnected, | ||
.recycled = recycled_cb, | ||
#ifdef CONFIG_BT_SMP | ||
.security_changed = security_changed, | ||
#endif | ||
}; | ||
|
||
#if defined(CONFIG_BT_SMP) | ||
static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey) | ||
{ | ||
char addr[BT_ADDR_LE_STR_LEN]; | ||
|
||
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); | ||
|
||
LOG_INF("Passkey for %s: %06u", addr, passkey); | ||
} | ||
|
||
static void auth_cancel(struct bt_conn *conn) | ||
{ | ||
char addr[BT_ADDR_LE_STR_LEN]; | ||
|
||
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); | ||
|
||
LOG_INF("Pairing cancelled: %s", addr); | ||
} | ||
|
||
static void pairing_complete(struct bt_conn *conn, bool bonded) | ||
{ | ||
char addr[BT_ADDR_LE_STR_LEN]; | ||
|
||
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); | ||
|
||
LOG_INF("Pairing completed: %s, bonded: %d", addr, bonded); | ||
} | ||
|
||
static void pairing_failed(struct bt_conn *conn, enum bt_security_err reason) | ||
{ | ||
char addr[BT_ADDR_LE_STR_LEN]; | ||
|
||
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); | ||
|
||
LOG_INF("Pairing failed conn: %s, reason: %d (%s)", addr, reason, | ||
bt_security_err_to_str(reason)); | ||
} | ||
|
||
static struct bt_conn_auth_cb conn_auth_callbacks = { | ||
.passkey_display = auth_passkey_display, | ||
.cancel = auth_cancel, | ||
}; | ||
|
||
static struct bt_conn_auth_info_cb conn_auth_info_callbacks = { | ||
.pairing_complete = pairing_complete, | ||
.pairing_failed = pairing_failed | ||
}; | ||
#else | ||
static struct bt_conn_auth_cb conn_auth_callbacks; | ||
static struct bt_conn_auth_info_cb conn_auth_info_callbacks; | ||
#endif | ||
|
||
int main(void) | ||
{ | ||
int rc; | ||
|
||
if (IS_ENABLED(CONFIG_BT_SMP)) { | ||
rc = bt_conn_auth_cb_register(&conn_auth_callbacks); | ||
|
||
if (rc) { | ||
LOG_ERR("Failed to register authorization callbacks."); | ||
return 0; | ||
} | ||
|
||
rc = bt_conn_auth_info_cb_register(&conn_auth_info_callbacks); | ||
|
||
if (rc) { | ||
LOG_ERR("Failed to register authorization info callbacks."); | ||
return 0; | ||
} | ||
} | ||
|
||
rc = bt_enable(NULL); | ||
|
||
if (rc) { | ||
LOG_ERR("Bluetooth init failed: %d", rc); | ||
return 0; | ||
} | ||
|
||
LOG_INF("Bluetooth initialized"); | ||
|
||
if (IS_ENABLED(CONFIG_SETTINGS)) { | ||
settings_load(); | ||
} | ||
|
||
k_work_init(&adv_work, adv_work_handler); | ||
advertising_start(); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suggest that main prints out something along the lines of "Reset the device while holding Button 0/1 to enter DFU mode", so users understand how to enter firmware loader mode. |
||
return 0; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# | ||
# Copyright (c) 2025 Nordic Semiconductor ASA | ||
# | ||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause | ||
# | ||
|
||
SB_CONFIG_BOOTLOADER_MCUBOOT=y | ||
SB_CONFIG_MCUBOOT_MODE_FIRMWARE_UPDATER=y | ||
SB_CONFIG_MCUBOOT_MODE_FIRMWARE_UPDATER_BOOT_MODE_ENTRANCE=y | ||
SB_CONFIG_FIRMWARE_LOADER_IMAGE_SMP_SVR_MINI_BOOT=y |
Uh oh!
There was an error while loading. Please reload this page.