test/freetest/IAP升级方案.md

27 KiB
Raw Permalink Blame History

BMS 从机 CAN-UDS IAP 升级方案

基于 ISO 14229 (UDS) + ISO 15765 (CAN-TP) 标准
硬件: STM32F103C8T6 (64KB Flash, 20KB RAM)
通信: CAN 500kbps, 标准帧
日期: 2026-08-06


一、Flash 存储分区

1.1 地址布局

区域 起始地址 结束地址 大小 页数 说明
Bootloader 0x08000000 0x08003FFF 16KB 16 引导程序,不可升级
Application 0x08004000 0x0800EFFF 44KB 44 应用程序,IAP目标区
参数区 0x0800F000 0x0800FFFF 4KB 4 升级标志 + 用户参数

1.2 升级标志定义(参数区首字 0x0800F000)

标志值 含义
0xFFFFFFFF 空闲,无升级任务
0xA5A55A5A 有新固件待处理
0x55AA55AA 升级进行中(断电续传标志)
0x12345678 升级完成,可跳转App

1.3 参数区布局(断电续传)

偏移    字段          大小    说明
0x00    flag          4字节   升级标志(见1.2)
0x04    fw_size       4字节   固件总大小
0x08    bitmap_lo     4字节   进度位图(块0-31, 1=未完成, 0=完成)
0x0C    bitmap_hi     4字节   进度位图(块32-63)

进度位图原理:

  • Flash 擦除后全 1 (0xFFFFFFFF),表示所有块未完成
  • 每完成一个 1KB 块,将对应位清 0 (1→0,符合 Flash 物理特性)
  • 上电后扫描位图,第一个为 1 的位即为续传起点
  • 优点: 每次仅写 1 个字(~40μs),无需擦除参数页,不阻塞 CAN 接收

1.4 启动流程

上电
  ↓
Bootloader 读取 0x0800F000 标志
  ├─ IAP_FLAG_COMPLETE (0x12345678) → 检查App合法性 → 跳转App
  ├─ IAP_FLAG_UPGRADING(0x55AA55AA) → 读取进度位图 → 等待IAP续传
  ├─ IAP_FLAG_NEW_FW   (0xA5A55A5A) → 等待IAP升级
  └─ IAP_FLAG_NONE     (0xFFFFFFFF) → 检查App栈顶 → 跳转或等待

二、UDS 服务详解 (ISO 14229)

2.1 服务总览

SID 服务名称 阶段 说明
0x10 DiagnosticSessionControl 握手 切换诊断会话
0x22 ReadDataByIdentifier 握手 读取版本/固件信息
0x27 SecurityAccess 握手 安全解锁(Seed/Key)
0x31 RoutineControl 校验 擦除Flash / CRC校验
0x34 RequestDownload 传输 请求下载,声明固件大小
0x36 TransferData 传输 传输固件数据
0x37 RequestTransferExit 传输 结束传输
0x11 ECUReset 完成 复位跳转App

2.2 0x10 DiagnosticSessionControl

功能: 切换诊断会话模式,升级前必须进入编程会话。

请求格式:

[A0]  [SID]  [SubFunction]
       0x10   0x01 = Default Session
              0x02 = Programming Session
              0x03 = Extended Session

正响应:

[A0]  [SID|0x40]  [SubFunction echo]
       0x50        0x02

否定响应:

[A0]  [0x7F]  [SID]  [NRC]
       0x7F     0x10   见NRC表

本项目实现: 收到 0x10 0x02 后进入 IAP_STATE_SESSION,允许后续升级服务。


2.3 0x22 ReadDataByIdentifier

功能: 通过DID读取数据,用于握手和版本确认。

请求格式:

[A0]  [SID]  [DID_High]  [DID_Low]
       0x22   0xF1         0x00      (DID=0xF100: 版本信息)

正响应:

[A0]  [SID|0x40]  [DID_High]  [DID_Low]  [Data...]
       0x62        0xF1         0x00       "IAP01"  (5字节ASCII)

DID 定义:

DID 含义 数据格式
0xF100 Bootloader版本 5字节ASCII "IAP01"
0xF101 固件大小 4字节大端
0xF102 CRC32 4字节大端

2.4 0x27 SecurityAccess

功能: 安全访问,升级前必须解锁。采用Seed/Key机制。

请求Seed (子功能=0x01):

[A0]  [SID]  [SubFunction]
       0x27   0x01

正响应(返回Seed):

[A0]  [SID|0x40]  [SubFunction]  [Seed 4字节]
       0x67        0x01           0x12 0x34 0x56 0x78

发送Key (子功能=0x02):

[A0]  [SID]  [SubFunction]  [Key 4字节]
       0x27   0x02           0xED 0xCB 0xA9 0x87

Key算法: Key = ~Seed (简化版,实际项目应使用更复杂算法)

Seed Key
0x12345678 0xEDCBA987
0xAABBCCDD 0x55443322

正响应:

[A0]  [SID|0x40]  [SubFunction]
       0x67        0x02

否定响应: Key错误时返回 NRC=0x35 (InvalidKey) 或 0x36 (ExceededNumberOfAttempts)。


2.5 0x31 RoutineControl

功能: 例程控制,用于擦除Flash和CRC校验。

请求格式:

[A0]  [SID]  [SubFunction]  [RoutineID_High]  [RoutineID_Low]
       0x31   0x01            0xFF               0x01         (EraseFlash)
              0x01            0xFF               0x02         (VerifyCRC)

RoutineID 定义:

RoutineID 含义 触发动作
0xFF01 EraseFlash 擦除App区44页
0xFF02 VerifyCRC 读回Flash计算CRC32

正响应:

[A0]  [SID|0x40]  [SubFunction]  [RoutineID_High]  [RoutineID_Low]
       0x71        0x01            0xFF               0x01

2.6 0x34 RequestDownload

功能: 请求下载,声明固件大小。标准ISO 14229格式。

标准请求格式:

[A0]  [SID]  [DataFormatId]  [AddrSizeFormatId]  [MemoryAddr]  [MemorySize]
       0x34   0x00             0x44                 4字节         4字节
字段 说明
DataFormatId 0x00 无压缩,无加密
AddrSizeFormatId 0x44 地址4字节,大小4字节
MemoryAddr 0x08004000 App区起始地址
MemorySize 固件大小 大端4字节

本项目简化格式(CAN 8字节限制):

[A0]  [SID]  [Size_3]  [Size_2]  [Size_1]  [Size_0]
       0x34   0x00      0x00      0x5A      0x00      (size=23040=0x5A00)

正响应(支持断电续传):

[A0]  [SID|0x40]  [LengthFormatId]  [Offset_3]  [Offset_2]  [Offset_1]  [Offset_0]
       0x74        0x08              0x00         0x00         0x00         0x00
字段 说明
LengthFormatId 0x08, 每帧可接收8字节数据
Offset 续传偏移量(大端4字节), 0=全新升级, >0=从该偏移续传

断电续传判断逻辑:

  • 板子收到 0x34 后,检查参数区 flagfw_size
  • flag == IAP_FLAG_UPGRADINGfw_size 匹配 → 续传模式
    • 不擦除 App 区,从进度位图计算 offset
    • 上位机从固件 offset 处开始发送数据
  • 否则 → 全新升级
    • 擦除 App 区,初始化参数区(flag=UPGRADING, fw_size, bitmap=0xFFFFFFFF)
    • offset = 0

2.7 0x36 TransferData

功能: 传输固件数据。

标准格式(带块序号)

请求格式:

[A0]  [SID]  [BlockSeqCounter]  [Data 0~6字节]
       0x36   0x01               [固件数据]

BlockSequenceCounter: 从0x01开始递增,到0xFF后回绕到0x00。

正响应:

[A0]  [SID|0x40]  [BlockSeqCounter echo]
       0x76        0x01

每帧有效数据: 8 - 2 = 6字节(SID + 序号占2字节)。

本项目优化格式(纯数据模式 + 乒乓缓冲区)

为提高传输效率,采用两阶段数据传输 + 乒乓缓冲区:

阶段1: 命令帧(0x36 0x01)

[A0]  [SID]  [BlockSeqCounter]
       0x36   0x01              → 正响应 0x76, 进入纯数据模式

阶段2: 纯数据帧(无SID,无序号,乒乓缓冲区)

[A0]  [Data 0]  [Data 1]  [Data 2]  [Data 3]  [Data 4]  [Data 5]  [Data 6]  [Data 7]
       8字节全部是固件数据, 写入乒乓缓冲区, 无响应

乒乓缓冲区机制:

  • 两个1KB缓冲区交替使用(共2KB RAM)
  • CAN数据先写入活跃缓冲区(纯内存操作,极快)
  • 缓冲区满(128帧×8字节=1KB)后切换到另一个缓冲区
  • 上一轮满缓冲区在下一帧到来时批量写入Flash(只Unlock/Lock一次)
  • 每完成1KB块写入Flash后,更新进度位图(断电续传)
  • Flash写入期间,CAN中断继续往frame_buf写入,实现半并行
帧1~128:   写入缓冲区A (纯内存, ~0μs/帧)
帧129:     缓冲区A满 → 切换到缓冲区B
           → 批量写Flash(缓冲区A, 1KB=256个字, ~10ms)
           → 更新进度位图(块0完成, 位0清0, ~40μs)
           → 帧129写入缓冲区B
帧130~256: 写入缓冲区B (纯内存)
帧257:     缓冲区B满 → 切换到缓冲区A
           → 批量写Flash(缓冲区B, 1KB)
           → 帧257写入缓冲区A
...        循环往复

按固件 size 计数,收够自动退出数据模式,发送最终正响应:

[A0]  [SID|0x40]
       0x76        (传输完成通知)

效率对比:

模式 每帧有效数据 44KB所需帧数 传输时间@500kbps
标准模式(带序号) 6字节 7467帧 0.97s
纯数据模式(乒乓) 8字节 5600帧 0.73s
提升 +33% -25% -25%

Flash写入效率对比:

指标 每帧写Flash 乒乓缓冲区(1KB)
HAL_FLASH_Unlock/Lock 每8字节2次 每1KB 2次
Flash写入粒度 2个字/帧 256个字/批
Unlock/Lock次数(44KB) 11264次 88次
Flash写入耗时/批 ~80μs ~10ms
写入期间CAN缓冲 frame_buf(200帧) frame_buf(200帧)
RAM占用 0 2KB (2×1KB)

2.8 0x37 RequestTransferExit

功能: 结束数据传输。

请求格式:

[A0]  [SID]
       0x37

正响应:

[A0]  [SID|0x40]
       0x77

2.9 0x11 ECUReset

功能: ECU复位,跳转到新App。

请求格式:

[A0]  [SID]  [SubFunction]
       0x11   0x01 = Hard Reset
              0x02 = Key Off On Reset
              0x03 = Soft Reset

正响应:

[A0]  [SID|0x40]  [SubFunction echo]
       0x51        0x01

正响应发送后,延时100ms确保帧发出,然后 NVIC_SystemReset()


三、完整升级时序

3.1 标准升级流程

上位机 (Tester)                          板子 (ECU)
    │                                       │
    │═══ 阶段1: 握手 ═══════════════════════│
    │── 0x10 0x02 ──────────────────────→  │ 进入编程会话
    │←── 0x50 0x02 ──────────────────────  │
    │                                       │
    │── 0x22 0xF1 0x00 ────────────────→  │ 读版本
    │←── 0x62 0xF1 0x00 "IAP01" ────────  │
    │                                       │
    │── 0x27 0x01 ──────────────────────→  │ 请求Seed
    │←── 0x67 0x01 [4字节Seed] ──────────  │
    │                                       │
    │── 0x27 0x02 [4字节Key] ───────────→  │ 发送Key
    │←── 0x67 0x02 ──────────────────────  │ 解锁成功
    │                                       │
    │═══ 阶段2: 数据传输 ═══════════════════│
    │── 0x31 0x01 0xFF 0x01 ────────────→  │ 擦除App区
    │←── 0x71 0x01 0xFF 0x01 ────────────  │ 擦除完成
    │                                       │
    │── 0x34 [固件大小4字节] ────────────→  │ 请求下载
    │←── 0x74 0x08 ──────────────────────  │ 允许,每帧8字节
    │                                       │
    │── 0x36 0x01 ──────────────────────→  │ 开始数据传输
    │←── 0x76 0x01 ──────────────────────  │ 进入纯数据模式
    │                                       │
    │── [8字节数据 #1] ─────────────────→  │ 写入Flash (无响应)
    │── [8字节数据 #2] ─────────────────→  │ 写入Flash (无响应)
    │── [8字节数据 #3] ─────────────────→  │ 写入Flash (无响应)
    │   ...                                 │
    │── [8字节数据 #N] ─────────────────→  │ 写入最后一块
    │←── 0x76 ────────────────────────────  │ 传输完成(自动)
    │                                       │
    │── 0x37 ───────────────────────────→  │ 传输退出
    │←── 0x77 ────────────────────────────  │
    │                                       │
    │═══ 阶段3: 校验烧写 ═══════════════════│
    │── 0x31 0x01 0xFF 0x02 ────────────→  │ CRC校验
    │←── 0x71 0x01 0xFF 0x02 [CRC 4字节]─  │ 校验通过
    │                                       │
    │── 0x11 0x01 ──────────────────────→  │ 硬复位
    │←── 0x51 0x01 ──────────────────────  │
    │                                       │ 复位,跳转新App

3.2 超时机制

等待事件 超时时间 超时处理
会话请求 (0x10) 5s 回到IDLE
安全访问 (0x27) 5s 回到SESSION
数据帧间隔 1s 回到DOWNLOADING,发NRC
传输完成 (0x37) 10s 回到SESSION
整体升级 60s 回到IDLE

3.3 断电续传时序

上位机 (Tester)                          板子 (ECU)
    │                                       │
    │═══ 首次升级(传输到50%断电) ═══════════│
    │── 0x34 [size] ────────────────────→  │ 全新升级,擦除App区
    │←── 0x74 0x08 [offset=0] ────────────  │ flag=UPGRADING, bitmap=0xFF...
    │── 0x36 0x01 ──────────────────────→  │ 开始传输
    │←── 0x76 0x01 ──────────────────────  │
    │── [数据帧...传输到50%] ────────────→  │ 已写22KB(22块完成)
    │   ✗ 断电                              │ bitmap: 0xFFC00000 (块0-21=0)
    │                                       │
    │═══ 重新上电,续传 ═════════════════════│
    │                                       │ Bootloader读flag=UPGRADING
    │                                       │ 扫描bitmap, offset=22KB
    │── 0x10 0x02 ──────────────────────→  │ 进入会话
    │←── 0x50 0x02 ──────────────────────  │
    │── 0x27 0x01 ──────────────────────→  │ 安全访问
    │←── 0x67 0x01 [Seed] ────────────────  │
    │── 0x27 0x02 [Key] ─────────────────→  │
    │←── 0x67 0x02 ──────────────────────  │
    │                                       │
    │── 0x34 [size] ────────────────────→  │ 检查: flag=UPGRADING, size匹配
    │←── 0x74 0x08 [offset=22528] ────────  │ 续传模式! 不擦除App区
    │                                       │
    │── 0x36 0x01 ──────────────────────→  │ 开始传输
    │←── 0x76 0x01 ──────────────────────  │
    │── [从offset=22KB处开始发数据] ─────→  │ 继续写入Flash
    │── [数据帧...] ─────────────────────→  │
    │←── 0x76 ────────────────────────────  │ 传输完成
    │── 0x37 ───────────────────────────→  │
    │←── 0x77 ────────────────────────────  │
    │── 0x31 0x01 0xFF 0x02 ────────────→  │ CRC校验
    │←── 0x71 0x01 0xFF 0x02 [CRC] ───────  │ 校验通过, flag=COMPLETE
    │── 0x11 0x01 ──────────────────────→  │ 复位跳转
    │←── 0x51 0x01 ──────────────────────  │

四、NRC (否定响应码) 定义

4.1 标准NRC表 (ISO 14229)

NRC 名称 触发条件
0x10 GeneralReject 通用拒绝(Flash擦写失败等)
0x11 ServiceNotSupported 不支持的SID
0x22 ConditionsNotCorrect 状态不满足(未解锁就请求下载)
0x31 RequestOutOfRange 参数越界(固件大小=0或超限)
0x33 SecurityAccessDenied 未解锁就访问受保护服务
0x35 InvalidKey Key错误
0x36 ExceededNumberOfAttempts 超过最大尝试次数
0x72 GeneralProgrammingFailure Flash编程失败
0x73 WrongBlockSequenceCounter 块序号错误
0x78 ResponsePending 响应延迟(处理中)

4.2 本项目使用的NRC

NRC_GENERAL_REJECT          0x10  /* Flash擦写失败 */
NRC_SERVICE_NOT_SUPPORTED   0x11  /* 未知SID */
NRC_CONDITIONS_NOT_CORRECT  0x22  /* 状态不满足 */
NRC_REQUEST_OUT_OF_RANGE    0x31  /* 参数越界 */

五、状态机定义

5.1 状态转换图

                    ┌──────────────────────────────────────────┐
                    ↓                                          │
  ┌────────┐  0x10 0x02  ┌─────────┐  0x34  ┌──────────────┐  │
  │  IDLE  │ ──────────→ │ SESSION │ ─────→ │ DOWNLOADING  │  │
  └────────┘             └─────────┘        └──────────────┘  │
       ↑                      │                    │            │
       │                      │ 0x11               │ 0x36 0x01  │
       │ 0x11                 ↓                    ↓            │
       │                 ┌─────────┐        ┌──────────────┐   │
       │                 |  RESET  │        │  DATA_MODE   │   │
       │                 └─────────┘        └──────────────┘   │
       │                                          │            │
       │                              收够size    │            │
       │                                          ↓            │
       │                                   ┌──────────────┐    │
       └───────────────────────────────── │TRANSFER_DONE │────┘
                               0x11       └──────────────┘

5.2 状态说明

状态 允许的SID 说明
IDLE 0x10 仅接受会话控制
SESSION 0x10, 0x22, 0x27, 0x34, 0x11 握手+下载请求
DOWNLOADING 0x36 等待数据传输开始
DATA_MODE (纯数据) 8字节直接写Flash,不解析SID
TRANSFER_DONE 0x37, 0x31, 0x11 传输完成,校验/退出/复位

六、CRC32 校验

6.1 算法

  • 多项式: 0xEDB88320 (IEEE 802.3, 反射形式)
  • 初始值: 0xFFFFFFFF
  • 最终异或: 0xFFFFFFFF
  • 输入: 固件数据(按字节)
  • 输出: 4字节CRC32

6.2 校验流程

  1. 上位机计算固件BIN文件的CRC32
  2. 数据传输完成后,上位机发送 0x31 0x01 0xFF 0x02 请求校验
  3. 板子读回Flash中 fw_size 字节,计算CRC32
  4. 板子返回CRC32结果
  5. 上位机比对,一致则发 0x11 复位

6.3 CRC32 实现

uint32_t iap_crc32(const uint8_t *data, uint32_t len)
{
    uint32_t crc = 0xFFFFFFFFU;
    for (uint32_t i = 0; i < len; i++)
    {
        crc ^= data[i];
        for (uint8_t j = 0; j < 8; j++)
        {
            if (crc & 1)
                crc = (crc >> 1) ^ 0xEDB88320U;
            else
                crc >>= 1;
        }
    }
    return crc ^ 0xFFFFFFFFU;
}

七、安全机制

7.1 安全访问(Seed/Key)

  • 升级前必须通过 0x27 安全访问
  • Seed由板子随机生成(或基于HAL_GetTick)
  • Key算法: Key = ~Seed (简化版,生产环境应使用更复杂算法)

7.2 固件大小校验

  • 0x34 请求下载时检查固件大小
  • 限制: 0 < fw_size <= 44KB (IAP_APP_SIZE)
  • 超限返回 NRC=0x31

7.3 栈顶地址校验

  • 跳转App前检查栈顶地址
  • 合法范围: 0x20000000 <= SP <= 0x20005000 (20KB RAM)
  • 不合法则不跳转,留在Bootloader

7.4 Flash写保护

  • 参数区(0x0800F000)只有升级标志操作可写
  • Bootloader区(0x08000000-0x08003FFF)不可擦写
  • App区(0x08004000-0x0800EFFF)仅IAP模式可擦写

八、与标准UDS的差异说明

8.1 本项目简化项

标准要求 本项目实现 原因
0x34 带地址+大小格式标识符 仅带大小(4字节) CAN 8字节帧限制
0x36 带块序号,每帧响应 纯数据模式+乒乓缓冲区,无序号,无响应 提升传输效率33%,Flash批量写入
0x36 块序号校验 按固件size计数 + CRC32校验 简化协议,乒乓缓冲区1KB/批
0x78 ResponsePending 未实现 Flash擦写<10ms,不需要
ISO 15765 CAN-TP分包 未实现 固件44KB,纯数据模式够用

8.2 风险评估

风险 影响 缓解措施
纯数据模式无序号,丢帧无法检测 固件损坏 CRC32校验 + 上位机重传
乒乓缓冲区Flash写入~10ms,期间帧积压 最多积压78帧 frame_buf(200帧)足够缓存
无CAN-TP分包,单帧8字节 传输慢 44KB@500kbps仅需0.73s,可接受
安全访问算法简单 可被逆向 生产环境应换为AES或自定义算法
乒乓缓冲区占用2KB RAM RAM减少 F103有20KB RAM,可接受
断电续传位图写失败 续传位置不准 Flash写入有HAL返回值检查
断电发生在块写入中途 该块数据不完整 续传时该块重传(位图未清0)
断电发生在位图清0前 该块需重传 最多重传1KB,可接受

九、上位机实现指南

9.1 升级步骤(Python伪代码)

def iap_upgrade(can, fw_path):
    fw_data = open(fw_path, 'rb').read()
    fw_size = len(fw_data)
    fw_crc  = crc32(fw_data)

    # 阶段1: 握手
    can.send(0x180, [0x10, 0x02])
    assert can.recv(0x181)[0] == 0x50

    can.send(0x180, [0x22, 0xF1, 0x00])
    resp = can.recv(0x181)
    assert resp[0] == 0x62

    can.send(0x180, [0x27, 0x01])
    resp = can.recv(0x181)
    seed = resp[2:6]
    key  = bytes([~b & 0xFF for b in seed])
    can.send(0x180, [0x27, 0x02] + list(key))
    assert can.recv(0x181)[0] == 0x67

    # 阶段2: 数据传输(支持断电续传)
    can.send(0x180, [0x31, 0x01, 0xFF, 0x01])  # 擦除(仅首次,续传时板子自动跳过)
    assert can.recv(0x181)[0] == 0x71

    can.send(0x180, [0x34] + list(fw_size.to_bytes(4, 'big')))  # 请求下载
    resp = can.recv(0x181)
    assert resp[0] == 0x74
    offset = int.from_bytes(resp[2:6], 'big')  # 读取续传偏移量

    can.send(0x180, [0x36, 0x01])  # 开始传输
    assert can.recv(0x181)[0] == 0x76

    # 纯数据模式: 从offset处开始发送, 8字节/帧, 无响应
    for i in range(offset, fw_size, 8):
        chunk = fw_data[i:i+8]
        chunk = chunk.ljust(8, b'\xFF')  # 不足8字节补0xFF
        can.send(0x180, list(chunk))

    # 等待传输完成响应
    assert can.recv(0x181, timeout=2000)[0] == 0x76

    can.send(0x180, [0x37])  # 传输退出
    assert can.recv(0x181)[0] == 0x77

    # 阶段3: 校验
    can.send(0x180, [0x31, 0x01, 0xFF, 0x02])  # CRC校验
    resp = can.recv(0x181)
    calc_crc = int.from_bytes(resp[4:8], 'big')
    assert calc_crc == fw_crc

    can.send(0x180, [0x11, 0x01])  # 复位
    assert can.recv(0x181)[0] == 0x51

    print("升级成功!")

9.2 上位机CAN帧参数

参数
帧类型 标准帧
请求ID 0x180
响应ID 0x181
DLC 8
波特率 500kbps
帧间隔 ≥1ms (数据模式可连续)

十、测试验证

10.1 功能测试项

测试项 预期结果 状态
握手流程(0x10→0x22→0x27) 全部正响应
擦除App区(0x31 0xFF01) App区全0xFF
下载1KB固件 CRC校验通过
下载44KB固件(满载) CRC校验通过,0.73s完成
跳转App(0x11) App正常运行
错误Key NRC=0x35
固件大小超限 NRC=0x31
未解锁就下载 NRC=0x22
断电续传: 传输50%断电 重新上电后从断点续传
断电续传: 传输1KB后断电 重新上电后从1KB处续传
断电续传: 块写入中途断电 该块重传,CRC校验通过

10.2 压力测试

测试项 预期结果 状态
连续升级10次 每次成功
断电续传5次 最终CRC校验通过
数据帧丢1帧 CRC校验失败,拒绝跳转
总线错误(bus-off) 自动恢复,重试

十一、文件清单

文件 作用
app_iap.h IAP模块头文件,定义和API
app_iap.c IAP模块实现
app_flash.h Flash读写模块头文件
app_flash.c Flash读写模块实现

十二、待确认事项

  1. Bootloader独立工程: 当前App工程中包含IAP代码,实际应拆分为独立Bootloader工程(16KB) + App工程(44KB)
  2. 中断向量表偏移: App工程需设置 VECT_TAB_OFFSET=0x4000,或在system_stm32f1xx.c中修改 VECT_TAB_OFFSET
  3. 链接脚本: App工程的Flash起始地址需改为 0x08004000
  4. 安全访问算法: 当前 Key=~Seed 过于简单,生产环境是否需要加强?
  5. 数据模式丢帧处理: 纯数据模式无序号,如果CAN丢帧,CRC校验会失败。是否需要增加重传机制?