[STM32F4] STM32F407 Bootloader 问题

[复制链接]
246|38
没有太阳的晴天 发表于 2026-9-4 11:12 | 显示全部楼层
对比F103和F407的启动文件,F407的 SystemInit 会设置 SCB->VTOR 为向量表地址,但你跳转前没有禁用 SCB->VTOR 的当前设置,应用固件里再次设置时可能被硬件保护导致写入无效。
海滨消消 发表于 2026-9-4 12:59 | 显示全部楼层
你判断的是 ApplicationAddress_Firmware 也就是0x80E0000处的栈顶指针,但该地址存放的是升级固件,而你的应用固件实际在0x8008000,你逻辑混了:RTC标志有效时你跳转升级区,无效时跳转应用区,两个分支用不同地址是对的,但两个地址里至少有一个没烧录正确内容。
甜心puppy 发表于 2026-9-4 14:18 | 显示全部楼层
0x2FFE0000这个掩码是用来判断栈顶地址是否在内部SRAM范围0x20000000~0x20020000内的,F407的SRAM大小是192KB,最大到0x20030000,你的掩码排除了一部分合法区间,导致某些栈顶地址被误判无效。
等凌晨日出 发表于 2026-9-4 16:16 | 显示全部楼层
你用了RTC备份寄存器存跳转标志,但这个寄存器在F407上需要开启PWR和BKP时钟才能正常读写,你的 BKP_Init() 可能没完全使能时钟,导致读到的0xA5A5是随机的。
茉璃夏 发表于 2026-9-4 18:00 | 显示全部楼层
升级固件放在0x80E0000,但F407的Flash总共只有1MB,0x80E0000距离末尾只有128KB,如果你的升级包超过这个大小,烧录时已经覆盖了后面的保留区。
豌豆爹 发表于 2026-9-4 19:54 | 显示全部楼层
跳转前你应该用 __DSB() 和 __ISB() 指令做指令同步,F407的流水线比F103深,直接改SP再跳转会导致预取队列里还残留boot的指令,执行到非法地址。
进入猫次元 发表于 2026-9-4 21:20 | 显示全部楼层
你在判断通过后先读 JumpAddress 再设 MSP,但 Jump_To_Application 这个函数指针本身位于栈上,你改了MSP之后栈指针变了,再调用函数指针时返回地址被破坏
麻花油条 发表于 2026-9-4 22:55 | 显示全部楼层
F407的向量表里第二个字是复位地址,这个地址必须是奇数(Thumb模式),你读出来的 JumpAddress 如果最低位是0,跳转时CPU会进入HardFault,你的代码里没有检查这个最低位。
classroom 发表于 2026-9-5 13:10 | 显示全部楼层
你的应用固件里 VECT_TAB_OFFSET 定义为0x8000,但这个宏在F407的 system_stm32f4xx.c 里默认是0x0,如果你没有在编译时重新定义,实际编译出来的向量表还是放在0x0。
cr315 发表于 2026-9-5 10:17 | 显示全部楼层
建议用调试器直接读地址0x8008000的内存内容,看第一个字是不是0x2001xxxx格式,如果不是,说明你的应用固件链接脚本里FLASH起始地址没有改成0x8008000。
duo点 发表于 2026-9-5 16:34 | 显示全部楼层
你的boot代码没有禁用全局中断 __disable_irq(),跳转过程中如果发生SysTick中断,ISR地址在boot区但此时已跳转,程序计数器混乱导致复位。
flycamelaaa 发表于 2026-9-5 21:56 | 显示全部楼层
同样的boot逻辑在F103上正常,但F407的Flash控制器有ART加速器,预取缓冲可能在读向量表时返回了缓存中的旧数据,建议在判断前先调用 FLASH_ART_Disable() 关闭加速再读。
DreamWanderer 发表于 2026-9-4 11:56 | 显示全部楼层
看样子是栈顶地址的问题,你检查一下是否栈溢出到了CCM区域,或者检查一下CCM内存是否正确配置。我之前遇到过类似情况,是通过重新分配栈内存空间解决的。
Bowclad 发表于 2026-9-5 11:56 | 显示全部楼层
VECT_TAB_OFFSET设对,但还要检查链接脚本IROM1起始地址是否改对。F407栈配置要注意,可能用到CCM内存。
有何不可0365 发表于 2026-9-6 21:05 | 显示全部楼层
楼主代码里有个致命隐患,跳转前没关中断。虽然你后面写了__set_MSP,但如果跳转瞬间正好有个定时器中断来了,CPU就会用新的MSP去跑中断向量表里的旧地址,直接HardFault。建议在Jump_To_Application之前加一行__disable_irq(),或者把NVIC的所有中断都Disable掉再跳
漫天星yl 发表于 2026-9-7 10:05 | 显示全部楼层
关于0x2FFF0000这个地址,这是STM32F407内置的System Memory(出厂Bootloader)区域。你这样写逻辑没问题,但要注意,如果你的应用代码里不小心触发了系统复位且BOOT0引脚电平不对,可能会意外跑回这里。建议加个标志位判断,比如检测某个特定RAM区域是不是0xdeadbeef,是的话才允许跳转到System Memory,防止误操作
t61000 发表于 2026-9-8 11:15 | 显示全部楼层
你的ApplicationAddress定义是0x08010000,这意味着你的应用工程Linker Script里的FLASH起始地址必须也是0x08010000。很多新手只改了C代码里的跳转地址,忘了改应用工程的scatter file或者ld文件,导致编译出来的bin文件头还是0x08000000,烧进去肯定跑飞
kqh11a 发表于 2026-9-9 09:06 | 显示全部楼层
那个typedef void (*pFunction)(void)定义最好加上__noreturn属性,或者在调用Jump_To_Application后加个while(1);死循环。虽然理论上不会返回,但编译器优化有时候会乱猜,万一它以为函数会返回并尝试恢复上下文,栈指针早就变了,必死无疑
wailian1265k 发表于 2026-9-11 10:12 | 显示全部楼层
F407的Flash如果有读保护(RDP Level 1或2),跳转到System Memory可能会受限。如果你之前开过读保护,记得先解锁或者确认权限。另外,跳转前最好把用到的所有外设时钟都复位一下,特别是GPIO和UART,不然应用层初始化时可能会因为寄存器残留状态而卡住
caoyunhj2301 发表于 2026-9-13 12:07 | 显示全部楼层
你的代码里判断((uint32_t)ApplicationAddress & 0x2FFFE000) == 0x20000000这句有点多余且危险。Stack Pointer指向SRAM是正常的,但没必要校验这么死。万一你的应用用了外部SRAM或者MPU重映射了内存,这个判断就会失败。直接判断前四个字节是不是有效的指令地址(比如最高位是1,Flash地址都在0x08xxxxxx)更稳妥
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部