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

【经验分享】STM32H7的QSPI总线应用之QSPI Flash执行程序(BOOT+APP方式)

[复制链接]
STMCU小助手 发布时间:2021-12-21 23:21
82.1 初学者重要提示* B4 U( q- J, {: o8 j. ?, C# {6 B
  操作本章配套例子前务必先将QSPI Flash的下载算法放到MDK安装目录。2 G0 _4 k2 F- R' _& v: _
  QSPI Flash执行程序的BOOT和APP作用:
& i/ R* p7 p# A! W& }" a' C- q  BOOT程序需要下载到内部Flash。主要用于跳转到外部QSPI Flash执行程序。那么问题来了,我们可不可以不使用BOOT,上电就直接执行QSPI Flash的程序?不行,因为QSPI Flash不像内部Flash,无需初始化,上电就可以使用,而QSPI Flash不行。# Z4 L9 F* H( `' u1 e6 D: o
  APP应用程序要下载到QSPI Flash里面。APP应用程序可以在QSPI Flash里面执行主要是因为W25Q256支持XIP(Execution In Place),并且STM32H7的QSPI Flash支持内存映射。8 Z- M: \8 H$ X4 D2 s3 q
82.2 下载算法存放位置
; i1 S( }' o" x编译例子:V7-060_QSPI Flash的MDK下载算法制作,生成的算法文件位于此路径下:* z0 [) M; Y+ D% ~0 D9 ?( x% j

7 ]/ {2 W; L$ l0 G& b
618b073cf66c2944fcdb610aef0e67ea.png
& |9 J  G1 g6 }4 ]+ ~6 \5 M5 J2 f
& V, y5 g: w$ S+ `
生成算法文件后,需要大家将其存到到MDK安装目录,有两个位置可以存放,任选其一,推荐第2种:
0 O( Y9 U1 f) b& \& q' }
; _" }; b* i* P6 D" A; b# H7 }  第1种:存放到MDK的STM32H7软包安装目录里面:\Keil\STM32H7xx_DFP\2.6.0\CMSIS\Flash(软包版本不同,数值2.6.0不同)。( C0 }7 T$ `' h7 F* L* Z* \
  第2种:MDK的安装目录 \ARM\Flash里面。
9 j1 Z( X5 o# r6 {7 w* Z9 A. c. Y2 F) @
b192c51eb80b27959d7c06b80a142d6e.png
$ j+ |  W  B9 p# s( P; p) |

# s( @& c4 Y: J82.3 QSPI Flash的Bootloader说明
  H# a1 [4 ]5 D7 }& ]
Bootloader的实现比较简单,需要大家将其下载到内部Flash。程序实现上主要注意以下两点即可。
6 D/ f7 b5 p" L! v
; a5 ~1 c" T" G, s; F82.3.1 初始化QSPI Flash并设置内存映射模式1 k3 s4 p" A8 ~& |" }; W2 ^# K% ]
在bsp.c文件中初始QSPI Flash并设置为内存映射模式。
- @" }0 M; h5 c5 @
8 c1 G& M9 |9 K! X0 ?* e
  1. /*
    - ^) s% L: t* q2 X8 j8 f
  2. *********************************************************************************************************
    1 g( L4 z* m# c' G
  3. *    函 数 名: bsp_Init
    3 [, h7 O" m' R
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
    ' ~+ U' b' V; _
  5. *    形    参:无, ]3 s; C; s/ j* D3 P3 n
  6. *    返 回 值: 无
    : z, _' P, W0 t6 G
  7. *********************************************************************************************************
    5 `. j) a6 M3 w& ?
  8. */
    0 k' w7 [! [4 K+ t( E/ Y6 ^- J. B' a
  9. void bsp_Init(void)
    & _& M" }% s% v/ \
  10. {
    6 n! y: [% P: ]% r( l& f+ n
  11.     /* 配置MPU */
    & d) ]7 M/ O  @
  12.     MPU_Config();& G) w7 [" m* _! @
  13. * H: y& v/ L* V
  14.     /* 使能L1 Cache */
    1 p+ \. N$ _0 _/ H) F6 c* n
  15.     CPU_CACHE_Enable();) J7 P# e% T' e

  16. - {8 B4 T5 ]" S4 z* Z
  17.     /* ) d% |3 v: q" r) z0 I, N
  18.        STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:
    # d9 r2 V5 O6 |/ |/ x* q" a5 z
  19.        - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。3 H3 x4 ?+ Q% g! X% c
  20.        - 设置NVIV优先级分组为4。5 W- ]; O0 e& `
  21.      */4 U: x7 X9 b  M0 O
  22.     HAL_Init();
    $ I% F. [5 g9 ~% S0 }

  23. 6 _( \' ^* c& P( ]6 V
  24.     /* 9 _$ U% a6 H) r4 |& ]) Z. H
  25.        配置系统时钟到400MHz
    , ^3 I- f! ^+ j7 B
  26.        - 切换使用HSE。
      f  N8 p  z3 p% Z
  27.        - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。, Q- ]  f$ {9 j, }/ t$ ]0 M* m- L3 o( l
  28.     */
    7 r3 Y9 n/ I& M9 a% E
  29.     SystemClock_Config();
    : A/ Z9 M/ z1 P
  30. % l, }9 ^' t" N5 Z
  31.     /*
    4 E" i1 ]6 E8 J$ r# G
  32.        Event Recorder:& @3 [. x  }' b6 p$ o
  33.        - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。2 C# k$ M& c  F9 y8 R' K. J
  34.        - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章+ Z6 i0 k, L. {4 N2 i; F
  35.     */   
    5 W& {- d! d3 g0 M
  36. #if Enable_EventRecorder == 1    w1 M# A% Z; s. _0 o- K7 p! Z
  37.     /* 初始化EventRecorder并开启 */& O  b7 K. x8 H" e# D1 I; O6 [
  38.     EventRecorderInitialize(EventRecordAll, 1U);; f# A* ^3 d: _( a  \
  39.     EventRecorderStart();
    ' I$ E" P9 z4 s5 q3 r9 ?
  40. #endif
    5 _4 |2 ^0 m. E" I  w" W& j
  41. / }  P' N8 A+ a5 C
  42.     /* 针对不同的应用程序,添加需要的底层驱动模块初始化函数 */
    ' s7 r& C& j4 ~3 R) Q
  43.     bsp_InitQSPI_W25Q256();  /* 配置SPI总线 */   
    3 E& @) Q6 Z' R; K9 w" D
  44.      QSPI_MemoryMapped();0 T/ S& M# i, d! L: d
  45. }
复制代码
! _: P3 D+ P- E
82.3.2 程序跳转的实现
" s2 I9 v5 f) G' [' W3 a从内部Flash跳转到外部QSPI Flash的实现代码如下
6 ~, h% U6 a/ z9 R
5 e2 l/ G2 K% o
  1. 1.    /*' C# _0 }( N, U5 V# G( |6 L6 b& n
  2. 2.    ******************************************************************************************************6 n: o% @: x) c, l3 N
  3. 3.    *    函 数 名: JumpToApp
    " K9 Q9 R' t: a- w7 c
  4. 4.    *    功能说明: 跳转到应用JumpToApp
    / e( V' W2 p. y' M9 A
  5. 5.    *    形    参: 无( U+ I# e; [) L) ~& Z& T) e
  6. 6.    *    返 回 值: 无. h; t  Y" G1 k0 y" T0 g
  7. 7.    ******************************************************************************************************: @; m, V# }+ f4 R. o
  8. 8.    */
    ( f. |2 N' ^# z. \, V
  9. 9.    static void JumpToApp(void)# t0 ^0 e5 k% b, i5 O' P
  10. 10.    {
    + m- G; V1 F- l
  11. 11.        uint32_t i=0;0 J6 D3 \. Q' {
  12. 12.        void (*AppJump)(void);         /* 声明一个函数指针 */8 \+ p+ A: [+ W6 g) K+ C
  13. 13.        __IO uint32_t AppAddr = 0x90000000;  /* APP 地址 */
    2 C" \7 H/ E" v( M  I
  14. 14.        
    , D0 F: b( a& S4 _! ]2 J
  15. 15.    $ ], P% C3 @* }& U5 X
  16. 16.        /* 关闭全局中断 */: T4 N2 b4 V4 f6 F; R6 p. r$ U
  17. 17.        DISABLE_INT();
    # e# o, L/ l( R. h5 l. g* d
  18. 18.        
    ) y) K, L' V* ~& A
  19. 19.        /* 设置所有时钟到默认状态,使用HSI时钟 */5 X3 [3 `+ {$ U( x
  20. 20.        HAL_RCC_DeInit();
    3 w% B/ S) p2 U* `" R& z0 L4 I1 j
  21. 21.        + ?' H- q2 A( ?$ T" J. d& Y
  22. 22.        /* 关闭滴答定时器,复位到默认值 */
    0 L) Z+ z+ y( E2 g* w% f- u
  23. 23.        SysTick->CTRL = 0;
    1 [0 w0 w* q4 x- D( ]3 ~. _
  24. 24.        SysTick->LOAD = 0;! d- V6 d# r6 A8 d! T. G" U
  25. 25.        SysTick->VAL = 0;5 l3 |# `. J3 V+ M7 \, Z/ i8 P
  26. 26.    & x& N) f8 S. ~6 f
  27. 27.        /* 关闭所有中断,清除所有中断挂起标志 *// Y# ~0 R# k; y" I
  28. 28.        for (i = 0; i < 8; i++); e* e) S: h( [
  29. 29.        {/ P' q& o- |; r" {+ E1 t' l
  30. 30.            NVIC->ICER<i>=</i>0xFFFFFFFF;
    # ]1 T. x: `" U5 e) i* F" J  j
  31. 31.            NVIC->ICPR=0xFFFFFFFF;3 _5 }, N) W: Y
  32. 32.        }    # i5 j' m) y1 n
  33. 33.    , P) y3 Z+ {' {5 g! ^$ j7 E
  34. 34.        /* 使能全局中断 */% M8 v/ `6 [# w: P
  35. 35.        ENABLE_INT();4 _, r3 z/ U+ q; n3 z
  36. 36.    3 Y: `8 h9 W+ a( J+ f
  37. 37.        /* 跳转到应用程序,首地址是MSP,地址+4是复位中断服务程序地址 */
    4 ~2 [' H: d% l! A6 N4 m- C
  38. 38.        AppJump = (void (*)(void)) (*((uint32_t *) (AppAddr + 4)));
    " C& s# g1 o# F6 z* z; D
  39. 39.   
    $ `5 r) s" ~  s# E) u' `# R( J1 [" w
  40. 40.        /* 设置主堆栈指针 */9 G* h+ {, M* G  L
  41. 41.        __set_MSP(*(uint32_t *)AppAddr);9 J0 Y" {! p2 c7 Z! b' Z
  42. 42.        - ^2 S  C& @/ Z5 S
  43. 43.        /* 在RTOS工程,这条语句很重要,设置为特权级模式,使用MSP指针 */
    4 V6 M; T$ b; Y9 ~7 E* B
  44. 44.        __set_CONTROL(0);
      q! p5 m8 X1 {+ u- N7 i
  45. 45.   
    . A! j" H! t  E
  46. 46.        /* 跳转到系统BootLoader */
    7 O8 p0 E( r+ T' n
  47. 47.        AppJump(); , ~) K$ Y: ?- X/ C
  48. 48.   
    " K( a* B& D4 _6 x" Y
  49. 49.        /* 跳转成功的话,不会执行到这里,用户可以在这里添加代码 */7 h. x2 g2 K5 }* E: Z
  50. 50.        while (1)
    9 ~( y  e  [- B: N: r6 ?' f& ~- ~
  51. 51.        {0 ?$ U% [/ e6 @
  52. 52.   
    - r3 h' i% b0 W6 C6 U
  53. 53.        }
    " w+ N; G/ f1 m0 \: [/ {/ L9 }# f
  54. 54.    }
复制代码

+ ^- L: {* J% G0 V* m这里把程序设计中的几个关键地方做个说明:8 G* A! O/ \8 a4 k
! k5 Z' ]2 b. L1 ]$ \
  第12行,声明一个函数指针。, P3 U& N4 F, F5 A; I: G# g# D
  第13行,QSPI Flash地址在0x90000000。7 A6 X2 S# r" J0 z- e9 p( Z
  第20行,此函数比较省事,可以方便的设置H7所有时钟到复位值,内部时钟使用HSI。. S5 R3 d( r) Y- v+ }8 r
  第23到25行,设置滴答定时器到复位值。
. {+ E1 H) p7 }1 z+ q  Z  C# L  第28到32行,清除所有中断挂起标志并关闭中断,这里是直接通过一个for循环设置了NVIC所有配置位,共8组。
1 n' q( h) o, V/ o! c
/ A( ?- `, a: {0 M4 @4 l) {
bfe6b8c0ea19b535e2fb06c6618577f6.png

5 r; b$ S9 l9 Y* h: L2 P; f; q7 X2 B6 w- Q  S# W
  第38行,将系统bootLoader的中断复位服务程序的入口地址赋给第12行声明的函数,用户执行这个函数时,就会直接跳转过去。" o" }+ X  y6 S! N% P/ M8 }% c+ i2 {" u
  第41行,设置主堆栈指针位置,即QSPI Flash应用程序首地址存储的就是栈地址。
' _5 J' B; Q8 M; }( W  第44行,这个设置在RTOS应用程序中比较重要,因为基于Cortex-M内核的RTOS任务堆栈基本都是使用线程堆栈指针PSP。但系统bootLoader使用的是主堆栈指针MSP,所以务必要设置下,同时让M内核工作于特权级。此寄存器的作用如下:4 c0 d& p) f2 m, Z9 s. y
6 I( r; O- _- \
b00b09a901596bcedb07c31790d8d3d9.png

2 R% u6 j' l% m6 A2 [) P
6 Q5 B+ c1 |+ O3 W; V  第47行,跳转到系统bootLoader。" t9 b- H, `2 y, F, u7 k2 c7 R
4 G6 W! e, B9 H  D0 o
82.4 QSPI Flash的APP应用程序说明7 ~* B" [# c9 [. K1 v
APP应用程序是由第53章配套例子:V7-033_LCD的汉字小字库和全字库制作 简单修改而来,主要修改如下两个地方:
: p1 z' i  B7 A' Q& a2 |) ^7 ~) G
82.4.1 设置Flash地址; |7 g9 U) U5 [. S1 Y+ C& q+ e
设置Flash地址为QSPI Flash首地址0x90000000:% n- r& F1 q) _/ t- v7 _
6 X0 J  X0 M: j. U" I2 X3 q
75afb2342189857e8fa086fc0af08462.png
! y# I9 w( T1 I1 X
& ^6 }& p' z0 m
82.4.2 设置中断向量表
- D8 B8 a( z9 Y& Z/ f* ~0 ?! N在main函数最开始就设置中断向量表到QSPI Flash首地址0x90000000,也可以按照本教程第28章的说明,将中断向量表设置到DTCM里面。9 T+ I* o2 z7 M) k% u

9 ^: F; t$ V! }" e
  1. int main(void)
    " }$ |8 ^- l; i- B) D
  2. {
    4 v: S5 f, N8 ~8 f0 c4 n
  3.     uint16_t ucBright;           /* 背光亮度(0-255) */" u  s. l$ r3 i& B8 g/ U% C
  4.     uint8_t ucKeyCode;        /* 按键代码 */
    0 M0 s/ F, Y5 I
  5.     uint8_t ucStatus;        /* 主程序状态字 */
    8 P3 ~$ u6 z- O6 K, }6 c
  6.     uint8_t fRefresh;        /* 刷屏请求标志,1表示需要刷新 */' g' b. f" U; S# s" f1 C

  7.   A$ u3 \$ q' x7 {
  8.     SCB->VTOR = 0x90000000; /* 设置中断向量表地址 */
    + U7 F0 ?: V$ g( @: z
  9. ) {' H) F; ?4 s6 v& g8 ~& U+ [
  10.     bsp_Init();    /* 硬件初始化 */& m, I9 l# B1 L0 {
  11.     PrintfLogo();    /* 打印例程名称和版本等信息 */
    ; ?+ M7 I8 g0 e. H
  12.     PrintfHelp();    /* 打印操作提示 */
    - v3 F. H% M$ B5 W) i$ L- c* q

  13. % t" a, j( ^: b/ F" x
  14. 省略未写
    ) q( [& u. m1 ]: k1 g
  15. 2 e% Y  P6 X: G5 s
  16. }
复制代码

5 D7 g# g' K8 M6 @( s' d" ^- N. |) t82.5 QSPI Flash的APP应用程序调试下载配置7 `( T( |. C7 V0 E+ I
将下面两个地方配置后,就可以像使用内部Flash一样使用QSPI Flash进行调试了。
0 h6 i4 B4 d6 B% }
7 m: y3 p8 ^, x5 S; Y82.5.1 下载配置
0 \+ Y, @; J, u$ F8 M1 v. H+ A注意这里一定要够大,否则会提示算法文件无法加载:
, i4 [7 V# O: V, l  _9 F% q0 A8 V2 x7 }
96d039e1657c72042027eb7e46ffc33a.png
  t: a1 z+ |& a2 u; `3 _: n% }) z

, ^" N4 o( s# a7 x3 }, h! T$ A我们这里是将其加到DTCM中,即首地址为0x20000000,大家也可以存储到任意其它RAM地址,只要空间还够加载算法文件即可。推荐使用AXI SRAM(地址0x24000000),因为这块RAM空间足够大。. y& J1 E# ]+ w& q7 V' c
7 P! w; e: |: z7 S* Z3 a
如果要下载程序到QSPI Flash里面,需要做如下配置:& s. ~* n5 N! _6 `

, A  i; ^8 [. k# `0 {: t( M
5c95b0f51dbecf9eac259ddcf6b3da55.png
' v0 B& }5 E( O

! ]: W, |5 u/ y0 x" I3 R5 o, {5 x82.5.2 调试配置$ t* X% P" Y0 p2 \
注意这里一定要够大,否则会提示算法文件无法加载:
* @: _% O. q; |3 N: P2 q6 ]
$ Y+ I. b" I" A8 C1 {$ r" }8 |
6b0758d3dd4db39b7189a03d59f0eca0.png
0 ]: r2 ?: P1 v) x1 O$ R
$ `2 R: B+ m, U0 V& |
我们这里是将其加到DTCM中,即首地址为0x20000000,大家也可以存储到任意其它RAM地址,只要空间还够加载算法文件即可。' L2 _- s/ x! A- ?8 t2 j
. }! Y+ i" T  r: `5 n+ \! K
如果要做调试下载,需要做如下配置:9 F8 v, d7 S9 B6 J* R1 X. T& O5 }1 f

. K9 [, T9 L9 ^* S
927401ada0fef49a78ac8029e372a755.png
7 K: D( j( u2 P2 D0 Z7 X8 {" u
5 H, k, b' @) ~" c

2 V# M0 k0 W) c% j6 Z) N82.5.3 程序调试效果
0 n8 t# P6 c5 F6 g; ~* nAPP应用程序调试效果如下:
9 Q2 |8 h- r) t! _
" v5 M/ p* F% n/ P
681a23ba44bd11addce0fa9aae797dbd.png
( c+ F7 k" p+ a
& [# w# A( C( Z% a- A
82.6 实验例程说明

( B8 M3 A5 I3 _% j本章配套了两个例子:$ F( A0 z. d' \

0 d! u0 A) J+ I8 p8 z5 g% d" j  V7-062_QSPI Flash运行程序(Bootloader)。
  C/ P" M- M* c) F4 [1 y, K# s4 G3 L, u  V7-063_QSPI Flash运行程序(用户APP)。! i; V3 i3 r6 R4 J# _7 k+ X

" i7 f6 L) Z  l* _% Z% Y& G" y% f0 G" L, T
Bootloader例子需要大家先下载到内部Flash里面,然后按照本章第5小节的说明配置后,就可以像使用内部Flash一样调试下载QSPI Flash了。
$ X2 ~! u. b  [. D/ u- I0 C! f8 i- |* j
82.7 总结3 Z6 M! y, M# v. h
本章节就为大家讲解这么,为了熟练掌握,建议大家是操作练**。
# e' U3 O- N* }7 R5 r$ g$ S8 o( \+ M. x- F8 o: k

1 S0 W7 o3 b9 [7 t9 ~
- v) M- D. e9 [( h4 l- y
赞 收藏 评论0 发布时间:2021-12-21 23:21

举报

0个回答

所属标签

相似技术帖

官网相关资源

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