丽萨单片机固件升级,裁剪hex文件

丽萨单片机固定升级,主工程下建两个副工程,分别是 bootloader 和 app。固件升级需要 2 进制的文件,而瑞萨的 CS+ IDE 编译生成的是 mot,之后使用 J-flash 软件转为 hex 文件,升级时需要把后面大量的 FF 删去!!!

后面大量的 0xFF:可以不删,但删掉更好!!!

不删也能正常升级,但强烈建议删掉。原因和具体操作如下。


一、什么是 "后面大量的 FF"

你的 App 实际代码可能只到 0x8000 就结束了,但 Flash 末尾是 0x3FFFF(256KB)。如果转换时用了 -fill 0xFF 或 J-Flash 默认填充,生成的文件会包含:

复制代码
0x2000 ~ 0x8000   →  实际固件数据(有效)
0x8001 ~ 0x3FFFF  →  全是 0xFF(无效,Flash 擦除后本来就是这个值)
                  ↑
              这部分就是"后面大量的FF"

一个 256KB 的 Flash,实际 App 可能只有 30KB,剩下 200 多 KB 全是 0xFF,白白占用升级时间。


二、不删会怎样?

不删也能正常工作,因为:

  1. Flash 擦除后默认值就是 0xFF
  2. Bootloader 把收到的 0xFF 再写一遍,结果还是 0xFF,不影响
  3. 升级后 App 运行正常

但有 3 个缺点

缺点 说明
升级慢 200KB 的 0xFF 通过串口传输,115200 波特率要约 20 秒,实际有效数据可能 3 秒就传完
易出错 传输数据量越大,串口误码概率越高,CRC 校验失败要重传
占空间 升级包文件大,存储和分发不方便

三、删掉的正确做法

关键原则:只保留 "有实际数据" 的区域,不填充到 Flash 末尾

方法 1:srec_cat(推荐,最精确)

不要加 -fill 参数 ,只用 -crop 裁剪到实际数据范围:

复制代码
# 先查看 app.mot 中实际数据的最高地址
srec_info app.mot -Motorola

输出类似:

复制代码
Format: Motorola S-Record
Data:  0x002000 - 0x0087FF   ← 实际数据只到 0x87FF

然后只裁剪到实际结束地址 + 1:

复制代码
# 只保留 0x2000~0x87FF 的实际数据,不填充后面的FF
srec_cat app.mot -Motorola ^
    -crop 0x2000 0x8800 ^
    -o app.bin -Binary

0x8800 = 实际结束地址 0x87FF + 1。这样生成的 bin 文件只有约 26KB,而不是 248KB。

自动获取结束地址的脚本(Windows)

复制代码
@echo off
REM 自动获取 mot 中最高地址,裁剪生成最小 bin
for /f "tokens=3" %%a in ('srec_info app.mot -Motorola ^| findstr /C:"Data:"') do set END=%%a
echo 实际数据结束地址: %END%

REM 结束地址+1
set /a END_PLUS_1=%END% + 1

srec_cat app.mot -Motorola -crop 0x2000 %END_PLUS_1% -o app.bin -Binary
echo 生成 app.bin,大小:
srec_info app.bin -Binary

方法 2:J-Flash 中手动删除

  1. J-Flash 打开 app.mot
  2. 查看内存视图,找到实际数据的最高地址(后面全是 0xFF 的起点)
  3. 菜单 EditDelete range
  4. 输入:Start = 实际结束地址+1End = 0x3FFFF
  5. 删完后,File → Save as → 选择 .bin 格式

方法 3:J-Flash 保存时只保存有效区域

J-Flash 保存时,有些版本可以选择 "Save only occupied areas"(只保存有数据的区域),这样自动忽略后面的 0xFF。


四、删了之后 Bootloader 要怎么改

删掉后面的 0xFF 后,bin 文件大小 = 实际固件大小,不是固定的 Flash 大小。Bootloader 需要:

1. 上位机先发固件长度

复制代码
上位机 → Bootloader:
  字节0~3: 固件大小(4字节,小端或大端,约定好)
  字节4~N: 固件数据(bin 文件内容)
  最后2字节: CRC16 校验

2. Bootloader 按实际长度处理

复制代码
#define APP_START_ADDR  0x2000

void do_firmware_update(void)
{
    /* 1. 接收固件长度 */
    uint32_t fw_size = uart_recv_u32();
    
    /* 2. 按实际长度擦除 App 区(从 0x2000 开始) */
    flash_erase(APP_START_ADDR, fw_size);
    
    /* 3. 接收 fw_size 字节数据,依次写入 Flash */
    uint32_t addr = APP_START_ADDR;
    uint32_t received = 0;
    while (received < fw_size)
    {
        uint16_t len = uart_recv_frame(rx_buf, 256);
        flash_write(addr, rx_buf, len);
        addr += len;
        received += len;
    }
    
    /* 4. CRC 校验 */
    uint16_t crc_recv = uart_recv_u16();
    uint16_t crc_calc = crc16(APP_START_ADDR, fw_size);
    if (crc_recv != crc_calc) {
        /* 校验失败,不标记新固件,保持旧固件(回滚) */
        return;
    }
    
    /* 5. 标记新固件有效 */
    set_fw_valid_flag();
}

关键点 :擦除和写入都按实际固件长度,不是按整个 Flash 大小。


五、中间空隙的 0xFF 要不要删?

App 的段之间可能有空隙(比如 .text 结束到 .data 开始之间有几个字节的空隙),这些空隙也是 0xFF。

这些中间的 0xFF 不能删,因为:

  • bin 文件是连续地址流
  • 中间空隙的 0xFF 占据了正确的地址偏移
  • 如果删掉,后面的数据地址就错位了

只有 "最后面" 连续的 0xFF 可以删,因为它们不影响前面数据的地址偏移。


六、总结对比

处理方式 文件大小 升级速度 复杂度 推荐度
不删,填充到 Flash 末尾 大(如 248KB) ❌ 不推荐
删掉末尾 0xFF,只保留有效数据 小(如 26KB) ✅ 推荐
用压缩算法压缩后传输 更小 最快 ⭐ 高级方案

七、操作清单

  1. srec_info app.mot -Motorola 查看实际数据结束地址
  2. srec_cat -crop 0x2000 结束地址+1 生成 bin (不加 -fill
  3. 上位机先发 4 字节固件长度,再发 bin 数据,最后发 CRC16
  4. Bootloader 按实际长度擦除、写入、校验
  5. 不要删中间空隙的 0xFF,只删末尾连续的 0xFF
相关推荐
昌原的儿子LEO3 小时前
【单片机入门】UART 串行异步通信核心考点梳理
linux·单片机·51单片机
沐欣工作室_lvyiyi3 小时前
基于单片机的汽车防碰撞刹车系统的设计与实现(论文+源码)
单片机·嵌入式硬件·汽车·单片机智能小车
雨田言炎3 小时前
STM32之自定义协议帧格式
网络·笔记·stm32·单片机
云栖梦泽3 小时前
网络设备驱动(3)
linux·运维·服务器·网络·嵌入式硬件
洪核单片机4 小时前
DPJ-91基于32单片机的语音识别车语音播报车语音控制智能车
stm32·单片机·嵌入式硬件·智能车·语音识别车·语音播报车·语音控制智能车
zhaoshuzhaoshu4 小时前
守护进程(Daemon)详解:Android vs 嵌入式MCU平台对比
嵌入式硬件
单片机仿真设计13 小时前
【proteus仿真】基于 STM32 单片机衣柜温湿度监测系统(仿真图+程序)
stm32·单片机·嵌入式硬件·proteus
嵌入式学习菌13 小时前
Modbus‑RTU 数据类型分析
开发语言·单片机·bug
千秋岁rr14 小时前
11.USART
单片机·嵌入式硬件