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

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

[复制链接]
STMCU小助手 发布时间:2021-12-21 23:21
82.1 初学者重要提示
8 D6 {0 j4 e' E1 ^0 }' _  操作本章配套例子前务必先将QSPI Flash的下载算法放到MDK安装目录。
9 G5 y+ V8 y9 n. X) r6 _, e8 F  QSPI Flash执行程序的BOOT和APP作用:3 I) g8 L2 Z: x4 G$ `7 u6 W
  BOOT程序需要下载到内部Flash。主要用于跳转到外部QSPI Flash执行程序。那么问题来了,我们可不可以不使用BOOT,上电就直接执行QSPI Flash的程序?不行,因为QSPI Flash不像内部Flash,无需初始化,上电就可以使用,而QSPI Flash不行。( m3 X! F- _0 W2 T& W/ H- Y+ _# w
  APP应用程序要下载到QSPI Flash里面。APP应用程序可以在QSPI Flash里面执行主要是因为W25Q256支持XIP(Execution In Place),并且STM32H7的QSPI Flash支持内存映射。; }# ]$ {: W7 s8 N) R4 R! H8 w
82.2 下载算法存放位置* s& Y4 s5 j' H6 W2 B- E3 Y
编译例子:V7-060_QSPI Flash的MDK下载算法制作,生成的算法文件位于此路径下:
$ o0 `# j" X& I* K/ p) J3 ?! U/ b' b: r. e* d. |
618b073cf66c2944fcdb610aef0e67ea.png
9 ~) _) W" h# Z$ a6 a

& @: v, Q' ^& F$ E" S; `生成算法文件后,需要大家将其存到到MDK安装目录,有两个位置可以存放,任选其一,推荐第2种:
/ M2 S3 R+ S$ p9 ~' [
! L: ]% I' |9 J9 n/ E  第1种:存放到MDK的STM32H7软包安装目录里面:\Keil\STM32H7xx_DFP\2.6.0\CMSIS\Flash(软包版本不同,数值2.6.0不同)。; U3 |3 S" p) D* q/ ^  h
  第2种:MDK的安装目录 \ARM\Flash里面。
- n( N, i0 m# ~+ Y1 l
  N8 m. m0 h# a& c6 v
b192c51eb80b27959d7c06b80a142d6e.png
9 c* W; W1 b" o7 C+ y, F8 z
! V1 \4 e- J3 Q4 {' X& g6 g3 b6 R5 N
82.3 QSPI Flash的Bootloader说明
& C4 q$ K. D+ O) M" z1 E; V" Q
Bootloader的实现比较简单,需要大家将其下载到内部Flash。程序实现上主要注意以下两点即可。
0 y* ?# {5 q. n6 P
% P" x6 u/ G5 c0 W3 _( S82.3.1 初始化QSPI Flash并设置内存映射模式
1 F9 \3 {9 I0 L9 M% ]* ?; F在bsp.c文件中初始QSPI Flash并设置为内存映射模式。9 M1 B) w3 v) i: R* o, v9 S

- J2 }' `' t5 c) z& L: i1 v4 j
  1. /*
    ; Y; N5 S. l7 `1 C
  2. *********************************************************************************************************/ W% v1 E7 e. `+ `/ H- ~
  3. *    函 数 名: bsp_Init+ w+ ~6 h. q' o# e( r
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
      p' C. ~. ^, T# }8 P6 f
  5. *    形    参:无
    , X8 U2 t1 m3 B  m
  6. *    返 回 值: 无
    5 B$ z1 M6 x- v* J0 `
  7. *********************************************************************************************************) O, w6 |" k6 q, S% i
  8. */
    8 {/ Y3 I% b/ @( d& p2 ~! Z
  9. void bsp_Init(void); E" h/ h9 u3 b. y/ ^2 f5 O2 d3 y
  10. {6 r+ K' t3 C, @0 u$ h8 }' D) [1 P8 f, t
  11.     /* 配置MPU */
    7 U: u) j, O+ S' C
  12.     MPU_Config();
    9 H  W  q, O) x0 `  C9 |. I5 }

  13. 3 c9 N3 z1 B9 l9 o1 E7 B
  14.     /* 使能L1 Cache */
    : G7 C( b, v2 X: L" [
  15.     CPU_CACHE_Enable();
    . h* x1 |) N; z) J$ O0 `6 w
  16. + g0 E$ M7 S0 n/ k3 f
  17.     /*
    + C- Q# b2 i* N+ c
  18.        STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:/ ]8 \$ V- b6 {9 q
  19.        - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。' L6 F2 b7 [4 J7 O' g4 i7 D
  20.        - 设置NVIV优先级分组为4。
    , k+ b3 i4 |# @# K4 b+ o
  21.      */
    - D# w& u# K$ F4 X9 O9 M
  22.     HAL_Init();
    $ Q) R5 z; N  M- N
  23. ; f, c7 h# w- U% F, y
  24.     /*
    4 R8 k# Q& u, K5 `8 @6 }
  25.        配置系统时钟到400MHz8 b; L; |& b4 }
  26.        - 切换使用HSE。: G- W& @* L) ?' c7 G8 y# Z) K5 R
  27.        - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
    ; B% Y* a" e9 C' Y
  28.     */9 e. l) M5 S% h" ?
  29.     SystemClock_Config();
    ; X+ f/ W8 {8 }9 G2 ]- O- B/ I* m5 q4 Z
  30. ; Q* [: u& T" O
  31.     /* , S' d, H, R1 g; a* Z9 i0 z
  32.        Event Recorder:7 c. b8 ]6 N2 ~' i. [
  33.        - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。& V% \/ z0 I( [% _
  34.        - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章
    * v' Q" z+ ]2 l# o
  35.     */   
    $ I9 e! {7 y0 o/ O4 k
  36. #if Enable_EventRecorder == 1  
    3 t. V: t+ V' g+ s: j
  37.     /* 初始化EventRecorder并开启 */( P3 k  h- z9 `; L; X
  38.     EventRecorderInitialize(EventRecordAll, 1U);7 @5 ]7 {, T: w5 }
  39.     EventRecorderStart();% a0 f/ a2 j) U2 u
  40. #endif
    4 u! t  N- Y3 v. ^# R8 n" Q
  41. % I% A  W% [" k4 J
  42.     /* 针对不同的应用程序,添加需要的底层驱动模块初始化函数 */0 s+ V4 ^2 g! E0 w; `
  43.     bsp_InitQSPI_W25Q256();  /* 配置SPI总线 */   ( q4 @0 U- u+ O4 M# Z+ y5 a  o  b- w
  44.      QSPI_MemoryMapped();, F4 Z5 p. E1 I' E
  45. }
复制代码

! o4 z* O9 e" n% `+ D3 d82.3.2 程序跳转的实现
8 ~/ l. F0 ^- D* W, H从内部Flash跳转到外部QSPI Flash的实现代码如下
' D2 F9 \2 U6 [* h' i, g' g# K
2 L7 H( o; i3 [6 v
  1. 1.    /*
    + Y- x+ q, m7 E, G
  2. 2.    ******************************************************************************************************: K& n% X! `$ V' b! ]6 x% k
  3. 3.    *    函 数 名: JumpToApp: p- l1 p9 J7 P4 O- Z
  4. 4.    *    功能说明: 跳转到应用JumpToApp
    5 r" ]. u" d) Z, ~- ]
  5. 5.    *    形    参: 无% }7 c, [6 J! T$ t% M, z
  6. 6.    *    返 回 值: 无: ?2 U' Z# H' z" d" H2 I) ]
  7. 7.    ******************************************************************************************************
    & l0 l4 U/ x5 o
  8. 8.    */6 d9 Y' r- l1 |) L4 K
  9. 9.    static void JumpToApp(void)
    ; E$ E5 f2 L" I; n( A0 u4 B
  10. 10.    {
    $ V! a8 ~7 \8 x7 G3 a" F; n
  11. 11.        uint32_t i=0;
    " r9 M! K3 k0 A4 e
  12. 12.        void (*AppJump)(void);         /* 声明一个函数指针 */
    6 U3 u; `2 M8 j) @4 a; X
  13. 13.        __IO uint32_t AppAddr = 0x90000000;  /* APP 地址 */. v$ J4 b6 @% ~& C9 S/ ?
  14. 14.        
      B* h) h! b9 M' r  k: J* x
  15. 15.    5 R: t6 Y, f, k" D7 _* o* f
  16. 16.        /* 关闭全局中断 *// ]2 n  t+ d* s5 G9 D; \0 w
  17. 17.        DISABLE_INT(); - q2 g6 {: s/ E0 `; R
  18. 18.        
    $ |- m$ v9 F) B" y6 H; e
  19. 19.        /* 设置所有时钟到默认状态,使用HSI时钟 */
    6 H( }2 c  L( G3 D4 B
  20. 20.        HAL_RCC_DeInit();
    * ?- h0 C6 e: x" M$ `$ E( Z
  21. 21.        ( }0 q( R/ ?4 D: @) ^% K0 g: x
  22. 22.        /* 关闭滴答定时器,复位到默认值 */
    % i) D5 S/ N+ U$ }
  23. 23.        SysTick->CTRL = 0;
    # {8 k' U: O# N, C
  24. 24.        SysTick->LOAD = 0;
    , l' W9 i$ [" S5 i( `
  25. 25.        SysTick->VAL = 0;1 L- ?& M$ ?" \
  26. 26.   
    5 x  ~  z' z& m( \
  27. 27.        /* 关闭所有中断,清除所有中断挂起标志 */9 D7 I& p+ i$ T
  28. 28.        for (i = 0; i < 8; i++)
      }0 s7 ~8 C. A& I3 m" O
  29. 29.        {
    - z, }% X. {: _1 y) S( f( f
  30. 30.            NVIC->ICER<i>=</i>0xFFFFFFFF;. Y( C& |+ h4 A( ^
  31. 31.            NVIC->ICPR=0xFFFFFFFF;
    * t4 {7 Z* h2 b% d  ?8 _$ w
  32. 32.        }    ; O/ t' ~' k# c, ?3 m6 L3 f- N7 @
  33. 33.    $ t- U8 m0 F( R4 A
  34. 34.        /* 使能全局中断 */
    $ S; W5 D5 t0 Y, b8 H3 f5 d
  35. 35.        ENABLE_INT();
    ) e& V  a$ u6 [. t
  36. 36.    : W$ `3 W; j2 [- x
  37. 37.        /* 跳转到应用程序,首地址是MSP,地址+4是复位中断服务程序地址 */
    + P# \" c# C2 B# E. V% |5 {' B9 |: t( z
  38. 38.        AppJump = (void (*)(void)) (*((uint32_t *) (AppAddr + 4)));
    . P* [% R: V4 K% d+ l# B& y! I
  39. 39.    , k( T& n, H/ d' Z
  40. 40.        /* 设置主堆栈指针 */$ {' u% F0 S" G1 u+ w
  41. 41.        __set_MSP(*(uint32_t *)AppAddr);
    8 k! ~# s7 K. L* R
  42. 42.        1 _9 E% Y, r& w% q2 |0 H
  43. 43.        /* 在RTOS工程,这条语句很重要,设置为特权级模式,使用MSP指针 */. \+ F2 j; G9 S0 H
  44. 44.        __set_CONTROL(0);
    " n# E  s; D1 R! ~3 q
  45. 45.      f8 K; x; d. [0 c  g# _; F( K* B# t
  46. 46.        /* 跳转到系统BootLoader */
    1 r7 _2 o! e3 d' R+ u
  47. 47.        AppJump(); " b  z4 c5 S- R/ o) K; R
  48. 48.    - b9 V  t$ V" I, @
  49. 49.        /* 跳转成功的话,不会执行到这里,用户可以在这里添加代码 */, q0 }6 e3 v! ]/ U# p9 @
  50. 50.        while (1)9 M$ \" q3 d6 |
  51. 51.        {- ?+ f. I- l/ s4 t) q
  52. 52.    , q+ J! [9 j' k5 L# [
  53. 53.        }
    5 r  b" h0 q) G4 P, Y( L
  54. 54.    }
复制代码

! S6 i) _- ~$ A) g7 t9 Y# I; c这里把程序设计中的几个关键地方做个说明:4 w$ _2 l% `4 Y% e
  t: w# E: W# T! t# v+ W' v& Q
  第12行,声明一个函数指针。* k( _# z2 S2 T# J( L2 ^0 _7 I
  第13行,QSPI Flash地址在0x90000000。
( h: W4 L2 Y. }+ k7 t  第20行,此函数比较省事,可以方便的设置H7所有时钟到复位值,内部时钟使用HSI。
" b0 m# m1 C9 d; z/ `4 s  第23到25行,设置滴答定时器到复位值。' z# F6 ~; Y: [  R
  第28到32行,清除所有中断挂起标志并关闭中断,这里是直接通过一个for循环设置了NVIC所有配置位,共8组。
9 [/ O7 ]- D/ _8 K* m: j2 g
  C5 |0 {2 W: D# R5 E
bfe6b8c0ea19b535e2fb06c6618577f6.png

% M7 ?) E6 f5 L3 K. ]1 [8 i) \; a
  第38行,将系统bootLoader的中断复位服务程序的入口地址赋给第12行声明的函数,用户执行这个函数时,就会直接跳转过去。/ i# w  R1 C! T
  第41行,设置主堆栈指针位置,即QSPI Flash应用程序首地址存储的就是栈地址。0 P% ?9 j# s5 f8 O& S; m' c/ u0 O( c
  第44行,这个设置在RTOS应用程序中比较重要,因为基于Cortex-M内核的RTOS任务堆栈基本都是使用线程堆栈指针PSP。但系统bootLoader使用的是主堆栈指针MSP,所以务必要设置下,同时让M内核工作于特权级。此寄存器的作用如下:
+ f3 c; |. `* g) M. C: h5 E' ^9 E6 F/ F
b00b09a901596bcedb07c31790d8d3d9.png

: O# O( g0 G; R* c2 Y6 L5 f8 B/ \1 A  h3 C
  第47行,跳转到系统bootLoader。
: D" H; X9 w% |
) Y+ L9 J1 A: Y. ]82.4 QSPI Flash的APP应用程序说明
, C$ {& F) T3 f. C6 h! CAPP应用程序是由第53章配套例子:V7-033_LCD的汉字小字库和全字库制作 简单修改而来,主要修改如下两个地方:/ L  a0 |+ ?) L) F
6 F! H5 t) E- ^) x8 A1 {
82.4.1 设置Flash地址
' b" ]& m; Q) K9 x7 N设置Flash地址为QSPI Flash首地址0x90000000:
- l) F* L2 H/ x& i. ]  v
5 N+ D4 ^( W: e. B
75afb2342189857e8fa086fc0af08462.png
. Y" Z4 @2 Q2 ?3 {
; A7 l- I$ f5 D3 m8 ?7 F2 S. X3 {
82.4.2 设置中断向量表" m! G/ E3 Q4 y* P5 X# }: K
在main函数最开始就设置中断向量表到QSPI Flash首地址0x90000000,也可以按照本教程第28章的说明,将中断向量表设置到DTCM里面。
& G) E' T9 y6 Z) a2 s" p8 B" T* v4 O0 s
  1. int main(void)
    ) ?( `4 D2 o1 a! V/ U  k! B
  2. {) O' l' h( c/ g3 t
  3.     uint16_t ucBright;           /* 背光亮度(0-255) */* [) T- R8 m6 j6 ?! _4 c# w
  4.     uint8_t ucKeyCode;        /* 按键代码 */
    / Z# W1 T6 G, Y3 U
  5.     uint8_t ucStatus;        /* 主程序状态字 *// A2 p6 o* v6 s8 T8 O9 a
  6.     uint8_t fRefresh;        /* 刷屏请求标志,1表示需要刷新 */4 n, n8 M3 ]5 g5 e3 f

  7. * O8 H: I/ {' I  Z! t/ H( D
  8.     SCB->VTOR = 0x90000000; /* 设置中断向量表地址 */  `2 w/ k- w/ i1 [4 |
  9. . r" G5 T9 ]' W& E% ~
  10.     bsp_Init();    /* 硬件初始化 */" a8 i  O0 a; `" `, m/ g. e
  11.     PrintfLogo();    /* 打印例程名称和版本等信息 */
    * v, v3 p' c1 I" C6 ~
  12.     PrintfHelp();    /* 打印操作提示 */
    ) d& l7 q1 I; v& a

  13. 3 b3 K8 Z& l/ |' ~2 b% C9 E
  14. 省略未写4 z4 l( L7 ]: @3 z1 d+ h7 i2 Q  e

  15. . g( \% D9 y# f& m1 b: `
  16. }
复制代码
$ X" M7 B" C+ a" z( ]
82.5 QSPI Flash的APP应用程序调试下载配置# s- c% l- i; \
将下面两个地方配置后,就可以像使用内部Flash一样使用QSPI Flash进行调试了。& T, P$ M. Q+ |6 V) _9 d0 _

# e. i' ?$ u3 R& F& S; G82.5.1 下载配置
4 [! w: M8 c/ H! j- q. d, K6 N注意这里一定要够大,否则会提示算法文件无法加载:7 B' q, L" T! v( o# }2 q+ \- `- a
6 s5 U' `  i! g( @( D
96d039e1657c72042027eb7e46ffc33a.png

9 M: d$ K; K0 }: o( W) ]- _9 q. ]$ w2 y1 j
我们这里是将其加到DTCM中,即首地址为0x20000000,大家也可以存储到任意其它RAM地址,只要空间还够加载算法文件即可。推荐使用AXI SRAM(地址0x24000000),因为这块RAM空间足够大。/ ^6 s" o: g: ^
- j3 D* m: |9 a5 v1 @/ j3 l" `  R
如果要下载程序到QSPI Flash里面,需要做如下配置:
! e: ]: p% U9 h; R  p% [
6 s* ^% d( f6 m' ?
5c95b0f51dbecf9eac259ddcf6b3da55.png
$ k8 S1 m( D; s& e6 s  @
/ W4 ~2 U, Z0 f+ }; }1 P7 ]
82.5.2 调试配置
4 w5 S4 a7 E0 b. J8 f# \" B+ [注意这里一定要够大,否则会提示算法文件无法加载:
+ S* L2 M' H" ^0 r7 Q2 H; s4 k$ ^
0 v4 z! ]) W% T% e& g0 o/ E
6b0758d3dd4db39b7189a03d59f0eca0.png
7 a7 L5 i& W- N# _6 X+ b) A

& t' m9 h& z* J9 P5 n* K8 u我们这里是将其加到DTCM中,即首地址为0x20000000,大家也可以存储到任意其它RAM地址,只要空间还够加载算法文件即可。
1 t$ s) J# r. r) |5 R1 p  P% D
: G' X) e7 b! Z如果要做调试下载,需要做如下配置:
- y) C" n/ `: J- G9 i+ r7 k; z  h' G# N3 V( s# y! }; e
927401ada0fef49a78ac8029e372a755.png
3 T9 N$ m) z, l- E1 Z% s  @. H

( N& Y: Y5 m) H7 M7 G" g8 _
: n8 l% [; z( J, A) O2 c$ l% k3 m82.5.3 程序调试效果8 C0 W  J9 t3 j5 [0 l) J/ S
APP应用程序调试效果如下:! N* a2 X6 Z2 P: ^- E! T- i2 @5 m
' d0 R  i7 @- C3 Q& P0 a/ N
681a23ba44bd11addce0fa9aae797dbd.png

2 D8 Q% F9 y( j5 r, o1 h3 z& l7 X5 J' a1 q! _# f$ R7 d& N' e# S
82.6 实验例程说明
( a" `# C: T% a1 c3 U
本章配套了两个例子:! o9 t2 v( z" I" C( E/ [

7 i% d: E" Z, T  V7-062_QSPI Flash运行程序(Bootloader)。% K- F) |& Z! A5 H. n8 s3 R
  V7-063_QSPI Flash运行程序(用户APP)。: f1 V. A8 j" k: T

/ A5 N* x# y" |3 \! C& w
$ Q+ K$ M  O2 Q3 d% @. K. ~/ mBootloader例子需要大家先下载到内部Flash里面,然后按照本章第5小节的说明配置后,就可以像使用内部Flash一样调试下载QSPI Flash了。& R# i  W+ S! }+ p& @8 x; I
% f( V9 m4 U" e* \, v, K: Q
82.7 总结
' Y6 e- e) V7 N. t4 @8 j% f- |& Z0 v本章节就为大家讲解这么,为了熟练掌握,建议大家是操作练**。, Q# ~- R6 W* o

# q# c6 t1 `0 x) R& y
5 b- N9 R  d. }: B% h, g# m) `# t! b. ]% o7 I! F) Z0 N' z& ]1 y
收藏 评论0 发布时间:2021-12-21 23:21

举报

0个回答

所属标签

相似技术帖

官网相关资源

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