找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1522|回复: 7
收起左侧

关于keil 烧录hex文件问题

[复制链接]
ID:1144305 发表于 2025-2-24 13:46 | 显示全部楼层 |阅读模式
188黑币
这几天遇到了一个问题:
同样的一份hex文件,在keil(j-link)里烧录,程序能正常运行,但是通过J-flash反读出来的hex文件,会比原来的hex文件多出一段数据  比如:原来的hex在0x08049444的地址已经结束,反读出来的hex在此地址之后会多出一段数据。
            通过keil调试,memory窗口定位,在disassembly里对应地址显示的全是汇编,都是寄存器操作,没有对应代码。截取部分如下:
           0x08049477 0000      MOVS          r0,r0
           0x08049479 0000      MOVS          r0,r0           
           0x0804947B 0100      LSLS          r0,r0,#4           
           0x0804947D 3240      ADDS          r2,r2,#0x40           
           0x0804947F 4210      TST           r0,r2         
            0x08049481 0301      LSLS          r1,r0,#12         
            0x08049483 245D      MOVS          r4,#0x5D           
           0x08049485 1AF4      SUBS          r4,r6,r3           
           0x08049487 01AA      LSLS          r2,r5,#6         
用j-flash烧录或者上位机(can通讯),程序运行不起来,但是反读出来的hex与原本的hex一致!!!
想问问大佬是什么原因?keil的编译器问题还是其他的原因?

附加:单片机是stm32f407VGT6,程序时boot+app,这里运行不起来指的是app


0x08049479 0000      MOVS          r0,r00x0804947B 0100      LSLS          r0,r0,#40x0804947D 3240      ADDS          r2,r2,#0x400x0804947F 4210      TST           r0,r20x08049481 0301      LSLS          r1,r0,#120x08049483 245D      MOVS          r4,#0x5D0x08049485 1AF4      SUBS          r4,r6,r30x08049487 01AA      LSLS          r2,r5,#60x08049489 1401      ASRS          r1,r0,#160x0804948B 7C39      LDRB          r1,[r7,#0x10]0x0804948D 5291      STRH          r1,[r2,r2]0x0804948F 32C8      ADDS          r2,r2,#0xC80x08049491 0206      LSLS          r6,r0,#80x08049493 071B      LSLS          r3,r3,#280x08049495 0332      LSLS          r2,r6,#12


回复

使用道具 举报

ID:583948 发表于 2025-2-25 09:36 | 显示全部楼层
1、keil生成的HEX文件可能仅包含有效代码段,而J-Flash反读时会以Flash扇区为单位读取,导致未使用的扇区尾部数据被包含进来,例如,STM32F407的Flash扇区大小为16KB或128KB,若原HEX文件结束地址在扇区中间,反读时会读取整个扇区,包含未写入的随机残留数据;
2、keil烧录时可能采用仅擦除代码占用的扇区,且不处理后续未使用的区域。J-Flash默认可能擦除整个扇区,导致未初始化的Flash区域被填充为随机值
3、在Boot+App架构中,App的中断向量表需要重映射到其起始地址,若反读的HEX文件在App区域后包含额外数据,可能导致中断向量表被覆盖或偏移错误,使得App无法响应中断

验证与解决
1、使用J-Link配合J-Flash的Memory Read功能,直接读取Flash中App区域的原始数据,与Keil生成的HEX文件逐字节对比,定位异常数据点
2、Keil调试模式下,单步执行App的启动代码(如Reset_Handler),确认栈指针(SP)和中断向量表地址(VTOR)是否正确加载。若SP指向无效地址,程序会立即崩溃
3、使用二进制工具(如HexView)对比Keil生成的HEX和J-Flash反读的HEX,确认多余数据的地址范围。手动裁剪反读的HEX文件,仅保留原HEX的有效地址段
回复

使用道具 举报

ID:1144404 发表于 2025-2-25 20:48 | 显示全部楼层
有未知格式,建议该换方案
回复

使用道具 举报

ID:1144305 发表于 2025-2-26 09:55 | 显示全部楼层
zpwgf 发表于 2025-2-25 09:36
1、keil生成的HEX文件可能仅包含有效代码段,而J-Flash反读时会以Flash扇区为单位读取,导致未使用的扇区尾 ...

谢谢大佬!
按照你的方法调试过程中,发现查找问题点有点偏离,我发现了个现象:
在我的工程里,有一个计算CRC的批处理文件,它生成完CRC之后会自动回填进hex,CRC地址是根据map文件来的,取的是ROM结束地址。
在全编译工程中,勾选这个bat文件,编译后hex显示以crc校验码截止;不勾选,编译后hex在crc之后就会有上述描述的多的一段数据。
(两次编译代码未进行改动,计算的crc的校验码一致)左边勾选编译,右边未勾选编译
ScreenClip.png
回复

使用道具 举报

ID:1144305 发表于 2025-2-26 10:02 | 显示全部楼层
批处理代码如下:
  1. @echo off
  2. ECHO Computing CRC
  3. ECHO -------------------------------------

  4. SET MAP_FILE=1.map
  5. REM::-------------------------------------get CRC address information line
  6. SET TMP_FILE=crc_temp.txt
  7. FINDSTR /R /C:"^  *CHECKSUM" %MAP_FILE%>%TMP_FILE%
  8. SET /p crc_search=<%TMP_FILE%
  9. DEL %TMP_FILE%
  10. REM::-------------------------------------CRC address
  11. for /f "tokens=1 delims=(" %%a in ("%crc_search%") do set crc_search=%%a
  12. SET crc_search=%crc_search:CHECKSUM=%
  13. for /f "tokens=1 delims= " %%a in ("%crc_search%") do set CRC_ADDR=%%a


  14. SET /a CRC_ADDR_END=%CRC_ADDR%+4

  15. set CRCA_START_ADDR=0x08020000

  16. REM::-------------------------------------CRC32  CRC校验范围 0x08020000 %CRC_ADDR%
  17. CRC_BIN\srec_cat.exe <font color="#ff0000">1.hex</font> -intel -crop %CRCA_START_ADDR% %CRC_ADDR%  -fill 0xff %CRCA_START_ADDR% %CRC_ADDR% -stm32-l-e %CRC_ADDR%  -o  BRMU\BRMU_checked.hex -intel -output_Block_Size 0x10
  18. CRC_BIN\srec_cat.exe 1.hex -intel  -crop %CRCA_START_ADDR% %CRC_ADDR% BRMU\BRMU_checked.hex -intel  -crop %CRC_ADDR% %CRC_ADDR_END%  -o  1.hex -intel -output_Block_Size 0x10
  19. CRC_BIN\srec_cat.exe 1.hex -intel  -crop %CRC_ADDR% %CRC_ADDR_END%  -byte_swap 4    -o  -hex-dump  
  20. del BRMU\BRMU_checked.hex

  21. ECHO -------------------------------------
  22. REM exit
复制代码


后面临时解决办法,不在原本的hex文件上进行填充,而是复制一份hex再修改,这样最后工程生成两个hex,如第一张图
  1. @echo off
  2. ECHO Computing CRC
  3. ECHO -------------------------------------

  4. <b><font color="#ff0000">copy 1.hex 2.hex</font></b>

  5. SET MAP_FILE=1.map
  6. REM::-------------------------------------get CRC address information line
  7. SET TMP_FILE=crc_temp.txt
  8. FINDSTR /R /C:"^  *CHECKSUM" %MAP_FILE%>%TMP_FILE%
  9. SET /p crc_search=<%TMP_FILE%
  10. DEL %TMP_FILE%
  11. REM::-------------------------------------CRC address
  12. for /f "tokens=1 delims=(" %%a in ("%crc_search%") do set crc_search=%%a
  13. SET crc_search=%crc_search:CHECKSUM=%
  14. for /f "tokens=1 delims= " %%a in ("%crc_search%") do set CRC_ADDR=%%a


  15. SET /a CRC_ADDR_END=%CRC_ADDR%+4

  16. set CRCA_START_ADDR=0x08020000

  17. REM::-------------------------------------CRC32  CRC校验范围 0x08020000 %CRC_ADDR%
  18. CRC_BIN\srec_cat.exe <font color="#ff0000">2.hex</font> -intel -crop %CRCA_START_ADDR% %CRC_ADDR%  -fill 0xff %CRCA_START_ADDR% %CRC_ADDR% -stm32-l-e %CRC_ADDR%  -o  BRMU\BRMU_checked.hex -intel -output_Block_Size 0x10
  19. CRC_BIN\srec_cat.exe 2.hex -intel  -crop %CRCA_START_ADDR% %CRC_ADDR% BRMU\BRMU_checked.hex -intel  -crop %CRC_ADDR% %CRC_ADDR_END%  -o  2.hex -intel -output_Block_Size 0x10
  20. CRC_BIN\srec_cat.exe 2.hex -intel  -crop %CRC_ADDR% %CRC_ADDR_END%  -byte_swap 4    -o  -hex-dump  
  21. del BRMU\BRMU_checked.hex

  22. ECHO -------------------------------------
  23. REM exit
复制代码
我猜这个批处理对hex进行处理的时候,去掉了后面那一段数据,但是不知道这个批处理代码该怎么修改?
但我还是很奇怪,map里显示0x080406C4已经结束,后面那一段的数据从哪里来的
51hei图片_20250226100256.png
麻烦您看看,xiexie!
回复

使用道具 举报

ID:1144305 发表于 2025-2-26 15:01 | 显示全部楼层
批处理代码如下:
  1. @echo off
  2. ECHO Computing CRC
  3. ECHO -------------------------------------

  4. SET MAP_FILE=1.map
  5. REM::-------------------------------------get CRC address information line
  6. SET TMP_FILE=crc_temp.txt
  7. FINDSTR /R /C:"^  *CHECKSUM" %MAP_FILE%>%TMP_FILE%
  8. SET /p crc_search=<%TMP_FILE%
  9. DEL %TMP_FILE%
  10. REM::-------------------------------------CRC address
  11. for /f "tokens=1 delims=(" %%a in ("%crc_search%") do set crc_search=%%a
  12. SET crc_search=%crc_search:CHECKSUM=%
  13. for /f "tokens=1 delims= " %%a in ("%crc_search%") do set CRC_ADDR=%%a


  14. SET /a CRC_ADDR_END=%CRC_ADDR%+4

  15. set CRCA_START_ADDR=0x08020000

  16. REM::-------------------------------------CRC32  CRC校验范围 0x08020000 %CRC_ADDR%
  17. CRC_BIN\srec_cat.exe <font color="#ff0000">1.hex</font> -intel -crop %CRCA_START_ADDR% %CRC_ADDR%  -fill 0xff %CRCA_START_ADDR% %CRC_ADDR% -stm32-l-e %CRC_ADDR%  -o  BRMU\BRMU_checked.hex -intel -output_Block_Size 0x10
  18. CRC_BIN\srec_cat.exe 1.hex -intel  -crop %CRCA_START_ADDR% %CRC_ADDR% BRMU\BRMU_checked.hex -intel  -crop %CRC_ADDR% %CRC_ADDR_END%  -o  1.hex -intel -output_Block_Size 0x10
  19. CRC_BIN\srec_cat.exe 1.hex -intel  -crop %CRC_ADDR% %CRC_ADDR_END%  -byte_swap 4    -o  -hex-dump  
  20. del BRMU\BRMU_checked.hex

  21. ECHO -------------------------------------
  22. REM exit
复制代码
后面临时解决办法,不在原本的hex文件上进行填充,而是复制一份hex再修改,这样最后工程生成两个hex,如第一张图
  1. @echo off
  2. ECHO Computing CRC
  3. ECHO -------------------------------------

复制代码
我猜这个批处理对hex进行处理的时候,去掉了后面那一段数据,但是不知道这个批处理代码该怎么修改?
但我还是很奇怪,map里显示0x080406C4已经结束,后面那一段的数据从哪里来的
51hei图片_20250226100256.png


麻烦您看看,xiexie!

回复

使用道具 举报

ID:866313 发表于 2025-2-27 02:54 | 显示全部楼层
以下内容由 DeepSeek R1 生成根据你提供的批处理脚本和现象分析,问题的核心在于 srec_cat工具对HEX文件的裁剪逻辑不完整,导致未勾选批处理时HEX文件中残留了编译器生成的填充数据,而勾选批处理时意外截断了这些数据。以下是详细分析和解决方案:


问题根源
  • 编译器填充行为  Keil编译器在生成HEX文件时,默认会根据Flash扇区大小(如STM32F407的16KB/128KB)对代码段进行填充,填充内容通常为0xFF或未定义值。这些填充数据在MAP文件中不会显示,但实际会存在于HEX文件中。
  • 批处理脚本的裁剪缺陷  你的批处理脚本通过srec_cat裁剪HEX文件时,仅保留了0x08020000到CRC_ADDR之间的数据,忽略了CRC_ADDR之后可能存在的填充数据。这导致:

    • 勾选批处理:生成的HEX文件仅包含有效代码和CRC,裁剪掉了填充数据。
    • 未勾选批处理:HEX文件保留编译器生成的填充数据,J-Flash反读时读取整个扇区,包含这些残留值。

  • Flash擦除差异  Keil烧录时可能仅擦除代码占用的扇区,而J-Flash默认擦除整个扇区,导致未初始化区域被填充为随机值(如0x00),覆盖了中断向量表或其他关键数据。



解决方案
修改批处理脚本,确保在计算CRC后,保留原HEX文件中CRC_ADDR之后的所有填充数据。以下是修正后的脚本关键步骤:
1. 修改srec_cat命令
将第二个srec_cat命令改为合并三部分数据:
  • 原HEX的CRC地址前部分 (0x08020000到CRC_ADDR)
  • 新生成的CRC部分 (CRC_ADDR到CRC_ADDR_END)
  • 原HEX的CRC地址后部分 (CRC_ADDR_END到Flash末尾)

REM 合并三部分:原HEX的CRC前部分 + 新CRC部分 + 原HEX的CRC后部分
CRC_BIN\srec_cat.exe ^
   1.hex -intel -crop %CRCA_START_ADDR% %CRC_ADDR% ^
   BRMU\BRMU_checked.hex -intel -crop %CRC_ADDR% %CRC_ADDR_END% ^
   1.hex -intel -crop %CRC_ADDR_END% 0x08080000 ^
   -o 1.hex -intel -output_Block_Size 0x102. 添加Flash范围参数
明确指定Flash的完整地址范围(如0x08000000到0x08080000),确保填充未使用的区域为0xFF:
REM 生成临时CRC文件时填充未使用区域
CRC_BIN\srec_cat.exe ^
   1.hex -intel ^
   -crop %CRCA_START_ADDR% %CRC_ADDR% ^
   -fill 0xFF %CRCA_START_ADDR% 0x08080000 ^
   -stm32-l-e %CRC_ADDR% ^
   -o BRMU\BRMU_checked.hex -intel

完整修正脚本 @echo off
ECHO Computing CRC
ECHO -------------------------------------

SET MAP_FILE=1.map
SET TMP_FILE=crc_temp.txt

REM 提取CRC地址
FINDSTR /R /C:"^  *CHECKSUM" %MAP_FILE% > %TMP_FILE%
SET /p crc_search=<%TMP_FILE%
DEL %TMP_FILE%

FOR /F "tokens=1 delims=(" %%a IN ("%crc_search%") DO SET crc_search=%%a
SET crc_search=%crc_search:CHECKSUM=%
FOR /F "tokens=1 delims= " %%a IN ("%crc_search%") DO SET CRC_ADDR=%%a
SET /a CRC_ADDR_END=%CRC_ADDR% + 4

SET CRCA_START_ADDR=0x08020000

REM 生成包含CRC的临时文件,并填充未使用区域为0xFF
CRC_BIN\srec_cat.exe ^
   1.hex -intel ^
   -crop %CRCA_START_ADDR% %CRC_ADDR% ^
   -fill 0xFF %CRCA_START_ADDR% 0x08080000 ^
   -stm32-l-e %CRC_ADDR% ^
   -o BRMU\BRMU_checked.hex -intel

REM 合并原HEX的CRC前部分、新CRC部分、原HEX的CRC后部分
CRC_BIN\srec_cat.exe ^
   1.hex -intel -crop %CRCA_START_ADDR% %CRC_ADDR% ^
   BRMU\BRMU_checked.hex -intel -crop %CRC_ADDR% %CRC_ADDR_END% ^
   1.hex -intel -crop %CRC_ADDR_END% 0x08080000 ^
   -o 1.hex -intel -output_Block_Size 0x10

REM 清理临时文件
DEL BRMU\BRMU_checked.hex

ECHO -------------------------------------

关键改进点
  • 保留填充数据  通过-crop %CRC_ADDR_END% 0x08080000显式保留原HEX文件中CRC地址后的所有数据,避免截断编译器生成的填充。
  • 统一填充值  使用-fill 0xFF ...确保未使用的Flash区域被初始化为0xFF,避免J-Flash读取到随机值。
  • 完整Flash覆盖  指定Flash的完整地址范围(0x08080000为STM32F407VGT6的Flash末尾地址),确保操作覆盖整个空间。



验证方法
  • HEX文件对比  使用二进制工具(如HexCompare)对比Keil生成的原始HEX和批处理后的HEX,确认CRC地址后的数据是否一致。
  • Flash内容检查  在Keil调试模式下,通过Memory窗口查看CRC_ADDR之后的Flash内容,确认是否为0xFF或有效数据。
  • J-Flash烧录测试  使用修正后的HEX文件通过J-Flash烧录,验证App是否能正常启动。



通过上述修正,批处理脚本将正确保留编译器生成的填充数据,同时确保CRC校验码的完整性,解决J-Flash反读多余数据导致程序无法运行的问题。

回复

使用道具 举报

ID:879809 发表于 2025-3-8 11:11 | 显示全部楼层
读flash的软件又不知道哪里结束当然把全部内容读出来了。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表