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

【经验分享】STM32F0 不同代码区跳转时总失败…这些操作你做对了吗?

[复制链接]
STMCU小助手 发布时间:2022-2-26 16:47
对于 STM32 用户,经常会涉及到通过用户启动程序实现对用户应用程序的更新升级。一般来讲,用户启动程序主要用来跟外界通信,获取新的用户程序代码并实现对用户代码区的应用程序升级。用户应用程序是指实现各种用户功能的代码。
. a, d# V/ z7 r  K- a" n在这个过程中,往往需要做从用户引导程序区(以下简称【BOOT 区】)到用户应用程序区(以下简称【APP 区】)的跳转,有时可能还需实现从用户应用程序区跳回到用户启动程序区,甚至不同用户程序区的互相跳转等操作。在这些跳转过程中,常常有人的开发工作在此遇到阻碍,甚至破费周折。
/ U3 b& R" ^0 |4 s' Z- D
' }4 e$ Y; J/ D) KSTM32F0 代码区跳转
; \! P2 i+ Q4 m- z在此我们以 STM32F0 为例,就芯片内不同程序区的跳转问题做些交流与介绍,限于篇幅,这里仅直接介绍具体操作和注意事项,不做过多拓展介绍。相关知识点可阅读 STM32 芯片参考手册、STM32 相关内核编程手册。% r9 X& t% E1 }3 w

5 E9 Y4 D6 a# Y1 D3 n( |  k下面介绍中提及的集成编译环境是指 ARM MDK,硬件基于 STM32F072RB Nucleo 开发板。后面我将逐一介绍不同跳转操作的基本流程和注意事项,涉及以下三种情况:/ `: _, X  D6 T; `
 从【BOOT 区】跳转到【APP 区】6 M: z5 @8 p# x2 [
 从【APP 区】跳转到另外新【APP 区】
6 {2 B* b5 V  @2 B; Y+ e 从【APP 区】跳回【BOOT 区】
7 o- L  A% [& a1 P* b) w7 Y一般来讲,不同区段的执行代码我们通过建立不同的工程项目来实现,最终将不同区段执行代码写入芯片。这里假定 BOOT 区对应的内部 FLASH 地址段为 0x8000000—0x8004000,APP1 区对应的内部 FLASH 地址段为 0x8004000—0x8008000, APP2 区对应的内部 FLASH 地址段为 0x8008000—0x800C000.! k1 s! G  X3 Z9 |( N

' }3 h9 U3 d8 \; W( g 0GN(9UI)P~PEX[EH{(0QA(3.png
$ ~5 D% x7 Z- a9 n" D) a# e# l* S/ d* F  p) J
从【BOOT 区】跳转到【APP 区】
: e( q- y2 B. z+ o& v6 c, G+ C
9 G6 }4 K8 H- y3 l* Y6 t先说从 BOOT 区跳转到 APP 区。这个跳转代码比较简洁、简单,注意跳转前要关闭刚才程序区开启过的所有中断使能,保证所有中断请求位都被清除,不是简单的关闭总中断,否则往往隐患多多。BOOT 区相关跳转代码如下:: F9 L5 W; p$ ^7 n
  1. If ( Jump_Condition Satisfied )
    7 r3 g0 m5 [- A  _, z$ x
  2. { if(((*(__IO uint32_t*)APPLICATION_ADDRESS_APP) & 0x2FFE0000) == 0x20000000)
    8 \8 z& z. b9 `! r- z% a$ w
  3. { /* Jump to user app */
    6 [# d  M: p; g, Q
  4. JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS_APP + 4+ V- i3 }& t1 O4 w" K1 }+ W
  5. JumpToApplication = (pFunction) JumpAddress;: [0 ~; S2 @% W
  6. __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS_APP);
    ! W1 ^$ _2 Z8 a' i( {
  7. JumpToApplication();
    9 z( Z5 Q" _* t' [/ m
  8. }
复制代码
! s3 d! f6 e+ C
这个从 BOOT 区到 APP 区的跳转最终能否成功,关键还是取决于 APP 区代码相关配置及准备工作。假设这里的 APP 区是上面提到的 APP1 区,内部 FLASH 地址段为 0x8004000—0x8008000,那么在 MDK 的 option 项里的 memory 配置板块要做正确配置,即 flash 空间与 ram 空间的配置,如下图所示:
0 v$ f3 n9 y# s$ Z5 b% d
0 p% j! L1 q# w2 O8 `8 P S16[CYC[)F5H{){R8PQ376H.png
3 l! G/ k. m: T/ U5 m! ~' y0 b% V- ?* F4 o
IROM1 的配置就是 APP1 代码摆放的起始空间地址及长度。IRAM 的配置要注意先保留 48个字的空间用来存放中断矢量表的内容。因为 stm32F0 芯片的中断矢量表的大小就是 48个字(即 0xc0 字节)。至于剩下的内部 RAM 空间大小由芯片本身的 RAM 容量决定(这里是基于 STM32F072RB 芯片,其内部 RAM 总容量为 0x40000)。
, D5 t- V$ i& Q1 ~) w! E' U& H3 v# W
另外一件很重要的事情就是做中断矢量表的拷贝。在 APP1 区的 main()程序开头部分,将放在 flash 程序空间起始部分的连续 48 个中断矢量地址表拷贝到内部 RAM 的起始地址段。即将矢量表从 0x8004000 地址开始拷到 0x20000000 开始的连续 48 个字空间(前面提到的存储配置正是为了配合这个拷贝操作)。基于 MDK 环境的参考代码如下:
0 ^$ C# m. t2 j3 a' ^2 q; G: T/ K

' j; @6 @* {/ D) e+ E/ B0 _
  1. #define APPLICATION_ADDRESS4 (uint32_t)0x080040007 r4 A, }( `8 F* [% C
  2. __IO uint32_t VectorTable[48] __attribute__((at(0x20000000)));8 D. J6 @: L4 M4 P
  3. int main(void)
    " j3 @" o1 \6 T3 r/ ^
  4. { HAL_Init();
    ) \, C0 ~! g4 s: Q  e
  5. SystemClock_Config();; x1 M0 |/ A3 }8 y- G0 H
  6. for(i = 0; i < 48; i++)
    ; A( u: _; s3 V4 B4 n
  7. { VectorTable[i] = *(__IO uint32_t*)(APPLICATION_ADDRESS4 + (i<<2)); }
    * i( l! O; g# T( u
  8. /* Enable the SYSCFG peripheral clock*/. B4 e) W# v3 B' _$ Y" J
  9. __HAL_RCC_SYSCFG_CLK_ENABLE(); //使能 SYSCFG 外设
    ) r# f2 J4 L! v( L
  10. __HAL_SYSCFG_REMAPMEMORY_SRAM();//将内部 SRAM 映射到 0x00000000 地址2 C4 l# e5 b, w+ e
复制代码

8 M. p* F# A5 \) v9 B8 k7 @8 D* \& L
3 S. O2 [9 w6 F 。。。。。。 后面为用户功能代码。。。。。。
5 l, Y+ f6 l2 M) k, a$ p
# _9 g9 ^' |0 o! Y$ F# S: d8 Y上面代码中绿色语句就是实现中断矢量表从内部 flash 到内部 RAM 的拷贝,而红色语句则是为了实现将程序执行的 0 地址域的重映射,即将程序运行的 0 地址从内部 flash 的0x8000000 通过重映射机制切换到 0x20000000,为的是在 APP1 区发生中断时 CPU 能从正确的地方准确获取相应中断矢量地址去执行中断服务程序。 $ k: H8 T! P& m4 q

  d, v- y6 B3 d  {到此,从 BOOT 区跳转到 APP1 区就算完成了。
/ k' E6 o1 O6 }: N
! q9 z. x6 F3 c, V$ b' k" |) ^从【APP 区】调转到新【APP 区】 7 L- h* t8 @. j! P& X7 p

9 @( l9 H0 l( N  Z! |4 U" G那么,如果想从 APP1 区跳转到另外 APP2 代码区呢?这个跟从 BOOT 区跳转到 APP1 区类似。在 APP1 区的跳转代码这里就不说了,地址给对、代码写对就好。APP2 区的代码也同样必须做中断矢量表的拷贝和 0 地址域的重映射。但因为在 APP1 代码里已经做过了 0 地址的重映射,所以就不必重复做了。
9 B# `2 x9 C2 b$ I
6 d0 u0 h+ v: `5 N8 a$ F: ^假定 APP2 代码区的内部 flash 空间安排在为 0x8008000—0x800C000。则 MDK 里 memory布局配置如下:$ l0 R' Y* q% G: h' s+ t) o9 l

3 N, G1 L9 C; }1 h8 y )`S(%VOK7T7X45BX3C`C6.png
1 N) l3 ?7 B5 K8 E5 X  n( |& X- }2 A2 {7 Q
从【APP 区】跳转到【BOOT 区】- n3 z% H5 W' h! ~9 c
! `# B, T2 Y/ s3 R/ I/ e
有时我们还希望或需要程序能从 APP 区跳回用户 BOOT 区,那如何操作呢?对于 STM32F0芯片而言,程序执行区从 APP 区跳回 BOOT 区跟从 BOOT 区跳到 APP 区还不太一样,经常有人在这个跳转过程中卡壳,对于跳得出而跳不回感到难以理解。  W4 a) l( r9 C- O* ?, S
$ w% K( X/ y5 C# U8 p( W+ x: i
假设从 APP2 区跳回 BOOT 区,在 APP2 区做跳转准备时除了给定正确的跳转地址外,另一个要做的就是将之前通过重映射将 0 地址程序空间从内部 SRAM 切换回内部 flash 区。实际应用中,我们往往因为忽视了这点,跳回去后一碰到中断就问题来了。另外,从 APP' ]# B9 B2 G: T* P
区跳回 BOOT 区无须矢量表的拷贝操作。所以在 APP2 区执行跳转前需将 0 地址重映射回内部 flash 空间,通过运行如下库代码完成:
+ E9 l" ~: d1 \) I
: G2 e% W7 U8 [) n% O0 b__HAL_SYSCFG_REMAPMEMORY_FLASH();
0 t9 E1 N8 R2 [  W; m! R: O5 P; f- r0 S
几点重要经验总结
! k. ^( ?+ q$ ?1 T' ~/ v9 m* b( Z1 ?# U1 R/ H) g7 v
通过以上几种不同情况下操作过程的描述,我们可以知道,想要避免 STM32F0 在代码调转中出错,应该遵循以下几条关键的经验:
7 ]9 P5 \! b' R2 m& _
+ Y7 U" }/ J+ Z; T4 `2 K 从【BOOT 区】跳转到【APP 区】,在【APP 区】要做中断矢量表的拷贝和将 0 地址从内部 flash 切换到内部 SRAM 起始地址。1 X6 y: e3 y& f1 X
1 c% Z; Q" ?5 ^
 从【APP 区】跳转到其它新的【APP 区】,只需在新的【APP 区】的代码里再做中断矢量表的拷贝,并保证相关存储配置的正确。* S7 z# y1 ~. C" H- ?

8 ?" {+ l  p$ O8 ? 从【APP 区】跳回【BOOT 区】,该过程无矢量表的拷贝,只需将 0 地址执行域重新映射回内部flash 区。7 }9 Q" F3 _- x2 l  x

5 X+ A* h! O) J* g" b* l6 C 不论从什么区跳往什么区,跳转前禁用当前用户打开过的所有中断使能、确保无未处理的中断请求存在或在跳转过程中发生中断。; N! [% {/ p) e/ e1 m; o

- e" x: v9 u6 S 以上操作流程主要针对基于 COMTEX M0 内核的 STM32F0 系列芯片。4 q" h* _0 g5 @; f7 |" G

" C% ^! s, v) I& p! a3 v; V5 e4 \+ E  Z1 q
( y5 J5 u. K$ M7 d

9 d' C' `5 k7 J6 N
, u7 k; h1 g/ k- _+ y
* r' G* p) Y, u+ S7 {. i& |: \2 C8 O
- x2 n. l2 S2 \$ t, t6 X; P8 _  w/ z2 X0 J1 r- n  n' E: ?

) p! C8 I4 K3 }. m* b. p
) @' E6 Y3 U# r$ o% n5 \" V
/ \' e" J( X" }' V
# ^, a& P" L' Y3 Z4 D: {; B
/ t8 ~3 Y3 ~) k# c/ v
收藏 评论0 发布时间:2022-2-26 16:47

举报

0个回答

所属标签

相似分享

官网相关资源

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