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

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

[复制链接]
STMCU小助手 发布时间:2021-12-21 23:21
82.1 初学者重要提示5 j9 |6 Y! x" x% {" ]. ^) Y* j- J
  操作本章配套例子前务必先将QSPI Flash的下载算法放到MDK安装目录。4 o8 x- x3 s1 o6 Z
  QSPI Flash执行程序的BOOT和APP作用:
8 h% k: C1 {! f) H& N0 D2 p  BOOT程序需要下载到内部Flash。主要用于跳转到外部QSPI Flash执行程序。那么问题来了,我们可不可以不使用BOOT,上电就直接执行QSPI Flash的程序?不行,因为QSPI Flash不像内部Flash,无需初始化,上电就可以使用,而QSPI Flash不行。) @: v3 t1 n, r7 U* P5 ^& Y4 C
  APP应用程序要下载到QSPI Flash里面。APP应用程序可以在QSPI Flash里面执行主要是因为W25Q256支持XIP(Execution In Place),并且STM32H7的QSPI Flash支持内存映射。* f* E1 a6 k+ U) Z, n1 T: e
82.2 下载算法存放位置* _' P/ }  X0 t& \
编译例子:V7-060_QSPI Flash的MDK下载算法制作,生成的算法文件位于此路径下:& F3 c$ f; ?! d: N) T3 M
" I" r$ U: \. G) {, P
618b073cf66c2944fcdb610aef0e67ea.png

5 A! p8 y- P8 Y# ^- m8 f3 u$ b& w# Z5 f( u: }: p
生成算法文件后,需要大家将其存到到MDK安装目录,有两个位置可以存放,任选其一,推荐第2种:! e/ R- }3 i/ g; \* Q

( V' f% ^& e) A  第1种:存放到MDK的STM32H7软包安装目录里面:\Keil\STM32H7xx_DFP\2.6.0\CMSIS\Flash(软包版本不同,数值2.6.0不同)。! b: J+ q; ]* b* b0 Y: v) h
  第2种:MDK的安装目录 \ARM\Flash里面。0 W/ Q" [* p" Y& z+ V
. @' d8 X( e$ K% e, q
b192c51eb80b27959d7c06b80a142d6e.png
. V( O5 Z. \: ^

% X+ B+ w2 r. B7 z# L82.3 QSPI Flash的Bootloader说明

9 c8 K# K$ I9 F3 `+ @5 `% h! ZBootloader的实现比较简单,需要大家将其下载到内部Flash。程序实现上主要注意以下两点即可。
4 C5 s! |% |+ J8 ?: K' r6 b
& D# X. b* f8 d7 H82.3.1 初始化QSPI Flash并设置内存映射模式
0 B% B9 m9 g$ l  C8 y; p在bsp.c文件中初始QSPI Flash并设置为内存映射模式。
; `4 X) C- R* L1 k7 V- r" C1 B( c' p, |8 G/ p5 B& {- q% z
  1. /*
    & H4 q) b# j# U' \7 E' G8 W
  2. *********************************************************************************************************! x) T& @6 O% @( V9 `
  3. *    函 数 名: bsp_Init
    # m" E$ i8 u" h: L
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次6 |% \7 {! O/ j+ H' J% t* P
  5. *    形    参:无3 [- u9 U7 H6 }
  6. *    返 回 值: 无
    8 [/ m5 y3 T( c
  7. *********************************************************************************************************
    , x/ ^; ?" n2 }( _
  8. */
    9 S9 a& C5 B: S) w9 t
  9. void bsp_Init(void)9 x7 b9 c$ Z( J4 {9 a6 b+ w0 n# h$ J
  10. {& H: a6 T3 y2 [' p2 N
  11.     /* 配置MPU */' M& M, R8 a% L" l' c6 a1 H
  12.     MPU_Config();  x% L2 P' y) m: I( L- _2 B

  13. $ V: M4 r5 r' F; @# R
  14.     /* 使能L1 Cache */0 l  ]+ T" N( J3 `
  15.     CPU_CACHE_Enable();- k! m9 ?6 g. t& h" l/ f

  16. & s7 s; \7 B% u9 I$ d9 x
  17.     /* 5 c/ P; H7 x) S! ]" b  ?' z) r) v
  18.        STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:) V. ?# r) B6 P: y1 ~
  19.        - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。7 D5 [2 a3 H& w, G# W$ i- o
  20.        - 设置NVIV优先级分组为4。
    * n  @) }" R9 b9 U  W8 I) N5 Q0 p/ A
  21.      */+ R/ X2 b' f9 f1 J1 C$ e
  22.     HAL_Init();
    " }) l5 C0 X) k' f9 R. C
  23. ) c2 F# h7 K) l4 A
  24.     /* 0 U" L; z% D; q$ z$ |
  25.        配置系统时钟到400MHz
    5 Z" @6 N) b8 c: ^
  26.        - 切换使用HSE。
    % G7 D; N0 j6 c$ u( |$ `1 B& V
  27.        - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。' Y4 |7 H, `) w$ S0 o$ ]
  28.     *// D! Z+ ]2 K  S: e3 w  s3 N
  29.     SystemClock_Config();
    6 M& J, I/ Z! L$ c

  30. / E* U- J: p3 i8 b
  31.     /*
    . \. e0 i% M% e& {! l
  32.        Event Recorder:
    ! \6 Z/ Z3 J4 P" Z8 N, V
  33.        - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
    ; Z# |/ a) U. N6 d, i  q
  34.        - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章
    7 g' X" Q" F5 i& M
  35.     */    ' ]9 z/ y2 G* R, p6 X+ I
  36. #if Enable_EventRecorder == 1  
    ; X' Z7 }3 A' x5 R' i6 ~3 `
  37.     /* 初始化EventRecorder并开启 */
    : e) Y% H" N2 `3 Y5 ~; f
  38.     EventRecorderInitialize(EventRecordAll, 1U);
    % f! A! E  C9 ?* |; G  d, s8 Y
  39.     EventRecorderStart();# O) |9 {" K' o- [" X; @
  40. #endif
    # w! H/ Q# f% S1 n: l% h

  41. ) \2 Z' g7 A- z" d" V& }5 a5 j
  42.     /* 针对不同的应用程序,添加需要的底层驱动模块初始化函数 */
    0 S8 _) P/ t% z" h( `5 c
  43.     bsp_InitQSPI_W25Q256();  /* 配置SPI总线 */   6 g4 H, P! H/ _. Z
  44.      QSPI_MemoryMapped();
    + z; x/ b6 t+ t1 ]4 |# @5 f' F
  45. }
复制代码
8 M& {  |/ a; e4 X1 _
82.3.2 程序跳转的实现
6 q& b7 h$ a$ }/ j从内部Flash跳转到外部QSPI Flash的实现代码如下+ [0 }! e$ ]6 t% T7 v, u0 M8 m2 y% W

* x8 Y5 y9 J8 F/ R8 {6 M0 T4 ^
  1. 1.    /*7 C0 r, Y9 T' x" F
  2. 2.    ******************************************************************************************************
    3 E1 Z& ?9 H9 M8 z! X0 s6 Y3 [
  3. 3.    *    函 数 名: JumpToApp
    7 W0 k, L7 u$ n2 C: ^
  4. 4.    *    功能说明: 跳转到应用JumpToApp
    ' }- U  K. t( [* A. W/ t
  5. 5.    *    形    参: 无
      d" a5 u- X( ~" i& Q$ X
  6. 6.    *    返 回 值: 无
    8 ^4 A! V5 G7 F8 m" e$ l. r
  7. 7.    ******************************************************************************************************
    / f2 D7 A' Z8 V; d/ ], ]) |8 _- G1 |
  8. 8.    */% R  c) f7 G. g7 L* p5 t5 {
  9. 9.    static void JumpToApp(void)
    # |$ M+ t" z4 ~3 x* b
  10. 10.    {3 y: w5 g5 j, t5 D! D
  11. 11.        uint32_t i=0;* o0 a% ?; v5 y5 C* Z
  12. 12.        void (*AppJump)(void);         /* 声明一个函数指针 */
    3 @2 C( _% y0 N" c: w" y9 P$ e: L
  13. 13.        __IO uint32_t AppAddr = 0x90000000;  /* APP 地址 */
      s( h& t- E  n* ?. i, }( j
  14. 14.        $ |; }& Q" L, D& c+ x+ m& M
  15. 15.    & T! V* o! n8 i2 ^
  16. 16.        /* 关闭全局中断 */
    . P, E' f) S0 y3 Z0 M) I/ G. S0 ^8 Y
  17. 17.        DISABLE_INT();
    & E" J4 l% T+ n, e1 a6 O6 A
  18. 18.        . I. t3 K$ l9 v5 Q. j
  19. 19.        /* 设置所有时钟到默认状态,使用HSI时钟 */! z" _: M" Y5 ~! G2 X+ n
  20. 20.        HAL_RCC_DeInit();
    & Z( n& ~  a! i& e1 Q
  21. 21.        / ^# I0 ?5 d, _  r9 }8 c7 N" ]% u
  22. 22.        /* 关闭滴答定时器,复位到默认值 */
    " _, z2 f3 g, ?/ p/ t
  23. 23.        SysTick->CTRL = 0;& B$ K: @6 S4 @! P9 u
  24. 24.        SysTick->LOAD = 0;
    . P7 J0 I# H9 Z- M5 S" v
  25. 25.        SysTick->VAL = 0;  k/ _6 r, r0 l. O) r' r
  26. 26.    ; M3 }, x5 t1 C" h
  27. 27.        /* 关闭所有中断,清除所有中断挂起标志 */8 v; f# G7 q9 k0 T
  28. 28.        for (i = 0; i < 8; i++)$ \7 o$ N. J, k! \) A
  29. 29.        {
    + S! z, U9 b, R6 ]- T5 D
  30. 30.            NVIC->ICER<i>=</i>0xFFFFFFFF;* P( X& q1 y+ R
  31. 31.            NVIC->ICPR=0xFFFFFFFF;  X% l) r& P8 s
  32. 32.        }      {: v- p5 [. B4 d5 M
  33. 33.   
    6 U; N; j4 L& A9 z( T
  34. 34.        /* 使能全局中断 */
    , Q) Q- |; D/ z! Q+ H
  35. 35.        ENABLE_INT();
    ) O6 X) W0 ?  |/ @! @8 p& x3 {
  36. 36.      f$ s7 u3 n! p4 _
  37. 37.        /* 跳转到应用程序,首地址是MSP,地址+4是复位中断服务程序地址 */
    7 `; W7 C8 d4 l+ ?1 Z5 i+ l
  38. 38.        AppJump = (void (*)(void)) (*((uint32_t *) (AppAddr + 4)));. H' B) @+ k/ [% B5 f  }
  39. 39.   
    . h- C3 e5 J( `
  40. 40.        /* 设置主堆栈指针 */
    6 u" {1 N  |- w8 E) }
  41. 41.        __set_MSP(*(uint32_t *)AppAddr);/ n$ V: X2 ?& I2 A3 u6 `# F
  42. 42.        
    & o: G  z- c. u) e
  43. 43.        /* 在RTOS工程,这条语句很重要,设置为特权级模式,使用MSP指针 */) C3 ?( W( w! \! P
  44. 44.        __set_CONTROL(0);) S0 \  v, ^" B. B- E0 H
  45. 45.    2 d- x+ A# x) Z9 I) V; q) h3 p$ d' Q
  46. 46.        /* 跳转到系统BootLoader */! x0 e1 i$ |& h4 L4 m
  47. 47.        AppJump();
    : Z: ]! u: n+ i9 r( o4 J
  48. 48.    8 Q7 j4 }4 |6 n7 z# ^& s
  49. 49.        /* 跳转成功的话,不会执行到这里,用户可以在这里添加代码 */0 i; a9 s) P9 y  |! ~6 t! h1 O8 Y
  50. 50.        while (1). i3 n& O- k1 W, Q+ F, F) u
  51. 51.        {
    6 d- L, |* R0 b. u
  52. 52.   
    0 Z9 _; E, Z  T
  53. 53.        }) N4 S. r: ^7 u( y/ P: A0 i, {
  54. 54.    }
复制代码
5 r+ o: ]( ^/ T6 E! j
这里把程序设计中的几个关键地方做个说明:
) _9 K! ^) f' a& h. `* \+ {) O1 F8 N% ~7 ~6 J% N4 B
  第12行,声明一个函数指针。. f) Z2 r/ Q; O2 ~4 ~: T! X5 e
  第13行,QSPI Flash地址在0x90000000。: T: `3 z! P. R" Q0 D! T. S
  第20行,此函数比较省事,可以方便的设置H7所有时钟到复位值,内部时钟使用HSI。; `$ t2 Z7 |' |" M1 A# H
  第23到25行,设置滴答定时器到复位值。
& a  w2 k" h# k6 \. j6 z# |* W  第28到32行,清除所有中断挂起标志并关闭中断,这里是直接通过一个for循环设置了NVIC所有配置位,共8组。+ Y, C! y- r" i4 F* T& T

" n4 B" m2 j) u1 a: I2 h6 Y
bfe6b8c0ea19b535e2fb06c6618577f6.png
8 y$ x. }% s$ ~' t. L9 ?
. s  V* ]+ k$ H2 o3 ?5 J
  第38行,将系统bootLoader的中断复位服务程序的入口地址赋给第12行声明的函数,用户执行这个函数时,就会直接跳转过去。. ~. K* _. ?! f: t: X
  第41行,设置主堆栈指针位置,即QSPI Flash应用程序首地址存储的就是栈地址。
& L) N" U' u& j1 ?. I! X  第44行,这个设置在RTOS应用程序中比较重要,因为基于Cortex-M内核的RTOS任务堆栈基本都是使用线程堆栈指针PSP。但系统bootLoader使用的是主堆栈指针MSP,所以务必要设置下,同时让M内核工作于特权级。此寄存器的作用如下:( l: m) V1 [6 @7 K. S' W! i

+ Q0 x# f/ q  T4 \% S2 @  M) p
b00b09a901596bcedb07c31790d8d3d9.png
+ p$ u0 O! X# \! h3 t6 y
# w/ J9 o% R! Y/ @2 W( O, b
  第47行,跳转到系统bootLoader。, d3 Q  @" D) B, @. Z# Q8 v/ u0 }

8 O$ C1 t+ q" @/ j82.4 QSPI Flash的APP应用程序说明0 x' s$ Z- R* ^' O, y! \
APP应用程序是由第53章配套例子:V7-033_LCD的汉字小字库和全字库制作 简单修改而来,主要修改如下两个地方:0 G/ i/ n4 ^/ h$ |% I& _

# q  q5 h8 b) p. Y+ M5 m) B82.4.1 设置Flash地址
+ U% C$ a0 M  J7 U1 n- `1 b设置Flash地址为QSPI Flash首地址0x90000000:
! c1 Z2 T4 o6 t* ?
4 h7 O/ Q0 N0 T1 ]
75afb2342189857e8fa086fc0af08462.png

' Z& V: ^$ C# N& O. [1 W3 T' p2 f
* X, I0 l! {6 c: |% z82.4.2 设置中断向量表6 F- S7 v2 v# r( v- F/ m
在main函数最开始就设置中断向量表到QSPI Flash首地址0x90000000,也可以按照本教程第28章的说明,将中断向量表设置到DTCM里面。8 H5 c9 e" L3 \+ @9 D0 g8 P
4 z$ _' Z/ C3 Z& ?0 O  p, H
  1. int main(void)
    , }0 x8 f: N0 i$ T& r) j6 _% }
  2. {3 c/ s6 I: C$ K$ X0 L/ ]+ `
  3.     uint16_t ucBright;           /* 背光亮度(0-255) */; @( v, X6 e- N2 _4 S% J  ^, q
  4.     uint8_t ucKeyCode;        /* 按键代码 */2 t- a" k" R% b9 G0 D- ~1 x
  5.     uint8_t ucStatus;        /* 主程序状态字 */* `* Y/ G2 @* k0 f( ]% H( S5 n
  6.     uint8_t fRefresh;        /* 刷屏请求标志,1表示需要刷新 */
    & v$ H/ z) Q9 v
  7. ' G- T8 f( [6 E) N! ?& s
  8.     SCB->VTOR = 0x90000000; /* 设置中断向量表地址 */8 t; N- L! N2 A& k
  9. : i' u. e% X3 I$ @$ w- A" O
  10.     bsp_Init();    /* 硬件初始化 */
    9 @/ ?$ L3 W+ I3 A
  11.     PrintfLogo();    /* 打印例程名称和版本等信息 */
    ! y2 ^0 k- p: x* E7 [$ z; U# e
  12.     PrintfHelp();    /* 打印操作提示 */- w4 w# v2 h0 Y

  13. ' I; l; L/ _5 x% j) e2 y
  14. 省略未写
    * D* I7 Q2 g! n& b7 U

  15. # J4 ~: _; |' b6 }8 I+ i
  16. }
复制代码
' q# V8 Z4 N. y6 E
82.5 QSPI Flash的APP应用程序调试下载配置
, y2 R  f" s# S' l& o1 b1 }将下面两个地方配置后,就可以像使用内部Flash一样使用QSPI Flash进行调试了。
7 u# k( |6 U: n6 }  n( ^. p* V$ l" b: P- x
82.5.1 下载配置4 r, P7 X5 A1 Z
注意这里一定要够大,否则会提示算法文件无法加载:
) e- {* p2 }' R; k
# p; B% [% f" m$ R6 r0 x8 W; M
96d039e1657c72042027eb7e46ffc33a.png
/ X: l& }5 Z# H, B. ]/ n
8 k3 g5 n$ o( p+ E$ [
我们这里是将其加到DTCM中,即首地址为0x20000000,大家也可以存储到任意其它RAM地址,只要空间还够加载算法文件即可。推荐使用AXI SRAM(地址0x24000000),因为这块RAM空间足够大。
- r: m( W9 R) G; y$ T5 ^
2 c" C2 O" K  _! a如果要下载程序到QSPI Flash里面,需要做如下配置:" Z( b: g; Z+ F1 V5 @
5 e, O' G' W4 a9 M# r: d/ [
5c95b0f51dbecf9eac259ddcf6b3da55.png
, n3 a) F" l# s

. A1 J& i! K% D82.5.2 调试配置
! s0 r1 w2 Q* u1 i8 B% k: W3 H注意这里一定要够大,否则会提示算法文件无法加载:$ a5 o" V; W4 k9 ?- y
1 ]- a( @# N8 v& p- i! Z4 R7 W
6b0758d3dd4db39b7189a03d59f0eca0.png

; m9 A6 w  U9 z( l, w+ q! r
% |& V+ {5 M- _& m3 B# a: [2 c我们这里是将其加到DTCM中,即首地址为0x20000000,大家也可以存储到任意其它RAM地址,只要空间还够加载算法文件即可。
, }* L- W; z8 P$ x  o* l) R( R$ K6 }9 d1 Z8 X
如果要做调试下载,需要做如下配置:
4 v1 f% c! C6 a9 T+ b% I  i6 n# d6 }8 Z6 o9 G
927401ada0fef49a78ac8029e372a755.png
3 Q; C* i; I* K3 `2 E

1 W: b# [% H* [7 Y2 S" W, D; V
, O( }0 o4 r; }: v, p' F4 J' ?82.5.3 程序调试效果0 h- s! a$ _8 N% H( ~1 i
APP应用程序调试效果如下:8 U+ O2 r4 |9 f6 w) t% B- B

$ ]  P$ W& u4 C. `5 v
681a23ba44bd11addce0fa9aae797dbd.png

6 X9 Y) S' y1 U& n; Q( }0 _9 J4 e5 _2 f+ b2 X" g5 C: f3 B3 v
82.6 实验例程说明
3 U# M* E" M: q5 w
本章配套了两个例子:
; T* l% r8 l$ P* g3 f$ u
  N0 l( e% M, K- |* n' n  V7-062_QSPI Flash运行程序(Bootloader)。8 u. e. e. f$ W0 K5 e2 V
  V7-063_QSPI Flash运行程序(用户APP)。
% _: z" ~* p0 U4 ~% X' k) g$ I$ M+ ?- I1 T

; Q; _" h  A( B- ]' `Bootloader例子需要大家先下载到内部Flash里面,然后按照本章第5小节的说明配置后,就可以像使用内部Flash一样调试下载QSPI Flash了。
' p9 j# I0 O6 o0 O/ d# h* y* @7 \, F3 b+ r7 p9 \/ t, k. I7 m
82.7 总结4 u' @4 \+ {& K8 y# i( f
本章节就为大家讲解这么,为了熟练掌握,建议大家是操作练**。/ n0 o6 L4 r/ O- i) v' Z

- `7 K4 A$ B* q/ I+ t2 b: c
  G' `! `$ J2 \% g  v
- J+ X$ R5 N0 ^8 n* d
赞 收藏 评论0 发布时间:2021-12-21 23:21

举报

0个回答

所属标签

相似技术帖

官网相关资源

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