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

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

[复制链接]
STMCU小助手 发布时间:2021-12-21 23:21
82.1 初学者重要提示9 W2 t* j- {" ?9 C3 U$ d5 {
  操作本章配套例子前务必先将QSPI Flash的下载算法放到MDK安装目录。" _. l3 V! t+ y
  QSPI Flash执行程序的BOOT和APP作用:
7 ^+ W$ A$ p2 x# U  BOOT程序需要下载到内部Flash。主要用于跳转到外部QSPI Flash执行程序。那么问题来了,我们可不可以不使用BOOT,上电就直接执行QSPI Flash的程序?不行,因为QSPI Flash不像内部Flash,无需初始化,上电就可以使用,而QSPI Flash不行。5 q1 x: N% {5 N
  APP应用程序要下载到QSPI Flash里面。APP应用程序可以在QSPI Flash里面执行主要是因为W25Q256支持XIP(Execution In Place),并且STM32H7的QSPI Flash支持内存映射。$ X, \" {2 K" z! y3 l6 f1 y  L$ w, z
82.2 下载算法存放位置! Y% p4 n0 v4 x! J
编译例子:V7-060_QSPI Flash的MDK下载算法制作,生成的算法文件位于此路径下:8 E9 g  k; S9 V! `' ~5 _7 L

  j2 }4 `$ g9 ^2 ~4 X6 c: {
618b073cf66c2944fcdb610aef0e67ea.png
6 J' r( I3 @" t$ l' a3 I, T

3 D* ]& t  h! J) j- k# T生成算法文件后,需要大家将其存到到MDK安装目录,有两个位置可以存放,任选其一,推荐第2种:: Q8 w4 u# ^8 I9 E: f( V9 X7 {

0 O; l$ K. J$ g* [0 L5 U# d  第1种:存放到MDK的STM32H7软包安装目录里面:\Keil\STM32H7xx_DFP\2.6.0\CMSIS\Flash(软包版本不同,数值2.6.0不同)。
2 J) N( b1 A# _' @* O  第2种:MDK的安装目录 \ARM\Flash里面。$ G4 u/ C& P' @* L0 _, j
( H3 w9 c" z) t6 [, s* `6 e# i# e
b192c51eb80b27959d7c06b80a142d6e.png

6 q6 j# D/ m: R: u
9 L6 [/ w8 p1 H6 G  I- q8 q82.3 QSPI Flash的Bootloader说明

$ J1 ?- C$ [4 s9 S8 {Bootloader的实现比较简单,需要大家将其下载到内部Flash。程序实现上主要注意以下两点即可。. r' w7 Q# P7 J+ ~$ H1 Y; H
8 ], [1 z! h1 U
82.3.1 初始化QSPI Flash并设置内存映射模式) B1 D7 p3 i# z3 G  Q# Q; U8 L) }
在bsp.c文件中初始QSPI Flash并设置为内存映射模式。2 m) p+ F  u6 m$ v* {: ?
/ M# B2 @$ G3 N7 {8 L
  1. /*
    ' s  q& M& A/ ?) w7 w4 D4 e2 |
  2. *********************************************************************************************************. ~7 t, N  S8 M1 s  @' m# A( j
  3. *    函 数 名: bsp_Init# U* T# [; J# d: k
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
    + p1 C2 h  K2 B8 D3 D2 A
  5. *    形    参:无
    1 @' c$ n$ d6 o! ]
  6. *    返 回 值: 无
    , f9 j+ J) G$ t8 K9 f+ e! ?
  7. *********************************************************************************************************
    ' h& G1 a+ m% j; e6 A
  8. */
    & v" X' P7 l$ ]. t# U8 P- i* A) v
  9. void bsp_Init(void)" ?5 I0 k  e+ T+ d8 b: H8 `; B
  10. {
    1 A% J% b! J; G: @& b9 i, W
  11.     /* 配置MPU */
    ! `: A/ G  k( S9 q2 y
  12.     MPU_Config();) P+ O- y+ y$ M/ s- y  X4 O8 _. b
  13. : _' O4 E# T/ f6 Z' Z( x" n
  14.     /* 使能L1 Cache */
    8 f; l" z9 k/ A# B: r( x& q  \4 O
  15.     CPU_CACHE_Enable();' U/ H) E, o; \& M# y8 a) p  X4 n) Z
  16. / T+ R- l8 b6 G3 ^* z
  17.     /* 7 E' u$ b9 O2 U1 r
  18.        STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:
    # F  {7 p" o' b3 F  b2 |
  19.        - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
    7 Z: ^" h1 `8 R- w$ {
  20.        - 设置NVIV优先级分组为4。. X; y% @+ \3 J& ^
  21.      */' k( X8 K0 D8 Q, c$ Z0 K" h) ^
  22.     HAL_Init();
    & s: x  U7 r7 K; U
  23. : w, F3 x, a3 {! S# S2 u7 r
  24.     /* ' ?# B& [6 h+ m$ d
  25.        配置系统时钟到400MHz  j( x4 v7 x: ~
  26.        - 切换使用HSE。3 d( R5 V* b+ U! F# s
  27.        - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。$ s5 L) \0 s+ ^9 E* ~- }4 ^2 ]& U
  28.     */! x7 H/ f+ D, c  g0 _
  29.     SystemClock_Config();1 @% @7 q! I* l( h$ E

  30. 5 t  I4 @$ W; N1 [
  31.     /*
    " ~+ |) A( D5 c) g
  32.        Event Recorder:
    3 x" e6 {' M6 Q
  33.        - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
    # `0 R" ?4 d; w' b# p2 A& a% M
  34.        - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章
    ! @4 ?, U4 w  ~% b3 _4 ^+ ]
  35.     */    ) N) @' }9 C3 v, r* W
  36. #if Enable_EventRecorder == 1  
    ' w0 ?! f$ t. Z6 {% p4 ?
  37.     /* 初始化EventRecorder并开启 */
    2 j) k6 ?1 Y% O" H$ S& p
  38.     EventRecorderInitialize(EventRecordAll, 1U);7 k% p4 v0 o9 z! ?" T7 }# T
  39.     EventRecorderStart();3 S" K  ?" Q' U
  40. #endif
    0 c0 K  U- S2 O! r9 h
  41. 6 N( a  C1 D& z! Z- H# d
  42.     /* 针对不同的应用程序,添加需要的底层驱动模块初始化函数 *// l: c; e& Y* j9 l  k5 K: V
  43.     bsp_InitQSPI_W25Q256();  /* 配置SPI总线 */   7 z4 ~! ]' j  \& L
  44.      QSPI_MemoryMapped();
    - j* M* D  a( g
  45. }
复制代码
+ ]6 j; T2 E0 i$ w3 d
82.3.2 程序跳转的实现! O. G8 D9 k0 R( b/ F
从内部Flash跳转到外部QSPI Flash的实现代码如下. J" W& @( m: a0 d1 m
3 x7 M, M& A- `, U* u) l
  1. 1.    /*
    8 R' m* r' i0 T2 h# z0 d$ _# F
  2. 2.    ******************************************************************************************************" m2 V2 }/ U# U0 C
  3. 3.    *    函 数 名: JumpToApp
    - v. B/ z% e8 K& u3 n( M
  4. 4.    *    功能说明: 跳转到应用JumpToApp( s2 ^) e$ V4 ~. ?$ H
  5. 5.    *    形    参: 无
    ' {- B. l4 b0 E: T, Z6 J$ c
  6. 6.    *    返 回 值: 无
    ) s. ?& `4 o' D2 @
  7. 7.    ******************************************************************************************************
    9 A8 M7 k6 M6 V6 U& U
  8. 8.    */
    ; {# r% _3 d1 A8 m
  9. 9.    static void JumpToApp(void)
    * w7 d) |* L8 C. u1 K: E
  10. 10.    {
    9 {( p+ ]8 R: d  P7 j. n7 a& S2 ^# }
  11. 11.        uint32_t i=0;
    - `* v, a% [; V8 Z  E- k
  12. 12.        void (*AppJump)(void);         /* 声明一个函数指针 */
    * T* R' F( S1 i9 c4 A1 Q1 O
  13. 13.        __IO uint32_t AppAddr = 0x90000000;  /* APP 地址 */
    * f; @+ `3 l' P' p  S) E. u9 b
  14. 14.        ; A4 Y' r# A0 ^1 G/ f
  15. 15.   
    . l. S4 e: r) p
  16. 16.        /* 关闭全局中断 */& p1 R: n! ^; H; b3 I4 h
  17. 17.        DISABLE_INT();
    % o& t; b7 R$ P, @$ u5 b
  18. 18.        
    % f! L- ?9 A* l1 N8 x
  19. 19.        /* 设置所有时钟到默认状态,使用HSI时钟 */
    6 w% }, G" k0 |' o0 _* E, h
  20. 20.        HAL_RCC_DeInit();3 Q) w& ]5 G1 e6 W+ Y& b8 Y
  21. 21.        
    : W) ~- ~& R! k! Q" B$ k& B! B0 e
  22. 22.        /* 关闭滴答定时器,复位到默认值 */
    4 I7 c& ?  B% S" q
  23. 23.        SysTick->CTRL = 0;+ c. U% B0 q' H- P
  24. 24.        SysTick->LOAD = 0;
    4 [) R1 J# R/ O3 r
  25. 25.        SysTick->VAL = 0;
      \9 ]% V8 b% G( _* w
  26. 26.    ' t# W  u9 o& N. e2 A
  27. 27.        /* 关闭所有中断,清除所有中断挂起标志 */
    ( x) y9 J* c& N5 y3 `7 V1 Q7 L
  28. 28.        for (i = 0; i < 8; i++), T7 }! n# s6 A, Y' D; m  w
  29. 29.        {6 n1 W* T: q* ~( t2 p/ l* S) O
  30. 30.            NVIC->ICER<i>=</i>0xFFFFFFFF;$ m2 U1 \$ M+ r! U
  31. 31.            NVIC->ICPR=0xFFFFFFFF;
    ) Q' f; ?( J+ y) Y$ V6 z0 h
  32. 32.        }   
    0 v# t7 C$ p2 A
  33. 33.   
    " E$ y8 j# e  n5 `8 O
  34. 34.        /* 使能全局中断 */
    / X- S, B4 U/ b5 z8 t
  35. 35.        ENABLE_INT();
    # h' V8 k1 n( Q9 O/ s$ L
  36. 36.   
    5 O& U$ S0 n9 g3 l# o1 J1 M/ e
  37. 37.        /* 跳转到应用程序,首地址是MSP,地址+4是复位中断服务程序地址 */
    - ^/ p4 A; w  r- I1 t  l  s
  38. 38.        AppJump = (void (*)(void)) (*((uint32_t *) (AppAddr + 4)));
    - I3 r8 r, t' S" P8 h
  39. 39.   
    " w8 L# m0 O: v5 a/ g
  40. 40.        /* 设置主堆栈指针 */
    : e8 I6 O! e6 Z1 d  I
  41. 41.        __set_MSP(*(uint32_t *)AppAddr);4 f+ j# a* a) C( [1 z" g
  42. 42.        4 s2 r, `3 |9 f5 S9 t
  43. 43.        /* 在RTOS工程,这条语句很重要,设置为特权级模式,使用MSP指针 */
    : F, `! g; R0 ]! U* S* y
  44. 44.        __set_CONTROL(0);- k( _: B. O+ [4 S$ o" R
  45. 45.    5 @5 B) P+ e. @9 M1 t
  46. 46.        /* 跳转到系统BootLoader */' `/ b) t6 {) U) N/ m3 ?5 k
  47. 47.        AppJump();
    ) n! U* Q9 F- q0 Q
  48. 48.    # o; w  G7 y% Q5 G1 O: }4 w  U
  49. 49.        /* 跳转成功的话,不会执行到这里,用户可以在这里添加代码 */
    $ V2 M' p; x/ W1 h' {% o9 O
  50. 50.        while (1)
      y1 A! f1 Y7 Q) R' T/ e5 ]
  51. 51.        {
    1 o( G. n0 D# p- Q
  52. 52.    5 V) k" A1 r7 h/ N: E
  53. 53.        }
    ( @1 Q1 S9 y6 ?7 b; o, `& d" G
  54. 54.    }
复制代码
& v9 u3 d6 f, I, }, B
这里把程序设计中的几个关键地方做个说明:5 B5 y8 ~6 y1 c$ t4 w& I
: S: g/ S. Y& w; F; q- f
  第12行,声明一个函数指针。4 n' f; D1 b/ w# L
  第13行,QSPI Flash地址在0x90000000。; W& X' S  E) @. z: C) t7 t
  第20行,此函数比较省事,可以方便的设置H7所有时钟到复位值,内部时钟使用HSI。- j) ?: v* r2 Y+ j7 G8 T
  第23到25行,设置滴答定时器到复位值。
" h# _! N, u- R2 n2 L! S: G  第28到32行,清除所有中断挂起标志并关闭中断,这里是直接通过一个for循环设置了NVIC所有配置位,共8组。
3 v8 B6 V4 W/ I9 [/ q. E! u+ I4 j/ Z2 d( A
bfe6b8c0ea19b535e2fb06c6618577f6.png
: b: a( e6 Z) A% }3 ]( a

0 t* E0 f* j" t+ O; ^$ u  第38行,将系统bootLoader的中断复位服务程序的入口地址赋给第12行声明的函数,用户执行这个函数时,就会直接跳转过去。- C6 C$ \% E% N$ l* N
  第41行,设置主堆栈指针位置,即QSPI Flash应用程序首地址存储的就是栈地址。' \2 R5 t) j# d1 @: l+ q" g0 j! q
  第44行,这个设置在RTOS应用程序中比较重要,因为基于Cortex-M内核的RTOS任务堆栈基本都是使用线程堆栈指针PSP。但系统bootLoader使用的是主堆栈指针MSP,所以务必要设置下,同时让M内核工作于特权级。此寄存器的作用如下:/ r6 ]4 i9 N) ~7 Y& j( Q8 H8 L- K0 M
/ z8 k3 I" O8 F6 i
b00b09a901596bcedb07c31790d8d3d9.png
8 g- |0 q+ \3 j3 ^
% V; l+ C+ q7 ]+ W1 L& m
  第47行,跳转到系统bootLoader。
- r7 x. g3 W5 {/ q8 g1 `, B- w6 _2 N
82.4 QSPI Flash的APP应用程序说明# Q% U; {) ~6 g1 r6 \4 i6 o% p% B
APP应用程序是由第53章配套例子:V7-033_LCD的汉字小字库和全字库制作 简单修改而来,主要修改如下两个地方:) f' X8 b3 k; M/ p1 `
) ?) K; ]' D2 w+ I6 L
82.4.1 设置Flash地址9 Q% x+ F& Q' A5 I
设置Flash地址为QSPI Flash首地址0x90000000:
. G0 l+ u9 `* c* L
4 w! n; |. C, a4 ~
75afb2342189857e8fa086fc0af08462.png
; T6 M7 G4 D6 j
! E0 g) N) I1 n/ z
82.4.2 设置中断向量表
- H3 a; I2 M- l: G  @$ M在main函数最开始就设置中断向量表到QSPI Flash首地址0x90000000,也可以按照本教程第28章的说明,将中断向量表设置到DTCM里面。3 C8 d$ D1 @* C  _) W

4 w  Z% B5 l/ l; Z1 b
  1. int main(void)
    . w& Y6 L& ?( \. ], R% i
  2. {
    . p$ c* a3 i% A) i. ~- ~  u
  3.     uint16_t ucBright;           /* 背光亮度(0-255) */
    ; |' u( p4 T) _: W+ E, ]- N5 J0 V
  4.     uint8_t ucKeyCode;        /* 按键代码 */
    * @& A& w: A! o& A9 Z9 M, ~
  5.     uint8_t ucStatus;        /* 主程序状态字 */
    + d% W5 G# I" \! R$ o: l" t
  6.     uint8_t fRefresh;        /* 刷屏请求标志,1表示需要刷新 */
    - V1 S, ]* }2 k3 x

  7. 4 L5 S4 P6 j/ F; N
  8.     SCB->VTOR = 0x90000000; /* 设置中断向量表地址 */
    ; M; B- d0 z1 {- _7 M! r
  9. 3 f4 z5 `1 s+ T* D) M1 J: C6 ^
  10.     bsp_Init();    /* 硬件初始化 */( P6 c+ o/ L& x3 t2 [
  11.     PrintfLogo();    /* 打印例程名称和版本等信息 */
    6 {$ Z2 h" G3 V; V2 Y
  12.     PrintfHelp();    /* 打印操作提示 */( T" y" }) E* U/ B9 x: u0 p
  13. * {2 \/ @0 V/ x7 p2 d
  14. 省略未写! H; [; h% p4 J- _
  15. $ H- J  i" f# a2 o& @4 r
  16. }
复制代码
' d) Z" r4 x; s
82.5 QSPI Flash的APP应用程序调试下载配置
. Q  z4 C$ t9 d) }9 v2 i将下面两个地方配置后,就可以像使用内部Flash一样使用QSPI Flash进行调试了。" I! t; z+ q" W* ]# J  l, w
2 E9 F5 D/ ^# C; C8 n3 c$ h5 L
82.5.1 下载配置
3 l$ ?; U- Q  D9 v, \' Z3 ^+ K注意这里一定要够大,否则会提示算法文件无法加载:+ r' F8 W0 f  S+ e' M2 a; h
9 a) D" a4 y* u0 b" Z# r
96d039e1657c72042027eb7e46ffc33a.png

: d5 U3 k" t& z- g  b
$ e9 k1 T  J/ N8 l7 `我们这里是将其加到DTCM中,即首地址为0x20000000,大家也可以存储到任意其它RAM地址,只要空间还够加载算法文件即可。推荐使用AXI SRAM(地址0x24000000),因为这块RAM空间足够大。+ J1 Q4 o( s: P! J
) J6 W; `% _. y$ [- `0 \( M2 t3 v
如果要下载程序到QSPI Flash里面,需要做如下配置:& g. ^7 N2 N! Z
: Y: k/ D* P5 l" V9 H3 f' s0 C: _
5c95b0f51dbecf9eac259ddcf6b3da55.png

, f- h7 B" O9 U6 o& y2 D- f
  m; C: g8 L' u5 B# s82.5.2 调试配置3 N! G7 `' v1 C2 j9 `7 Q
注意这里一定要够大,否则会提示算法文件无法加载:
6 m* N. m# @5 |
- |1 k2 }) o/ y" |4 x4 ^
6b0758d3dd4db39b7189a03d59f0eca0.png
( c: I+ c0 X' Q

: o4 _' X3 A) W5 l# w5 O' m我们这里是将其加到DTCM中,即首地址为0x20000000,大家也可以存储到任意其它RAM地址,只要空间还够加载算法文件即可。
& Z- s8 _! Z1 C/ W" t2 n/ H5 `* v3 v1 d9 b# t* `
如果要做调试下载,需要做如下配置:
+ m! _2 A0 F* U, c  Y# ~- V5 M9 h' _0 i4 s( n  K- q/ [; f8 u+ C. B) f
927401ada0fef49a78ac8029e372a755.png

7 I' s5 A& o7 e- v. q/ m* E. ?! Q0 p4 |0 U. ?4 L; d' u

; T0 |: e5 t4 I+ q3 m- K3 |82.5.3 程序调试效果# z9 H& r% u" m
APP应用程序调试效果如下:
& ]3 M1 L" I/ C0 O) \3 f  o8 \( \
$ S3 L( Q; b  L, b
681a23ba44bd11addce0fa9aae797dbd.png

$ u8 q6 n. R4 q- J# O, s8 `! i- E+ ^2 u' r9 U# }* u
82.6 实验例程说明
% f6 c  X: A8 m
本章配套了两个例子:7 p5 {$ p9 ^* m5 I4 S

/ F7 h& a& I: J9 ~1 i# [  V7-062_QSPI Flash运行程序(Bootloader)。9 y) T9 K" W& u9 ~
  V7-063_QSPI Flash运行程序(用户APP)。' C1 k; x9 c; ^* y) r
: M4 {$ Y$ n( ^0 p4 V

: ]/ J4 ^( b% P$ Q7 S) NBootloader例子需要大家先下载到内部Flash里面,然后按照本章第5小节的说明配置后,就可以像使用内部Flash一样调试下载QSPI Flash了。, C+ U+ w$ t- T8 ~# z6 i) q6 L

( u1 }; p  r# w+ V82.7 总结$ C# H9 k0 t8 e, R" s
本章节就为大家讲解这么,为了熟练掌握,建议大家是操作练**。
( E! G( z- o+ }* W% ?# I: R# ^
1 H" w3 Z& d- O7 Q& n
& }- Y- j; h7 c* T3 H9 Q4 g4 L: R
收藏 评论0 发布时间:2021-12-21 23:21

举报

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