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

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

[复制链接]
STMCU小助手 发布时间:2021-12-21 23:21
82.1 初学者重要提示: I" ^) s# H2 d# e
  操作本章配套例子前务必先将QSPI Flash的下载算法放到MDK安装目录。
0 I( C  Q6 Z" S' J4 N. A; ]  QSPI Flash执行程序的BOOT和APP作用:
  R' S& }- P1 @" ~4 i. s" w+ x  BOOT程序需要下载到内部Flash。主要用于跳转到外部QSPI Flash执行程序。那么问题来了,我们可不可以不使用BOOT,上电就直接执行QSPI Flash的程序?不行,因为QSPI Flash不像内部Flash,无需初始化,上电就可以使用,而QSPI Flash不行。
, e, J) |  t: P1 d2 d8 T  APP应用程序要下载到QSPI Flash里面。APP应用程序可以在QSPI Flash里面执行主要是因为W25Q256支持XIP(Execution In Place),并且STM32H7的QSPI Flash支持内存映射。, c5 |3 g1 m+ I' q9 ~: p
82.2 下载算法存放位置# L8 O. T0 b0 D! k6 u% m* [
编译例子:V7-060_QSPI Flash的MDK下载算法制作,生成的算法文件位于此路径下:9 w0 a: G/ P4 @0 k4 v5 M4 b

: U% Q9 l% G8 L* ^
618b073cf66c2944fcdb610aef0e67ea.png
: \/ J) l4 X  M; u
! i, P" Q- n$ U) T. Z* [/ P
生成算法文件后,需要大家将其存到到MDK安装目录,有两个位置可以存放,任选其一,推荐第2种:
7 ]" v( `0 D' c8 o5 f7 J! p# M
8 ~  h+ c4 t) s/ b- R6 k4 X  第1种:存放到MDK的STM32H7软包安装目录里面:\Keil\STM32H7xx_DFP\2.6.0\CMSIS\Flash(软包版本不同,数值2.6.0不同)。2 _4 M+ ]7 e7 n! b: f$ d2 Q
  第2种:MDK的安装目录 \ARM\Flash里面。
8 z4 A* A8 u' r8 j, Y& }) g( |. ]) U. k, b- n
b192c51eb80b27959d7c06b80a142d6e.png

$ v+ }% a& m# b$ y: @6 L9 c8 R% y2 O
6 n& m0 j/ M, _82.3 QSPI Flash的Bootloader说明

0 x& U0 M3 y) RBootloader的实现比较简单,需要大家将其下载到内部Flash。程序实现上主要注意以下两点即可。( D# R, q2 |0 j6 X  O! x# J

: |4 v8 H2 e! I* R. y4 K82.3.1 初始化QSPI Flash并设置内存映射模式
1 Q8 I# z( f8 X; l8 [; V在bsp.c文件中初始QSPI Flash并设置为内存映射模式。1 _# s' {% I8 a5 h; p
; [  Y5 w/ g8 q6 R' x+ }3 \
  1. /*3 v5 s/ Z" s2 ]- b" q
  2. *********************************************************************************************************; u& [3 |; [* F3 f0 e$ m4 `
  3. *    函 数 名: bsp_Init
    6 E8 F. B' D! k( C+ q
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次+ t8 n$ G9 x) G* k5 X
  5. *    形    参:无7 t% L' W, U# p4 N/ p2 L  _
  6. *    返 回 值: 无
    + G' \& i. R% }! B5 a( g3 ^5 H
  7. *********************************************************************************************************
    ! d$ Q9 c& t; R5 D1 R/ t
  8. */
    5 U5 ]7 \  ~0 O0 g: c5 l$ d. h
  9. void bsp_Init(void): k$ ?4 V# F. n  K) P/ Z3 [3 p
  10. {4 k+ C9 [9 w0 v" W& Q: X: C
  11.     /* 配置MPU */5 f: l& g9 r8 O3 o+ c  O- l
  12.     MPU_Config();
    2 s2 l3 f$ c* b( _

  13. 8 d# A$ X- ~( L" g. m
  14.     /* 使能L1 Cache */: B' L: w' e3 @" o% J
  15.     CPU_CACHE_Enable();$ d9 y/ S' f) n, k) w& X

  16. 3 P( `+ U, r7 y! c5 e7 l# g
  17.     /* 3 v, r( z5 s2 B0 v# K
  18.        STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:
    5 R6 A  A% U7 g0 r
  19.        - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。% U  z( v4 N$ I
  20.        - 设置NVIV优先级分组为4。
      N7 P+ O/ [9 x3 e5 a7 }9 u
  21.      */7 m1 G, y0 i* W' j
  22.     HAL_Init();- Q: w0 s( x- _# M8 x& V

  23. 3 V7 Y. k& c9 j$ L9 S- y
  24.     /* 8 t5 b0 R! I" Z) K+ ^; p0 y
  25.        配置系统时钟到400MHz
    ( S, t: a! Z. ?' O7 x* N5 _( K% q- Y
  26.        - 切换使用HSE。
    ! ]7 C. k' v% D2 j7 E2 Q# C
  27.        - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
    5 w7 f! S8 z, I% K" a% ~: v6 T; {
  28.     */7 n) z% X# o2 I! \
  29.     SystemClock_Config();
    9 q7 l6 f' V; a3 j
  30. / r) g4 H  O9 z: R" k  ]7 Q! y
  31.     /*
    " ?  k! n  {: c/ n* D9 @8 B5 @3 N& c
  32.        Event Recorder:
    . p# _5 {: n  w" z& I2 G: o+ Y
  33.        - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
    5 |8 O: i2 ]% V: U
  34.        - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章9 L8 W! l2 [; E& M8 j
  35.     */    " T6 ]! Z/ E8 n  m4 B
  36. #if Enable_EventRecorder == 1  
    * i& B5 x& x' T) j! c  ]3 d
  37.     /* 初始化EventRecorder并开启 */
    4 a; C# M! e! A/ I" g8 K. k
  38.     EventRecorderInitialize(EventRecordAll, 1U);
      x! l5 L6 ]8 N- S. C8 G, F  M
  39.     EventRecorderStart();3 ?. W. g" P1 @
  40. #endif9 s' Z# o9 l, N$ k% g( ^

  41. 9 v. J0 m! m( ~( T' D
  42.     /* 针对不同的应用程序,添加需要的底层驱动模块初始化函数 */* d  U: @+ g3 }7 C2 s# i; U) T  c, P
  43.     bsp_InitQSPI_W25Q256();  /* 配置SPI总线 */   ( J- `+ s& r# t6 Z: h# ]4 z
  44.      QSPI_MemoryMapped();+ G0 |/ {/ c7 i, V8 r2 ~
  45. }
复制代码

1 S9 T+ X9 F' w5 A0 Q" X! s6 G3 R82.3.2 程序跳转的实现: v* Q: N0 E( N0 Y1 R# G
从内部Flash跳转到外部QSPI Flash的实现代码如下. j3 D# F- v7 T) h0 C/ g) e" {- b
  z' U. U! d0 ^' U
  1. 1.    /*
    ; b% ?9 i" B/ q+ f2 G0 n. N
  2. 2.    ******************************************************************************************************0 g# k. g! W2 f  l# ~( R
  3. 3.    *    函 数 名: JumpToApp
    1 ]4 @( o  ?- r: D9 o0 B* L1 Q2 n
  4. 4.    *    功能说明: 跳转到应用JumpToApp4 A* w8 \1 N7 u8 M( P% F2 D
  5. 5.    *    形    参: 无
    2 [4 C1 ]; k, N; V
  6. 6.    *    返 回 值: 无
    0 E3 g; q) f) J2 I
  7. 7.    ******************************************************************************************************: F5 b6 ]5 _2 x- M* \1 K& R# Y# l5 s
  8. 8.    */) i8 K( q8 y3 v- }
  9. 9.    static void JumpToApp(void)3 ]% g! e$ n! ~: U. w6 ?
  10. 10.    {
    : k; Y3 b) m; [; _0 r
  11. 11.        uint32_t i=0;+ d# k6 i2 c; z! s! P2 o7 a
  12. 12.        void (*AppJump)(void);         /* 声明一个函数指针 */
    3 t- h7 r+ J  C" Q7 s4 @+ E. @$ `
  13. 13.        __IO uint32_t AppAddr = 0x90000000;  /* APP 地址 */4 ^3 r8 w; j/ @4 S6 q
  14. 14.          U/ p- o" G3 V0 M6 [7 c+ f* _  A
  15. 15.   
    : a# m6 G0 m/ Q
  16. 16.        /* 关闭全局中断 */. L9 v, d* A6 I( p! Q
  17. 17.        DISABLE_INT();
    $ S+ p) F* Z; J& _; O. O
  18. 18.        6 @1 ]. @# ]0 Z+ _
  19. 19.        /* 设置所有时钟到默认状态,使用HSI时钟 */
    8 `5 ?4 ^; @0 i- v6 N" V8 d+ ~
  20. 20.        HAL_RCC_DeInit();) r- a2 k9 M) z
  21. 21.        ! Q7 ?* y3 G8 e
  22. 22.        /* 关闭滴答定时器,复位到默认值 */
    + @8 g2 P, G0 F: j  F
  23. 23.        SysTick->CTRL = 0;; v2 h6 C3 l8 i3 A# J$ i* m' e
  24. 24.        SysTick->LOAD = 0;, A' x0 }- F1 Q
  25. 25.        SysTick->VAL = 0;
    0 I% F( E+ O2 B( J" D( Y+ n$ ~
  26. 26.   
    6 O' W" l1 y# Z9 U
  27. 27.        /* 关闭所有中断,清除所有中断挂起标志 */. B0 }* f. g3 U+ U9 I' _! @6 v4 J
  28. 28.        for (i = 0; i < 8; i++)
    6 \* @2 N1 H5 I# M' Z- J: Y1 O/ ^
  29. 29.        {. Q# o9 w' }+ R& K
  30. 30.            NVIC->ICER<i>=</i>0xFFFFFFFF;5 S/ w7 z( N5 l+ [
  31. 31.            NVIC->ICPR=0xFFFFFFFF;& C9 V& @% @6 s( f8 t5 x
  32. 32.        }   
    8 _, l& Y- k& u& m( o3 }
  33. 33.    ; F8 O/ H9 M5 a2 _* X
  34. 34.        /* 使能全局中断 */
    : k# D6 M. P0 X: e" `
  35. 35.        ENABLE_INT();
    " y7 `: c/ K( l7 P( t! T0 \6 h
  36. 36.   
    2 l2 s3 Q1 T$ B+ b
  37. 37.        /* 跳转到应用程序,首地址是MSP,地址+4是复位中断服务程序地址 */
    + V6 p' T6 @/ w1 }- h
  38. 38.        AppJump = (void (*)(void)) (*((uint32_t *) (AppAddr + 4)));0 \7 y- _# U7 T0 B; H9 z
  39. 39.   
    , F* [5 l  s9 p# t
  40. 40.        /* 设置主堆栈指针 */
    6 T! F; Y: ~! n  t
  41. 41.        __set_MSP(*(uint32_t *)AppAddr);" U0 m. w3 ^% j" }5 i8 z
  42. 42.        
    3 f& G$ Q8 x1 P% y+ E% B+ K
  43. 43.        /* 在RTOS工程,这条语句很重要,设置为特权级模式,使用MSP指针 */
    * E- g1 k7 \+ m1 l! F& u- S& R% |
  44. 44.        __set_CONTROL(0);
    $ W$ {( S+ ~. D6 q+ R9 F4 T
  45. 45.   
    ( \# S' v/ Q9 {8 h
  46. 46.        /* 跳转到系统BootLoader */+ Q. g6 Z  r( e
  47. 47.        AppJump(); 1 Y1 K6 s+ y. s) ^0 s
  48. 48.   
    ) H3 {) a% D( U/ z9 @/ A. E. g
  49. 49.        /* 跳转成功的话,不会执行到这里,用户可以在这里添加代码 */1 J6 Y. j0 k2 _1 F# u4 R7 h, v
  50. 50.        while (1)
    1 f1 q* q# S* `9 \
  51. 51.        {
    ' ^: @& F2 F) ]! x
  52. 52.   
    7 z1 v8 C; ~* M+ O
  53. 53.        }
    : v. x- {+ H, U& l5 i+ U' X
  54. 54.    }
复制代码
2 M' |8 P& f% S7 y1 f- \
这里把程序设计中的几个关键地方做个说明:
( h) @; b! C$ \, ~& }4 P
  L1 M' S9 [% I! M  第12行,声明一个函数指针。
8 R" t5 f/ Z" v. ^5 j  第13行,QSPI Flash地址在0x90000000。/ B4 J  E- V9 l: I8 \, t
  第20行,此函数比较省事,可以方便的设置H7所有时钟到复位值,内部时钟使用HSI。
' b% T7 M0 N" |/ X8 @5 h8 y  第23到25行,设置滴答定时器到复位值。; q5 U$ f; M' @( f9 }% `
  第28到32行,清除所有中断挂起标志并关闭中断,这里是直接通过一个for循环设置了NVIC所有配置位,共8组。
% O! V/ l) ?$ B5 ^) }( T) E; i- a  \5 W3 w
bfe6b8c0ea19b535e2fb06c6618577f6.png
7 {$ b; o3 ~& C. D& n4 D- w
1 s$ X$ B0 H2 b) f$ A* [1 s
  第38行,将系统bootLoader的中断复位服务程序的入口地址赋给第12行声明的函数,用户执行这个函数时,就会直接跳转过去。! n4 E5 K2 L) W& g3 _3 U
  第41行,设置主堆栈指针位置,即QSPI Flash应用程序首地址存储的就是栈地址。. G" w1 P) K& k7 o
  第44行,这个设置在RTOS应用程序中比较重要,因为基于Cortex-M内核的RTOS任务堆栈基本都是使用线程堆栈指针PSP。但系统bootLoader使用的是主堆栈指针MSP,所以务必要设置下,同时让M内核工作于特权级。此寄存器的作用如下:
' i$ c1 h  E+ c6 |$ f6 h0 }9 P! D8 f
b00b09a901596bcedb07c31790d8d3d9.png
4 D+ o- r+ ~2 u
1 Y/ m2 @$ H* }) ~3 u2 H$ d* u) h4 ~
  第47行,跳转到系统bootLoader。
6 n4 g* y# x( W, x. s  @3 h1 U  o9 I8 h. @7 a$ Y# r4 M% Y
82.4 QSPI Flash的APP应用程序说明
& |, H: g4 d" G* ]6 P) ?APP应用程序是由第53章配套例子:V7-033_LCD的汉字小字库和全字库制作 简单修改而来,主要修改如下两个地方:
; I8 K; T+ `/ K" ?: d( B  L5 p
+ l0 ?/ b8 v. G) P82.4.1 设置Flash地址: X" y, Y# U9 M
设置Flash地址为QSPI Flash首地址0x90000000:
$ ~4 c9 a- s2 P! H/ x/ \: D
% J& C( M# t& \3 E( K* s* M
75afb2342189857e8fa086fc0af08462.png
7 }' Q  i% c9 f: b9 J
$ v. H( D4 r( @# V4 O- k
82.4.2 设置中断向量表8 e& w  u. E. H8 ?& L) q: f
在main函数最开始就设置中断向量表到QSPI Flash首地址0x90000000,也可以按照本教程第28章的说明,将中断向量表设置到DTCM里面。
' d6 A* X6 |3 l" F7 f( [3 G$ L# r9 W
+ @7 n7 y1 n  W8 f
  1. int main(void)! n7 B" Q$ V" v+ I; p/ _& t+ t
  2. {. f4 a6 V  G9 {! f
  3.     uint16_t ucBright;           /* 背光亮度(0-255) */, E; f* P' ?9 K$ G  q
  4.     uint8_t ucKeyCode;        /* 按键代码 */" ^' [& t9 |, e
  5.     uint8_t ucStatus;        /* 主程序状态字 */
    2 F/ j& F9 t/ l* P) R+ U3 \' Q
  6.     uint8_t fRefresh;        /* 刷屏请求标志,1表示需要刷新 */
    % y' Y$ t4 L- [9 J% Q' y2 [
  7. 3 i$ b+ j! y# O* v8 V) x
  8.     SCB->VTOR = 0x90000000; /* 设置中断向量表地址 */
    + P! {6 R+ u! |5 t5 c$ v( w

  9.   i2 s9 E; M% I4 a! x
  10.     bsp_Init();    /* 硬件初始化 */( e( t5 R& C% W* o% f7 }: I( j
  11.     PrintfLogo();    /* 打印例程名称和版本等信息 */7 x" Z* P( Z' s7 w, f- I
  12.     PrintfHelp();    /* 打印操作提示 */
    2 E3 P' U! p( x/ N% [( G2 {
  13. " r! t4 X5 G* K- h+ |
  14. 省略未写! e0 H" x/ y7 z% v: s, S# `
  15. / d- T9 k/ N& L% t. _, `$ E7 W
  16. }
复制代码
, k: s2 ^: y. E+ i2 d1 @
82.5 QSPI Flash的APP应用程序调试下载配置7 D& q# s$ i! E: ]1 L4 A. @
将下面两个地方配置后,就可以像使用内部Flash一样使用QSPI Flash进行调试了。
- I$ v: ?7 l# j4 q' O2 p# ^8 @% [
, {- k6 [+ {* R* F% B1 [( Z7 W" \82.5.1 下载配置; D0 @/ W+ S+ e5 \/ v+ ]# w' k% i4 E
注意这里一定要够大,否则会提示算法文件无法加载:
. }  u! ^' c/ c9 h$ p4 w- E/ K, l* t
96d039e1657c72042027eb7e46ffc33a.png

7 ~1 Y5 d- u% w" L/ |  Y5 T( i2 f) W/ i+ [) j" h8 @
我们这里是将其加到DTCM中,即首地址为0x20000000,大家也可以存储到任意其它RAM地址,只要空间还够加载算法文件即可。推荐使用AXI SRAM(地址0x24000000),因为这块RAM空间足够大。) j# |0 b' R7 ?; {% @
: o* L7 C% I9 h/ w
如果要下载程序到QSPI Flash里面,需要做如下配置:
' G; @6 }1 L' W1 j" c* i) e5 T( ?  B2 U% n% x- _
5c95b0f51dbecf9eac259ddcf6b3da55.png
5 u" M, b# W8 @3 u! m% A1 O
& |: r  {8 y: {) d/ c/ q9 D  r
82.5.2 调试配置- v* z: h0 J3 {8 V/ T/ z+ ~
注意这里一定要够大,否则会提示算法文件无法加载:
$ O% q& V6 T2 Q: ]0 |! R( K) P7 D/ A  y$ H: ]
6b0758d3dd4db39b7189a03d59f0eca0.png
- C2 c. S+ T2 j% Z2 u( w
9 G& V. R8 N  B- l* ^- s4 X
我们这里是将其加到DTCM中,即首地址为0x20000000,大家也可以存储到任意其它RAM地址,只要空间还够加载算法文件即可。
5 s0 F1 `* C0 U' ^. w
* H0 |$ A. `% ~3 K3 v如果要做调试下载,需要做如下配置:
) Q/ ?6 O& @0 l3 E
0 I% Q6 l3 T, M0 U( i
927401ada0fef49a78ac8029e372a755.png

8 r! Z- j  `7 L' G3 X( I9 [2 R$ u( A' \

3 V/ ~$ I$ \) k& w: I82.5.3 程序调试效果
$ E: H, Q. a! u7 PAPP应用程序调试效果如下:( d3 {# H" ~5 p
% Q+ A& n7 F1 d- w: n- N2 I
681a23ba44bd11addce0fa9aae797dbd.png

; N" j/ R2 ?7 \5 j6 j4 A
4 W, x7 v/ f, g1 j8 J3 V82.6 实验例程说明
4 Q0 R) H) n0 W% q% y
本章配套了两个例子:5 ]% ^) T! T7 F$ w6 V) ]

! q9 Y9 |* u5 i$ `9 k  V7-062_QSPI Flash运行程序(Bootloader)。
9 Y8 t5 g- E+ H8 x- D. [* I  V7-063_QSPI Flash运行程序(用户APP)。; A) d* _0 {+ A/ W
! w, `- I: U6 y6 j/ _2 U

7 {, }2 s- I+ ?# `! ~Bootloader例子需要大家先下载到内部Flash里面,然后按照本章第5小节的说明配置后,就可以像使用内部Flash一样调试下载QSPI Flash了。' H' W5 I$ P' a: X. f/ n4 R
2 p6 x/ @+ I% U# ?- r
82.7 总结
, V; f1 ?1 i* r1 X本章节就为大家讲解这么,为了熟练掌握,建议大家是操作练**。
0 c* k& D0 S5 t7 G4 ?1 h2 H. L
7 ~6 S4 A& H+ D3 E) P! @1 m7 E! v" d0 t4 E. _7 c
. }% x; D% W; y7 [% ~
收藏 评论0 发布时间:2021-12-21 23:21

举报

0个回答

所属标签

相似分享

官网相关资源

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