STM32自定义IAP Bootloader固件头部添加与有效性校验技术问询
Hey there! Let's walk through how to implement the firmware header and validation logic for your STM32 custom IAP Bootloader, matching your Flash layout (scratch, user app, IAP) and referencing AN4657.
First, create a packed struct to hold all necessary metadata. This will sit at the start of your scratch Flash area. We'll include fields to quickly validate firmware validity and track versioning:
#include <stdint.h> // Packed struct to avoid padding issues on STM32's 32-bit architecture typedef __packed struct { uint32_t magic_word; // Unique identifier (e.g., 0xABCD1234) to flag valid firmware uint32_t version; // Version number (e.g., 0x01020304 = v1.2.3.4) uint32_t firmware_length; // Length of the user application (excluding this header) uint32_t checksum; // CRC32 checksum of the user application data } FirmwareHeader_t;
- Magic Word: Acts as a quick sanity check—if this doesn't match your predefined value, the firmware is immediately invalid.
- Version: Lets you implement version checks (e.g., only upgrade to newer versions).
- Firmware Length: Ensures you don't read beyond valid Flash boundaries during validation.
- Checksum: Guarantees the firmware data hasn't been corrupted during transfer/storage. CRC32 is recommended here because it's fast to compute on embedded hardware.
You'll need to prepend this header to your compiled user application binary before transferring it to the scratch area. The most flexible way is to use a post-compilation script (Python works great for this):
import crcmod # Configuration USER_APP_BIN = "user_app.bin" UPGRADE_BIN = "upgrade_with_header.bin" MAGIC_WORD = 0xABCD1234 FIRMWARE_VERSION = 0x01020304 # Read the raw user application binary with open(USER_APP_BIN, "rb") as f: firmware_data = f.read() # Calculate CRC32 checksum of the firmware data crc32 = crcmod.predefined.mkPredefinedCrcFun('crc-32') calculated_checksum = crc32(firmware_data) # Build the header (STM32 uses little-endian byte order) header = b"" header += MAGIC_WORD.to_bytes(4, byteorder="little") header += FIRMWARE_VERSION.to_bytes(4, byteorder="little") header += len(firmware_data).to_bytes(4, byteorder="little") header += calculated_checksum.to_bytes(4, byteorder="little") # Combine header and firmware into the final upgrade binary with open(UPGRADE_BIN, "wb") as f: f.write(header + firmware_data)
Alternatively, if you control the user application code, you could embed the header as a global const at a fixed address—but this is less flexible for version updates.
Once the upgrade firmware is in the scratch area, your Bootloader needs to run through three validation steps before proceeding with the upgrade:
Step 1: Check the Magic Word
First, verify the magic word to confirm this is a legitimate firmware image:
#include "stm32f4xx_hal.h" #define SCRATCH_FLASH_START 0x08020000 // Adjust to your actual scratch area start address #define USER_APP_MAX_SIZE 0x10000 // Max size of your user application area void validate_and_upgrade(void) { FirmwareHeader_t *fw_header = (FirmwareHeader_t *)SCRATCH_FLASH_START; // Check magic word first if (fw_header->magic_word != 0xABCD1234) { // Invalid firmware—exit upgrade flow return; }
Step 2: Validate Firmware Length
Ensure the firmware doesn't exceed the size of your user application area (prevents writing outside valid Flash):
// Check if firmware length is within valid bounds if (fw_header->firmware_length == 0 || fw_header->firmware_length > USER_APP_MAX_SIZE) { return; }
Step 3: Verify the Checksum
Use STM32's hardware CRC peripheral to compute the checksum of the firmware data and compare it to the header's value:
// Initialize CRC peripheral CRC_HandleTypeDef hcrc; hcrc.Instance = CRC; hcrc.Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_ENABLE; hcrc.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_ENABLE; hcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_NONE; hcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_NONE; hcrc.InputDataFormat = CRC_INPUTDATA_FORMAT_WORDS; if (HAL_CRC_Init(&hcrc) != HAL_OK) { // CRC init failed—exit return; } // Calculate CRC32 of the firmware data (skip the header) uint32_t computed_crc = HAL_CRC_Calculate(&hcrc, (uint32_t*)(SCRATCH_FLASH_START + sizeof(FirmwareHeader_t)), fw_header->firmware_length / 4); // Handle cases where firmware length isn't a multiple of 4 // (add logic to process remaining bytes if needed) // Compare computed CRC to header value if (computed_crc != fw_header->checksum) { HAL_CRC_DeInit(&hcrc); return; } // All checks passed—proceed to copy firmware from scratch to user area HAL_CRC_DeInit(&hcrc); // ... add your Flash erase/write logic here }
- Flash Alignment: STM32 Flash is erased in pages, so ensure your scratch area size aligns with the Flash page size of your MCU.
- Byte Order: Always use little-endian for multi-byte fields (matches STM32's native byte order).
- AN4657 Reference: ST's AN4657 document includes full IAP examples—focus on the Firmware Validation and Firmware Update sections. You can adapt their Flash handling and upgrade logic to fit your custom layout.
内容的提问来源于stack exchange,提问作者SamForiYana

