前言本篇记录我第一次使用mcuboot的记录。这里只是快速的使用起来很多细节还没有理解到位请酌情参考。本次使用到的工具为Clion,结合AI工具来帮助理解。本次使用的开发板为正点原子探索者主控STM32F407ZGT6,其他的也支持。本次使用的烧录器为Jlink。使用Clion打开Zephyr的项目工程找到mcuboot提供的zephyr项目工程加载项目工程选择我们需要的开发板我这里选择的是官方提供的如果没有的话需要自己去适配在boards目录下添加我们自己开发板的信息这里可以参考已有的文件进行编写。stm32f4_disco.overlay的编写/{chosen{zephyr,consoleusart1;zephyr,shellusart1;zephyr,code-partitionboot_partition;};aliases{usart1usart1;};};usart1{pinctrl-0usart1_tx_pa9usart1_rx_pa10;pinctrl-namesdefault;current-speed115200;statusokay;};// 扇区分布 //Sector0:16KB(0x0800_0000 - 0x0800_3FFF)← 最小擦除单位 //Sector1:16KB(0x0800_4000 - 0x0800_7FFF)//Sector2:16KB(0x0800_8000 - 0x0800_BFFF)//Sector3:16KB(0x0800_C000 - 0x0800_FFFF)//Sector4:64KB(0x0801_0000 - 0x0801_FFFF)//Sector5:128KB(0x0802_0000 - 0x0803_FFFF)← Slot0起始 //Sector6:128KB(0x0804_0000 - 0x0805_FFFF)← Slot1起始 //Sector7:128KB(0x0806_0000 - 0x0807_FFFF)← Scratch 起始flash0{statusokay;partitions{compatiblefixed-partitions;#address-cells 1;#size-cells 1;boot_partition: partition0{labelmcuboot;reg0x00000000 DT_SIZE_K(128);read-only;};slot0_partition: partition20000{labelimage-0;reg0x00020000 DT_SIZE_K(128);};slot1_partition: partition40000{labelimage-1;reg0x00040000 DT_SIZE_K(128);};scratch_partition: partition60000{labelimage-scratch;reg0x00060000 DT_SIZE_K(128);};};};stm32f4_disco.conf的编写# 禁用自动计算手动设置最大镜像扇区数根据你的分区大小调整CONFIG_BOOT_MAX_IMG_SECTORS_AUTOnCONFIG_BOOT_MAX_IMG_SECTORS16bootloader工程进行编译注意:如果你的配置文件不生效的话需要通过清除缓存重新编译来解决此问题观察日志输出bootloader工程进行烧录注意我这里使用的jlink烧录需要在烧录时配置一下参数烧录结果控制台输出创建app固件程序打开自己创建的工程或使用示例工程编写对应的配置prj.conf文件编写# nothing hereCONFIG_LOGy# CONFIG_USE_SEGGER_RTTy# CONFIG_SHELLy# CONFIG_SHELL_BACKEND_RTTy# 串口配置CONFIG_SERIALyCONFIG_UART_INTERRUPT_DRIVENy# 开启FLASHCONFIG_SPIyCONFIG_FLASHyCONFIG_FLASH_LOG_LEVEL_INFy# Enable Zephyr application to be booted by MCUbootCONFIG_BOOTLOADER_MCUBOOTy# Use the default MCUBoot PEM key file (BOOT_SIGNATURE_KEY_FILE)CONFIG_MCUBOOT_SIGNATURE_KEY_FILEbootloader/mcuboot/root-rsa-2048.pem设备树覆盖文件编写注意:flash0里面的分区要和bootloader里面的保持一致/{chosen{zephyr,consoleusart1;zephyr,shellusart1;zephyr,code-partitionslot0_partition;};aliases{usart1usart1;w25q128w25q128;};};usart1{pinctrl-0usart1_tx_pa9usart1_rx_pa10;pinctrl-namesdefault;current-speed115200;statusokay;};spi1{statusokay;// clk、mosi、miso pinctrl-0spi1_sck_pb3spi1_miso_pb4spi1_mosi_pb5;pinctrl-namesdefault;cs-gpiosgpiob14GPIO_ACTIVE_LOW;w25q128: w25q1280{compatiblejedec,spi-nor;sizeDT_SIZE_M(128);/*128Mbits */ reg0;spi-max-frequency4000000;statusokay;jedec-id[ef4018];};};flash0{statusokay;partitions{compatiblefixed-partitions;#address-cells 1;#size-cells 1;boot_partition: partition0{labelmcuboot;reg0x00000000 DT_SIZE_K(128);read-only;};slot0_partition: partition20000{labelimage-0;reg0x00020000 DT_SIZE_K(128);};slot1_partition: partition40000{labelimage-1;reg0x00040000 DT_SIZE_K(128);};scratch_partition: partition60000{labelimage-scratch;reg0x00060000 DT_SIZE_K(128);};};};编写测试main函数/* * Copyright (c) 2025 Embeint Inc * * SPDX-License-Identifier: Apache-2.0 */#includezephyr/kernel.h#includezephyr/device.h#includezephyr/net_buf.h#includezephyr/logging/log.h#includezephyr/drivers/flash.h#includestdio.h#includestring.h// SPI测试LOG_MODULE_REGISTER(test,LOG_LEVEL_DBG);#defineSPI_FLASH_TEST_REGION_OFFSET0xff000#defineSPI_FLASH_SECTOR_SIZE4096constuint8_terased[]{0xff,0xff,0xff,0xff};voidsingle_sector_test(conststructdevice*flash_dev){constuint8_texpected[]{0x55,0xaa,0x66,0x99};constsize_tlensizeof(expected);uint8_tbuf[sizeof(expected)];intrc;LOG_DBG(\nPerform test on single sector);/* Write protection needs to be disabled before each write or * erase, since the flash component turns on write protection * automatically after completion of write and erase * operations. */LOG_DBG(\nTest 1: Flash erase\n);/* Full flash erase if SPI_FLASH_TEST_REGION_OFFSET 0 and * SPI_FLASH_SECTOR_SIZE flash size */rcflash_erase(flash_dev,SPI_FLASH_TEST_REGION_OFFSET,SPI_FLASH_SECTOR_SIZE);if(rc!0){LOG_DBG(Flash erase failed! %d\n,rc);}else{/* Check erased pattern */memset(buf,0,len);rcflash_read(flash_dev,SPI_FLASH_TEST_REGION_OFFSET,buf,len);if(rc!0){LOG_DBG(Flash read failed! %d\n,rc);return;}if(memcmp(erased,buf,len)!0){LOG_DBG(Flash erase failed at offset 0x%x got 0x%x\n,SPI_FLASH_TEST_REGION_OFFSET,*(uint32_t*)buf);return;}LOG_DBG(Flash erase succeeded!\n);}LOG_DBG(\nTest 2: Flash write\n);LOG_DBG(Attempting to write %zu bytes\n,len);rcflash_write(flash_dev,SPI_FLASH_TEST_REGION_OFFSET,expected,len);if(rc!0){LOG_DBG(Flash write failed! %d\n,rc);return;}memset(buf,0,len);rcflash_read(flash_dev,SPI_FLASH_TEST_REGION_OFFSET,buf,len);if(rc!0){LOG_DBG(Flash read failed! %d\n,rc);return;}if(memcmp(expected,buf,len)0){LOG_DBG(Data read matches data written. Good!!\n);}else{constuint8_t*wpexpected;constuint8_t*rpbuf;constuint8_t*rperplen;LOG_DBG(Data read does not match data written!!\n);while(rprpe){LOG_DBG(%08x wrote %02x read %02x %s\n,(uint32_t)(SPI_FLASH_TEST_REGION_OFFSET(rp-buf)),*wp,*rp,(*rp*wp)?match:MISMATCH);rp;wp;}}}intmain(void){conststructdevice*flash_devDEVICE_DT_GET(DT_ALIAS(w25q128));if(!device_is_ready(flash_dev)){LOG_ERR(%s: device not ready.\n,flash_dev-name);return0;}LOG_DBG(\n%s SPI flash testing\n,flash_dev-name);LOG_DBG(\n);while(1){LOG_DBG(Testing123...\n);k_sleep(K_MSEC(5000));}//single_sector_test(flash_dev);return0;}编译并烧录(这里通过编译出来的固件就可以直接烧录)控制台运行情况总结mcuboot的使用和集成借助ide工具还是非常的方便。第一次接触mcuboot的时候在网上查找的东西不能很直观的让人快速的使用起来。这里提供一个参考思路。个人观点先跑起来然后慢慢去理解其中的细节。