l

Firmware Updates with Bank Switching on STM32H5

Firmware Updates with Bank Switching on STM32H5

How dual-bank architecture enables seamless, zero-downtime firmware updates via CAN


Firmware updates are crucial for modern embedded systems—enabling remote device maintenance, feature additions, and security patches without physical access.

This article explores a sophisticated implementation on the STM32 microcontroller, specifically the STM32H562, which features a dual-bank flash architecture that enables seamless firmware updates through bank switching.

The implementation is optimized for CAN FD (Controller Area Network with Flexible Data-Rate) communication, providing high-speed data transfer with 64-byte frame payloads.

Key highlights: • Zero-downtime atomic updates • Power-loss safe operation
• Automatic rollback capability

Bank Configuration Constants

// STM32H5 Dual-Bank Flash Configuration
#define BANK1_BASE        0x08000000  // Bank 1 start
#define BANK2_BASE        0x08100000  // Bank 2 start  
#define BANK_SIZE         0x00100000  // 1MB per bank
#define SECTOR_SIZE       0x00002000  // 8KB per sector

// Flash Layout per Bank
#define FIRMWARE_MAX_SIZE (BANK_SIZE - 2 * SECTOR_SIZE)
#define METADATA_OFFSET   (BANK_SIZE - SECTOR_SIZE)

Key Features

Dual-bank architecture with simultaneous read-while-write capability

8KB sector size for fine-grained erase operations

Hardware bank swapping via option bytes

Metadata storage in reserved sectors

This architecture forms the foundation for safe, atomic firmware updates.

Bank Switching Mechanism

The SWAP_BANK Option Byte

The STM32H5's bank switching is controlled by the SWAP_BANK bit (bit 31) in the OPTSR (Option Status Register).

When you toggle this bit and reset the system, the hardware automatically remaps which physical bank appears at logical address 0x08000000.

This is the magic that enables zero-downtime updates!

Normal Mode (SWAP_BANK = 0): • Logical address 0x08000000 → Physical Bank 1 • Logical address 0x08100000 → Physical Bank 2 • System boots from Physical Bank 1

Swapped Mode (SWAP_BANK = 1): • Logical address 0x08000000 → Physical Bank 2 • Logical address 0x08100000 → Physical Bank 1
• System boots from Physical Bank 2

The beauty? Your firmware always runs from 0x08000000, but the hardware handles the mapping!

Bank Switch Implementation

error_t switch_bank(void) {
    // Unlock flash and option bytes
    HAL_FLASH_Unlock();
    HAL_FLASH_OB_Unlock();
    
    uint32_t optsr_cur = FLASH->OPTSR_CUR;
    
    // Toggle SWAP_BANK bit
    if (optsr_cur & FLASH_OPTSR_SWAP_BANK_Msk) {
        CLEAR_BIT(FLASH->OPTSR_PRG, FLASH_OPTSR_SWAP_BANK_Msk);
        printf("Clearing SWAP_BANK bit (Bank 2 -> Bank 1)\n");
    } else {
        SET_BIT(FLASH->OPTSR_PRG, FLASH_OPTSR_SWAP_BANK_Msk);
        printf("Setting SWAP_BANK bit (Bank 1 -> Bank 2)\n");
    }
    
    // Start option byte programming
    SET_BIT(FLASH->OPTCR, FLASH_OPTCR_OPTSTART);
    
    // Wait for completion and launch
    HAL_FLASH_OB_Launch();  // This triggers system reset
    
    HAL_FLASH_OB_Lock();
    HAL_FLASH_Lock();
    
    NVIC_SystemReset();  // Force reset if launch didn't trigger it
    return FU_OK;
}
  1. CM4 Host sends firmware via CAN FD (64-byte frames)
  2. STM32H562 receives and buffers the data
  3. Flash writes are performed in 16-byte aligned chunks
  4. Target bank (inactive bank) stores the new firmware
  5. Validation ensures firmware integrity
  6. Bank switch makes new firmware active

Why this works: • Active bank keeps running during update • No downtime or broken states • Power loss during update? Old firmware still works! • Validation fails? Stay on old firmware

Flash Operations

Sector Erase with Bank Awareness

static error_t flash_erase_sector(uint32_t sector_addr, uint32_t bank_number) {
    // CRITICAL: Determine physical bank based on current SWAP_BANK state
    uint32_t optsr_cur = FLASH->OPTSR_CUR;
    bool swap_bank = (optsr_cur & FLASH_OPTSR_SWAP_BANK_Msk) != 0;
    
    // Map logical bank number to physical bank
    uint32_t physical_bank;
    if (swap_bank) {
        // When swapped: Bank1 logical = Bank2 physical
        physical_bank = (bank_number == 1) ? FLASH_BANK_2 : FLASH_BANK_1;
    } else {
        // Normal mapping
        physical_bank = (bank_number == 1) ? FLASH_BANK_1 : FLASH_BANK_2;
    }
    
    // Calculate sector number within the bank
    uint32_t sector_offset = sector_addr & 0xFFFFF;  // Offset within 1MB bank
    uint32_t sector_num = sector_offset / SECTOR_SIZE;
    
    // Configure and execute erase
    FLASH_EraseInitTypeDef erase_init = {0};
    erase_init.TypeErase = FLASH_TYPEERASE_SECTORS;
    erase_init.Banks = physical_bank;  // Use physical bank!
    erase_init.Sector = sector_num;
    erase_init.NbSectors = 1;
    
    return HAL_FLASHEx_Erase(&erase_init, &sector_error);
}

Why this matters: You must account for the current SWAP_BANK state when erasing sectors, or you'll erase the wrong bank!

Flash Write with STM32H5 Alignment

static error_t flash_write_data(uint32_t address, const uint8_t *data, uint32_t size) {
    // STM32H5 requires 16-byte (128-bit) aligned writes
    if (size % 16 != 0 || address % 16 != 0) {
        return FU_ERROR_PARAM;
    }
    
    HAL_FLASH_Unlock();
    
    // Program flash in 16-byte chunks
    for (uint32_t i = 0; i < size; i += 16) {
        HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD, 
                                                    address + i, 
                                                    (uint32_t)&data[i]);
        if (status != HAL_OK) {
            HAL_FLASH_Lock();
            return FU_ERROR_COMM_FAIL;
        }
        
        // Verify write
        if (memcmp((void*)(address + i), &data[i], 16) != 0) {
            HAL_FLASH_Lock();
            return FU_ERROR_COMM_FAIL;
        }
    }
    
    HAL_FLASH_Lock();
    return FU_OK;
}

STM32H5 requires 16-byte aligned writes. Always pad your data appropriately!

Security Considerations

1. Firmware Validation

Multiple layers of protection:

Magic number verification prevents invalid metadata

CRC32 checksum ensures data integrity

Reset vector validation confirms valid firmware structure

Stack pointer validation prevents stack overflow

Every check must pass before the new firmware is accepted.

2. Atomic Updates

Bank switching ensures atomic firmware replacement

Rollback capability via bank toggle on failure

Power-loss protection through dual-bank architecture

If anything goes wrong during update, the system automatically stays on the working firmware.

3. Communication Security

Target node validation prevents unauthorized updates

Image ID tracking prevents replay attacks

Timeout mechanisms prevent resource exhaustion

Only the intended device accepts the update, protecting against accidental or malicious updates to wrong devices.

Best Practices

DO: ✓ Always check SWAP_BANK state before erasing ✓ Use 16-byte aligned writes ✓ Implement comprehensive validation ✓ Add watchdog protection during long operations ✓ Test power-loss scenarios

DON'T: ✗ Forget to verify writes after programming ✗ Skip CRC validation ✗ Ignore alignment requirements ✗ Update without proper testing ✗ Overlook timeout handling

Conclusion

The STM32H5's dual-bank architecture, combined with CAN FD optimization, provides a robust, production-ready firmware update solution.

Key achievements: • 10x performance improvement • Zero-downtime operation • Power-loss safe • Automatic rollback

This implementation demonstrates how modern microcontrollers can handle complex firmware updates safely and efficiently.

The result? Field-deployed devices that can be updated remotely with confidence, knowing that even if something goes wrong, the system stays operational.

Technical Specifications

Hardware: • STM32H562 (ARM Cortex-M33 @ 250 MHz) • 2MB dual-bank flash • CAN FD capable

Software: • FreeRTOS v10.x • HAL Drivers (STM32CubeH5) • Custom CAN FD protocol

Resources

• STM32H562 Datasheet • STM32H5 Reference Manual • CAN FD Protocol Specification (ISO 11898-1:2015) • Application Note AN4767: On-the-fly firmware update for dual bank STM32 microcontrollers

Read more