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

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

[复制链接]
STMCU小助手 发布时间:2021-12-21 23:21
82.1 初学者重要提示' H! @* D$ i2 ^4 c! r4 q1 L
  操作本章配套例子前务必先将QSPI Flash的下载算法放到MDK安装目录。
4 h1 P; Y$ X; O2 ]9 u( C7 \  QSPI Flash执行程序的BOOT和APP作用:8 R. v2 T3 Y% c8 u4 V2 K
  BOOT程序需要下载到内部Flash。主要用于跳转到外部QSPI Flash执行程序。那么问题来了,我们可不可以不使用BOOT,上电就直接执行QSPI Flash的程序?不行,因为QSPI Flash不像内部Flash,无需初始化,上电就可以使用,而QSPI Flash不行。7 j$ w( }$ C4 y' Q$ \. z
  APP应用程序要下载到QSPI Flash里面。APP应用程序可以在QSPI Flash里面执行主要是因为W25Q256支持XIP(Execution In Place),并且STM32H7的QSPI Flash支持内存映射。
, C1 u& a) A. A+ J* b) i6 Y82.2 下载算法存放位置* M, m; R$ H$ y" C
编译例子:V7-060_QSPI Flash的MDK下载算法制作,生成的算法文件位于此路径下:
$ t: f: X, W8 J4 N) U) N, z1 E/ S9 l; \% q6 h4 ?8 e- n
618b073cf66c2944fcdb610aef0e67ea.png

4 ~  _% Z% p1 K+ d0 ~  W) L6 C0 x9 ~3 E$ T9 D/ O
生成算法文件后,需要大家将其存到到MDK安装目录,有两个位置可以存放,任选其一,推荐第2种:! U3 y8 B) F, N5 U1 x7 k8 L: T
8 A" j7 Y+ \# ?
  第1种:存放到MDK的STM32H7软包安装目录里面:\Keil\STM32H7xx_DFP\2.6.0\CMSIS\Flash(软包版本不同,数值2.6.0不同)。
0 C$ v5 ^8 T; K3 e8 b  第2种:MDK的安装目录 \ARM\Flash里面。
: @& I/ |  ~3 S9 T& S6 D
7 a( m; C' Q1 m0 J1 H( H
b192c51eb80b27959d7c06b80a142d6e.png
/ w0 q3 |. N' D0 g* \: @7 @

0 _/ l) S& B3 L, S2 _/ w! a' j82.3 QSPI Flash的Bootloader说明

- T6 q4 O: y" O% rBootloader的实现比较简单,需要大家将其下载到内部Flash。程序实现上主要注意以下两点即可。
' b8 C" [; i% x+ U7 f# E& E0 E5 _8 X" D# O
82.3.1 初始化QSPI Flash并设置内存映射模式) w& z) ]" |4 k, h- w3 A* Y7 k9 j
在bsp.c文件中初始QSPI Flash并设置为内存映射模式。% F/ G9 a7 R! g
6 _3 X! F2 i% c1 M5 c
  1. /*9 P  b: d1 }; N$ x+ L0 R
  2. *********************************************************************************************************
    5 c0 P1 y7 S: i" `) n
  3. *    函 数 名: bsp_Init4 M) w+ p; x# P( _& V
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次. Y" B" e7 J9 _) T! V! v. D4 e$ v
  5. *    形    参:无# g- q2 J/ ~6 X( |) W. R
  6. *    返 回 值: 无* N4 i2 C; }3 g& e& j# U8 f0 }
  7. *********************************************************************************************************
    6 n$ t2 i; t/ h
  8. */
    * r# v5 t' C9 W! B
  9. void bsp_Init(void)) v$ [& P. L0 I( g& x4 Y+ j
  10. {
    3 m: c* j3 g: Q9 M
  11.     /* 配置MPU */
    / w3 N# n1 s1 l7 R6 x$ p
  12.     MPU_Config();( d" X: p3 m0 ^6 s, f) G$ j" U2 l" o

  13. 8 h- Z: e$ o8 P$ n( M
  14.     /* 使能L1 Cache */
    % t# {" v$ }& N& V
  15.     CPU_CACHE_Enable();' i' T, m1 h$ x( E+ q+ X
  16. $ u  j3 N8 a8 o, y: O) t
  17.     /*
    , O4 {2 P3 B3 I9 @* ]' l
  18.        STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:
    # U6 r2 F9 v( ?( f
  19.        - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
    # s  X& w' @5 c$ B9 N3 i
  20.        - 设置NVIV优先级分组为4。9 L# t6 f$ ?8 V) J+ i
  21.      */; s4 s. E) C9 H3 v8 X- d# V  \
  22.     HAL_Init();
    . @7 J* W5 T) N
  23. 3 f! u6 S5 c4 ^' ]/ w; w( w& ~
  24.     /* ' a" ]  R# }( w0 S( N/ m
  25.        配置系统时钟到400MHz8 y* W: F, t4 T: N1 j/ f
  26.        - 切换使用HSE。
    : h) _2 Q* n5 ]! o3 v% S
  27.        - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
    $ ]5 d8 N* ?  T- W6 `9 j: b
  28.     */# G4 V8 Y' j! G6 L
  29.     SystemClock_Config();6 R% V& c# d! O2 e7 _! |3 Q
  30.   |' V4 ?. @0 P% v( F0 l# A0 u7 \0 K
  31.     /* $ C: }+ r/ }) p: C" Q9 K/ ?2 h
  32.        Event Recorder:) t6 J( S3 ]8 l8 O" ~+ O& y
  33.        - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
    7 z7 {9 y) ~7 }- N
  34.        - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章
    + h# B, |; g( V: s
  35.     */    ( X) G- C, ?. V, ^8 E4 q9 Z
  36. #if Enable_EventRecorder == 1  
    9 E8 T' A& E0 Y: h& s0 [: U) l7 n
  37.     /* 初始化EventRecorder并开启 */
    0 f& x3 a; E3 f; t
  38.     EventRecorderInitialize(EventRecordAll, 1U);
    - i7 c) ?9 F+ p5 s+ {1 ?8 P5 N
  39.     EventRecorderStart();
    ! o# G7 o1 K/ r
  40. #endif
    ) p; J- ^6 H2 M% H8 V7 O/ w* [: V

  41. ; k* I2 M8 Z% O( M7 w# S
  42.     /* 针对不同的应用程序,添加需要的底层驱动模块初始化函数 */
    / t$ I( r: \: X/ F% W4 a* [
  43.     bsp_InitQSPI_W25Q256();  /* 配置SPI总线 */   
      T0 b& F. p  j/ O! A5 A
  44.      QSPI_MemoryMapped();
    ' ^3 d9 y) }2 q+ H
  45. }
复制代码
7 _1 ^  ?2 Z4 C1 _
82.3.2 程序跳转的实现/ o7 i0 E$ |2 s7 M
从内部Flash跳转到外部QSPI Flash的实现代码如下+ X/ V1 ?4 d- F; O' A8 K
4 J) q6 @& r9 @7 j& Z" g6 j
  1. 1.    /*. u9 L  K$ W& |5 g
  2. 2.    ******************************************************************************************************$ P% J& \/ q  S' ]
  3. 3.    *    函 数 名: JumpToApp
    - f. K0 o' _' ]# S% s3 s& M: t6 ~
  4. 4.    *    功能说明: 跳转到应用JumpToApp
    $ c* Z8 R6 ]- @; j: P& n
  5. 5.    *    形    参: 无# P3 x' [% a+ U; N
  6. 6.    *    返 回 值: 无: y" ?% |. d1 y; \
  7. 7.    ******************************************************************************************************1 M  N* i! h6 \8 R8 @; N
  8. 8.    */8 Q0 v7 h2 n5 P0 i5 o2 B
  9. 9.    static void JumpToApp(void)/ U* E  [- [3 k2 D0 N! ?- S
  10. 10.    {8 ?* C% x% ?+ a7 W) l4 l7 ^+ F& G7 {6 }
  11. 11.        uint32_t i=0;
    5 U" h* p: L% l  j# t+ V; y
  12. 12.        void (*AppJump)(void);         /* 声明一个函数指针 */. Y2 d5 @8 B( k1 y! g, o2 g
  13. 13.        __IO uint32_t AppAddr = 0x90000000;  /* APP 地址 */
    $ I" i" c% w& k+ @9 j) R" V# v
  14. 14.        ! [* y2 [* K3 g; x
  15. 15.   
    * H% |: u, x8 t3 U
  16. 16.        /* 关闭全局中断 */
    % K& E# J: V+ ^! Z2 G
  17. 17.        DISABLE_INT(); 3 ~) I9 M2 q9 `) ^5 P# b
  18. 18.        4 d7 h& S, ^& o: |9 W: L9 h. z
  19. 19.        /* 设置所有时钟到默认状态,使用HSI时钟 */
    1 Q3 ~) z6 S1 _+ i2 K
  20. 20.        HAL_RCC_DeInit();
    5 t6 y1 p! V! ^1 d6 V5 \, Y/ r
  21. 21.        
    7 b+ H( y! c7 V. F% ^
  22. 22.        /* 关闭滴答定时器,复位到默认值 */2 d; L9 l0 l! F! ^7 X& h
  23. 23.        SysTick->CTRL = 0;
    ( b: \, Z3 ]& p( o
  24. 24.        SysTick->LOAD = 0;9 g  O4 [! f4 r3 F
  25. 25.        SysTick->VAL = 0;
      j" i  t% Z/ `* @# |7 y6 N
  26. 26.   
    0 L4 W' Q* u9 s
  27. 27.        /* 关闭所有中断,清除所有中断挂起标志 *// N2 j/ ~6 X( y: `1 @7 Y; d0 z3 E- d
  28. 28.        for (i = 0; i < 8; i++)
    / e0 t6 G+ p$ i+ {: h
  29. 29.        {5 E6 ]+ k# N8 z# b1 G
  30. 30.            NVIC->ICER<i>=</i>0xFFFFFFFF;
    3 b* c+ `8 {' R1 t3 f0 R6 V
  31. 31.            NVIC->ICPR=0xFFFFFFFF;
    1 q  O& U0 T  t& v) x! z5 T9 x" ?
  32. 32.        }    : W$ y9 j  q, p' ?
  33. 33.   
    # S4 o7 E+ J4 Z5 t9 ], A
  34. 34.        /* 使能全局中断 */
    2 T' q; |! F4 H6 V# o1 E% Z5 @3 \
  35. 35.        ENABLE_INT();0 X5 s! ]' v5 l  [
  36. 36.   
    6 G# ^9 R2 h/ Z$ x
  37. 37.        /* 跳转到应用程序,首地址是MSP,地址+4是复位中断服务程序地址 */' _& C1 K* R1 l! x8 ^
  38. 38.        AppJump = (void (*)(void)) (*((uint32_t *) (AppAddr + 4)));6 j7 \  z+ M& u) e8 O+ i6 F
  39. 39.    ' c2 d4 U+ \7 A' C7 `2 B0 c' X
  40. 40.        /* 设置主堆栈指针 */: @% X- o& ~8 [9 S$ N# u
  41. 41.        __set_MSP(*(uint32_t *)AppAddr);
      ]& `* P, h. K, D" x$ I& P
  42. 42.        
    # j8 X, H6 e, ?2 B, U1 T/ ?
  43. 43.        /* 在RTOS工程,这条语句很重要,设置为特权级模式,使用MSP指针 */( y1 B. E. m; ]- g- e
  44. 44.        __set_CONTROL(0);
      }% f, T* T( {6 I' ~( H
  45. 45.    : ?( I+ @; j4 c: m; h9 [: n
  46. 46.        /* 跳转到系统BootLoader */  Y8 G" R% R- D
  47. 47.        AppJump();
      C" Q- G% Q+ \5 W% k. A$ h
  48. 48.   
    , D; U! k5 \. m- h  j5 U& }
  49. 49.        /* 跳转成功的话,不会执行到这里,用户可以在这里添加代码 */5 X  p1 j! `0 P9 \( X- Z6 c2 G
  50. 50.        while (1): L/ N/ R# r9 a( A. @
  51. 51.        {
    ( o" |. x, O! P$ `- x$ i
  52. 52.    . Q5 B2 e+ x  d. J" ?% p- \3 [
  53. 53.        }
    ! M3 s0 [+ M$ ^; }3 e
  54. 54.    }
复制代码
0 E1 l' }& K; B6 I6 {, i
这里把程序设计中的几个关键地方做个说明:
: d. X5 X% l' a" I* J4 G6 a" P3 D7 F4 V
  第12行,声明一个函数指针。
+ I) p' l( M, V, t  第13行,QSPI Flash地址在0x90000000。) ~$ @. w/ R& x2 U6 q
  第20行,此函数比较省事,可以方便的设置H7所有时钟到复位值,内部时钟使用HSI。
5 U4 @2 b, y- u. T7 m  第23到25行,设置滴答定时器到复位值。
, b  G3 L5 J# F. _  第28到32行,清除所有中断挂起标志并关闭中断,这里是直接通过一个for循环设置了NVIC所有配置位,共8组。
8 s0 y# U: A8 O+ F4 N0 }' n/ e3 c7 W. p
bfe6b8c0ea19b535e2fb06c6618577f6.png
$ u4 K$ b: Y: i& m7 n- F

4 K* g) u3 \4 Y" [1 e: p  第38行,将系统bootLoader的中断复位服务程序的入口地址赋给第12行声明的函数,用户执行这个函数时,就会直接跳转过去。1 R- {8 E; J2 a6 H) o7 ?
  第41行,设置主堆栈指针位置,即QSPI Flash应用程序首地址存储的就是栈地址。
& V& t1 l) m7 z  i6 k  第44行,这个设置在RTOS应用程序中比较重要,因为基于Cortex-M内核的RTOS任务堆栈基本都是使用线程堆栈指针PSP。但系统bootLoader使用的是主堆栈指针MSP,所以务必要设置下,同时让M内核工作于特权级。此寄存器的作用如下:/ w6 G) Q" a8 }4 m3 c% {( y

* J2 m. [' s+ v
b00b09a901596bcedb07c31790d8d3d9.png
* X- J+ u7 u) j! \( U

8 R: V3 O4 m# m& S4 M  第47行,跳转到系统bootLoader。
7 m5 f) l, M; [+ v2 h4 R# W- q% K
4 s$ `* m& X7 q+ k! Q5 h: V3 l82.4 QSPI Flash的APP应用程序说明1 f6 v' P8 m  |, c
APP应用程序是由第53章配套例子:V7-033_LCD的汉字小字库和全字库制作 简单修改而来,主要修改如下两个地方:6 ^7 `# s: D8 V! b/ S

: @% {- ^7 W& {+ Y# P! M/ U82.4.1 设置Flash地址
! A- B1 X; R) \& _: ]设置Flash地址为QSPI Flash首地址0x90000000:
$ q  }9 @& ^9 t8 O2 c1 [# R8 T3 j9 V# G
75afb2342189857e8fa086fc0af08462.png

  ^3 A$ d2 M+ W* M, y) S8 V7 Y2 z9 |6 O' Z; E# e( w% O* M
82.4.2 设置中断向量表
" ?8 W& x" J# H, L6 v在main函数最开始就设置中断向量表到QSPI Flash首地址0x90000000,也可以按照本教程第28章的说明,将中断向量表设置到DTCM里面。) O2 ~  I* f8 ?0 O) Q1 ~- i
* P8 s# P/ \7 l
  1. int main(void)
    # N! h! L$ _) K! E7 o+ a
  2. {
    3 ^. |! m9 K. ^/ w
  3.     uint16_t ucBright;           /* 背光亮度(0-255) */, ~( [( ^+ ]& Z4 G! M# D' k: M
  4.     uint8_t ucKeyCode;        /* 按键代码 */9 _, y& e5 \; S3 B' e& x
  5.     uint8_t ucStatus;        /* 主程序状态字 */% W' H) Q. O2 T* @$ K- p
  6.     uint8_t fRefresh;        /* 刷屏请求标志,1表示需要刷新 */
    0 w1 P  c0 F- o9 ]9 Q% c
  7. , y+ @" z- Z& E6 ^& f2 D* d
  8.     SCB->VTOR = 0x90000000; /* 设置中断向量表地址 */
    ' s+ W  N6 a3 q9 x$ H/ D
  9. - T7 c0 M) j7 d2 O% |( B
  10.     bsp_Init();    /* 硬件初始化 */  L% C: T  G. t+ J) V
  11.     PrintfLogo();    /* 打印例程名称和版本等信息 */. Z0 h+ G# Z/ z2 P' c3 F$ K* N* B  r
  12.     PrintfHelp();    /* 打印操作提示 */8 B1 m5 U" Z9 X, f
  13. 0 h! [6 N! y2 t+ E
  14. 省略未写
    . v7 P/ B5 K5 c3 s

  15. - {/ ]+ D5 s8 A# O+ E
  16. }
复制代码

. `0 c( C# H" T5 Z82.5 QSPI Flash的APP应用程序调试下载配置
5 z& Y; F" y( E将下面两个地方配置后,就可以像使用内部Flash一样使用QSPI Flash进行调试了。$ E/ N9 N& b+ Z2 F: ?' a5 {

& f4 ?7 y* p7 J; _2 T4 R82.5.1 下载配置7 B/ q* I  f# J( w% q/ P* y. Y. n
注意这里一定要够大,否则会提示算法文件无法加载:
/ Q7 F+ g0 V1 o) w9 I0 a) o; w8 j5 e! E1 T6 [, y8 I1 L1 }' W8 y9 z
96d039e1657c72042027eb7e46ffc33a.png
4 B9 l; j; Y9 ~8 {: G( e
: P5 S8 V: ^. Y0 X' x
我们这里是将其加到DTCM中,即首地址为0x20000000,大家也可以存储到任意其它RAM地址,只要空间还够加载算法文件即可。推荐使用AXI SRAM(地址0x24000000),因为这块RAM空间足够大。* y# y2 y  D, T4 r

% \. Y: d& t- a2 S如果要下载程序到QSPI Flash里面,需要做如下配置:
( y0 ?7 ?, c  x) V. P4 ]4 f0 |! b' R4 n/ m
5c95b0f51dbecf9eac259ddcf6b3da55.png
/ H2 e2 `2 O8 O' F/ a4 T% u
# t& d) j8 t& |9 y  s- w6 c5 ~
82.5.2 调试配置; w4 c7 ]+ `+ g% E8 W& i
注意这里一定要够大,否则会提示算法文件无法加载:
) M9 r9 U: X( X" I! {# z1 z- l6 z! o3 w8 f3 Z, y' m" c
6b0758d3dd4db39b7189a03d59f0eca0.png

6 p4 t1 i2 L6 S" d* X1 c. Z1 ]# k/ r
" x- h& s! }! P9 ^; a3 g- O; [我们这里是将其加到DTCM中,即首地址为0x20000000,大家也可以存储到任意其它RAM地址,只要空间还够加载算法文件即可。/ S( ~5 ~8 N6 h8 c1 N5 A+ ]) v5 x
) l% W/ G0 |3 B" o8 n
如果要做调试下载,需要做如下配置:/ Y" e/ ~* E) z. @, |6 [2 k
2 g$ m) i. y* L2 M6 q* K
927401ada0fef49a78ac8029e372a755.png
; m0 M" a/ R8 b

8 n4 n" i; F' G: C# B
% b/ ]! A0 r7 E! C1 w0 T+ B82.5.3 程序调试效果* @8 |; g+ f% ]4 M1 \
APP应用程序调试效果如下:; p* ]6 Q5 N9 R! W  m1 Z# E* f+ n  s( ^

/ \/ D; m3 K; |$ X
681a23ba44bd11addce0fa9aae797dbd.png

2 Z, i$ P( F; }. g, r
7 X: [  Z" E" E82.6 实验例程说明

  f# t6 \" ?& S& r, p/ v本章配套了两个例子:
! p+ R; }* x0 r4 R. R9 f+ p* K* e' d7 r% t; m3 g# Y
  V7-062_QSPI Flash运行程序(Bootloader)。( y6 Z- J6 s( D& o( N1 g" c
  V7-063_QSPI Flash运行程序(用户APP)。! H4 I& h# I. _0 C) ?' ?

; D3 ^" p' s3 H! s0 R4 T1 m
% q$ }) K2 x; M, _Bootloader例子需要大家先下载到内部Flash里面,然后按照本章第5小节的说明配置后,就可以像使用内部Flash一样调试下载QSPI Flash了。
" H( |- k! L* \- L4 e0 _# d$ S% D* S' y! ?% q9 g3 l& a3 E0 t
82.7 总结# h* H" y4 I. u" }$ s
本章节就为大家讲解这么,为了熟练掌握,建议大家是操作练**。
; m! g. K" l2 F" b
7 I4 f* Q4 w- \- a* g
! S5 K. e; d' u. v. x
3 ~7 M4 @% V& Q5 `  {; N
收藏 评论0 发布时间:2021-12-21 23:21

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版