You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MCUboot复位后丢失Slot1待更新镜像,提示镜像无效求助

MCUboot secondary slot镜像复位后无效问题排查

我尝试在运行时下载并烧录MCUboot镜像至外部SPI Flash的secondary slot,烧录、确认、标记升级流程均正常完成。但复位后,MCUboot无法识别secondary slot中的镜像,仍启动primary slot镜像。开启日志后发现错误:mcuboot: Image in the secondary slot is not valid!,不清楚镜像无效的原因。以下为相关日志、配置及代码:

更新日志

[00:00:10.516,021] ␛[0m<dbg> spi_nrfx_spim: spi_context_update_tx: tx buf/len 0x20005177/1␛[0m
[00:00:10.517,211] ␛[0m<dbg> spi_nrfx_spim: spi_context_update_rx: rx buf/len 0x20005177/1␛[0m
[00:00:10.518,432] ␛[0m<dbg> spi_nrfx_spim: spi_context_update_tx: tx buf/len (nil)/0␛[0m
[00:00:10.519,592] ␛[0m<dbg> spi_nrfx_spim: spi_context_update_rx: rx buf/len (nil)/0␛[0m
[00:00:10.520,721] ␛[0m<dbg> spi_nrfx_spim: finish_transaction: Transaction finished with status 0␛[0m
[00:00:10.522,033] ␛[0m<dbg> spi_nrfx_spim: spi_context_buffers_setup: tx_bufs 0x20005140 - rx_bufs (nil) - 1␛[0m
[00:00:10.523,620] ␛[0m<dbg> spi_nrfx_spim: spi_context_buffers_setup: current_tx 0x20005150 (1), current_rx (nil) (0), tx buf/len 0x20005138/1, rx buf/len (nil)/0␛[0m
[00:00:10.525,878] ␛[0m<dbg> spi_nrfx_spim: spi_context_update_tx: tx buf/len (nil)/0␛[0m
[00:00:10.527,038] ␛[0m<dbg> spi_nrfx_spim: finish_transaction: Transaction finished with status 0␛[0m
[00:00:10.528,320] ␛[1;31m<err> mcuboot: Image in the secondary slot is not valid!␛[0m
[00:00:10.583,068] ␛[0m<inf> mcuboot: Bootloader chainload address offset: 0x20000␛[0m
[00:00:10.584,259] ␛[0m<inf> mcuboot: Jumping to the first image slot␛[0m

复位前栈追踪

I: Image index: 0, Swap type: none
D: mcuboot_swap_type: 1
D: writing magic; fa_id=1 off=0xd7ff0 (0xd7ff0)
D: writing swap_info; fa_id=1 off=0xd7fd8 (0xd7fd8), swap_type=0x2 image_num=0x0
D: 
Image info: mcuboot_primary
I: Image index: 0, Swap type: test
I: MCUboot swap type: 2
I: Image Version 0.3.0-0
I: Image is confirmed OK
D: 
Image info: mcuboot_secondary
I: Image index: 0, Swap type: test
I: MCUboot swap type: 2
I: Image Version 0.3.1-0
I: Image is confirmed OK

复位后栈追踪

*** Booting nRF Connect SDK v2.5.2 ***
I: Reset Reason 2, Flags:
W: RESET_SOFTWARE
D: 
Image info: mcuboot_primary
I: Image index: 0, Swap type: none
I: MCUboot swap type: 1
I: Image Version 0.3.0-0
I: Image is confirmed OK
D: 
Image info: mcuboot_secondary
I: Image index: 0, Swap type: none
I: MCUboot swap type: 1
I: Image Version 76.146.8194-224105
I: Image is confirmed OK

mcuboot.conf配置

# Core should be on a clean state when TF-M starts
CONFIG_MCUBOOT_CLEANUP_ARM_CORE=y

# Enable echo command
CONFIG_BOOT_MGMT_ECHO=y

# Increase MCUboot image sectors and set static partition size
CONFIG_BOOT_MAX_IMG_SECTORS=256
CONFIG_PM_PARTITION_SIZE_MCUBOOT=0x20000

# Enable flash operations
CONFIG_FLASH=y

# Enable serial recovery
CONFIG_MCUBOOT_SERIAL=y
CONFIG_BOOT_SERIAL_UART=y
CONFIG_MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD=y
CONFIG_BOOT_SERIAL_WAIT_FOR_DFU=y
CONFIG_BOOT_SERIAL_WAIT_FOR_DFU_TIMEOUT=1000
CONFIG_BOOT_SERIAL_IMG_GRP_IMAGE_STATE=y

# SPI Flash
CONFIG_SPI=y
CONFIG_NVS=y
CONFIG_PM_EXTERNAL_FLASH_BASE=0x0
CONFIG_SPI_NOR=y
CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096
CONFIG_PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY=y
CONFIG_PM_OVERRIDE_EXTERNAL_DRIVER_CHECK=y

# Erase Flash Progressively
CONFIG_BOOT_ERASE_PROGRESSIVELY=y

相关代码

#include "fota.h"

#include <zephyr/device.h>
#include <zephyr/dfu/flash_img.h>
#include <zephyr/dfu/mcuboot.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/stats/stats.h>
#include <zephyr/storage/flash_map.h>

#include "custom_http_client.h"
#include "pm_config.h"

LOG_MODULE_REGISTER(fota, LOG_LEVEL_DBG);

#define STRINGIZE(arg) #arg
#define STRINGIZE_VALUE(arg) STRINGIZE(arg)
#define PM_MCUBOOT_PRIMARY_STRING STRINGIZE_VALUE(PM_MCUBOOT_PRIMARY_NAME)
#define PM_MCUBOOT_SECONDARY_STRING STRINGIZE_VALUE(PM_MCUBOOT_SECONDARY_NAME)

BUILD_ASSERT(
    FIXED_PARTITION_EXISTS(PM_MCUBOOT_SECONDARY_NAME),
    "Missing " PM_MCUBOOT_SECONDARY_STRING
    " fixed partition. Secondary slot partition is required!"
);

struct flash_img_context ctx;

void image_info(uint8_t area_id) {
  int rc;
  char buf[BOOT_IMG_VER_STRLEN_MAX];
  struct mcuboot_img_header header;

  boot_read_bank_header(area_id, &header, sizeof(header));
  snprintk(
      buf, sizeof(buf), "%d.%d.%d-%d", header.h.v1.sem_ver.major,
      header.h.v1.sem_ver.minor, header.h.v1.sem_ver.revision,
      header.h.v1.sem_ver.build_num
  );
  LOG_INF("MCUboot swap type: %d", mcuboot_swap_type());
  LOG_INF("Image Version %s", buf);
  rc = boot_is_img_confirmed();
  LOG_INF("Image is%s confirmed OK", rc ? "" : " not");
}

int write_buffer_to_flash(char *data, size_t len, _Bool flush) {
  int rc;
  if (flush) {
    rc = flash_img_buffered_write(&ctx, data, len, true);
  } else {
    rc = flash_img_buffered_write(&ctx, data, len, false);
  }

  LOG_DBG("Flash img bytes written: %d", flash_img_bytes_written(&ctx));

  return rc;
}

void download_update(void) {
  int rc;

  char headers_buf[1024];
  char write_buf[CONFIG_IMG_BLOCK_BUF_SIZE];

  rc = flash_img_init_id(&ctx, PM_MCUBOOT_SECONDARY_ID);
  if (rc < 0) {
    LOG_ERR("Failed to init stream flash");
  }

  (void)http_get_firmware(
      write_buf, sizeof(write_buf), headers_buf, sizeof(headers_buf)
  );

  LOG_DBG("mcuboot_swap_type: %d", mcuboot_swap_type());

  rc = boot_request_upgrade(BOOT_UPGRADE_TEST);
  if (rc < 0) {
    LOG_ERR("Failed to REQUEST FIRMWARE UPGRADE");
  }

  LOG_DBG("\nImage info: " PM_MCUBOOT_PRIMARY_STRING);
  (void)image_info(PM_MCUBOOT_PRIMARY_ID);

  LOG_DBG("\nImage info: " PM_MCUBOOT_SECONDARY_STRING);
  (void)image_info(PM_MCUBOOT_SECONDARY_ID);
}

问题分析与解决方案

核心异常点

从复位前后的栈追踪对比可见:

  • 复位前secondary slot的镜像版本为0.3.1-0,复位后变为乱码76.146.8194-224105,说明SPI Flash中的镜像数据或元数据在复位后被破坏/读取错误,直接导致MCUboot判定镜像无效。

可能原因及排查方向

  1. SPI Flash页大小配置不匹配

    • 配置中CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096,需确认外部SPI Flash的实际页大小是否为4096字节。若实际为256/512字节,会导致写入时的页操作错误,复位后读取到错误数据。
    • 同时需确保CONFIG_IMG_BLOCK_BUF_SIZE是SPI Flash页大小的整数倍,避免缓冲写入时的对齐错误。
  2. 镜像未完全写入Flash

    • 代码中http_get_firmware下载完成后,未调用flash_img_buffered_write的flush操作(最后一次写入需传入true强制刷新缓冲)。若最后一块数据留在缓冲中未写入Flash,复位后secondary slot镜像不完整,校验失败。
    • 修复:在http_get_firmware执行完成后添加flash_img_buffered_write(&ctx, NULL, 0, true);,确保所有数据刷入Flash。
  3. MCUboot元数据存储位置错误

    • 复位前日志显示writing magic; fa_id=1 off=0xd7ff0,需确认fa_id=1是否对应外部SPI Flash的分区ID。若元数据写入内部Flash,复位后无法正确关联外部Flash的secondary slot,导致镜像识别失败。
    • 检查是否启用CONFIG_MCUBOOT_EXTERNAL_FLASH_METADATA(若适用),确保元数据存储在外部Flash的对应区域。
  4. 镜像签名校验失败

    • 若镜像启用了签名校验,需确认CONFIG_MCUBOOT_SIGNATURE_KEY_FILE配置正确,且下载的镜像使用对应密钥签名。签名验证失败时,MCUboot会直接判定镜像无效。
    • 可临时关闭CONFIG_MCUBOOT_SIGNATURE(仅用于排查),验证是否因签名问题导致镜像无效。
  5. SPI Flash复位后初始化异常

    • 复位前SPI操作日志显示状态均为0(成功),但复位后读取异常,可能是SPI Flash复位后初始化不完整(如片选信号、时钟配置未恢复)。
    • 检查系统复位后的SPI驱动初始化流程,确保外部Flash能被正确重新识别。

内容的提问来源于stack exchange,提问作者Voxorin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 11:10:54