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

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

[复制链接]
STMCU小助手 发布时间:2022-2-26 16:47
对于 STM32 用户,经常会涉及到通过用户启动程序实现对用户应用程序的更新升级。一般来讲,用户启动程序主要用来跟外界通信,获取新的用户程序代码并实现对用户代码区的应用程序升级。用户应用程序是指实现各种用户功能的代码。9 A/ l/ m2 q$ P% ^( v2 s6 h6 P4 T
在这个过程中,往往需要做从用户引导程序区(以下简称【BOOT 区】)到用户应用程序区(以下简称【APP 区】)的跳转,有时可能还需实现从用户应用程序区跳回到用户启动程序区,甚至不同用户程序区的互相跳转等操作。在这些跳转过程中,常常有人的开发工作在此遇到阻碍,甚至破费周折。+ `9 Z3 F! }8 I+ Y+ F. s

7 t  X( l6 G; J7 r& j: \. C5 |) u" l9 ]STM32F0 代码区跳转# x$ ?* o8 M, \; {
在此我们以 STM32F0 为例,就芯片内不同程序区的跳转问题做些交流与介绍,限于篇幅,这里仅直接介绍具体操作和注意事项,不做过多拓展介绍。相关知识点可阅读 STM32 芯片参考手册、STM32 相关内核编程手册。
- {: Y* o  {: P! H( l6 u: U% C4 _
+ j5 E% M" a" U: f) i, ^下面介绍中提及的集成编译环境是指 ARM MDK,硬件基于 STM32F072RB Nucleo 开发板。后面我将逐一介绍不同跳转操作的基本流程和注意事项,涉及以下三种情况:
/ m. n& _/ T) u4 U$ |# c5 J$ H8 Q$ _ 从【BOOT 区】跳转到【APP 区】
$ q# @8 M+ X- T5 a' ~& U 从【APP 区】跳转到另外新【APP 区】- }$ I# o: ], i  b( a
 从【APP 区】跳回【BOOT 区】0 d8 r5 p; z3 g2 E4 d7 c2 m. H6 }
一般来讲,不同区段的执行代码我们通过建立不同的工程项目来实现,最终将不同区段执行代码写入芯片。这里假定 BOOT 区对应的内部 FLASH 地址段为 0x8000000—0x8004000,APP1 区对应的内部 FLASH 地址段为 0x8004000—0x8008000, APP2 区对应的内部 FLASH 地址段为 0x8008000—0x800C000.
2 |3 {" x. a5 x: x7 M2 K
) r& s0 D3 p9 m0 `* x 0GN(9UI)P~PEX[EH{(0QA(3.png % p! i  z) i' a4 m) q$ n- g$ ^

8 q" Q! \2 Z$ J; w. l$ L从【BOOT 区】跳转到【APP 区】/ l6 G; a5 v) H" o; W
  r. s( i; r7 f3 S# q: k4 B  f
先说从 BOOT 区跳转到 APP 区。这个跳转代码比较简洁、简单,注意跳转前要关闭刚才程序区开启过的所有中断使能,保证所有中断请求位都被清除,不是简单的关闭总中断,否则往往隐患多多。BOOT 区相关跳转代码如下:% b9 u. Y0 [( `! y( S; Q, S
  1. If ( Jump_Condition Satisfied )
    , Y1 q& u5 K3 P+ r) G9 W
  2. { if(((*(__IO uint32_t*)APPLICATION_ADDRESS_APP) & 0x2FFE0000) == 0x20000000)
    4 _& l: ^& ?- D# b' G- h
  3. { /* Jump to user app */$ L3 v- K6 X" J+ d. y! H" E
  4. JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS_APP + 4, Y  r; [5 R0 W% Y
  5. JumpToApplication = (pFunction) JumpAddress;% s+ f. V% u* s/ d/ B6 I
  6. __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS_APP);' m# E% C7 H5 n( \9 w4 r) H+ ^
  7. JumpToApplication();3 |" b: Z% [( V5 ?' N7 M, z
  8. }
复制代码

  i4 c% y4 b6 b4 N$ P这个从 BOOT 区到 APP 区的跳转最终能否成功,关键还是取决于 APP 区代码相关配置及准备工作。假设这里的 APP 区是上面提到的 APP1 区,内部 FLASH 地址段为 0x8004000—0x8008000,那么在 MDK 的 option 项里的 memory 配置板块要做正确配置,即 flash 空间与 ram 空间的配置,如下图所示:
. H$ Y2 D, F: A! E
5 G* s) F; Q3 ` S16[CYC[)F5H{){R8PQ376H.png * x4 g6 B0 q) `# G3 @/ r+ T) r  x( G! I

: o7 E: I( D  m1 T' d8 f$ [9 V5 RIROM1 的配置就是 APP1 代码摆放的起始空间地址及长度。IRAM 的配置要注意先保留 48个字的空间用来存放中断矢量表的内容。因为 stm32F0 芯片的中断矢量表的大小就是 48个字(即 0xc0 字节)。至于剩下的内部 RAM 空间大小由芯片本身的 RAM 容量决定(这里是基于 STM32F072RB 芯片,其内部 RAM 总容量为 0x40000)。
. [9 k# I. E. y4 z. e: g$ K# d9 I7 Q+ I+ C* c% O
另外一件很重要的事情就是做中断矢量表的拷贝。在 APP1 区的 main()程序开头部分,将放在 flash 程序空间起始部分的连续 48 个中断矢量地址表拷贝到内部 RAM 的起始地址段。即将矢量表从 0x8004000 地址开始拷到 0x20000000 开始的连续 48 个字空间(前面提到的存储配置正是为了配合这个拷贝操作)。基于 MDK 环境的参考代码如下:
( X: c) P, A7 |: X6 a1 w* D$ |: i9 y2 w" p, \6 F2 `8 b
- v; U! o) ~3 A) Z9 q
  1. #define APPLICATION_ADDRESS4 (uint32_t)0x080040003 Y3 n! V* a" [6 k  h. \+ G2 n
  2. __IO uint32_t VectorTable[48] __attribute__((at(0x20000000)));
    2 g% Q6 p2 d. j. G, _: I- G" x+ s4 [0 z
  3. int main(void)
    / [, }! ]' W7 G- G: h; {
  4. { HAL_Init();
    ( K( m8 a  Q7 w. J) e  C
  5. SystemClock_Config();
    ' S% K  s" ]4 e  C
  6. for(i = 0; i < 48; i++)
    ; D2 _  T* @3 S: W6 P* g2 g
  7. { VectorTable[i] = *(__IO uint32_t*)(APPLICATION_ADDRESS4 + (i<<2)); }8 y( c* r# P2 j! o. A, Y5 N) Q3 q
  8. /* Enable the SYSCFG peripheral clock*/
    7 _2 R6 u9 m0 a, {
  9. __HAL_RCC_SYSCFG_CLK_ENABLE(); //使能 SYSCFG 外设
    ' o" f; C$ w$ R. p2 S0 S  |  v
  10. __HAL_SYSCFG_REMAPMEMORY_SRAM();//将内部 SRAM 映射到 0x00000000 地址
    5 w- C& N6 [! B$ [5 P) r* h. d/ v
复制代码
' u5 O- E- J, I

8 U4 Q0 e4 `2 s4 `0 }$ k2 I. p7 ` 。。。。。。 后面为用户功能代码。。。。。。 0 U2 Q7 ]7 l, {! P' j# X3 k
6 x" [$ N; s8 l/ D" R: b
上面代码中绿色语句就是实现中断矢量表从内部 flash 到内部 RAM 的拷贝,而红色语句则是为了实现将程序执行的 0 地址域的重映射,即将程序运行的 0 地址从内部 flash 的0x8000000 通过重映射机制切换到 0x20000000,为的是在 APP1 区发生中断时 CPU 能从正确的地方准确获取相应中断矢量地址去执行中断服务程序。
. v8 K9 N# M, g) K/ B
) O- q5 n+ b3 D2 z$ G! R+ g8 t到此,从 BOOT 区跳转到 APP1 区就算完成了。
* ]; A! Y  y, D% C9 K8 F
; g+ k% I  }; E从【APP 区】调转到新【APP 区】 * I- _& Q. A! o& ~! l

# I) U) b8 t& C$ ~5 _- {那么,如果想从 APP1 区跳转到另外 APP2 代码区呢?这个跟从 BOOT 区跳转到 APP1 区类似。在 APP1 区的跳转代码这里就不说了,地址给对、代码写对就好。APP2 区的代码也同样必须做中断矢量表的拷贝和 0 地址域的重映射。但因为在 APP1 代码里已经做过了 0 地址的重映射,所以就不必重复做了。
3 c1 T1 k2 k& ^3 k  n/ X) r  m) T( F- V- B( y* Y! `* H8 x$ B
假定 APP2 代码区的内部 flash 空间安排在为 0x8008000—0x800C000。则 MDK 里 memory布局配置如下:$ o, u: K  W2 P  p' D+ \' F
6 K/ ^2 M, p+ a3 z
)`S(%VOK7T7X45BX3C`C6.png
5 v1 ^$ }' d- K9 @% `# u" q; \
9 H2 B7 K! K! k! ?从【APP 区】跳转到【BOOT 区】6 O/ N% K  j2 J7 h
  N2 c0 G: d" j' d3 ?! Y8 G
有时我们还希望或需要程序能从 APP 区跳回用户 BOOT 区,那如何操作呢?对于 STM32F0芯片而言,程序执行区从 APP 区跳回 BOOT 区跟从 BOOT 区跳到 APP 区还不太一样,经常有人在这个跳转过程中卡壳,对于跳得出而跳不回感到难以理解。
  O" @/ K7 g. A- B! A0 d  J! q- i4 a* q' b! M8 i- v' S
假设从 APP2 区跳回 BOOT 区,在 APP2 区做跳转准备时除了给定正确的跳转地址外,另一个要做的就是将之前通过重映射将 0 地址程序空间从内部 SRAM 切换回内部 flash 区。实际应用中,我们往往因为忽视了这点,跳回去后一碰到中断就问题来了。另外,从 APP2 S- _0 A3 U7 N) b
区跳回 BOOT 区无须矢量表的拷贝操作。所以在 APP2 区执行跳转前需将 0 地址重映射回内部 flash 空间,通过运行如下库代码完成:0 g# Z/ \; Q& B" K) e% d

" V" e8 y  S9 ]# M__HAL_SYSCFG_REMAPMEMORY_FLASH();6 _( ]4 H0 @, k; u& q" P
5 m* |1 o. N* W2 r  |  u! s4 i
几点重要经验总结% E/ s0 z' l' D
( s) y6 ], J' o0 K8 q, P
通过以上几种不同情况下操作过程的描述,我们可以知道,想要避免 STM32F0 在代码调转中出错,应该遵循以下几条关键的经验:; h& r8 J$ M: ]+ S7 J9 Q7 Q: e8 r7 `

4 n# _: h1 R8 ^1 m+ q& P" a 从【BOOT 区】跳转到【APP 区】,在【APP 区】要做中断矢量表的拷贝和将 0 地址从内部 flash 切换到内部 SRAM 起始地址。
4 C' r. i* V8 P/ \8 X. Q3 t8 B9 L( u: l4 n. K$ i
 从【APP 区】跳转到其它新的【APP 区】,只需在新的【APP 区】的代码里再做中断矢量表的拷贝,并保证相关存储配置的正确。
" c0 ?: u2 }4 W; X6 I* a6 Y4 Q  Z4 `" M$ V; j& O" ^
 从【APP 区】跳回【BOOT 区】,该过程无矢量表的拷贝,只需将 0 地址执行域重新映射回内部flash 区。: ~+ `: L( b1 S; N$ e! z

1 d/ W# m9 y% H  w$ _3 d+ ^: q2 V 不论从什么区跳往什么区,跳转前禁用当前用户打开过的所有中断使能、确保无未处理的中断请求存在或在跳转过程中发生中断。
6 }3 f1 D6 G+ C/ A
- w% g% i6 [# S5 Q% w' i% j 以上操作流程主要针对基于 COMTEX M0 内核的 STM32F0 系列芯片。
+ Z* Z1 n# g( n/ b& D
' |4 ]* M+ v* _; f6 Y5 H" n( \$ }; f' m" K6 D) d- t7 S( H. L

* Q9 R" R, ^& m. H% @
* [' p+ c9 i* ?8 U* Q6 Y: p# V  j4 E8 w+ @1 Z- M

7 a2 {5 u: u3 X- i/ E: [7 X9 U+ u, R
3 Q* ^) v! h. F' z. \
# r1 T) v& v. I7 q  G2 F0 a3 y5 u9 C+ l
, V. f) O5 R. {8 b

- b$ O0 H  P$ A% h5 {4 a( ^- h6 ?. u& q3 m( c3 r( z
* ?  `9 O9 {0 f( U9 S3 I5 W
赞 收藏 评论0 发布时间:2022-2-26 16:47

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版