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

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

[复制链接]
STMCU小助手 发布时间:2021-12-21 23:21
82.1 初学者重要提示6 h  ^4 e# |  @, G  l0 b" \, p
  操作本章配套例子前务必先将QSPI Flash的下载算法放到MDK安装目录。
$ a% D2 [) e0 F0 o( [1 V& D) d  QSPI Flash执行程序的BOOT和APP作用:5 J8 s' x3 @$ |1 p6 F( a- e0 e
  BOOT程序需要下载到内部Flash。主要用于跳转到外部QSPI Flash执行程序。那么问题来了,我们可不可以不使用BOOT,上电就直接执行QSPI Flash的程序?不行,因为QSPI Flash不像内部Flash,无需初始化,上电就可以使用,而QSPI Flash不行。
+ S; q5 M, @' e' O6 _- ]* H  APP应用程序要下载到QSPI Flash里面。APP应用程序可以在QSPI Flash里面执行主要是因为W25Q256支持XIP(Execution In Place),并且STM32H7的QSPI Flash支持内存映射。0 @4 D: f3 }5 i, i3 e9 i
82.2 下载算法存放位置0 A! d5 s7 y- S
编译例子:V7-060_QSPI Flash的MDK下载算法制作,生成的算法文件位于此路径下:
* ^  ^4 V; y: r  Q( v& C
/ X! `1 ]* T( R3 ~3 P1 U
618b073cf66c2944fcdb610aef0e67ea.png
8 o/ k: N. h3 F, D
  D, s- x( l" D+ C# T% A
生成算法文件后,需要大家将其存到到MDK安装目录,有两个位置可以存放,任选其一,推荐第2种:  M9 C. m% ^  T
$ T6 X# n5 A6 v+ N
  第1种:存放到MDK的STM32H7软包安装目录里面:\Keil\STM32H7xx_DFP\2.6.0\CMSIS\Flash(软包版本不同,数值2.6.0不同)。5 j+ M9 B8 E8 @2 c9 e8 x% b
  第2种:MDK的安装目录 \ARM\Flash里面。
1 u9 Z" w4 L9 Q. _
" p" G* H. ~% ^
b192c51eb80b27959d7c06b80a142d6e.png
1 ~) z" v* {6 Q' s. P7 E
) t5 y9 g0 }. I# Y4 k& G# |2 ~
82.3 QSPI Flash的Bootloader说明
9 O) T! S' N0 |" {1 x/ G
Bootloader的实现比较简单,需要大家将其下载到内部Flash。程序实现上主要注意以下两点即可。
1 N; Z2 V2 |9 }0 g& |% l8 m2 X! }% M* \6 @2 W, W
82.3.1 初始化QSPI Flash并设置内存映射模式  ~7 o  c' q$ U) \$ C! l/ p1 j
在bsp.c文件中初始QSPI Flash并设置为内存映射模式。" c: L. G$ Q- E  K) @+ J

8 w# g" e2 P& ?* W) W6 p
  1. /*3 ~! F- r, `. N+ T# `+ S
  2. *********************************************************************************************************3 l; T5 x* X% S# Q# \# m
  3. *    函 数 名: bsp_Init
    % j! z! J: I+ `" `. K! S
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
      H( Z3 r+ C" A8 b* w
  5. *    形    参:无
    5 R- m5 h! d, [% v" |
  6. *    返 回 值: 无
    5 W1 `+ R; j3 G' |7 `! F/ Z7 x4 ]2 D1 ]
  7. ********************************************************************************************************** P2 L+ z. P5 ?
  8. */, A/ m; B( m: f
  9. void bsp_Init(void)
    . W' x) R5 N& b% M
  10. {
    5 \" B. {: a8 P: @% S5 b7 f
  11.     /* 配置MPU */
    6 s5 E; h0 n" q5 G( @
  12.     MPU_Config();
    6 Q/ K2 \" b* `) q

  13. * U& i) \& {# w# |8 G$ q9 u
  14.     /* 使能L1 Cache */$ W7 ?" o0 e( p1 \( `, u
  15.     CPU_CACHE_Enable();
    0 O% I3 v' P# z% f
  16. 3 w* ?) G5 f+ ]
  17.     /* 2 L! Y8 F! K( E4 `
  18.        STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:8 N% z; `  @2 O/ z6 B: Z
  19.        - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
    + F, N+ ?0 M+ ^4 ]/ X. N: v1 e
  20.        - 设置NVIV优先级分组为4。
    1 L' {2 i  ^) K% v1 Y6 Y4 ~
  21.      */
    ; B4 i, d  @7 h& {1 W; d
  22.     HAL_Init();
    & T* h8 \  `/ t) A0 y

  23. . Z+ z, b! f4 H
  24.     /* : L1 A- G+ ]- b, a5 \
  25.        配置系统时钟到400MHz
    2 O$ s6 F4 _3 A2 F0 l2 `
  26.        - 切换使用HSE。5 k! X8 Z3 H, q. u5 x' W' d
  27.        - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
    , f; U1 f5 H3 _5 `, H$ p
  28.     */
    + N+ Z2 I+ `2 p5 t% n, k, k
  29.     SystemClock_Config();" d& ]1 S$ s) s( k2 o% h- b
  30. " M' N1 d0 d3 b5 o. a
  31.     /* ' p7 f- P  ?/ c6 Q
  32.        Event Recorder:, K  h3 z/ L! F1 A1 w3 D
  33.        - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
      N  F! v6 A9 N2 q; ^
  34.        - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章6 C  p, a1 A# O7 J+ z/ v2 {) w
  35.     */   
    5 X9 S% a, ]% O5 ~$ ]
  36. #if Enable_EventRecorder == 1  9 e) g0 x8 H/ r% b1 R7 l
  37.     /* 初始化EventRecorder并开启 */
    . w# }" q* p% {  A; z0 I
  38.     EventRecorderInitialize(EventRecordAll, 1U);/ |0 J8 G! i. K1 Q
  39.     EventRecorderStart();
    8 r! j( ?- S+ k: f' X) ?) s
  40. #endif
    ' L# g0 b- _3 a; U( Y

  41. " S1 V7 ?/ x6 M3 c
  42.     /* 针对不同的应用程序,添加需要的底层驱动模块初始化函数 */
    . q  t" r7 W, e
  43.     bsp_InitQSPI_W25Q256();  /* 配置SPI总线 */   # A; M4 I' E8 b2 [1 e6 p
  44.      QSPI_MemoryMapped();
    ( A# w. H1 b, ~( x# p
  45. }
复制代码

! @# p. `/ w1 {6 X82.3.2 程序跳转的实现
& I1 x* u3 C# g% l% L+ f) ^! N从内部Flash跳转到外部QSPI Flash的实现代码如下
' C; {8 _! G  p9 R+ [$ Z6 S! o, \+ E5 g& h* [
  1. 1.    /*
      Q% X0 S; H: `/ h4 b
  2. 2.    ******************************************************************************************************
    * S: I) s6 G0 P
  3. 3.    *    函 数 名: JumpToApp
    : c- z# i  {% n' X
  4. 4.    *    功能说明: 跳转到应用JumpToApp
    , B0 ?1 k) `% i7 V/ n
  5. 5.    *    形    参: 无
    2 u) Y. ?2 t  G* R3 a" |1 r
  6. 6.    *    返 回 值: 无0 h' j8 w! g  W. {; T2 |( L6 C
  7. 7.    ******************************************************************************************************9 h" u  Z$ c) C' z/ }
  8. 8.    */; P: C. e& Q7 ]* ?
  9. 9.    static void JumpToApp(void)% P+ U3 @  E, f5 {, {
  10. 10.    {
    # u  g+ E1 y7 A: S1 c1 y
  11. 11.        uint32_t i=0;- v# h$ e2 {* [+ H
  12. 12.        void (*AppJump)(void);         /* 声明一个函数指针 */- _* g0 L# t9 k0 h; l3 m
  13. 13.        __IO uint32_t AppAddr = 0x90000000;  /* APP 地址 */
    ; ?7 n1 S7 C6 N3 _7 L  _
  14. 14.        / Z9 ]2 @5 r7 ^8 [
  15. 15.    - }: D, R) F9 g  \' b$ A
  16. 16.        /* 关闭全局中断 */
    4 k" C; {8 r9 u  l
  17. 17.        DISABLE_INT();
    ; b( h" v" b6 u+ t* L3 k+ W
  18. 18.        
    , _5 @+ j& V- U5 F
  19. 19.        /* 设置所有时钟到默认状态,使用HSI时钟 */- n7 m0 z; I: A3 G
  20. 20.        HAL_RCC_DeInit();$ C% m" F0 Y0 r" W
  21. 21.        
    % I. F# a% m' M8 G
  22. 22.        /* 关闭滴答定时器,复位到默认值 */  h  C: k1 k% y& f! f. [* a
  23. 23.        SysTick->CTRL = 0;1 f% o& l$ Z) H% G8 |- }4 i8 J
  24. 24.        SysTick->LOAD = 0;9 V! ]. E9 i1 h7 Z; `7 U
  25. 25.        SysTick->VAL = 0;7 s% c. `3 g: b7 W" Y5 n- \
  26. 26.    + ]: x6 [$ ]# [% d/ u7 d) `
  27. 27.        /* 关闭所有中断,清除所有中断挂起标志 */$ R9 B& b: k* A. k! D
  28. 28.        for (i = 0; i < 8; i++)
    0 O/ s( y1 c/ w  x) l
  29. 29.        {9 k5 H4 x$ G$ ]1 Q5 Q9 _
  30. 30.            NVIC->ICER<i>=</i>0xFFFFFFFF;+ o+ |0 Z' i* h. w) w6 @) C
  31. 31.            NVIC->ICPR=0xFFFFFFFF;( @! s, a2 A! }) A' m9 C5 |5 y$ p6 H
  32. 32.        }   
    ) x0 ~- k" g4 E* S3 i3 q8 |
  33. 33.   
    & n  T- a. G6 F: c# T% F
  34. 34.        /* 使能全局中断 */& p# L' G9 g  l" W: [
  35. 35.        ENABLE_INT();
    & Q' E4 Y2 L. x8 y1 c1 P0 f$ g$ T
  36. 36.   
    / D$ y1 ~7 U8 N  i
  37. 37.        /* 跳转到应用程序,首地址是MSP,地址+4是复位中断服务程序地址 */$ ^6 }3 @/ Z( X# r
  38. 38.        AppJump = (void (*)(void)) (*((uint32_t *) (AppAddr + 4)));$ J* ~4 K1 H; c6 l, ~9 H* I
  39. 39.   
    : M4 r/ Y) t% ~7 n8 u- E7 H
  40. 40.        /* 设置主堆栈指针 */: E% v) l! X1 W' T/ o8 M
  41. 41.        __set_MSP(*(uint32_t *)AppAddr);8 L, B; z) |7 v
  42. 42.        0 r+ G' {- [9 G7 O6 B
  43. 43.        /* 在RTOS工程,这条语句很重要,设置为特权级模式,使用MSP指针 */, E7 U6 l. f7 T4 i( e  C7 l. w
  44. 44.        __set_CONTROL(0);
    $ t) d2 b( k# Q  f
  45. 45.    $ |; Y/ f9 M( c
  46. 46.        /* 跳转到系统BootLoader */
    4 ^0 b' X  C! ~, K( C4 ~9 D  A
  47. 47.        AppJump();
    . Q. E2 C# L: j: {- m1 h' Y! b1 x
  48. 48.   
    4 a6 M$ L& j2 L% L
  49. 49.        /* 跳转成功的话,不会执行到这里,用户可以在这里添加代码 */# t4 ^) I0 f2 J7 \) s. k
  50. 50.        while (1)( w+ }  H) ]/ u, k: I; V
  51. 51.        {+ F( ^3 }6 k. `' Q
  52. 52.    $ ~: b- d" Q3 p( I/ ~
  53. 53.        }
    & D1 H8 B6 j  a# U& s
  54. 54.    }
复制代码
: \1 @$ T  R/ q+ A8 C& K, _
这里把程序设计中的几个关键地方做个说明:) [+ D. i# I1 ?2 N& e5 h

3 R4 d) ]/ ?9 f" ~  第12行,声明一个函数指针。! u9 ~! u' E7 G! r5 \& `- C
  第13行,QSPI Flash地址在0x90000000。
' Q  Z' `4 {9 j# W& D5 G! }  第20行,此函数比较省事,可以方便的设置H7所有时钟到复位值,内部时钟使用HSI。2 D3 s) q! N: T& h1 m* t
  第23到25行,设置滴答定时器到复位值。
/ b; V, @( q. t0 ]( y/ ]  第28到32行,清除所有中断挂起标志并关闭中断,这里是直接通过一个for循环设置了NVIC所有配置位,共8组。" s/ v9 `3 ?+ o

6 e7 w1 c% Y! G# H+ S" s4 H" j
bfe6b8c0ea19b535e2fb06c6618577f6.png

- t1 K9 ^8 T, u) `! t
0 k$ z- @; G, x1 Z  第38行,将系统bootLoader的中断复位服务程序的入口地址赋给第12行声明的函数,用户执行这个函数时,就会直接跳转过去。4 S- g# `: W) K( H
  第41行,设置主堆栈指针位置,即QSPI Flash应用程序首地址存储的就是栈地址。
! k$ e  f& k+ I9 ^2 J  第44行,这个设置在RTOS应用程序中比较重要,因为基于Cortex-M内核的RTOS任务堆栈基本都是使用线程堆栈指针PSP。但系统bootLoader使用的是主堆栈指针MSP,所以务必要设置下,同时让M内核工作于特权级。此寄存器的作用如下:
* v; {4 Z4 Q1 Q/ |
$ x# [( |. C7 ]% F! V$ N1 t
b00b09a901596bcedb07c31790d8d3d9.png

/ u2 a4 B, h/ C! \( r. F" e+ j8 z0 b8 o+ ^
  第47行,跳转到系统bootLoader。1 [! m2 ]& m: m

9 w) f; j, K2 n0 Y82.4 QSPI Flash的APP应用程序说明& b7 m, r3 M1 e  _+ e- J3 w
APP应用程序是由第53章配套例子:V7-033_LCD的汉字小字库和全字库制作 简单修改而来,主要修改如下两个地方:
% A) E- h5 g6 p
0 }% X8 V2 A( u8 U. ]82.4.1 设置Flash地址# c5 w/ A# s+ m0 k* t7 z
设置Flash地址为QSPI Flash首地址0x90000000:
/ i9 v/ ]8 ?/ x$ I6 p; j+ E
2 }; D6 h; e" R1 x' o
75afb2342189857e8fa086fc0af08462.png
; ?  x4 w- Y. g
3 [9 G8 F" \+ U4 W
82.4.2 设置中断向量表9 m2 E- z$ |# J0 n: v
在main函数最开始就设置中断向量表到QSPI Flash首地址0x90000000,也可以按照本教程第28章的说明,将中断向量表设置到DTCM里面。, h' M$ [* v1 e1 i
1 J, Q' Y; Z+ R; C8 B- ]- g
  1. int main(void)+ |* R+ D! Y8 A
  2. {# o( c6 Y0 u  L5 H+ Q+ W
  3.     uint16_t ucBright;           /* 背光亮度(0-255) */+ ]5 I5 \# W. ]6 @9 G; h0 ~/ |/ T
  4.     uint8_t ucKeyCode;        /* 按键代码 */
    4 f* l8 N+ d% x5 G+ s
  5.     uint8_t ucStatus;        /* 主程序状态字 */- Y9 P: \" o+ h: i) ]9 z0 R
  6.     uint8_t fRefresh;        /* 刷屏请求标志,1表示需要刷新 */2 T, E0 r5 j: O5 F: ]
  7. : ]! m3 u$ g) G6 m
  8.     SCB->VTOR = 0x90000000; /* 设置中断向量表地址 */
    ( ]; J$ h/ [  j. D, ?8 ]
  9. % s1 F8 n/ I  |( p
  10.     bsp_Init();    /* 硬件初始化 */& B. y% Z( w  E7 T
  11.     PrintfLogo();    /* 打印例程名称和版本等信息 */7 ~9 }' m2 @% k
  12.     PrintfHelp();    /* 打印操作提示 */
    , s- s1 g/ J, u- m5 m9 F

  13. 5 n! Q8 ~1 ^  P, m3 l3 x8 b$ H
  14. 省略未写: V9 d5 S& q- @5 s9 `, }/ z1 `" K2 {
  15. 1 R. S1 Z. g8 ?4 {; V8 p) v
  16. }
复制代码

; u7 ^& u$ C8 ?; S' Z82.5 QSPI Flash的APP应用程序调试下载配置
+ q- q- J8 i* y" T将下面两个地方配置后,就可以像使用内部Flash一样使用QSPI Flash进行调试了。
% E. ?4 b6 Z- B  @4 {: {0 ]* y, U, S6 d# d; v0 L
82.5.1 下载配置
. P$ v" G" E+ j! o& Z注意这里一定要够大,否则会提示算法文件无法加载:
) D4 B% f! \* s$ N; S, _6 D7 y; m/ \; D6 N2 t6 r$ |) j+ p2 i9 `. @
96d039e1657c72042027eb7e46ffc33a.png

+ D# Q- c6 n& @* V* |
/ W+ A* j) V( i' p! F( Y2 Q8 G我们这里是将其加到DTCM中,即首地址为0x20000000,大家也可以存储到任意其它RAM地址,只要空间还够加载算法文件即可。推荐使用AXI SRAM(地址0x24000000),因为这块RAM空间足够大。
$ `/ w( ?0 @3 r; k# D) w  L
7 y9 Q9 ]) N) a$ ^3 e2 e* i如果要下载程序到QSPI Flash里面,需要做如下配置:
  L* B9 m- M- `' q: K4 u6 H% {
, J- k4 h6 u0 G! E" B* [  B
5c95b0f51dbecf9eac259ddcf6b3da55.png
& w  a: @* n- A# a# D" I, h$ i

  j, [9 ]$ m9 }1 _5 S82.5.2 调试配置
% |' s! ~* F% B. C, c3 A注意这里一定要够大,否则会提示算法文件无法加载:$ r' q; J6 N- ]) V; `

+ B$ E. a( @5 `6 T1 i
6b0758d3dd4db39b7189a03d59f0eca0.png

1 t; E# E+ W- C% X9 C# Q2 Y7 z2 j; w5 X) C
我们这里是将其加到DTCM中,即首地址为0x20000000,大家也可以存储到任意其它RAM地址,只要空间还够加载算法文件即可。
( ]$ D, j# |- q8 T/ Z3 ^7 Q1 P  S/ C  z0 N! V
如果要做调试下载,需要做如下配置:8 E9 E* }% ?: m" V

" T$ J/ b% G/ M, g
927401ada0fef49a78ac8029e372a755.png

$ M2 h) ?6 x' W" Y0 i# \3 \* E4 z1 F6 x* e; O, Z6 @% m
: ~3 r$ {$ e+ r& u# E
82.5.3 程序调试效果# \' E/ t/ G/ l4 u6 W  m( n
APP应用程序调试效果如下:4 Y4 q+ Z: V- m2 @' N" M: `
+ ~! M4 d, j0 z* S4 n3 _
681a23ba44bd11addce0fa9aae797dbd.png

$ W$ H3 S2 C7 \( m1 a
0 I1 \5 {3 L% Y+ B82.6 实验例程说明
) \% ?. ]* G! |6 n" Z! I' h
本章配套了两个例子:
6 e5 N' N# i4 }7 ]" c( m) ?
9 v6 J) T1 n+ J3 i  V7-062_QSPI Flash运行程序(Bootloader)。. I8 x- J0 C2 t" i" T
  V7-063_QSPI Flash运行程序(用户APP)。$ u% x% c7 u6 j( l

% M8 N. n- T1 e* ?$ [) d6 B' `7 c. u0 e6 U: H8 d1 d
Bootloader例子需要大家先下载到内部Flash里面,然后按照本章第5小节的说明配置后,就可以像使用内部Flash一样调试下载QSPI Flash了。
7 s+ h+ f! r/ X& I( b" C8 E$ B7 u% T, d
82.7 总结5 y9 |) Y1 \& [) W* @
本章节就为大家讲解这么,为了熟练掌握,建议大家是操作练**。& M: |# \" p3 V. Q
; {" ~$ ?% S+ p

+ `9 N0 K, `# |9 O
$ O! N8 O, A* B, B  c/ w) ?
收藏 评论0 发布时间:2021-12-21 23:21

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版