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

【经验分享】STM32H7 启动过程及bootloader跳转详解

[复制链接]
STMCU小助手 发布时间:2021-12-24 18:00
最近公司开发的一个项目使用到STM32H7系列芯片,由于该系列芯片内部flash只有128k,为了方便产品的远程升级,需要开发对应的升级协议及bootloader引导程序。由于片内flash容量不够,需要采用外挂flash的方式存储应用程序,片内flash单纯作为bootloader引导程序存储空间。为了节省成本采用单QSPI flash外挂BANK2作为应用程序外部存储。) J2 }% f1 h( z: P5 f) V
6 p) J$ p& x8 p. q1 a3 v  M4 {9 X
20210114225354296.png

& C; h3 n- A& A& Y/ M0 ^) R' Z0 Z: }1 F$ T
1.STM32H7启动流程
5 k( F/ J, F+ y6 u( ]# c3 xIAR工程建立后,系统默认生成的启动文件为startup_stm32h750xx.s,默认生成工程一般在EWARM目录下1 Y4 h/ z4 e9 I' z3 i3 I
! z+ N! z7 B8 u' x

  1. ) K8 p5 @, L& E
  2.         MODULE  ?cstartup
    4 M" {( u6 J5 P3 y3 A8 N

  3. 1 Z; q! d2 j# H7 l3 c( }+ _$ r
  4.         ;; Forward declaration of sections.- u3 y+ \# E; A( M0 {/ y- V; \' g( G
  5.         SECTION CSTACK:DATA:NOROOT(3)
    8 U' a/ d' ?: g6 W/ @
  6. 5 a, [! }1 s" T
  7.         SECTION .intvec:CODE:NOROOT(2)& S+ o6 {- ]: S
  8. * w6 Q0 [, `: f2 N7 g
  9.         EXTERN  __iar_program_start
    0 p4 R+ L8 _2 s4 _- [& D
  10.         EXTERN  SystemInit2 F; d; }+ `6 D
  11.         PUBLIC  __vector_table
    + p1 h) y; |( ]% L1 v) b
  12. : D" W! L, q3 G. \2 r8 L4 b
  13.         DATA
    ) i% `2 X" f: j2 k9 l: L3 ]  M
  14. __vector_table
    ' e; _8 w; E- ?* @2 d/ p* s
  15.         DCD     sfe(CSTACK)$ b/ a+ E. l7 ]4 f
  16.         DCD     Reset_Handler                     ; Reset Handler
    7 {( k% m- O; Z+ i
  17. ( ~* |0 a+ T# j( V; ^2 f
  18.         DCD     NMI_Handler                       ; NMI Handler
复制代码
& t( F8 ~1 V$ ]* F0 v& q& t
定义了一个 CSTACK 的段,然后在启动代码中先声明这个段
4 o# p- ?& z# q1 ?
/ F" S- F4 ~; \定义 .intvec 段,中断向量独立在一个叫 .intvec 的段当中,这个段是 4字节对齐(2^2)所以用 DATA 来首先处理向量的入口地址为 4的倍数,然后放向量表! I( B. M- r6 X- [9 C
. H( H9 I. K" S( M# y' h3 v" q
DATA 进入DATA模式, z, r: U" M& O, ?  w1 h

9 F' @7 h! x9 O+ T) L& U6 l, JDCD sfe(CSTACK) 通过 SFE 运算得到改段的结束地址(注意这个运算是在link的时候完成,链接文件为xxxx.icf,比如:stm32h750xx_flash.icf)' K3 O6 Z+ v7 u+ P2 \

4 C, `. m0 _! u- k" x) ]& [( y文件剩下为定义中断向量表。/ s- y7 ?! ~. P5 s2 u

' M7 @) r% Y$ N, ~0 `
  1. ;; Default interrupt handlers.
    * N. ~, T0 l) P2 S% _/ p* x
  2. ;;
    8 g) h- Q2 |2 J8 `5 \5 Y
  3.         THUMB
    ' ^& O: X- x4 h, Z: z
  4.         PUBWEAK Reset_Handler
    . u/ W; i) d# e8 G( I
  5.         SECTION .text:CODE:NOROOT:REORDER(2)
    4 Q% [  d9 A# d3 b/ _7 Q& t1 C
  6. Reset_Handler
    1 R( ~; H+ ]" k+ n3 R

  7. + `" R& J, `( h- E5 ]$ Q
  8.         LDR     R0, =SystemInit
    3 X; E$ k* I" l
  9.         BLX     R03 w* @$ `. i1 I% Q6 x
  10.         LDR     R0, =__iar_program_start
    7 W% |$ e# m& m; q5 M
  11.         BX      R0
    " [9 h( F* x( f4 C" I  g
  12. " _& r1 y- P& H" E& w/ N3 B- ^
  13.         PUBWEAK NMI_Handler
    - ^: g  Q" _, s0 ]7 M: O
  14.         SECTION .text:CODE:NOROOT:REORDER(1)
复制代码
5 y' @* E; T4 O1 Z: y
THUMB 进入THUMB模式(THUMB-2指令集)9 G5 M- c1 y& R: N2 ?! I+ x7 z

9 x, v" m$ e4 O% J" Q( C8 i启动文件先使用PUBWEAK 指令声明Reset_Handler为弱定义
% f1 k7 I; R" Q3 f3 l2 }$ V5 j
& }  H1 T! p1 Y/ e$ c0 ^SECTION .text:CODE:NOROOT:REORDER(2) 从.text段开始. ]4 _4 O' @4 s2 R6 m& @- g
3 X! E' i  M; X0 |
LDR R0, =SystemInit 将SystemInit指针地址赋值给R0
5 d6 M! G! {$ l: c7 [. B5 E4 ^7 i* m; P0 h9 d
SystemInit 函数一般由STM32 库提供,对于STM32 HAL库,该函数一般位于system_stm32h7xx.c文件中! e% m' R# P0 F7 m
7 O& N$ `+ O$ n% y" H
20210114230836389.png
/ [+ ~) H6 q# [, B) \  a
/ j- Q- T0 L4 c% J& A
  1. void SystemInit (void)
    ! [2 r9 R: a7 n2 t2 W
  2. {9 P  X( F$ W3 Z
  3. #if defined (DATA_IN_D2_SRAM)
    " |1 E" K- K1 A) Z. d
  4. __IO uint32_t tmpreg;
    4 ~  l$ J) {* `. |, _+ L
  5. #endif /* DATA_IN_D2_SRAM */
    8 T' q+ V8 U2 h1 u0 I! y( E( ^
  6. ' `4 U* @! x* \7 }# @
  7.   /* FPU settings ------------------------------------------------------------*/' b  f( c) B8 Y" ^3 J1 K. F
  8.   #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
      `4 d* A4 y3 N, S: Q; _( H
  9.     SCB->CPACR |= ((3UL << (10*2))|(3UL << (11*2)));  /* set CP10 and CP11 Full Access */
    7 v& J- B* j# w$ n0 d9 ~
  10.   #endif  Y+ v" T7 J" K( `2 @5 H* _! [
  11.   /* Reset the RCC clock configuration to the default reset state ------------*/0 @& u9 w; `5 V0 `1 F- X. W
  12.   /* Set HSION bit */
      P% l4 y+ R0 n+ I: G; v' c3 }9 c
  13.   RCC->CR |= RCC_CR_HSION;
    ) d1 z/ A3 j- N3 Q
  14. 3 Z+ \) @- l. u- X, a9 l
  15.   /* Reset CFGR register */
    0 y8 e. @' [+ `! B: Q
  16.   RCC->CFGR = 0x00000000;
    9 z2 x, o- l$ r0 \; z
  17. ......- W. I, [' A( Y: C5 E& q, |( \
  18.   /* Configure the Vector Table location add offset address for cortex-M7 ------------------*/
    # q) p3 [( _1 B6 E
  19. #ifdef VECT_TAB_SRAM+ B+ ?5 c- U. n+ w) L# s! N
  20.   SCB->VTOR = D1_AXISRAM_BASE  | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal AXI-RAM */' i9 L3 z% _9 t/ j, c4 I; O' S
  21. #else' T2 E2 \! A, S5 v. {( T
  22.   SCB->VTOR = FLASH_BANK1_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */; v1 l* T: X+ x9 l$ d4 x5 F
  23. #endif
    - R- k% U8 f/ ]7 h: _3 G" T, l
  24. # D  q/ Q/ @. g) R
  25. #endif /*DUAL_CORE && CORE_CM4*/
    # H+ g- i1 o; w# ^& v  S3 K) j# m
  26. # C- _8 {1 [( _* T. S( \3 {% O, p/ [
  27. }
复制代码
/ Q8 V4 H/ i: I* [
SystemInit 函数完成系统时钟、RAM、中断向量表地址的初始化。
) I% H  J+ g3 B4 f0 k1 Q* H2 q& ^6 F6 x! `: K
  1. BLX     R0 跳转到*R0*中的地址,执行SystemInit 并返回
复制代码
  1. LDR     R0, =__iar_program_start //将__iar_program_start地址赋值给R0
复制代码
8 ]8 e2 \) c2 p/ ^
__iar_program_start 函数一般都IAR系统提供,,我们可以在IAR工程中Option进行修改$ j  v7 ^1 F' Z, L2 B8 b: n
8 y& a) u+ v8 \9 X( q% `" W
如果想具体了解__iar_program_start干了那些事情,可以参考《在main()之前,IAR都做了啥?》
6 u1 ]- [$ a' ^8 k5 ^& u* I0 Y
5 s, c+ C$ }2 K: r( N' S8 ?启动文件主要完成如下工作,即程序执行过程:" V2 o+ j& c, ?% P6 A+ X4 N6 c
5 D+ i/ Y6 E# U) K' E
- 设置堆栈指针SP = __initial_sp。
" e+ z) B6 ]% }& r; E8 M1 i0 n& ~6 ^3 E7 `, r, g8 W
- 设置PC指针 = Reset_Handler。
* _  Q5 ?+ p# [5 n. D) K/ h
' r- I8 p7 V1 S1 t- 设置中断向量表。
' q/ [- ~! o& B- ^( D2 z: b$ ^5 r: }8 L! _0 O. g! i
- 配置系统时钟。5 E2 U$ X$ O, T% m% G5 ]

0 p  n; z0 E& r# {& m6 y( t- 配置外部SRAM/SDRAM用于程序变量等数据存储(这是可选的)。
  Y9 b8 r. O9 l; B  M4 }/ _- }! `2 e$ h/ Y' [! V: a$ H9 V% D
- 跳转到C库中的 __main ,最终会调用用户程序的main()函数。
; X0 z3 R& G& D6 ~" R
3 O$ z) Y0 v- j9 H+ O  N5 |/ ^$ i1 v; ^2.XIP技术
! Y' w, O4 J* e' t: m4 eXIP,executed in place,本地执行。操作系统采用这种系统,可以不用将内核或执行代码拷贝到内存,而直接在代码的存储空间直接运行。采用这样的技术既可以节省可用内存又可以减少加载的时间。应用程序可以直接在flash闪存内运行,不必再把代码读到系统RAM中。flash内执行是指nor flash 不需要初始化,可以直接在flash内执行代码。但往往只执行部分代码,比如初始化RAM.比如在arm处理器中,Nor flash就存放了引导系统启动的Bootloader,不过大小比较小(仅2M空间)。1 s7 \0 L/ I1 ?  F
20210114225737419.png
$ ?4 |  D3 S# }8 `, W( Y# t2 e0 `

/ |% o, l7 m  x% E7 w但是,Flash的存储器访问周期要比RAM大得多,在使用XIP技 术后可能会降低程序的运行速度,不过由于CPU的指令预取机制以及Cache机制,实际使用起来并不会明显降低应用程序的运行速度。
5 g  j6 O, S) a' O) D) a  F; f
20210114225835865.png

2 h" e; G; a, E7 i/ E
0 z- ?" j+ e' v4 Q1 x( X9 b; n8 r而右边的图,是针对Nor Flash的,这个很明显,CPU可以像读内存一样,直接跟Nor flash交互,即可以直接从Nor Flash中取指令,然后交给译码模块和执行模块进行执行,可以说,相比较Nand flash,Nor flash的操作对于CPU来说,简直就像是面对面一样。
5 C! t: b+ }+ L# i2 E- S' h  T8 d6 H1 f! o7 |% f8 S
进一步, 为什么Nor Flash可以实现XIP,而Nand flash就不行呢?# n1 S/ g- }# y
0 q) H% _* S% V- Z8 C. s3 R2 ]
有一个概念:嵌入式系统中代码的执行方式:
+ v7 X9 ~. }# Y8 w
# U% x, v9 [& T' o(1)完全映射:嵌入式系统程序运行时,将所有代码从非易失存储器(Flash、ROM等)复制到RAM中运行。
7 |! W+ _- ^- |/ D- Q8 m6 S4 b1 }# G1 I1 G
(2)按需分页:只复制部分代码到RAM中,这种方法对RAM中的页进行导入/导出管理,如果访问位于虚存中但不在物理RAM中会产生页错位,这时才将代码和数据映射到RAM中。7 D4 C& G) t* I0 O: R
5 x0 v% d7 ]' C* a0 B1 u! t
(3)XIP:在系统启动时,不将代码复制到RAM,而是直接在非易失性存储位置执行,RAM中只存放需要不断变化的数据部分,如下图
- u+ n3 F1 O5 Z2 e* [0 y  j* x. F4 B4 y* k- }
20210114225911954.png
4 m0 f9 [& {8 N" b6 ?+ t3 D' ^

# S# ^6 m9 d: K9 M  m+ G如果非易失性存储器(Flash)的读取速度与RAM相近,则XIP可以节省复制和解压的时间,Nor flash和rom的读取速度比较看(约100ns),比较适合XIP,而Nand flash的读取操作是基于扇区的,速度相对很慢(us级),因此不适合实现XIP系统,不过Nand flash的写速度比Nor的快,更适合做存储和下载系统。9 U& {/ w* H/ R. k+ e: n+ H; K; H7 M) z
2 C* j6 z3 j! q; y0 t* ?, }
解释二:4 f, S0 J1 a/ [3 E8 `' B- b
两种芯片的结构不同4 k( \9 t" U, B; x" P
NOR flash之所以可以片内执行,就是因为他符合CPU去指令译码执行的要求。CPU送一个地址出来,Nor flash就能给出一个数据让CPU执行,中间不需要额外的处理操作。
7 @9 x$ \7 t% z0 @! Z, c1 u; J2 ANAND flash不一样是因为nand flash有地址,数据,命令共用IO口的问题,cpu把地址发出来之后,并不能直接得到数据,还需要控制线的操作才能完成。就是他没有专用的SRAM接口。
+ k$ j. v: ?& v; r) G7 T! \* S3 N. o+ n% q8 u' r# L- y
解释三:' c/ m" B" B& z8 W' N: s0 e
芯片内执行主要是是看芯片可不可以线性存储代码(假如硬件支持芯片接口),只要能保证芯片的存储空间是线性的(也就是无坏块),都可以片上执行,在读取Flash时候,容易出现“位翻转(bitconvert),在Flash的位翻转(一个bit位发生翻转)现象上,NAND的出现几率要比NorFlash大得多。这个问题在Flash存储关键文件时是致命的,所以在使用NandFlash时建议同时使用EDC/ECC等校验算法。 ”2 F+ Q: n/ I" ~
; M% G7 H6 n2 k+ f
但是,如果能保证不出错,也还是可以进行XIP,可以在其上执行代码的:  x9 j" N1 L2 z
“所谓XIP,就是CODE是在FLASH上直接运行. NANDFLASH只是不适合做XIP,但并不是不能做XIP“7 R- m# v4 \4 A  f: n7 c
要一段CODE能够正确的运行,要保证它的CODE是连续的,正确的.5 b6 \+ o0 x  ~: X. K, V
由于一些电气特性的原因,NOR FLASH能够做到这一点,不存在坏道或坏块,所以能够做XIP.' E, f) z8 i% o! e
而对于NAND FLASH, 它只保证它的BLOCK 0是好的,其他的块并不保证,虽然出错的几率比较低,但还是有出错的可能,所以CODE可能无法连续正确地执行.4 Z1 z0 A7 K+ `6 ^0 \
5 J' l8 l  V! L( a- l5 m$ \0 t
但只要你有额外的保障措施,比如说在执行CODE之前去做一次ECC校验,来确保CODE是连续正确的.那你也可以做XIP. 有人这么做了,而且也证明是成功的4 u; s! L% ?6 G3 o* I3 S+ Q" C

/ Y) s  O" {; e# A* u5 W由于芯片外挂的是W25Q16 为NOR flash,支持XIP,并且STM32H7系列芯片QSPI FLASH支持内存映射模式。STM32H7芯片可以将W25Q16芯片内的应用程序映射到地址0x90000000,虚拟为芯片内部内存进行执行。由于产品为了节省成本没有采用QSPI 双flash模式,执行效率会再降低一点。经过测试从bootloader跳转到应用程序,起来需要经过约2.6s左右。具体中断执行效率还需进行进一步测试。) w6 s' r  M- N
QSPI执行速度对比图5 s) Y6 x6 |+ [+ G% }6 s: T4 v5 {) P
1 u8 ~% g& o& {* z8 ?
20210114230031779.png
* }1 `" n9 I" h4 d. J
3 O* |% w# [8 P# _- x# Z
3.启动文件修改
+ u* ?% y$ S! W: @7 g) a. X9 I( E对于bootloader程序,程序再芯片内部128k flash中执行,程序默认启动执行地址为0x8000000,无需修改IAR 的link链接配置文件。
) p$ ]* G, P# H& L* D) J4 V对于应用程序,需将IAR 的link链接配置文件****.icf文件中的__ICFEDIT_intvec_start__ 地址,__ICFEDIT_region_ROM_start__地址,__ICFEDIT_region_ROM_end__地址进行修改,具体可以通过IAR options->Linker->Config,里面进行修改1 N7 R1 p5 H& d# F- f: M5 O

" D8 U6 s8 m2 t$ |
20210114225558558.png

2 S; T+ `$ L% X& v  r
/ _/ G# }9 p/ y# w/ m6 g. |
20210114225618875.png
" h1 A# b  E3 v( G3 [, d; w
5 H! H& U6 J4 J2 n6 U# p/ ~) n
修改完成后,查看IAR配置后的icf文件,具体内容如下
7 A3 `5 o. h' R& L6 ?1 ?3 k1 m4 C4 y+ a" v% F) g. N3 X
  1. /*###ICF### Section handled by ICF editor, don't touch! ****/* ]/ t4 P) l$ W6 M$ g" d, l0 E
  2. /*-Editor annotation file-*/4 T& U7 @/ d! h: i
  3. /* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */8 ]5 {2 t& d( V! ]' D& b
  4. /*-Specials-*/) c, S4 \/ \8 P
  5. define symbol __ICFEDIT_intvec_start__ = 0x90000000;
    , g, F  E- x# X$ }2 |8 W9 L
  6. /*-Memory Regions-*/, S# k% \3 K5 t
  7. define symbol __ICFEDIT_region_ROM_start__     = 0x90000000;5 g  z( N  z# v8 l, S
  8. define symbol __ICFEDIT_region_ROM_end__       = 0x90100000;/ L& H# A( F- p: M
  9. define symbol __ICFEDIT_region_RAM_start__     = 0x20000000;" y& \1 ?# u& i2 H8 a' E
  10. define symbol __ICFEDIT_region_RAM_end__       = 0x2001FFFF;  X5 Y3 I( K! F
  11. define symbol __ICFEDIT_region_ITCMRAM_start__ = 0x00000000;* \* e2 ]; Z2 z5 L  G9 ~
  12. define symbol __ICFEDIT_region_ITCMRAM_end__   = 0x0000FFFF;
复制代码

+ N- G# Z6 x* o2 A2 x6 e1 P4.bootloader程序与应用程序设计2 G  h* K" }: n% e/ B
对于bootloader而言,主要的任务有一下点:4 Z4 W3 _( X5 K0 P" @) P  {+ t/ h
; w; x" Q. ]! c
1、接受和处理上位机下发的更新程序,并将其写入到外部flash备份区
( P; `' `  Z& V: H5 c  F5 ?8 t( Z% F) x* Z, \0 E
2、对更新到外部备份区的程序拷贝到应用区
0 K6 |: i1 q( E3 J2 S2 e$ m. K* E7 @6 l) ]+ f6 M
3、初始化QSPI为内存映射模式,引导程序启动,跳转到应用程序/ c/ H- |. v7 ?% B& P. w% n' g0 i1 G4 Z

- `5 T, g, G) C
2021011423012391.png

1 p7 J* E+ s5 D/ T* d& {) e
2 h/ K& C$ r- j4 S% s" A, p' n
20210114230131258.png

) s& B5 M: @% ]& \! j, m
- s; Z# F8 ~2 s1 L1 |- ]7 Q我们将STM32H7整个内部128k flash分配为bootloader程序存储区。装置上电,首先从内部flash 地址0x8000000进行启动,具体执行流程如下图所示:
! b" F% u1 E) Y0 E" H0 {5 \7 h9 P
0 t! K  `" v4 T5 Y, M" W
20210114230154821.png

' d8 r8 W3 ~: K+ g/ k/ q0 u
) g& @& p$ [7 ^, Z% h) c' V
* H8 H' k- \: c, F+ m! g
. y$ c! m. m$ ~- ^, u" J7 k& Z9 X
- f, F; A9 O- B: ?" f
收藏 评论0 发布时间:2021-12-24 18:00

举报

0个回答

所属标签

相似分享

官网相关资源

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