单片机 IAP(可实现OTA), ISP, ICP

以赛元单片机为例讲解:

IAP(In-Application Programming,在应用中编程) 是一种允许微控制器在运行用户程序的同时,通过软件手段对自身FLASH存储器进行编程(擦除/写入) 的技术。

一、IAP的核心定义

与传统编程方式的对比

编程方式 如何编程 是否需要外部工具 应用场景
ICP (In-Circuit Programming) 通过编程器/调试器 需要专用编程器 工厂量产、初次烧录
ISP (In-System Programming) 通过BootLoader+通信接口 需要上位机软件 板级测试、维修升级
IAP (In-Application Programming) 用户程序自身操作 无需外部工具 (可通过网络等) 远程升级、参数存储

关键区别

  • ICP/ISP:需要停止用户程序,进入特殊模式

  • IAP:不停止 用户程序,在运行中更新FLASH

二、IAP的典型应用场景

1. 固件在线升级(OTA/FOTA)

复制代码
// 用户程序中的IAP升级流程
void UserApp_Main(void) {
    while(1) {
        // 正常执行应用程序功能
        Process_User_Tasks();
        
        // 检查是否需要升级(如通过网络、串口)
        if(Check_Upgrade_Request()) {
            // 调用IAP函数,自我更新
            Prepare_For_IAP_Update();
            IAP_Erase_And_Program_New_Firmware();
            Reboot_System();  // 重启运行新程序
        }
    }
}

2. 动态数据存储

复制代码
// 使用IAP功能存储运行参数
void Save_Runtime_Parameters(void) {
    // 在FLASH中存储数据(非易失性)
    IAP_Erase_Sector(DATA_SECTOR_ADDR);
    IAP_Program(DATA_SECTOR_ADDR, parameters, sizeof(parameters));
    
    // 可以继续运行,无需重启
    Continue_Normal_Operation();
}

3. 自编程实现功能切换

复制代码
// 通过IAP修改程序自身行为
void Dynamic_Feature_Enable(void) {
    // 例如:解锁高级功能
    if(license_valid) {
        // 修改特定FLASH位置,使能功能
        IAP_Program(FEATURE_FLAG_ADDR, ENABLE_CODE, 4);
    }
}

三、IAP的工作原理

1. 硬件基础

  • 自编程能力 :芯片FLASH控制器支持自我编程

  • 独立总线:指令总线和数据总线分离(哈佛架构)

  • 特殊寄存器:IAP操作专用控制寄存器

2. 操作流程(以赛元单片机为例)

复制代码
// 典型的IAP操作序列
uint8_t IAP_Program_Flash(uint32_t addr, uint8_t *data, uint16_t len) {
    // 步骤1:解锁IAP功能(特定序列)
    IAP_CONTR = 0x5A;          // 解锁密钥1
    IAP_CONTR |= IAP_EN;       // 使能IAP
    
    // 步骤2:设置操作模式
    IAP_CMD = IAP_PROGRAM_CMD; // 编程命令
    IAP_ADDRH = (addr >> 8);   // 地址高字节
    IAP_ADDRL = (addr & 0xFF); // 地址低字节
    
    // 步骤3:写入数据
    for(uint16_t i = 0; i < len; i++) {
        // 注意:不同架构写法不同
        *((__xdata uint8_t *)addr + i) = data[i];
    }
    
    // 步骤4:触发操作(特定序列)
    IAP_TRIG = 0xA5;
    IAP_TRIG = 0x5A;           // 立即执行
    
    // 步骤5:等待完成并检查状态
    while(IAP_CONTR & IAP_BUSY); // 等待完成
    
    // 步骤6:重新锁定
    IAP_CONTR = 0;             // 禁用IAP
    
    return IAP_STATUS;         // 返回操作状态
}

3. 关键限制与注意事项

复制代码
// IAP操作的重要限制
void IAP_Important_Limits(void) {
    // 1. **不能擦除/写入正在执行的代码**
    //    会导致崩溃或未定义行为
    
    // 2. **必须按页/扇区操作**
    //    FLASH最小擦除单位是扇区(如512字节)
    
    // 3. **需要特殊电压/时钟条件**
    //    有些芯片要求特定电压下才能IAP
    
    // 4. **操作期间中断影响**
    //    通常需要关闭中断或使用特殊处理
}

四、IAP vs BootLoader

很多人混淆这两个概念,其实它们不同但相关

1. BootLoader + IAP 组合方案

复制代码
┌─────────────────────────────────────────────────┐
│                  FLASH 存储器                    │
├──────────────┬────────────────┬─────────────────┤
│  BootLoader  │  应用程序区     │  备份区/参数区  │
│  (8KB)       │  (56KB)        │  (8KB)          │
└──────────────┴────────────────┴─────────────────┘
     ↑              ↑                  ↑
启动代码     通过IAP更新自己       通过IAP读写数据

2. 工作模式对比

复制代码
/* 方案A:传统BootLoader更新(ISP)*/
上电 → BootLoader → 检查升级 → 接收新固件 → 写入APP区 → 跳转APP

/* 方案B:IAP自我更新 */
APP运行 → 检测升级 → 接收新固件 → IAP写入自身 → 重启验证

3. 混合方案(推荐)

复制代码
// 分阶段IAP实现
void Smart_IAP_System(void) {
    // 阶段1:BootLoader(不可更新)
    // 负责最基础的恢复和紧急更新
    
    // 阶段2:应用程序(可IAP更新)
    // 包含主要功能,支持自我更新
    
    // 阶段3:备份应用程序
    // 当主应用程序损坏时回滚
}

五、IAP的具体实现步骤

1. 安全准备阶段

复制代码
bool Prepare_For_IAP_Update(void) {
    // 1. 验证新固件的合法性
    if(!Verify_Firmware_Signature(new_firmware)) {
        return false;
    }
    
    // 2. 检查FLASH空间
    if(!Check_Flash_Space_Available()) {
        return false;
    }
    
    // 3. 保存关键状态到RAM
    Save_Critical_State_To_RAM();
    
    // 4. 禁用不必要的中断和外设
    Disable_Interrupts_And_Peripherals();
    
    return true;
}

2. 双缓冲区更新策略

复制代码
// 避免更新失败变砖的常用方案
void Safe_IAP_Update(void) {
    // FLASH分区布局:
    // 区A: 当前运行程序 (v1.0)
    // 区B: 下载缓存区 (空)
    // 区C: 备份程序 (v1.0备份)
    
    // 步骤1:下载新固件到区B
    Download_To_Sector_B(new_firmware);
    
    // 步骤2:验证区B的程序
    if(Verify_Sector_B() == PASS) {
        // 步骤3:复制当前程序到区C(备份)
        Copy_Sector_A_To_Sector_C();
        
        // 步骤4:擦除区A并写入新程序
        IAP_Erase_Sector_A();
        IAP_Program_Sector_A_From_Sector_B();
        
        // 步骤5:验证并决定
        if(Verify_Sector_A() == PASS) {
            // 成功:运行新程序
            Reboot_And_Run_New_Firmware();
        } else {
            // 失败:从区C恢复
            Restore_From_Sector_C();
        }
    }
}

3. 通信协议设计

复制代码
// IAP通信协议示例
typedef struct {
    uint8_t  start_flag;      // 0xAA
    uint8_t  command;         // 命令字
    uint32_t address;         // FLASH地址
    uint16_t length;          // 数据长度
    uint8_t  data[256];       // 数据载荷
    uint16_t crc16;           // CRC校验
    uint8_t  end_flag;        // 0x55
} IAP_Packet_t;

// 常用命令集
#define IAP_CMD_CONNECT     0x01  // 连接
#define IAP_CMD_ERASE       0x02  // 擦除扇区
#define IAP_CMD_WRITE       0x03  // 写入数据
#define IAP_CMD_READ        0x04  // 读取验证
#define IAP_CMD_EXECUTE     0x05  // 执行新程序
#define IAP_CMD_RESET       0x06  // 复位系统

六、实际开发注意事项

1. 中断处理策略

复制代码
// 方法1:完全禁用中断(简单但可能丢数据)
void IAP_Operation_With_IRQ_Disabled(void) {
    EA = 0;                    // 关闭全局中断
    Perform_IAP_Operation();
    EA = 1;                    // 恢复中断
}

// 方法2:重映射中断向量到RAM(高级方案)
void IAP_Operation_With_IRQ_Remapped(void) {
    // 1. 复制中断向量表到RAM
    Copy_IVT_To_RAM();
    
    // 2. 重映射中断到RAM中的向量表
    Remap_Interrupt_Vector_To_RAM();
    
    // 3. 执行IAP操作(中断可正常响应)
    Perform_IAP_Operation();
    
    // 4. 恢复原中断向量
    Restore_Original_IVT();
}

2. 电源稳定性要求

复制代码
// IAP期间必须保证电源稳定
void Check_Power_Before_IAP(void) {
    // 1. 检查电压
    if(Get_VCC_Voltage() < MIN_IAP_VOLTAGE) {
        Postpone_IAP_Operation();
        return;
    }
    
    // 2. 启用看门狗防止死锁
    Enable_Watchdog_Timeout(IAP_TIMEOUT);
    
    // 3. 可能需要的特殊操作
    if(Chip_Requires_Special_IAP_Voltage()) {
        Enable_IAP_Voltage_Regulator();
        Wait_For_Voltage_Stable();
    }
}

3. 错误恢复机制

复制代码
// 实现可靠的IAP错误处理
IAP_Status_t Robust_IAP_Update(void) {
    IAP_Status_t status = IAP_SUCCESS;
    
    for(uint8_t retry = 0; retry < MAX_RETRIES; retry++) {
        status = Try_IAP_Operation();
        
        switch(status) {
            case IAP_SUCCESS:
                return IAP_SUCCESS;
                
            case IAP_VOLTAGE_ERROR:
                Adjust_Power_Supply();
                break;
                
            case IAP_VERIFY_ERROR:
                // 验证失败,重新传输
                Request_Data_Retransmission();
                break;
                
            case IAP_ADDRESS_ERROR:
                // 地址错误,不可恢复
                return IAP_FATAL_ERROR;
                
            default:
                Delay_ms(RETRY_DELAY_MS);
                break;
        }
    }
    
    // 所有重试失败
    Enter_Recovery_Mode();
    return IAP_MAX_RETRIES_EXCEEDED;
}

七、IAP的高级应用

1. 差分升级(减少数据传输量)

复制代码
// 只传输变化的部分,不是整个固件
void Differential_IAP_Update(void) {
    // 1. 计算当前固件和新固件的差异
    Calculate_Delta(current_firmware, new_firmware, &delta);
    
    // 2. 仅传输差异数据
    Transmit_Delta_Data(delta);
    
    // 3. 在设备端应用差异
    Apply_Delta_To_Current_Firmware(delta);
}

2. A/B分区无缝切换

复制代码
// 实现无感知固件更新
void Seamless_A_B_Switching(void) {
    // 分区A: v1.0 (当前运行)
    // 分区B: v2.0 (已更新)
    
    // 1. 在后台更新分区B
    Update_Partition_B_Background();
    
    // 2. 验证分区B的完整性
    if(Verify_Partition_B() == PASS) {
        // 3. 更新引导标志(下次启动到B)
        Update_Boot_Flag_TO_B();
        
        // 4. 正常完成本次运行
        //    下次重启自动运行新版本
    }
}

3. 远程IAP(物联网设备)

复制代码
// 通过网络进行IAP更新
void Remote_IAP_Over_Network(void) {
    // 1. 接收更新通知(MQTT/HTTP/CoAP)
    if(Received_OTA_Update_Command()) {
        // 2. 安全验证
        if(Authenticate_Update_Server()) {
            // 3. 分段下载固件
            while(!Download_Complete()) {
                Download_Next_Fragment();
                Store_Fragment_To_Flash();
            }
            
            // 4. 验证并切换
            if(Verify_Downloaded_Firmware()) {
                Schedule_Reboot_For_Update();
            }
        }
    }
}

八、总结:IAP的核心价值

  1. 现场升级能力:无需返厂或使用专用工具

  2. 产品生命周期管理:可以持续改进和修复bug

  3. 参数非易失存储:替代部分EEPROM功能

  4. 功能动态配置:通过更新改变设备行为

  5. 降低维护成本:远程解决问题,减少现场服务

关键要点

  • IAP是自我编程能力,不是特定的编程方法

  • 必须考虑安全性可靠性,防止设备变砖

  • 通常与BootLoader配合实现更稳健的更新机制

  • 需要深入了解芯片的FLASH架构限制

IAP是现代嵌入式系统的标配功能,尤其对于需要远程维护或长期现场运行的设备至关重要。

相关推荐
恶魔泡泡糖2 小时前
51单片机蜂鸣器应用
单片机·嵌入式硬件·51单片机
进击的小头2 小时前
01_嵌入式C与控制理论入门:从原理到MCU实战落地
c语言·单片机·算法
小尧嵌入式2 小时前
STM32中OTA介绍及使用
开发语言·stm32·单片机·嵌入式硬件
会编程是什么感觉...2 小时前
单片机 - STM32CubeMX HAL库开发部分
stm32·单片机·嵌入式硬件
日更嵌入式的打工仔2 小时前
两种核心消息队列:环形队列与RTOS消息队列解析
笔记·单片机
石马马户2 小时前
keil使用Jlink下载时出现No Cortex-M SW Device Found 解决方法
单片机·嵌入式硬件
快乐的划水a2 小时前
嵌入式时间测量方法总结
c++·stm32·单片机
文弱书生6562 小时前
3-electronbot舵机板电路分析
linux·单片机·嵌入式硬件
风哥在风中3 小时前
一“芯”二用,氧化铝陶瓷发热芯的温度控制原理与技术特性分析
嵌入式硬件·硬件工程·焊接工具