你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

高级篇——STM32在线升级之中断向量重定向深度剖析

[复制链接]
eefishing 发布时间:2019-12-19 23:53
在做stm32 iap升级固件的时候通常需要多份中断向量表。比如bootloader的中断向量表在0x00000000位置,应用程序的中断向量表则会放在flash的另一个地方或者是放在RAM中运行。

+ d6 O+ `% [4 G0 F! h/ ^2 Q# r# p+ C
要维护向量表位置就需要用VTOR这个东西,那么就要先从VTOR来聊聊, 先弄清这个东西又是干嘛的。
% f% e9 k6 G9 f  q3 s" u, T9 @
VTOR是arm内核的一个寄存器,叫做中断向量偏移量寄存器。当系统上电启动的时候CPU会从先找到中断向量表的位置,然后从表中找到复位中断Reset_Handler,而main函数的执行实际上就是在复位中断函数中的。如下汇编代码就是复位中断服务函数,该函数在启动文件中定义。在Reset_Handler 中会执行__main(),而main函数又是被__main()调用了。
* n/ D. J1 M$ M9 L; A+ ~9 _: a
Reset_Handler    PROC( E  S) R5 s/ L# U, Q" H
                 EXPORT  Reset_Handler                 [WEAK]
% K! s9 c" |5 O        IMPORT  __main4 E3 k6 J5 S) J: S7 j0 J7 E
        IMPORT  SystemInit/ q& u* N7 X7 |4 I8 k& w! V* V
                 LDR     R0, =SystemInit
3 R  g! w) K" p" p; A                 BLX     R0
1 ~1 E( I9 }" s                 LDR     R0, =__main6 ]" |; s: O9 u, E( K$ M4 ~
                 BX      R0
" U4 x, Y' O6 ]1 Z* d2 h/ r                 ENDP' Q0 `# z, a* ~$ q4 t# J$ B- ^
6 z8 x, C$ c: A. ]- w  U/ ?/ {

% F7 _, e1 K/ b; i6 d1 i
前面复习一下ARM处理器启动到执行main的一个大概流程。再回归正题继续探讨这个VTOR。当来一个中断时,cpu就会从0x0000000+VTOR位置找到中断向量表,然后再查表跳转到对应的中断服务函数去执行。所以你代码里面存在多份中断向量表是可以的,只需要动态改变VTOR的值就可以了。
3 d" _9 q) F0 w0 K3 r: j

3 Y& i  V0 Y5 n2 F+ e
APP的中断向量放在flash中:
; o1 [  z+ B  X! y
如下图所示,在运行bootloader的时候用的是他自己的bootloader,当从bootloader跳转到app以后就需要用app的向量表了。所以进入APP的首要任务就是设置VTOR值为0x0x8001000,再产生中断的时候让cpu去app的向量表里找中断服务函数入口。
/ O) K/ A6 O! }" Z1 O$ @: K

/ d$ H( q7 F# _0 V$ c
所以从在app中重定义向量表是不是很简单。但是有个前提,就是要有VTOR寄存器。实际上,并不是所有stm32都带有VTOR的。准确的说是因为ARM-CORTEX-M0内核的芯片没有,所以stm32F0系列所采用M0内核的芯片就没有VTOR。但是还有需要注意的就是L0系列使用的M0+内核和M0内核又是不同的,是有VTOR的。

( k8 {7 v' P# P/ ?0 E" Q  g/ U
这就意味着stm32F0系列没有办法使用这种简单的修改VTOR的方式重新定位APP的中断向量表。那肯定还有其他思路,就是稍微麻烦一点。
& W7 c+ `4 F3 p; M" t- e* |
中断向量放在RAM中:
那就是把中断向量表放在RAM中去,并且针对F0没有VTOR的还必须把中断向量表拷贝到RAM的起始地址。

9 _" ~6 O; C8 O6 o3 Q, s
为什么这样做,因为前面我们提到过CPU默认会认为0x00000000处放的就是向量表。那么我们换种思路可以把RAM的地址映射到0x00000000处。这个通过配置SYSCFG寄存器的MEM_MODE就可以把RAM地址映射到0x00000000处。
  N1 m) V& N! s: F0 d9 q& E

4 a5 s3 A) @6 n6 L& U) y4 F' o
这时候再进入到APP以后首要任务就是把APP的中断向量表拷贝到RAM的起始地址,并且修改MEM_MODE位。
/ B+ g6 t+ I) l+ Y7 k0 @
在代码里面比较简单的做法就是在ram起始地址处定义一个数组,上电以后把向量表拷贝到这个数组中。如下代码是在MDK中定义的方法,在IAR或者GCC定义的方式会有区别。
- A, Z) Z3 f8 _  B6 {& h" d8 y
__IO uint32_t vector_t[48 __attribute__((at(0x20000000)));0 t& A) a/ j( h' ^- I$ U" X9 `# X. \

9 @8 |% `% @0 V! _7 D: i7 {) \
- @! m. {  \, ^  p) Z0 r* M+ i6 G
但是要编译通过还需要在mdk配置里面把ram的起始地址设置为0x200000c0,前面的0xc0的空间腾出来存放定义的这个数组。
3 ~" S5 O! A, e- h2 E. h- @( B
有VTOR的系列向量表放在RAM中
stm32F0系列内核决定了即便把向量表放在RAM中也只能放在RAM的起始位置而不能任意放。但是有VTOR的型号就可以随便放。这样分配存放向量表的数组也可以不用定位在0x20000000位置了。可以如下方式定义:
3 V) V4 W- j6 H# w8 @5 P. O
__align(256) uint32_t vector_t[48];
3 J4 f7 q+ @( i* ]3 G! `2 P- w2 E+ ]) Z3 @1 O1 j
5 w' q9 W* N6 P. C& Q1 [, R
可以看到虽然没有了必须放在ram起始地址的限制,但是还是要遵守一定的规则。就是对齐有要求的。比如L0系列有48个中断向量,一共占用内存为48*4=192bytes。扩大为2的整次方为256:28=256。所以就要求向量存储的地址必须是256对齐的。存放在0x0或者0x20000100都可以满足要求。
: \/ F; x' N! }: C+ j; Z9 Y- E* L
另外这种方式虽然更灵活了一些,但是却造成了一定RAM空间的浪费。我在这样定义编译以后查看MAP文件如下,红色的区域空出来的一段内存空间就会被浪费掉:
$ {/ a: o& U! T

( V# M% s8 I! U- T" `" }) Y
关于0X00000000地址
; K" I1 t3 ^$ `$ {
前面说过默认cpu会从0x00000000地址来取向量表,那么stm32的flash都是从0x8000000地址开始的,这时候不设置VTOR偏移为什么也可以正常运行。实际上当从用户flash启动的时候,从0x8000000或者0x00000000访问的都是同一片区域。所以cpu从0x0取向量表相当于取的就是0x8000000地址处的数据。
2 K5 p, R1 o" L5 g: D5 F
更进一步理解,stm32通过配置boot脚(或者SYSCFG中MEM_MODE位)有三种启动模式选择,这三种模式的本质就是看把那个区域重映射为0x00000000地址。这样CPU取第一条指令就是从哪里取:

" \* [" P/ s+ O+ v
  • 从用户flash区启动,用户flash起始地址被映射到0x00000000上
  • 从系统flash区启动,系统flash起始地址被映射到0x00000000上,上电就执行内置的bootloader
  • 从RAM区启动,RAM起始地址被映射到0x00000000上,这时候你再回过去看我刚才说的F0无VTOR寄存器实现IAP就是这样的思路。向量表放在了RAM区域的起始地址。
    ! Y' K# {' S. v( T7 n
收藏 2 评论0 发布时间:2019-12-19 23:53

举报

0个回答

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版