硬汉嵌入式论坛

 找回密码
 立即注册
查看: 1481|回复: 4
收起左侧

[BOOT/IAP] 经验分享 STM32H7因未修改SCB->VTOR跳转失败

[复制链接]

1

主题

3

回帖

6

积分

新手上路

积分
6
发表于 2024-9-1 15:57:40 | 显示全部楼层 |阅读模式
先说结论无论是APP还是IAP,无论运行在哪个扇区,都要重新设置中断向量偏移SCB->VTOR。
环境:STM32H723,有两个程序APP1和APP3,分别在扇区0和扇区7,如下:



  
0x08000000
  
  
扇区0
  
  
APP1
  
  
0x08020000
  
  
扇区1
  
  
0x08040000
  
  
扇区2
  
  
APP2
  
(和APP1相同,中断向量偏移不同) 
  
  
0x08060000
  
  
扇区3
  
  
  
  
0x08080000
  
  
扇区4
  
  
  
  
0x080A0000
  
  
扇区5
  
  
  
  
0x080C0000
  
  
扇区6
  
  
  
  
0x080E0000
  
  
扇区7
  
  
APP3
  


目的:从APP1跳转到APP3,再从APP3跳转到APP1。
现象:当从APP1跳转到APP3程序一切正常,但从APP3跳回APP1程序异常。
排查过程:
首先把BootAddr0改为扇区7,上电从APP3跳转到APP1,发现也不行,RT-Thread初始化完成后进入main()函数马上异常。
然后我把APP1重新烧录到扇区2(程序中已经修了中断向量偏移),然后从APP3跳转过去发现能正常运行。
我又把BootAddr0改回扇区0(默认就是扇区0),上电直接运行APP1,一切正常。
一般boot0默认上电运行的就是扇区0的程序,我错误的以为APP1在扇区0不需要修改SCB->VTOR(如果没有跳转的操作确实不需要修改)。
当我的程序从APP3跳转到APP1,我以为SCB->VTOR会在APP1中自己改回来,实际情况是不开启USER_VECT_TAB_ADDRESS宏,程序是不会修改SCB->VTOR的,而 APP1是没开启这个宏的。
APP3已经把断向量表偏移SCB->VTOR修改了,跳转到APP1后没有更回来,导致异常:
APP3 - APP1异常.PNG
最终在APP1中开启宏定义USER_VECT_TAB_ADDRESS,修改中断向量偏移VECT_TAB_OFFSET为0解决。
#define USER_VECT_TAB_ADDRESS
#define VECT_TAB_OFFSET     0U
没开启这个宏上电能运行是因为系统上电后中断向量偏移默认是BOOT_ADD0映射的地址,在扇区0,而我的APP1也在扇区0,不需要偏移,所以程序能正常运行。


回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115488
QQ
发表于 2024-9-2 08:37:46 | 显示全部楼层
谢谢楼主分享。
回复

使用道具 举报

6

主题

68

回帖

86

积分

初级会员

积分
86
发表于 2024-9-2 16:39:15 | 显示全部楼层
我没有改这个宏,但是程序也会自动定位到偏移量
[C] 纯文本查看 复制代码
[16:33:11.473]收←◆[OK]###########   App is RUNNING!!!! @ 08040000
[OK]####CPU : STM32H743IIT6 @ 480MHz
回复

使用道具 举报

22

主题

182

回帖

248

积分

高级会员

积分
248
QQ
发表于 2024-9-2 17:55:54 | 显示全部楼层
这个有两种方式
其一是像楼主说的那样,在 void SystemInit (void) 函数定义的源码文件中开启宏定义 USER_VECT_TAB_ADDRESS ,并修改中断向量偏移 VECT_TAB_OFFSET ,这样将“修改中断向量表偏移”这个操作集成进厂家提供的上电配置流。

其二是硬汉大哥的bootload教程中提供的,在main函数的最开头,一切外设配置前调用一个自己包装的函数进行手动修改。
我倾向于第二种做法,这样可移植性更强,用任何芯片都拉一个这个函数并且按步骤配置,

[C] 纯文本查看 复制代码
/**
  * @brief 关闭并清除所有中断
  * @param None
  * @retval None
*/
void InitNVIC(void)
{
    uint32_t i = 0;
    __set_PRIMASK(1); // 关闭全局中断

    /* 关闭滴答定时器,复位到默认值 */
    SysTick->CTRL = 0;
    SysTick->LOAD = 0;
    SysTick->VAL  = 0;

    /* 关闭所有中断,清除所有中断挂起标志 */
    for(i = 0; i < 8; i++)
    {
        NVIC->ICER[i] = 0xFFFFFFFF;
        NVIC->ICPR[i] = 0xFFFFFFFF;
    }

    /* 设置中断向量表偏移量 */
    SCB->VTOR &= 0xFFF00000;
    SCB->VTOR |= 0x00020000;

    __set_PRIMASK(0); // 打开全局中断
}


回复

使用道具 举报

1

主题

3

回帖

6

积分

新手上路

积分
6
 楼主| 发表于 2024-9-3 20:12:50 | 显示全部楼层
yono 发表于 2024-9-2 17:55
这个有两种方式
其一是像楼主说的那样,在 void SystemInit (void) 函数定义的源码文件中开启宏定义 USER_ ...

第二种方法是稳妥的,感谢分享!
回复

使用道具 举报

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

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-4-28 17:22 , Processed in 0.255177 second(s), 32 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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