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

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

[复制链接]
STMCU小助手 发布时间:2021-11-6 22:55
82.1 初学者重要提示
7 V0 U! K  [. T  QSPI Flash的相关知识点可以看第78章和79章。" K% z3 o1 a) f, j/ ]+ q% Y# u
  操作本章配套例子前务必先将QSPI Flash的下载算法放到MDK安装目录。2 _8 d% o& b2 h4 \" `
  QSPI Flash执行程序的BOOT和APP作用:
0 Y  D! M! Z0 Q( d  BOOT程序需要下载到内部Flash。主要用于跳转到外部QSPI Flash执行程序。那么问题来了,我们可不可以不使用BOOT,上电就直接执行QSPI Flash的程序?不行,因为QSPI Flash不像内部Flash,无需初始化,上电就可以使用,而QSPI Flash不行。
; x; D, @. k4 r, A  APP应用程序要下载到QSPI Flash里面。APP应用程序可以在QSPI Flash里面执行主要是因为W25Q256支持XIP(Execution In Place),并且STM32H7的QSPI Flash支持内存映射。2 ^4 L$ A( {! T! T) k5 m- `+ Q. |( {; ?
82.2 下载算法存放位置4 v3 \: {0 @' T. H  d/ V
编译例子:V7-060_QSPI Flash的MDK下载算法制作,生成的算法文件位于此路径下:) D$ L0 B0 `- I- D! L! ]
2 F8 u  i. p  ?' d. d. ]* m
618b073cf66c2944fcdb610aef0e67ea.png
& q" ^) R1 R$ U( o3 w) F2 }

# L  e: N0 W8 u! `  f% B+ j! I: I生成算法文件后,需要大家将其存到到MDK安装目录,有两个位置可以存放,任选其一,推荐第2种:" p/ U$ y$ }: }; f5 s1 ^; x  l+ h$ ?" Z
$ C- [* l* j: C$ l4 E
  第1种:存放到MDK的STM32H7软包安装目录里面:\Keil\STM32H7xx_DFP\2.6.0\CMSIS\Flash(软包版本不同,数值2.6.0不同)。; \  }6 G4 `6 ]5 ^  L
  第2种:MDK的安装目录 \ARM\Flash里面。
. V% M. J2 D. |! ]6 ]2 w
4 b7 w7 a1 Q& E8 }- K5 e
b192c51eb80b27959d7c06b80a142d6e.png
5 Y" H! `8 q. c) T4 {

% @5 ]0 V, j2 u6 T9 b82.3 QSPI Flash的Bootloader说明7 c3 Q2 w0 W4 o5 ?6 S
Bootloader的实现比较简单,需要大家将其下载到内部Flash。程序实现上主要注意以下两点即可。5 t8 [, G7 l6 A
. c% H$ L+ o. g- k- c/ \$ F1 S
82.3.1 初始化QSPI Flash并设置内存映射模式. n3 H$ k/ j/ A6 z* x
在bsp.c文件中初始QSPI Flash并设置为内存映射模式。% s) U( f' ^  {- E6 y4 e/ Y

( p0 i' O1 h" f9 S8 r6 l3 q
  1. /*
    $ Q+ J, Y! o, g0 f) ?% Q, _
  2. *********************************************************************************************************8 v  h8 k+ g. U% i% \) Z0 f( X# D) _/ |
  3. *    函 数 名: bsp_Init
    ; N" F9 r& `" z) }1 b; m
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次% I. k: G* O# ^9 b1 p  P$ Q  Q
  5. *    形    参:无. `; e0 f3 e4 Q" A, D/ }6 ]) |+ j
  6. *    返 回 值: 无% s! b# }3 r% m& ?  h7 F' h* s
  7. *********************************************************************************************************1 v$ {7 P  W& X3 Q& n- y, U$ c
  8. */
    # C6 C# U' `3 ]( B0 p' N
  9. void bsp_Init(void)
    8 V$ }. B$ s, }
  10. {& R" h$ F! Z; l% z6 q0 z7 v
  11.     /* 配置MPU */& O8 {" q2 i9 I5 F* d# k
  12.     MPU_Config();/ h' t7 t7 T; ?; c- m

  13. * Q, O# c: m; e$ o
  14.     /* 使能L1 Cache */% k. B- F, b( ?- H9 O) m; E
  15.     CPU_CACHE_Enable();0 A- B/ V6 H6 y) w
  16. $ i8 ~- T1 V& ]/ T/ B( y; w
  17.     /*
    ; k1 ?8 G( Z) j# |2 X6 R% K& `) e
  18.        STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:
    1 {" O  P/ Z. f. C
  19.        - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
    % y8 K, a- B4 M. H# R
  20.        - 设置NVIV优先级分组为4。
      m: S8 s: B! c
  21.      */
    * x, j3 H5 o0 Q" ^% V: i
  22.     HAL_Init();
    3 d  D% X* R) B% F/ b7 a, Y) s/ r( s
  23. 5 W5 c# ?# Y" i- P2 n
  24.     /* 5 m/ y1 X" ]% i. k; F
  25.        配置系统时钟到400MHz
    , v) ~7 Y( ~5 [! E+ y8 ^$ V2 c
  26.        - 切换使用HSE。3 ~! h. T: K1 p5 x" p' u. e; ?
  27.        - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。- F" |, Q" h& n, v- j/ v( i
  28.     */
    . }) |* l' }: k# s6 d9 r
  29.     SystemClock_Config();
    4 N7 L& {* i/ Z" @
  30. 5 Q; J4 L+ e+ c6 \' M
  31.     /* ; K, r8 b; W- @6 f8 V, h$ E7 t
  32.        Event Recorder:! s$ z5 F! _5 E0 I# T
  33.        - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
    # L; R8 n+ |" z
  34.        - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章
    9 b: Z7 k0 \" N6 a9 H
  35.     */    2 I4 v! [3 `; @  P4 V2 ?; G
  36. #if Enable_EventRecorder == 1  3 B0 a. `1 K0 n4 p1 K
  37.     /* 初始化EventRecorder并开启 */
    6 S; e3 H# z+ K6 l) p6 T  d
  38.     EventRecorderInitialize(EventRecordAll, 1U);
    3 R( e, S; l7 g5 `# z; y
  39.     EventRecorderStart();9 }5 K( O# I) R; y: I3 s
  40. #endif6 c) v7 j0 h1 g/ N

  41. : {5 \( _6 V: |
  42.     /* 针对不同的应用程序,添加需要的底层驱动模块初始化函数 */
    ( r7 E# h8 k# H' _. V2 @% u1 v
  43.     bsp_InitQSPI_W25Q256();  /* 配置SPI总线 */   . ]# r. J7 Y4 w% }
  44.      QSPI_MemoryMapped();
    6 f; d1 m2 j5 D! I  f  A0 T
  45. }
复制代码
$ s' y5 K, v# l" j; j% w
82.3.2 程序跳转的实现: E0 d2 K- @+ P% A
从内部Flash跳转到外部QSPI Flash的实现代码如下
) A7 k' w) J4 v$ h' A# ~( O
, J* c7 q# N7 J; T
  1. 1.    /*
    : q6 K. \. I- T  H: H) g  ~9 c
  2. 2.    ******************************************************************************************************
    0 u7 |. s7 q/ z3 |! ~- C
  3. 3.    *    函 数 名: JumpToApp, g+ H. A' ?. w) U
  4. 4.    *    功能说明: 跳转到应用JumpToApp
    " }, y) s4 x- c
  5. 5.    *    形    参: 无
    # e; d5 k2 }2 H& k  D4 M
  6. 6.    *    返 回 值: 无, K6 i+ c: z) T6 W: b) t
  7. 7.    ******************************************************************************************************, c$ o# Z. }* V/ i* D
  8. 8.    */
    - M4 K3 O8 g0 X7 I/ J5 @
  9. 9.    static void JumpToApp(void)
    5 ?/ K6 u) D; p
  10. 10.    {
    & E5 C% K% O+ o' M6 Y8 G9 ?. _6 ]2 B
  11. 11.        uint32_t i=0;
    9 Y0 Z1 P* h8 m, E9 C; R7 @6 L
  12. 12.        void (*AppJump)(void);         /* 声明一个函数指针 */
    & g1 f+ K) S8 p8 ~: }
  13. 13.        __IO uint32_t AppAddr = 0x90000000;  /* APP 地址 */
    0 \  a0 d6 }8 h2 T
  14. 14.        
    - W4 K( k* F7 D
  15. 15.    : D7 D& ]8 f0 G% D! `  r! B
  16. 16.        /* 关闭全局中断 */, P* {+ [2 g2 f0 V8 l8 c
  17. 17.        DISABLE_INT();
    # g/ G8 k: h' u
  18. 18.        
    4 D0 k( Y0 z6 n+ l) V* c, a7 |* b
  19. 19.        /* 设置所有时钟到默认状态,使用HSI时钟 */
    ( y5 w# X! C: |$ f4 P1 b
  20. 20.        HAL_RCC_DeInit();. D; n1 N, R* Y1 X
  21. 21.        
    - [5 n; C& `* q& a5 B
  22. 22.        /* 关闭滴答定时器,复位到默认值 *// v9 N# C, p* H
  23. 23.        SysTick->CTRL = 0;
    . \3 Q7 x% M8 s: H
  24. 24.        SysTick->LOAD = 0;7 w$ o/ U6 h. z# \; r+ r) V1 C
  25. 25.        SysTick->VAL = 0;! M  e0 S. ], H+ v
  26. 26.    $ [- t9 v, u: W  i
  27. 27.        /* 关闭所有中断,清除所有中断挂起标志 */- x& D( L. h" o' [: Y
  28. 28.        for (i = 0; i < 8; i++)
    ! N/ g7 s( ~; b; b. I
  29. 29.        {3 Z/ W* y- t! k5 s" `5 E* C, Q
  30. 30.            NVIC->ICER<i>=0xFFFFFFFF;</i>
    . ^2 [) \3 P- b! N. s9 w% h8 l
  31. 31.            NVIC->ICPR=0xFFFFFFFF;. L! l/ W- c) {- `
  32. 32.        }   
    + J: s/ M) a. o- R! c2 H' ?
  33. 33.   
    1 j4 d- X" K0 K$ E
  34. 34.        /* 使能全局中断 */
    7 \, k3 w; P6 d# |( ^! e" [; b- Z; |
  35. 35.        ENABLE_INT();7 ?6 ~2 V. D$ W
  36. 36.    , a8 r0 M$ k# [0 V" Y# D
  37. 37.        /* 跳转到应用程序,首地址是MSP,地址+4是复位中断服务程序地址 */
    5 |2 Z$ W5 L* ^( c0 \  y
  38. 38.        AppJump = (void (*)(void)) (*((uint32_t *) (AppAddr + 4)));$ u8 V* Y7 I/ ?' y6 E9 Z/ q
  39. 39.   
    3 V5 A& n9 z) U0 L# K: d- E2 S8 U
  40. 40.        /* 设置主堆栈指针 */8 W7 F7 r; U1 u$ e2 g: f$ x( @
  41. 41.        __set_MSP(*(uint32_t *)AppAddr);
    + j) Z3 \( n- ?8 p; Z! E" s( ?
  42. 42.        
    5 ^; n0 ?4 C+ |4 T7 [
  43. 43.        /* 在RTOS工程,这条语句很重要,设置为特权级模式,使用MSP指针 */
    8 H: T) |# I, q# y
  44. 44.        __set_CONTROL(0);
    3 c8 D2 @% ?4 G. t/ K
  45. 45.    ( J& v7 S) J- Y- E7 i! r1 u% Y& k$ O
  46. 46.        /* 跳转到系统BootLoader */
    + k) n. E) z5 M- a5 x0 Y
  47. 47.        AppJump(); & P' R# H3 o1 X7 {( k
  48. 48.    8 }0 A3 H8 B1 L0 o8 T
  49. 49.        /* 跳转成功的话,不会执行到这里,用户可以在这里添加代码 */
    : x$ U5 }7 R% [1 G; B$ e7 L. {
  50. 50.        while (1)4 `7 o8 a( R, c2 ]+ g
  51. 51.        {5 @' _* P# I5 ~2 Y
  52. 52.    3 f  ?# e( |  D3 I1 i
  53. 53.        }
    ( e: a7 _' x( _' K0 m
  54. 54.    }
复制代码
2 q* R' a5 C  r: |  V3 J
这里把程序设计中的几个关键地方做个说明:# `) U4 k8 b6 N( R# E7 J- d

3 ?  m" j9 U: R; w7 o/ l" N  第12行,声明一个函数指针。
% @1 \  W( o) y  第13行,QSPI Flash地址在0x90000000。
. r+ P/ m/ b% j- D& s/ Z  第20行,此函数比较省事,可以方便的设置H7所有时钟到复位值,内部时钟使用HSI。
0 l; \( L+ [! V8 ]7 Q  第23到25行,设置滴答定时器到复位值。/ h2 I2 v. b- t
  第28到32行,清除所有中断挂起标志并关闭中断,这里是直接通过一个for循环设置了NVIC所有配置位,共8组。: O0 |& S1 Q8 t1 @
+ T  Y( s7 l" ~* p  Q/ u" T
bfe6b8c0ea19b535e2fb06c6618577f6.png
8 R, w1 T1 i2 t- c0 a

  f5 z" Y9 f0 H  第38行,将系统bootLoader的中断复位服务程序的入口地址赋给第12行声明的函数,用户执行这个函数时,就会直接跳转过去。
% g3 T. t7 g2 f5 G# Y! h  l  第41行,设置主堆栈指针位置,即QSPI Flash应用程序首地址存储的就是栈地址。
) L) D( V$ W! m9 E$ i9 F$ P  第44行,这个设置在RTOS应用程序中比较重要,因为基于Cortex-M内核的RTOS任务堆栈基本都是使用线程堆栈指针PSP。但系统bootLoader使用的是主堆栈指针MSP,所以务必要设置下,同时让M内核工作于特权级。此寄存器的作用如下:
' W9 e# {  s/ W7 y" G- ^6 L! }/ t( r# T( W' t- X% E) o
b00b09a901596bcedb07c31790d8d3d9.png

, D! Y- O: t8 t* v8 u  K  D  ?: P/ Z# f0 f
  第47行,跳转到系统bootLoader。
- j0 ]1 z7 k* z, S6 D82.4 QSPI Flash的APP应用程序说明6 J5 Q+ z# B/ L
APP应用程序是由第53章配套例子:V7-033_LCD的汉字小字库和全字库制作 简单修改而来,主要修改如下两个地方:- @" Q" Z5 H" e  ~, w8 G* ?, J

* j  p9 m' v, M- o0 |! ]82.4.1 设置Flash地址: N) Q( c" |0 K: o
设置Flash地址为QSPI Flash首地址0x90000000:
0 x. Z. z0 C8 Y3 G2 l  q5 _; E$ H2 n' k+ w* m9 i# W# U+ M
75afb2342189857e8fa086fc0af08462.png

; O; M" [) K6 l# s. N! J- Y) Y4 U' _/ z0 @" o0 J" f
82.4.2 设置中断向量表
" {* r' F' c" s( P% f: J5 B# }在main函数最开始就设置中断向量表到QSPI Flash首地址0x90000000,也可以按照本教程第28章的说明,将中断向量表设置到DTCM里面。
; v- o/ J- u1 c6 u$ P8 g  {% E9 l: R2 v/ b! q. S  q
  1. int main(void)
    0 Q; ~, p4 U6 ], @4 D! J
  2. {1 S  k5 D: M: x% c
  3.     uint16_t ucBright;           /* 背光亮度(0-255) */
    2 q" }: @( z0 G$ m* j' q: E: l0 y
  4.     uint8_t ucKeyCode;        /* 按键代码 */& ^: F3 I3 F! m0 L
  5.     uint8_t ucStatus;        /* 主程序状态字 */
    1 S! k, u8 d0 V7 \
  6.     uint8_t fRefresh;        /* 刷屏请求标志,1表示需要刷新 */
    5 N; q7 L% t$ G) n
  7. " l/ M9 j5 q7 L8 A, @! e
  8.     SCB->VTOR = 0x90000000; /* 设置中断向量表地址 */6 N* `! C8 Y4 L( M- M

  9. ; q  B0 L" f  a
  10.     bsp_Init();    /* 硬件初始化 */* S, U' b# [! u  ~- S
  11.     PrintfLogo();    /* 打印例程名称和版本等信息 */
    8 e+ {9 q9 z" }: C. ^* z
  12.     PrintfHelp();    /* 打印操作提示 *// \; W$ D0 G1 y8 G

  13. 5 r8 `+ i" j$ l4 C/ |7 ~& R
  14. 省略未写
    % X; f; E9 V+ f. s& V/ e5 }# l1 y
  15. $ D8 o8 I5 m; @/ R! A- R" Q
  16. }
复制代码
" C0 {; R) p" S8 }8 B
82.5 QSPI Flash的APP应用程序调试下载配置
( t0 t4 Z5 w# l7 e: t3 B$ R将下面两个地方配置后,就可以像使用内部Flash一样使用QSPI Flash进行调试了。/ B# Z' W! A3 b. f# r

+ e, }, H0 h; g0 h) F82.5.1 下载配置- _4 x; Y# d6 D
注意这里一定要够大,否则会提示算法文件无法加载:6 {' ], ^+ Y% a/ B
6 p, H; U& N3 G. Z* e& ]" O5 j& _* M& Z
6b0758d3dd4db39b7189a03d59f0eca0.png
8 @2 ?$ _, D. H8 C" n
2 N6 `' s. Y  I/ F. t6 h1 n! K
我们这里是将其加到DTCM中,即首地址为0x20000000,大家也可以存储到任意其它RAM地址,只要空间还够加载算法文件即可。推荐使用AXI SRAM(地址0x24000000),因为这块RAM空间足够大。
( {1 |) @7 a- x6 h" m
9 k" j" g( h& \9 G- ]# |6 v' X7 O如果要下载程序到QSPI Flash里面,需要做如下配置:
( D. f% I- y3 g; e5 q5 D! ?& S- Z, ?8 e0 y5 M6 k
5c95b0f51dbecf9eac259ddcf6b3da55.png
; ?: I2 l2 L$ N* v! {
; Z0 `0 ^% D1 y1 Y* [! p! f2 `
82.5.2 调试配置
2 X3 f/ f! w) I$ M7 i注意这里一定要够大,否则会提示算法文件无法加载:9 v+ G" X+ l' j, ~3 }- D/ P

* t) {; ?! m# s. c9 s

8 J4 m6 |# s2 R4 t) M, s+ d  c) a) j/ q9 k1 f0 T
我们这里是将其加到DTCM中,即首地址为0x20000000,大家也可以存储到任意其它RAM地址,只要空间还够加载算法文件即可。7 X4 X1 K$ H6 c) w" Z
& p. s( F0 z) W$ A+ W
如果要做调试下载,需要做如下配置:
. C% E  b, y2 J8 m) `* h5 s" P5 I4 N' L7 S
927401ada0fef49a78ac8029e372a755.png
4 F7 C5 z: p! q, U4 p5 w- C+ I

5 e: }; n$ O/ Z2 B0 E
  ]5 h: P. V* p% n2 h7 {& `' c82.5.3 程序调试效果
& s& U+ x, W& L; j, |; ZAPP应用程序调试效果如下:
. n, u6 N+ A$ P- K( ?
( U2 D0 u: J9 H. ?9 c
681a23ba44bd11addce0fa9aae797dbd.png

$ Z" c! x7 @+ j& B5 f% Z9 m+ x3 I- P2 F7 {6 E" t% E
82.6 实验例程说明5 ~# R- s! ?0 l0 i
本章配套了两个例子:2 A& U2 ~; X5 R7 v  u, Z: a

* w0 |- q" M* s. ]- s& I  V7-062_QSPI Flash运行程序(Bootloader)。' }9 y2 _6 I) s' A
  V7-063_QSPI Flash运行程序(用户APP)。
- ^. g" O+ j/ ^. {' W- I# ~/ z8 |) y8 K( {9 u% r( ^

! [* T, D' f" l$ p' q7 P8 HBootloader例子需要大家先下载到内部Flash里面,然后按照本章第5小节的说明配置后,就可以像使用内部Flash一样调试下载QSPI Flash了。" X7 R2 ]  }# d9 l' ]2 ~
7 J+ Y* s5 Q* M  e# G- ^
82.7 总结
$ o) ]3 p0 {6 L7 w3 I% a本章节就为大家讲解这么,为了熟练掌握,建议大家是操作练**。
9 t0 Q: d4 N6 C2 W1 S
3 h) ^' _. W2 B) R- `$ K
) [/ ]* G  B8 C0 B1 B, ^' t
96d039e1657c72042027eb7e46ffc33a.png
赞 收藏 评论0 发布时间:2021-11-6 22:55

举报

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