Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學
您现在的位置: Windows教程網 >> Windows教程 >  >> Linux 系統教學 >> Linux 教學

STM32 IAP (In-Application Programming) 就地升級完整實作指南

編輯:Linux 教學

什麼是 IAP?

IAP (In-Application Programming):應用程式運行期間,透過外部介面 (UART/USB/CAN/Ethernet/Wireless) 接收新固件,**自行寫入內部 Flash**、**驗證**、**跳轉執行**,**無需外部程式器、無需硬體跳線、無需進入 ISP 模式**。

區別:

  • ICP (In-Circuit Programming):JTAG/SWD 程式器離線燒寫。
  • ISP (In-System Programming):內建 Bootloader (System Memory) 引導燒寫,需 BOOT0=1 進入特定模式。
  • IAP:用戶程式自帶升級邏輯,**產品量產後仍可遠程/現場升級**,核心競爭力。

STM32 實現 IAP 的核心前提

  1. 內部 Flash 可重複擦寫 (所有 STM32 滿足)。
  2. Cortex-M3/M4/M7 核心支援向量表偏移 (SCB->VTOR)。
  3. 豐富通訊外設 (UART/USB/CAN/ETH/SDIO) 做傳輸通道。

記憶體佈局規劃 (關鍵)

0x0800 0000 ┌────────────────────────┐
            │  IAP Bootloader (16~64KB)│  起始 0x0800 0000
            │  - 初始化外設            │
            │  - 檢測升級條件 (按鍵/標誌) │
            │  - 接收固件寫入 App 區    │
            │  - 校驗 + 跳轉 App        │
0x0800 4000 ├────────────────────────┤  ← APP_START_ADDR (例 0x0800 4000, 16KB 對齊)
            │  User Application       │
            │  - 向量表在 0x0800 4000  │
            │  - 主程式邏輯            │
            │  - 可再含 IAP 客戶端邏輯  │
0x080F FFFF └────────────────────────┘  (視 Flash 大小)

兩大鐵律:

  1. App 起始位址必須對齊頁/扇區邊界 (通常 4KB/16KB/64KB),便於 IAP 整頁擦除寫入。
  2. App 必須重定向向量表:SCB->VTOR = APP_START_ADDR,否則中斷會跑到 IAP 區導致崩潰。

IAP 流程時序圖

上電復位
   │
   ▼
┌─────────────────┐
│ IAP Bootloader  │
│ 初始化 UART/USB │
│ 檢測升級標誌/按鍵│
└────────┬────────┘
         │
    ┌────┴────┐
    ▼         ▼
  升級      無升級/超時
    │         │
    ▼         ▼
┌────────┐ ┌──────────────────┐
│ 接收固件│ │ 跳轉至 App       │
│ 寫入Flash│ │ SCB->VTOR=APP    │
│ 校驗CRC │ │ 跳轉 ResetHandler│
└────┬───┘ └────────┬─────────┘
     │              │
     ▼              ▼
  重新復位 ──────► 運行 App
     (或軟體跳轉)      │
                     ▼
              ┌──────────────┐
              │ App 主循環   │
              │ 可觸發 IAP   │
              │ 請求復位升級 │
              └──────────────┘

關鍵程式碼實作 (基於 STM32F1/F4 HAL 庫)

1. 連結腳本修改 — 定義 IAP 與 App 區域

STM32F103_IAP.ld (或 KEIL Target 選項 IROM1 Start=0x08000000 Size=0x4000 (IAP), IROM2 Start=0x08004000 Size=0x3C000 (App))

2. IAP Bootloader 主流程

#define APP_START_ADDR  0x08004000
#define APP_MAX_SIZE    (256*1024 - 0x4000)  // 256KB Flash - 16KB IAP

typedef void (*pFunction)(void);

int main(void) {
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_USART1_UART_Init();  // 或 USB/CAN
    
    // 檢測升級條件:按鍵按下 或 特定標誌位
    if (HAL_GPIO_ReadPin(KEY_GPIO_PORT, KEY_PIN) == GPIO_PIN_RESET 
        || checkUpgradeFlag()) {
        clearUpgradeFlag();
        iapProcess();  // 進入升級流程
    }
    
    // 無升級需求,跳轉 App
    jumpToApp();
    while(1); // 不會返回
}

void jumpToApp(void) {
    // 1. 檢查 App 區向量表合法性 (堆疊指標在 SRAM 範圍內)
    uint32_t app_sp = *(__IO uint32_t*)APP_START_ADDR;
    if ((app_sp & 0x2FFE0000) != 0x20000000) return; // 非法,停在 IAP
    
    // 2. 關閉所有中斷、外設、SysTick
    __disable_irq();
    HAL_RCC_DeInit();
    SysTick->CTRL = 0;
    SysTick->LOAD = 0;
    SysTick->VAL = 0;
    
    // 3. 設定 MSP 並跳轉
    __set_MSP(app_sp);
    pFunction app_reset = (pFunction)*( (__IO uint32_t*)(APP_START_ADDR + 4) );
    app_reset();
}

3. 固件接收與寫入 (以 UART XMODEM/YMODEM 為例)

void iapProcess(void) {
    uint32_t flash_addr = APP_START_ADDR;
    uint8_t buffer[1024];
    uint16_t len;
    uint32_t total = 0;
    
    // 擦除 App 區所有扇區
    FLASH_EraseAppArea(APP_START_ADDR, APP_MAX_SIZE);
    
    // 循環接收數據包 (簡化版,實際需 XMODEM 協議)
    while (1) {
        len = uartReceivePacket(buffer, sizeof(buffer), 5000); // 5s 超時
        if (len == 0) break; // 超時或傳輸結束
        
        if (verifyPacket(buffer, len)) {
            // 寫入 Flash
            if (FLASH_Write(flash_addr, buffer, len) != HAL_OK) {
                sendNAK(); break;
            }
            flash_addr += len;
            total += len;
            sendACK();
        } else {
            sendNAK();
        }
    }
    
    if (total > 0 && verifyAppCRC(APP_START_ADDR, total)) {
        setUpgradeSuccessFlag(); // 標誌升級成功
        NVIC_SystemReset();      // 復位跳轉 App
    }
}

4. App 端向量表重定向 (必須在 SystemInit() 之後、main() 之前)

// system_stm32f1xx.c 或啟動檔中
void SystemInit(void) {
    // ... 原有時鐘初始化 ...
    
    // IAP App 向量表偏移
    #ifdef VECT_TAB_OFFSET
    SCB->VTOR = VECT_TAB_OFFSET;  // 定義為 0x08004000
    #endif
}

KEIL 中:Options for Target → Target → IROM1 Start: 0x08004000,並在啟動檔 startup_stm32f10x.s 或 system_stm32f1xx.c 設定 VECT_TAB_OFFSET。

5. App 中觸發 IAP 升級 (軟體復位進入 Bootloader)

void requestIAPUpgrade(void) {
    setUpgradeFlag();           // 寫入備份寄存器或 Flash 標誌位
    NVIC_SystemReset();         // 系統復位,IAP 檢測標誌進入升級
}

// 備份寄存器標誌 (RTC 備份域,掉電保持)
#define UPGRADE_FLAG_REG  BKP_DR1
#define UPGRADE_FLAG_VAL  0xA5A5

void setUpgradeFlag(void) {
    HAL_PWR_EnableBkUpAccess();
    HAL_RTCEx_BKUPWrite(&hrtc, UPGRADE_FLAG_REG, UPGRADE_FLAG_VAL);
}

uint8_t checkUpgradeFlag(void) {
    return (HAL_RTCEx_BKUPRead(&hrtc, UPGRADE_FLAG_REG) == UPGRADE_FLAG_VAL);
}

進階可靠性設計

風險對策
傳輸中斷導致 App 損壞**雙 Bank / 備份區** (F4/F7/H7 支援) 或 **A/B 區雙映像**:IAP 寫入備用區,校驗通過再切換啟動位址或交換 Bank。
固件被竄改/偽造**簽名驗證**:RSA/ECDSA 簽名 + 公鑰內建;**加密傳輸**:AES-GCM。
升級過程掉電**斷點續傳**:記錄已寫入位址;**原子性切換**:雙映像 + 狀態機。
版本回滾攻擊**版本號單調遞增**,拒絕舊版本;**防重放**:Nonce/時間戳。
通訊介面被佔用**多通道備援**:UART + USB + CAN 同時監聽。

工具鏈配置要點 (KEIL MDK)

  1. IAP 專案:IROM1 Start=0x08000000, Size=0x4000 (16KB)。
  2. App 專案:IROM1 Start=0x08004000, Size=0x3C000 (剩餘空間)。
  3. App 專案 Options for Target → Linker → Scatter File 使用相同散佈檔或手動設定起始位址。
  4. 兩專案共用 startup_stm32f10x.s,App 專案啟用 VECT_TAB_OFFSET 宏定義。

結語

STM32 IAP 核心在於:**記憶體劃分合理、向量表正確重定向、Flash 擦寫可靠、通訊協議健壯、雙映像/簽名保障安全**。掌握此技術,能讓產品擁有「終身進化」能力,從容應對現場 Bug 修復、功能迭代、安全補丁,是嵌入式工程師從「寫驅動」邁向「架構產品」的關鍵里程碑。

Copyright © Windows教程網 All Rights Reserved