Unexpected RESET_SOFTWARE during BLE FOTA on nRF54L15 (NCS v3.4.0)

Hi Nordic Team,

I'm debugging an unexpected software reset on an nRF54L15 running nRF Connect SDK v3.4.0. BLE FOTA through MCUmgr completes successfully and the new image is marked as pending/test, but the device reboots while the application is still waiting for its own 120-second reboot timer to expire (this timeout configured by us).

This has happened repeatedly. I don't see the log from my FOTA reboot handler, my __wrap_sys_reboot() wrapper, or even the printk() statements I added directly to Zephyr's sys_reboot().

After reboot, HWINFO reports:

Reset cause: 0x00000002
Reset cause flag: software


I'm trying to identify what could trigger this reset without going through the normal Zephyr reboot path.

Setup

  • SoC: nRF54L15 on a custom PCB
  • Application Build: CPUAPP
  • nRF Connect SDK: v3.4.0
  • Boot chain: NSIB/b0 → MCUboot → application
  • MCUboot update method: swap using the move algorithm
  • FOTA: BLE SMP/MCUmgr
  • Image manager and OS management group enabled
  • MCUboot verification key provisioned using KMU
  • Other application components: LoRaWAN, external flash, NFC, a GRTC-based time service, and an event-driven workflow scheduler
  • FOTA App: nRF Connect Mobile App

Relevant sysbuild.conf settings:


SB_CONFIG_SECURE_BOOT_APPCORE=y
SB_CONFIG_BOOTLOADER_MCUBOOT=y

SB_CONFIG_SECURE_BOOT_SIGNATURE_TYPE_ED25519=y
SB_CONFIG_BOOT_SIGNATURE_TYPE_ED25519=y

SB_CONFIG_MCUBOOT_SIGNATURE_USING_KMU=y

SB_CONFIG_SECURE_BOOT_SIGNING_KEY_FILE="${APP_DIR}/keys/nsib_private_key.pem"
SB_CONFIG_BOOT_SIGNATURE_KEY_FILE="${APP_DIR}/keys/mcuboot_private_key.pem"

SB_CONFIG_MCUBOOT_GENERATE_DEFAULT_KEY_FILE=y
SB_CONFIG_SECURE_BOOT_GENERATE_DEFAULT_KMU_KEYFILE=y

SB_CONFIG_MCUBOOT_UPDATEABLE_IMAGES=1

Expected behavior

After the image upload finishes, the application starts a local 120-second timer rather than rebooting immediately:


#define FOTA_REBOOT_DELAY_S 120U


The MCUmgr OS reset event (MGMT_EVT_OP_OS_MGMT_RESET) is intercepted. The callback rejects the request with:


*rc = MGMT_ERR_EACCESSDENIED;
return MGMT_CB_ERROR_RC;


The request data is consistently logged as force=0 and boot_mode=0. The intended sequence is that the upload completes, the image is marked pending/test, the MCUmgr reset is rejected, and the application waits for its own timer before calling sys_reboot(SYS_REBOOT_COLD).

What happens in practice

I've reproduced this several times. The delay from marking the image pending to the unexpected reboot varies, but it is always shorter than 120 seconds.

Case 1: The image was uploaded and marked pending at 16:20:04.510. The local reboot timer started at 16:20:04.556, and the MCUmgr reset request was intercepted at 16:20:05.665. The device started booting again at 16:21:02.566, about 58 seconds after the image became pending.

MCUboot then reported:


I: Secondary image: magic=good, swap_type=0x2
I: Image index: 0, Swap type: test
I: Starting swap using move algorithm.
I: Image version: v1.0.1
I: Jumping to the first image slot


Case 2: The image was marked pending at 16:30:06.090, and the reset request was intercepted at 16:30:07.280. The next boot started at 16:30:54.692, about 48 seconds after the image became pending.

Case 3: The image was marked pending at 17:15:55.246. The callback received the reset request at 17:15:56.384, logged force=0 boot_mode=0, and rejected it. The device continued running, then rebooted at 17:16:39.101, around 43 seconds after the rejected request.

After these reboots, HWINFO reported:
Reset causes supported: 0x000009b3
Reset cause: 0x00000002
Reset cause flag: software

Case 4: I enabled additional fatal-error and stack diagnostics to check for a Zephyr fatal error, assertion, or stack overflow:


CONFIG_RESET_ON_FATAL_ERROR=n
CONFIG_ASSERT=y
CONFIG_STACK_SENTINEL=y
CONFIG_STACK_CANARIES=y
CONFIG_THREAD_NAME=y
CONFIG_THREAD_MONITOR=y
CONFIG_INIT_STACKS=y
CONFIG_THREAD_STACK_INFO=y
CONFIG_THREAD_ANALYZER=y
CONFIG_THREAD_ANALYZER_AUTO=y
CONFIG_THREAD_ANALYZER_AUTO_INTERVAL=10


After rejecting the MCUmgr reset request, the application continued running and the thread analyzer kept printing statistics. For example, the main thread used 956 of 2048 bytes (46%), the MCUmgr SMP thread used 1548 of 2048 bytes (75%), and the LoRaWAN thread used 1316 of 2048 bytes (64%). There was no assertion, hard fault, MPU fault, fatal-error message, or stack-overflow indication before the reboot. The device started booting again at 17:41:23.582; HWINFO again reported reset cause 0x00000002 (software).

In all cases, the image upload succeeds, the image becomes pending/test, the MCUmgr reset request is rejected, the BLE connection disconnects normally, and the application continues running for tens of seconds before the unexpected reset. MCUboot then detects and installs the pending image.

Reboot-path instrumentation

My own FOTA reboot handler logs this immediately before rebooting:


APP_LOG_ERR("### FOTA CALLING sys_reboot(SYS_REBOOT_COLD) ###");
k_msleep(100);
sys_reboot(SYS_REBOOT_COLD);

That message never appears during the unexpected reset.

I also enabled linker wrapping (-Wl,--wrap=sys_reboot) and added a wrapper that logs the caller and current thread before calling __real_sys_reboot(). The wrapper's log never appears either.

Finally, I added printk() instrumentation directly inside Zephyr's sys_reboot() implementation. Those messages also never appear, although the reset still happens. This makes me suspect the reset may be triggered by a lower-level mechanism that bypasses Zephyr's sys_reboot() path.

MCUmgr reset delay

My configuration includes:


CONFIG_MCUMGR_GRP_OS_RESET_MS=250


My understanding is that this controls the delay before rebooting after an accepted MCUmgr OS reset request, allowing the response to be sent first. Since my callback returns MGMT_ERR_EACCESSDENIED and MGMT_CB_ERROR_RC, I would like to confirm whether this delay can still schedule a reset after the callback rejects the request.

Other areas checked:

I checked the LoRaWAN service and GRTC-based time service for explicit reset calls but haven't found any. The GRTC driver schedules callbacks through compare channels and does not directly call sys_reboot(). I'm still auditing the timer users and other application timeout paths.

Debugging the protected boot chain

I also tried to start a debug session in nRF Connect for VS Code while retaining the full NSIB → MCUboot → application chain. I selected “Start a session on Application Core” and “Stop in My_Application at main()”, but the extension tried to program the sysbuild image and failed with:


-- runners.nrfutil: Connecting to probe
-- runners.nrfutil: Programming image

Error: One or more batch tasks failed:
* 1057728952:
Device error:
Address 0x00000000 is in a protected RRAMC region (Generic)

The device already has KMU/security information provisioned, so I have avoided running recover because I don't want to erase or reprovision the security state just to investigate this issue.

What is the recommended way to attach GDB to the Application Core/application ELF without reflashing the protected NSIB region?

Questions:

  1. On the nRF54L15, what mechanisms can cause RESET_SOFTWARE (Reset cause = 0x00000002) without going through Zephyr's sys_reboot()?
  2. Could MPSL, the SoftDevice Controller, MCUmgr/SMP, image management, MCUboot integration, NSIB/b0, secure firmware, the system event subsystem, GRTC/system timer, or the nRF54L security/protection subsystem initiate a software reset through a lower-level mechanism?
  3. Since neither __wrap_sys_reboot() nor the instrumented Zephyr sys_reboot() is reached, which lower-level nRF54L reset function, API, or register would you recommend instrumenting or setting a breakpoint on? Is there a hardware reset task/register below sys_arch_reboot() that could help identify the caller?
  4. Is there retained reset information on the nRF54L15 that can distinguish a Zephyr reboot, an NVIC/SystemReset, a secure-domain reset, a subsystem-initiated reset, or a bootloader-initiated reset when HWINFO reports the same software-reset cause?
  5. Does returning MGMT_ERR_EACCESSDENIED and MGMT_CB_ERROR_RC fully reject an MCUmgr OS reset request when force=0 and boot_mode=0 ?
  6. Is CONFIG_MCUMGR_GRP_OS_RESET_MS=250 used only after the request has been accepted, or can a delayed reset remain scheduled after the callback returns an error?
  7. Are there known issues in NCS v3.4.0 involving nRF54L15 + NSIB + MCUboot + BLE SMP FOTA where the image is marked TEST, the MCUmgr OS reset is rejected, but a software reset occurs later?
  8. What is the recommended way to debug the Application Core while preserving NSIB, MCUboot, KMU provisioning, and protected RRAM, without trying to reprogram address 0x00000000 ?

The main point is that the device keeps running after the MCUmgr reset request is rejected, but then resets roughly 43–58 seconds later. The local 120-second timer and all the sys_reboot() instrumentation remain silent, and no fatal-error or stack-overflow indication is logged. MCUboot subsequently sees the pending test image and completes the swap.

Let me know if additional information needed. I would appreciate any suggestions or solutions as soon as possible.

Best regards,
Mathiyazhagan S.

Parents
  • Hi,

    This seems strange, the common source for unexpected resets is fatal error handler calling sys_reboot(), but I see you have already disabled this by adding CONFIG_RESET_ON_FATAL_ERROR=n to your project configuration file. But just to be on the safe side, please check the .config output for your main app to verify that CONFIG_RESET_ON_FATAL_ERROR is indeed not selected. It should normally only be sys_reboot() that calls NVIC_SystemReset() in a zephyr application.

    Finally, I added printk() instrumentation directly inside Zephyr's sys_reboot() implementation. Those messages also never appear, although the reset still happens. This makes me suspect the reset may be triggered by a lower-level mechanism that bypasses Zephyr's sys_reboot() path.

    If you haven't already, I suggest you call sys_reboot() intentionally to verify that the message gets printed then. If you print the message without a k_sleep after, the device may reset before the log is printed.

    My understanding is that this controls the delay before rebooting after an accepted MCUmgr OS reset request, allowing the response to be sent first. Since my callback returns MGMT_ERR_EACCESSDENIED and MGMT_CB_ERROR_RC, I would like to confirm whether this delay can still schedule a reset after the callback rejects the request.

    You can use the "advanced" menu in the nRF Device Manager app on iOS/Android to upload the image and mark it as pending and not send the reset command at the end to test if the issue may be related to the mcumgr reset command or not.

    Debugging the protected boot chain

    I also tried to start a debug session in nRF Connect for VS Code while retaining the full NSIB → MCUboot → application chain. I selected “Start a session on Application Core” and “Stop in My_Application at main()”, but the extension tried to program the sysbuild image and failed with:

    Reprovisoining of KMU keys require an erase all (west flash --erase). To avoid this for debugging, you can select "debug without flashing"

    Best regards

    Vidar

  • Hi, 

    Thank you for the suggestion.
    You can use the "advanced" menu in the nRF Device Manager app on iOS/Android to upload the image and mark it as pending and not send the reset command at the end to test if the issue may be related to the mcumgr reset command or not.

    I tested the firmware update using the nRF Device Manager mobile app, following your recommendation to upload the image and mark it as pending without sending the reset command at the end.
    Success Log1:
     [18:48:32.035] [00:00:13.967,231]  <inf> fota: [fota_handle_event: 319] FOTA workflow started 
     [18:48:32.046] [00:00:13.975,235]  <inf> bt_sdc_hci_driver: SoftDevice Controller build revision: 
     [18:48:32.051]                                             c8 da 30 98 f9 f0 34 a4  4b 6e ba d3 08 19 cc 0c |..0...4. Kn......
     [18:48:32.062]                                             ea 51 da 47                                      |.Q.G              
     [18:48:32.082] [00:00:14.005,448]  <inf> bt_hci_core: HW Platform: Nordic Semiconductor (0x0002) 
     [18:48:32.082] [00:00:14.013,531]  <inf> bt_hci_core: HW Variant: nRF54Lx (0x0005) 
     [18:48:32.095] [00:00:14.020,385]  <inf> bt_hci_core: Firmware: Standard Bluetooth controller (0x00) Version 200.12506 Build 888207768 
     [18:48:32.108] [00:00:14.032,406]  <inf> bt_hci_core: HCI transport: SDC 
     [18:48:32.109] [00:00:14.038,296]  <inf> bt_hci_core: Identity: C6:1D:FC:E3:C6:49 (random) 
     [18:48:32.127] [00:00:14.045,862]  <inf> bt_hci_core: HCI: version 6.3 (0x11) revision 0x3039, manufacturer 0x0059 
     [18:48:32.127] [00:00:14.055,620]  <inf> bt_hci_core: LMP: version 6.3 (0x11) subver 0x3039 
     [18:48:32.143] [00:00:14.063,859]  <inf> fota: FOTA advertising started 
     [18:48:41.065] [00:00:22.997,214]  <inf> fota: FOTA central connected: 40:08:BF:CD:82:F2 (random) 
     [18:48:41.078] [00:00:23.007,707]  <inf> fota: Central connected; awaiting DFU upload 
     [18:50:43.679] [00:02:25.611,712]  <inf> mcuboot_util: Image index: 0, Swap type: none 
     [18:50:44.085] [00:02:26.017,320]  <inf> mcuboot_util: Image index: 0, Swap type: none 
     [18:50:44.092] [00:02:26.024,512]  <inf> mcuboot_util: Image index: 0, Swap type: none 
     [18:50:44.099] [00:02:26.031,840]  <inf> fota: FOTA image transfer started 
     [18:51:04.397] [00:02:46.329,260]  <inf> fota: FOTA image uploaded and set to pending 
     
     [18:51:04.406] [00:02:46.338,762]  <inf> fota: DFU upload done - starting reboot timer (30 s) 
     
     [18:51:34.416] [00:03:16.349,018]  <wrn> fota: ### FOTA REBOOT TIMER CALLBACK FIRED ### 
     [18:51:34.426] [00:03:16.359,151]  <wrn> fota: FOTA reboot event post ret=0 
     [18:51:34.438] [00:03:16.368,269]  <inf> fota: Reboot timeout reached: rebooting system 
     [18:51:34.446] [00:03:16.378,050]  <err> fota: ### FOTA CALLING sys_reboot(SYS_REBOOT_COLD) ### 
     [18:51:34.556] Printk: sys_reboot(1) called by thread 0x20003a68 (main)
     
     *** Booting nRF Connect SDK v3.4.0-99553055607b ***
     [18:51:34.569] *** Using Zephyr OS v4.4.0-bf801e4e3d19 ***
     [18:51:34.575] Fprotect disabled. No protection applied.
     [18:51:34.575] LCS-awareness disabled.
     [18:51:34.584] Attempting to boot slot 0.
     [18:51:34.584] Attempting to boot from address 0x1a800.
     [18:51:34.584] I: Trying to get Firmware version
     [18:51:34.595] I: Firmware signature verified.
     [18:51:34.595] Firmware version 1
     [18:51:34.595] Booting (0x1a800).*** Booting MCUboot v2.3.0-dev-c1d2d128a001 ***
     [18:51:34.605] *** Using nRF Connect SDK v3.4.0-99553055607b ***
     [18:51:34.605] *** Using Zephyr OS v4.4.0-bf801e4e3d19 ***
     [18:51:34.619] I: Starting bootloader
     [18:51:34.619] I: LCS-awareness disabled, skipping LCS check
     [18:51:34.619] I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
     [18:51:34.629] I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
     [18:51:34.629] I: Boot source: none
     [18:51:34.640] I: Image index: 0, Swap type: none
     [18:51:34.640] I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
     [18:51:34.640] I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
     [18:51:34.656] I: Boot source: none
     [18:51:34.697] I: Bootloader chainload address offset: 0x3a000
     [18:51:34.702] I: Image version: v1.0.0
     [18:51:34.708] I: Jumping to the first image slot
     [18:51:35.187] *** Booting My Application v1.0.0-c6ab95c1152e ***
     [18:51:35.195] *** Using nRF Connect SDK v3.4.0-99553055607b ***
     [18:51:35.203] *** Using Zephyr OS v4.4.0-bf801e4e3d19 ***
    Success Log2:
     [18:56:39.191] [00:00:52.591,891]  <inf> fota: [fota_handle_event: 319] FOTA workflow started 
     [18:56:39.199] [00:00:52.599,913]  <inf> bt_sdc_hci_driver: SoftDevice Controller build revision: 
     [18:56:39.209]                                             c8 da 30 98 f9 f0 34 a4  4b 6e ba d3 08 19 cc 0c |..0...4. Kn......
     [18:56:39.221]                                             ea 51 da 47                                      |.Q.G              
     [18:56:39.236] [00:00:52.629,953]  <inf> bt_hci_core: HW Platform: Nordic Semiconductor (0x0002) 
     [18:56:39.239] [00:00:52.638,024]  <inf> bt_hci_core: HW Variant: nRF54Lx (0x0005) 
     [18:56:39.245] [00:00:52.644,870]  <inf> bt_hci_core: Firmware: Standard Bluetooth controller (0x00) Version 200.12506 Build 888207768 
     [18:56:39.258] [00:00:52.656,866]  <inf> bt_hci_core: HCI transport: SDC 
     [18:56:39.267] [00:00:52.662,752]  <inf> bt_hci_core: Identity: C6:1D:FC:E3:C6:49 (random) 
     [18:56:39.274] [00:00:52.670,314]  <inf> bt_hci_core: HCI: version 6.3 (0x11) revision 0x3039, manufacturer 0x0059 
     [18:56:39.282] [00:00:52.680,097]  <inf> bt_hci_core: LMP: version 6.3 (0x11) subver 0x3039 
     [18:56:39.290] [00:00:52.688,313]  <inf> fota: FOTA advertising started 
     [18:56:56.228] [00:01:09.628,165]  <inf> fota: FOTA central connected: 70:4A:16:D9:79:E8 (random) 
     [18:56:56.241] [00:01:09.638,672]  <inf> fota: Central connected; awaiting DFU upload 
     [18:57:13.542] [00:01:26.943,840]  <inf> mcuboot_util: Image index: 0, Swap type: none 
     [18:57:13.842] [00:01:27.243,235]  <inf> mcuboot_util: Image index: 0, Swap type: none 
     [18:57:13.850] [00:01:27.250,437]  <inf> mcuboot_util: Image index: 0, Swap type: none 
     [18:57:13.857] [00:01:27.257,673]  <inf> fota: FOTA image transfer started 
     [18:57:29.159] [00:01:42.561,444]  <inf> fota: FOTA image uploaded and set to pending 
     
     [18:57:29.171] [00:01:42.570,927]  <inf> fota: DFU upload done - starting reboot timer (180 s)
     
     [19:00:29.172] [00:04:42.581,187]  <wrn> fota: ### FOTA REBOOT TIMER CALLBACK FIRED ### 
     [19:00:29.186] [00:04:42.591,321]  <wrn> fota: FOTA reboot event post ret=0 
     [19:00:29.193] [00:04:42.600,439]  <inf> fota: Reboot timeout reached: rebooting system 
     [19:00:29.203] [00:04:42.610,028]  <err> fota: ### FOTA CALLING sys_reboot(SYS_REBOOT_COLD) ### 
     [19:00:29.312] Printk: sys_reboot(1) called by thread 0x20003a68 (main)
     
     *** Booting nRF Connect SDK v3.4.0-99553055607b ***
     [19:00:29.324] *** Using Zephyr OS v4.4.0-bf801e4e3d19 ***
     [19:00:29.329] Fprotect disabled. No protection applied.
     [19:00:29.339] LCS-awareness disabled.
     [19:00:29.339] Attempting to boot slot 0.
     [19:00:29.339] Attempting to boot from address 0x1a800.
     [19:00:29.351] I: Trying to get Firmware version
     [19:00:29.351] I: Firmware signature verified.
     [19:00:29.351] Firmware version 1
     [19:00:29.351] Booting (0x1a800).*** Booting MCUboot v2.3.0-dev-c1d2d128a001 ***
     [19:00:29.359] *** Using nRF Connect SDK v3.4.0-99553055607b ***
     [19:00:29.372] *** Using Zephyr OS v4.4.0-bf801e4e3d19 ***
     [19:00:29.372] I: Starting bootloader
     [19:00:29.372] I: LCS-awareness disabled, skipping LCS check
     [19:00:29.372] I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
     [19:00:29.383] I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
     [19:00:29.393] I: Boot source: none
     [19:00:29.393] I: Image index: 0, Swap type: none
     [19:00:29.393] I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
     [19:00:29.402] I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
     [19:00:29.414] I: Boot source: none
     [19:00:29.465] I: Bootloader chainload address offset: 0x3a000
     [19:00:29.465] I: Image version: v1.0.0
     [19:00:29.465] I: Jumping to the first image slot
     [19:00:29.943] *** Booting My Application v1.0.0-c6ab95c1152e ***
     [19:00:29.950] *** Using nRF Connect SDK v3.4.0-99553055607b ***
     [19:00:29.958] *** Using Zephyr OS v4.4.0-bf801e4e3d19 ***
     [19:00:29.958] [00:00:00.058,648]  <inf> mflt: Reset Reason, HWINFO=0x0002 
     [19:00:29.972] [00:00:00.064,741]  <inf> mflt: Reset Cause: Software Reset 
     [19:00:29.972] [00:00:00.070,859]  <inf> mflt: Reset Cause Stored: 0x0008 
     [19:00:29.983] [00:00:00.077,857]  <inf> mflt: GNU Build ID: 0388326b293976881eda5d33398ca0e2b1578581 

    The firmware update works correctly with this approach, and I can also see the expected sys_reboot() logs when the device is intentionally reset. However, the unexpected reset issue still needs to be resolved when the FOTA process is initiated through the normal BLE SMP/MCUmgr workflow.

    I also tested the SMP Server sample with a configured reset timeout, but I encountered the same issue.

    Based on these tests, I would like to identify the root cause and fix the issue on the device side rather than rely on the mobile app to avoid sending the reset command.

    Could you please clarify the following?
    1. MCUmgr reset handling: Is there a recommended way to prevent or defer the reset command issued by the BLE SMP/MCUmgr client until the application is ready to reboot?
    2. Device-side reset control: Is there a recommended configuration or callback mechanism in NCS v3.4.0 to control the reset behavior after an image is uploaded and marked as pending?
    3. Unexpected reset: Since the sys_reboot() instrumentation does not print anything before the unexpected reset, could the reset originate from a lower-level component or another reset mechanism rather than an explicit application call to sys_reboot()?
    4. Recommended fix: Is there a known issue or recommended implementation for controlling the reset sequence in BLE FOTA using MCUmgr and MCUboot on the nRF54L15?

    My requirement is to complete the BLE firmware upload, wait for the application-defined delay, and then reboot the device in a controlled manner so that MCUboot can perform the firmware upgrade.

    Any suggestions on how to identify the root cause and implement the appropriate device-side fix would be appreciated.


    Best regards,
    Mathiyazhagan S.

  • Hi,

    Thanks for testing. The fact that you only see the unexpected reset when the client is sending the reset command helps us narrow down the problem, but it still doesn't explain the behaviour you are observing. I think to understand what is going on I would need to debug this on my end using your mcumgr hook. Can you share the modifications you made to the smp srv sample? I would also need any patches you have made to source files in the SDK tree.

    1.What determines if the application is ready to reboot? If you only need a fixed delay, you could simply set CONFIG_MCUMGR_GRP_OS_RESET_MS to the value you want (e.g. 2 minutes). And if the application becomes ready sooner, it could call sys_reboot() itself before the delay expires.

    2. 3. No

    4. This is application specific. See my suggestion in point 1.

  • Reply
    • Hi,

      Thanks for testing. The fact that you only see the unexpected reset when the client is sending the reset command helps us narrow down the problem, but it still doesn't explain the behaviour you are observing. I think to understand what is going on I would need to debug this on my end using your mcumgr hook. Can you share the modifications you made to the smp srv sample? I would also need any patches you have made to source files in the SDK tree.

      1.What determines if the application is ready to reboot? If you only need a fixed delay, you could simply set CONFIG_MCUMGR_GRP_OS_RESET_MS to the value you want (e.g. 2 minutes). And if the application becomes ready sooner, it could call sys_reboot() itself before the delay expires.

      2. 3. No

      4. This is application specific. See my suggestion in point 1.

    Children
    • Hi,

      Thank you for your response and suggestions.

      As requested, I will share the modifications I made to the SMP Server sample and the application code related to MCUmgr reset handling.

      sysbuild.conf:

      # Enable two-stage boot chain
      SB_CONFIG_SECURE_BOOT_APPCORE=y
      SB_CONFIG_BOOTLOADER_MCUBOOT=y
      
      # ED25519 keys for nRF54L15
      SB_CONFIG_SECURE_BOOT_SIGNATURE_TYPE_ED25519=y
      SB_CONFIG_BOOT_SIGNATURE_TYPE_ED25519=y
      
      # Store MCUboot verification key in KMU instead of compiling it into MCUboot
      SB_CONFIG_MCUBOOT_SIGNATURE_USING_KMU=y
      
      # Point to your private keys (use absolute paths)
      SB_CONFIG_SECURE_BOOT_SIGNING_KEY_FILE="\${APP_DIR}/keys/nsib_private_key.pem"
      SB_CONFIG_BOOT_SIGNATURE_KEY_FILE="\${APP_DIR}/keys/mcuboot_private_key.pem"
      
      # Auto-generate KMU keyfile for provisioning during west flash
      SB_CONFIG_MCUBOOT_GENERATE_DEFAULT_KEY_FILE=y
      SB_CONFIG_SECURE_BOOT_GENERATE_DEFAULT_KMU_KEYFILE=y
      
      
      #Tells MCUboot how many images to manage
      SB_CONFIG_MCUBOOT_UPDATEABLE_IMAGES=1

      prj.conf: (minimal)

      # Enable BLE SMP FOTA
      CONFIG_BT=y
      CONFIG_BT_PERIPHERAL=y
      
      CONFIG_BT=y
      CONFIG_BT_PERIPHERAL=y
      CONFIG_BT_DEVICE_NAME="nRF54L15 FOTA"
      CONFIG_NCS_SAMPLE_MCUMGR_BT_OTA_DFU=y
      CONFIG_MCUMGR_GRP_OS_RESET_HOOK=y
      
      # Enable MCUmgr callback/notification system
      CONFIG_MCUMGR_MGMT_NOTIFICATION_HOOKS=y

      main.c:

      /*
       * Copyright (c) 2012-2014 Wind River Systems, Inc.
       * Copyright (c) 2020 Prevas A/S
       *
       * SPDX-License-Identifier: Apache-2.0
       */
      
      #include <zephyr/kernel.h>
      #include <zephyr/stats/stats.h>
      #include <zephyr/usb/usb_device.h>
      
      #ifdef CONFIG_MCUMGR_GRP_FS
      #include <zephyr/device.h>
      #include <zephyr/fs/fs.h>
      #include <zephyr/fs/littlefs.h>
      #endif
      #ifdef CONFIG_MCUMGR_GRP_STAT
      #include <zephyr/mgmt/mcumgr/grp/stat_mgmt/stat_mgmt.h>
      #endif
      #ifdef CONFIG_MCUMGR_TRANSPORT_UDP_DTLS
      #include <zephyr/mgmt/mcumgr/transport/smp_udp.h>
      #endif
      
      #define LOG_LEVEL LOG_LEVEL_DBG
      #include <zephyr/logging/log.h>
      LOG_MODULE_REGISTER(smp_sample);
      
      #include "common.h"
      
      #define STORAGE_PARTITION_LABEL	storage_partition
      #define STORAGE_PARTITION_ID	PARTITION_ID(STORAGE_PARTITION_LABEL)
      
      /* Define an example stats group; approximates seconds since boot. */
      STATS_SECT_START(smp_svr_stats)
      STATS_SECT_ENTRY(ticks)
      STATS_SECT_END;
      
      /* Assign a name to the `ticks` stat. */
      STATS_NAME_START(smp_svr_stats)
      STATS_NAME(smp_svr_stats, ticks)
      STATS_NAME_END(smp_svr_stats);
      
      /* Define an instance of the stats group. */
      STATS_SECT_DECL(smp_svr_stats) smp_svr_stats;
      
      #ifdef CONFIG_MCUMGR_GRP_FS
      FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(cstorage);
      static struct fs_mount_t littlefs_mnt = {
      	.type = FS_LITTLEFS,
      	.fs_data = &cstorage,
      	.storage_dev = (void *)STORAGE_PARTITION_ID,
      	.mnt_point = "/lfs1"
      };
      #endif
      
      #include <zephyr/kernel.h>
      #include <zephyr/sys/reboot.h>
      #include <zephyr/mgmt/mcumgr/mgmt/mgmt.h>
      #include <zephyr/mgmt/mcumgr/mgmt/callbacks.h>
      
      /* Define your custom reset delay in milliseconds */
      #define FOTA_RESET_DELAY_MS 120000
      
      static struct mgmt_callback reset_callback;
      static struct k_timer fota_reset_timer;
      
      /* Timer expiry function — performs the actual system reboot */
      static void fota_reset_timer_handler(struct k_timer *timer)
      {
          LOG_WRN("Reboot after 120s");
          sys_reboot(SYS_REBOOT_WARM);
      }
      
      /* MCUmgr callback — called when SMP reset command is received */
      static enum mgmt_cb_return fota_reset_cb(uint32_t event,
                                                enum mgmt_cb_return prev_status,
                                                int32_t *rc,
                                                uint16_t *group,
                                                bool *abort_more,
                                                void *data,
                                                size_t data_size)
      {
          if (event == MGMT_EVT_OP_OS_MGMT_RESET) {
              /* Start the custom delay timer */
              k_timer_start(&fota_reset_timer,
                            K_MSEC(FOTA_RESET_DELAY_MS),
                            K_NO_WAIT);
                            
      	LOG_WRN("Mobile Reset Command Rejected - waiting for (%d)S for Reboot", (FOTA_RESET_DELAY_MS/1000));
      
              /* Return EBUSY to prevent MCUmgr from resetting immediately.
               * The timer handler will perform the reset after the delay. */
              *rc = MGMT_ERR_EBUSY;
              return MGMT_CB_ERROR_RC;
          }
      
          return MGMT_CB_OK;
      }
      
      int main(void)
      {
          /* Initialize the reset delay timer */
          k_timer_init(&fota_reset_timer, fota_reset_timer_handler, NULL);
      
          /* Register the MCUmgr OS reset callback */
          reset_callback.callback = fota_reset_cb;
          reset_callback.event_id = MGMT_EVT_OP_OS_MGMT_RESET;
          mgmt_callback_register(&reset_callback);
      	LOG_ERR("RESET Callback init done for fota");
          
      	int rc = STATS_INIT_AND_REG(smp_svr_stats, STATS_SIZE_32,
      				    "smp_svr_stats");
      
      	if (rc < 0) {
      		LOG_ERR("Error initializing stats system [%d]", rc);
      	}
      
      	/* Register the built-in mcumgr command handlers. */
      #ifdef CONFIG_MCUMGR_GRP_FS
      	rc = fs_mount(&littlefs_mnt);
      	if (rc < 0) {
      		LOG_ERR("Error mounting littlefs [%d]", rc);
      	}
      #endif
      
      #ifdef CONFIG_MCUMGR_TRANSPORT_UDP_DTLS
      	rc = setup_udp_dtls();
      
      	if (rc == 0) {
      		rc = smp_udp_open();
      
      		if (rc != 0) {
      			LOG_ERR("UDP transport open failed: %d", rc);
      		}
      	} else {
      		LOG_ERR("TLS init failed, cannot start UDP transport");
      	}
      #endif
      
      #ifdef CONFIG_MCUMGR_TRANSPORT_BT
      	start_smp_bluetooth_adverts();
      #endif
      
      	/* using __TIME__ ensure that a new binary will be built on every
      	 * compile which is convenient when testing firmware upgrade.
      	 */
      	LOG_INF("build time: " __DATE__ " " __TIME__);
      
      	/* The system work queue handles all incoming mcumgr requests.  Let the
      	 * main thread idle while the mcumgr server runs.
      	 */
      	while (1) {
      		k_sleep(K_MSEC(1000));
      		STATS_INC(smp_svr_stats, ticks);
      	}
      	return 0;
      }

      partition.dtsi

      &cpuapp_rram {
          partitions {
              /* No compatible on the container — goes on each partition node */
              #address-cells = <1>;
              #size-cells = <1>;
      
              b0_partition: partition@0 {
                  compatible = "zephyr,mapped-partition";
                  label = "b0";
                  reg = <0x0 0xC000>;             /* 48 KB */
              };
      
              provision_partition: partition@C000 {
                  compatible = "zephyr,mapped-partition";
                  label = "provision";
                  reg = <0xC000 0x4000>;          /* 16 KB */
              };
      
              s0_partition: boot_partition: partition@1A000 {
                  compatible = "zephyr,mapped-partition";
                  label = "mcuboot";
                  reg = <0x1A000 0x10000>;        /* 64 KB */
              };
      
              s1_partition: partition@2A000 {
                  compatible = "zephyr,mapped-partition";
                  label = "s1";
                  reg = <0x2A000 0x10000>;        /* 64 KB */
              };
      
              slot0_partition: partition@3A000 {
                  compatible = "zephyr,mapped-partition";
                  label = "image-0";
                  reg = <0x3A000 0x80000>;        /* 512 KB */
              };
      
              slot1_partition: partition@BA000 {
                  compatible = "zephyr,mapped-partition";
                  label = "image-1";
                  reg = <0xBA000 0x80000>;        /* 512 KB */
              };
      
              storage_partition: partition@13A000 {
                  compatible = "zephyr,mapped-partition";
                  label = "storage";
                  reg = <0x13A000 0x10000>;       /* 64 KB */
              };
          };
      };

      However, during the unexpected reset, the logs added to sys_reboot() are not printed. The same issue was also observed when testing the SMP Server sample with a configured reset timeout.

       [21:58:33.788] Fprotect disabled. No protection applied.
       [21:58:33.788] LCS-awareness disabled.
       [21:58:33.788] Attempting to boot slot 0.
       [21:58:33.788] Attempting to boot from address 0x1a800.
       [21:58:33.788] I: Trying to get Firmware version
       [21:58:33.788] I: Firmware signature verified.
       [21:58:33.788] Firmware version 1
       [21:58:33.788] I: Setting monotonic counter (version: 1, slot: 0)
       [21:58:33.788] Booting (0x1a800).*** Booting MCUboot v2.3.0-dev-c1d2d128a001 ***
       [21:58:33.788] *** Using nRF Connect SDK v3.4.0-99553055607b ***
       [21:58:33.788] *** Using Zephyr OS v4.4.0-bf801e4e3d19 ***
       [21:58:33.788] I: Starting bootloader
       [21:58:33.788] I: LCS-awareness disabled, skipping LCS check
       [21:58:33.820] I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
       [21:58:33.820] I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
       [21:58:33.820] I: Boot source: none
       [21:58:33.820] I: Image index: 0, Swap type: none
       [21:58:33.820] I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
       [21:58:33.820] I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
       [21:58:33.820] I: Boot source: none
       [21:58:33.848] I: Image index: 1, Swap type: none
       [21:58:33.863] I: Bootloader chainload address offset: 0x3a000
       [21:58:33.863] I: Image version: v1.5.8
       [21:58:33.863] I: Jumping to the first image slot
       [21:58:34.312] *** Booting My Application v1.5.8-56ead9088de1 ***
       [21:58:34.320] *** Using nRF Connect SDK v3.4.0-99553055607b ***
       [21:58:34.341] *** Using Zephyr OS v4.4.0-bf801e4e3d19 ***
       [21:58:34.341] [00:00:00.027,706]  <err> smp_sample: RESET Callback init done for fota 
       [21:58:34.341] [00:00:00.035,002]  <inf> bt_sdc_hci_driver: SoftDevice Controller build revision: 
       [21:58:34.341]                                             c8 da 30 98 f9 f0 34 a4  4b 6e ba d3 08 19 cc 0c |..0...4. Kn......
       [21:58:34.381]                                             ea 51 da 47                                      |.Q.G              
       [21:58:34.381] [00:00:00.063,889]  <inf> bt_hci_core: HW Platform: Nordic Semiconductor (0x0002) 
       [21:58:34.381] [00:00:00.071,657]  <inf> bt_hci_core: HW Variant: nRF54Lx (0x0005) 
       [21:58:34.381] [00:00:00.078,269]  <inf> bt_hci_core: Firmware: Standard Bluetooth controller (0x00) Version 200.12506 Build 888207768 
       [21:58:34.424] [00:00:00.089,804]  <inf> bt_hci_core: HCI transport: SDC 
       [21:58:34.424] [00:00:00.095,514]  <inf> bt_hci_core: Identity: C6:1D:FC:E3:C6:49 (random) 
       [21:58:34.424] [00:00:00.102,810]  <inf> bt_hci_core: HCI: version 6.3 (0x11) revision 0x3039, manufacturer 0x0059 
       [21:58:34.424] [00:00:00.112,194]  <inf> bt_hci_core: LMP: version 6.3 (0x11) subver 0x3039 
       [21:58:34.424] [00:00:00.120,080]  <inf> smp_bt_sample: Advertising successfully started 
       [21:58:34.474] [00:00:00.127,162]  <inf> smp_sample: build time: Oct 16 2026 21:52:15 
       [21:58:34.474] 
       [21:58:34.474] uart:~$ [00:00:19.984,380]  <inf> smp_bt_sample: Connected 
       [21:58:54.290] [00:00:19.984,380]  <inf> smp_bt_sample: Connected 
       
       [21:58:54.317] uart:~$ [00:01:34.267,048] <wrn> smp_sample: Mobile Reset Command Rejected - waiting for (120)S for Reboot 
       [22:00:08.578] [00:01:34.267,048] <wrn> smp_sample: Mobile Reset Command Rejected - waiting for (120)S for Reboot 
       
       [22:00:08.591] uart:~$ [00:01:34.392,263]  <inf> smp_bt_sample: Disconnected, reason 0x00  
       [22:00:08.698] [00:01:34.392,263]  <inf> smp_bt_sample: Disconnected, reason 0x00  
       [22:00:08.711] uart:~$ [00:01:34.407,626]  <err> smp_bt_sample: Advertising failed to start (rc -11) 
       [22:00:08.729] [00:01:34.407,626]  <err> smp_bt_sample: Advertising failed to start (rc -11) 
       
       Fprotect disabled. No protection applied.
       [22:00:34.324] LCS-awareness disabled.
       [22:00:34.324] Attempting to boot slot 0.
       [22:00:34.324] Attempting to boot from address 0x1a800.
       [22:00:34.368] I: Trying to get Firmware version
       [22:00:34.368] I: Firmware signature verified.
       [22:00:34.368] Firmware version 1
       [22:00:34.368] Booting (0x1a800).*** Booting MCUboot v2.3.0-dev-c1d2d128a001 ***
       [22:00:34.368] *** Using nRF Connect SDK v3.4.0-99553055607b ***
       [22:00:34.368] *** Using Zephyr OS v4.4.0-bf801e4e3d19 ***
       [22:00:34.368] I: Starting bootloader
       [22:00:34.368] I: LCS-awareness disabled, skipping LCS check
       [22:00:34.368] I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
       [22:00:34.368] I: Secondary image: magic=good, swap_type=0x2, copy_done=0x3, image_ok=0x3
       [22:00:34.441] I: Boot source: none
       [22:00:34.441] I: Image index: 0, Swap type: test
       [22:00:34.441] I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
       [22:00:34.441] I: Secondary image: magic=good, swap_type=0x2, copy_done=0x3, image_ok=0x3
       [22:00:34.441] I: Boot source: none
       [22:00:34.441] I: Starting swap using move algorithm.
       [22:00:35.381] I: Bootloader chainload address offset: 0x3a000
       [22:00:35.408] I: Image version: v1.5.8
       [22:00:35.408] I: Jumping to the first image slot
      

      Please let me know if you need any additional configuration files, logs, or build details.

      Best regards,
      Mathiyazhagan S.

    Related