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

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

[复制链接]
STMCU小助手 发布时间:2021-12-21 23:21
82.1 初学者重要提示' _, @  e# C2 K% B+ ^# I
  操作本章配套例子前务必先将QSPI Flash的下载算法放到MDK安装目录。
6 R, `0 r6 {$ y" ^+ V2 h6 y  QSPI Flash执行程序的BOOT和APP作用:) I5 Q3 s6 _7 Z+ C
  BOOT程序需要下载到内部Flash。主要用于跳转到外部QSPI Flash执行程序。那么问题来了,我们可不可以不使用BOOT,上电就直接执行QSPI Flash的程序?不行,因为QSPI Flash不像内部Flash,无需初始化,上电就可以使用,而QSPI Flash不行。
( I3 x3 X- P' A" b3 S  APP应用程序要下载到QSPI Flash里面。APP应用程序可以在QSPI Flash里面执行主要是因为W25Q256支持XIP(Execution In Place),并且STM32H7的QSPI Flash支持内存映射。
9 u& p. m" K0 X# e$ `5 H' Z+ ^82.2 下载算法存放位置
; j* r  t# u' _$ i* C编译例子:V7-060_QSPI Flash的MDK下载算法制作,生成的算法文件位于此路径下:
: D. A, @0 G, |0 I6 [/ a: Q: D$ z
618b073cf66c2944fcdb610aef0e67ea.png
; m0 }2 c5 T4 {4 F) [2 A7 Y/ C
2 C# K9 j8 A- g" F& l& O% v3 @
生成算法文件后,需要大家将其存到到MDK安装目录,有两个位置可以存放,任选其一,推荐第2种:% _" [8 K" X& l6 P, J

- U2 W& @  g  i, p$ p/ k  第1种:存放到MDK的STM32H7软包安装目录里面:\Keil\STM32H7xx_DFP\2.6.0\CMSIS\Flash(软包版本不同,数值2.6.0不同)。0 C: p! L8 Q5 }' h( q% u, x
  第2种:MDK的安装目录 \ARM\Flash里面。* Q% H# C# ^+ C& P; }

- c; D  {/ `/ V% H7 H
b192c51eb80b27959d7c06b80a142d6e.png

+ l. |- j: ~" m7 D" F
: A$ w' i$ I* P1 a( O! ?) I2 d82.3 QSPI Flash的Bootloader说明

6 |. D( A* F( l6 }* T5 t) }. k# K4 ~Bootloader的实现比较简单,需要大家将其下载到内部Flash。程序实现上主要注意以下两点即可。3 e" s- }, Q! ^, g

! P6 r! k+ o: d82.3.1 初始化QSPI Flash并设置内存映射模式0 W9 x) [6 l: d" O5 Y' W5 z
在bsp.c文件中初始QSPI Flash并设置为内存映射模式。
7 a- w5 N) D4 H( i/ I4 ^
. H. Y$ e! m  J; N+ S  }5 g
  1. /*
    & S& y! n4 k$ t, d$ `. Q. H, x/ D) [
  2. ********************************************************************************************************** ~0 @. B9 R* f7 k& I& S" e
  3. *    函 数 名: bsp_Init- b  ?" m, ~7 g' N, L+ O" J  c
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
    $ L+ ^: |1 z' P8 L
  5. *    形    参:无7 C2 t& }% G* R% B, X5 s
  6. *    返 回 值: 无
    0 T  `* ]3 A7 }2 Z0 M. J
  7. *********************************************************************************************************
    : w& x0 ]* e1 |" X, q
  8. */2 d5 H1 A4 d/ ?$ `! k
  9. void bsp_Init(void)
      F1 Y2 y; e7 B9 \
  10. {
    7 t& k2 ?- ^( {9 |6 `9 G( a( o$ g
  11.     /* 配置MPU */
    5 ^8 |0 Y; Q7 O+ o5 j  d
  12.     MPU_Config();& t2 b+ ]0 ~9 y2 u, [! W
  13. 8 [  k7 j1 o8 I. k) S% A. v
  14.     /* 使能L1 Cache */
    6 Z+ I/ E# p7 R* k0 V
  15.     CPU_CACHE_Enable();9 `/ A- y, @" S, O, \0 t! S) u
  16. % H/ l0 X1 [1 r: e; V2 @5 p$ }
  17.     /* 5 x& P. c  E7 X
  18.        STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:) J, [+ D0 T, r/ F- r$ g1 {
  19.        - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
    " q% ?8 R$ b  m( m! g/ E8 j! z: p% Y
  20.        - 设置NVIV优先级分组为4。
    4 m) H) A6 Y) T! c* N5 t2 y7 p
  21.      */5 M3 E- c8 E: q! a! l" ~
  22.     HAL_Init();
    4 m* n$ Z# {, z7 b% A. q+ T
  23. ' n, ]1 I% v8 `: C. L7 b" }
  24.     /*   a0 I6 H3 ?0 |5 i' R
  25.        配置系统时钟到400MHz
    - q# m7 D- G3 F1 x/ K# O' D
  26.        - 切换使用HSE。( y3 m4 K$ k* ^5 F; I
  27.        - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
    + ~9 G* c6 ^$ B( l
  28.     */
    3 U: T: K& V% ~5 R$ B" h) s) r
  29.     SystemClock_Config();2 @. }9 \. s; P/ U& F0 ~
  30. # i& D; b' n# J+ Q9 z$ c
  31.     /*
    6 j+ q3 Z* L! \" |8 j: O
  32.        Event Recorder:! w4 Y7 f1 ~# X3 T
  33.        - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。' H, F* B* p6 e
  34.        - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章
    + B+ W! n6 C8 z/ e; ]1 ]; C4 T3 [- F. u
  35.     */    ; a5 v/ g3 Q$ P* I$ W
  36. #if Enable_EventRecorder == 1  
    ; w) A7 d9 e" \$ P% t9 H& e
  37.     /* 初始化EventRecorder并开启 */
    : e, w8 ^8 Y' K6 r2 B! k6 q. T9 ]: u7 C
  38.     EventRecorderInitialize(EventRecordAll, 1U);
    6 E3 W6 w8 I4 n
  39.     EventRecorderStart();! M" P$ z" W6 |; Y4 O" b
  40. #endif
    * \9 m; \7 h0 O+ e$ C! l% D
  41. 9 w3 |2 e4 ^& u4 k! f  V
  42.     /* 针对不同的应用程序,添加需要的底层驱动模块初始化函数 */
    7 m1 |$ ~" D8 B( m( N, z% v! p
  43.     bsp_InitQSPI_W25Q256();  /* 配置SPI总线 */   % q+ L# \: k9 i8 z; W
  44.      QSPI_MemoryMapped();
    : Z$ f8 f* V2 u. P4 U* G
  45. }
复制代码

, z4 w8 V  Q' ^' d" _, X/ r82.3.2 程序跳转的实现
) B; w( I$ h2 Y. ^& `从内部Flash跳转到外部QSPI Flash的实现代码如下
/ `! d. C9 P7 A  b$ x
, L/ f$ p, j; U0 n6 ~3 p6 V
  1. 1.    /*
    2 c0 k4 l1 u  |, k3 ?) k0 X; n
  2. 2.    ******************************************************************************************************7 M) Q! Q( L. N0 ]' a
  3. 3.    *    函 数 名: JumpToApp3 P# {- o* I$ I! i% a0 ^; R# j
  4. 4.    *    功能说明: 跳转到应用JumpToApp
    , H3 v8 A- q( U9 W
  5. 5.    *    形    参: 无5 i: A; |& W6 o& y- H5 g
  6. 6.    *    返 回 值: 无
    1 N, k) |& j: o$ D* d( y
  7. 7.    ******************************************************************************************************
    " v  w- o' P2 ?' O; e5 T& B% B
  8. 8.    */: x/ k2 n! W: y9 B7 }4 b
  9. 9.    static void JumpToApp(void)( P3 r; @& X6 C, Z" D, g  y# {
  10. 10.    {0 P. r& G1 ^! f5 ~  D  ~
  11. 11.        uint32_t i=0;
    4 k0 Q: }% d. w. }$ V- v; d
  12. 12.        void (*AppJump)(void);         /* 声明一个函数指针 */
    ( c" f1 s7 Y; V3 \
  13. 13.        __IO uint32_t AppAddr = 0x90000000;  /* APP 地址 */3 Q- g3 _2 t( y3 G' C7 t
  14. 14.        & ]: h, C0 x. G1 }5 M
  15. 15.   
    7 ?' w# H5 B4 R1 _4 `+ |
  16. 16.        /* 关闭全局中断 */3 p; P" d% N$ u
  17. 17.        DISABLE_INT();
    , P7 [7 I4 S# t& d' ]- R4 f
  18. 18.        
    ) q# ^9 c+ ^8 U& G  \, t" s$ i
  19. 19.        /* 设置所有时钟到默认状态,使用HSI时钟 */# u% {3 h$ X& z7 k0 d: A
  20. 20.        HAL_RCC_DeInit();
    4 I' _9 b4 e2 ^! T) h5 v
  21. 21.        : m, p* Y) c* I4 m
  22. 22.        /* 关闭滴答定时器,复位到默认值 */9 v; r3 D0 F" h. y3 P* k( H) T
  23. 23.        SysTick->CTRL = 0;$ b" v# H+ n; Q& X# S6 X' B, c
  24. 24.        SysTick->LOAD = 0;
    / B1 D) u: L! b  f2 R# N: Y
  25. 25.        SysTick->VAL = 0;. w/ @6 o) D+ c, G% C
  26. 26.    , c) h" P( m2 a
  27. 27.        /* 关闭所有中断,清除所有中断挂起标志 */4 L9 b- X+ U( G! H9 s9 t
  28. 28.        for (i = 0; i < 8; i++), d' ~( z4 N7 I% F* ]+ p& G( Y
  29. 29.        {
    # O8 l# n* s9 o9 C3 v7 m4 u5 q6 L, {
  30. 30.            NVIC->ICER<i>=</i>0xFFFFFFFF;
    # a0 H. P9 j  t& h5 B5 `1 `
  31. 31.            NVIC->ICPR=0xFFFFFFFF;% K/ U' ?( b# {5 E+ y2 g
  32. 32.        }    ! X6 k- ]$ j7 g; F# S  w: ~4 v
  33. 33.   
    ( h4 t, G( U0 q* S
  34. 34.        /* 使能全局中断 */, P: `+ \' v$ R' ]4 q9 ^* |
  35. 35.        ENABLE_INT();2 \) |: }0 X" `. t( K
  36. 36.    ' g% }3 v; n$ @* M6 `5 T, h# I7 R
  37. 37.        /* 跳转到应用程序,首地址是MSP,地址+4是复位中断服务程序地址 */: m( L. Y5 l, c
  38. 38.        AppJump = (void (*)(void)) (*((uint32_t *) (AppAddr + 4)));
    : s  i4 Z1 F- e2 O
  39. 39.    * N0 i( r, [  p- A. r* v; |
  40. 40.        /* 设置主堆栈指针 */! X2 z5 o7 L) S
  41. 41.        __set_MSP(*(uint32_t *)AppAddr);5 F. w$ Q0 K0 k+ ?7 P) z
  42. 42.        
    - E" L$ C- a1 C& C0 {6 O) u
  43. 43.        /* 在RTOS工程,这条语句很重要,设置为特权级模式,使用MSP指针 */
    " f. h7 u8 ?  g
  44. 44.        __set_CONTROL(0);. d& F/ A5 Y: [0 V$ O8 j
  45. 45.   
    3 e* i  l5 B6 _1 L- j3 f
  46. 46.        /* 跳转到系统BootLoader */9 K$ u0 x1 e2 t1 s5 ^5 C
  47. 47.        AppJump();
    6 r( H6 u4 I$ O  k$ \, A, e
  48. 48.    ; d& ~$ F- f6 h' [, e6 Y5 u) z2 r# ?& b
  49. 49.        /* 跳转成功的话,不会执行到这里,用户可以在这里添加代码 */
    2 h2 c+ j  ~& G, {
  50. 50.        while (1)
    1 h" d4 d5 y. W! j6 d$ K* b
  51. 51.        {. g6 k( g( w" i) q7 H
  52. 52.    6 v/ Y- B  p8 h4 B& {
  53. 53.        }4 n, I: @+ O2 J! r
  54. 54.    }
复制代码
' V0 H) _- \3 F; _$ P8 z$ B
这里把程序设计中的几个关键地方做个说明:& P' M; n6 D, @& v: W/ T* F8 L
% `8 }# m2 R- I- ?2 |  \  d3 J0 E
  第12行,声明一个函数指针。' I3 E9 j. b. G2 M6 Y
  第13行,QSPI Flash地址在0x90000000。( @# c$ G8 }5 Q4 M& s' G
  第20行,此函数比较省事,可以方便的设置H7所有时钟到复位值,内部时钟使用HSI。* A( K- c7 Z; S& j
  第23到25行,设置滴答定时器到复位值。
0 M- t  p- V1 @) m5 `8 ^# P  第28到32行,清除所有中断挂起标志并关闭中断,这里是直接通过一个for循环设置了NVIC所有配置位,共8组。
# T. d" W% e9 g: T& \
) y3 ^/ I7 c7 g; I7 h2 \
bfe6b8c0ea19b535e2fb06c6618577f6.png

1 [" S1 o! J; e- H6 q& H
& L6 A+ ^( Z- p6 r8 {2 m  第38行,将系统bootLoader的中断复位服务程序的入口地址赋给第12行声明的函数,用户执行这个函数时,就会直接跳转过去。
# V# ?- b0 M  ^" g' W: `  第41行,设置主堆栈指针位置,即QSPI Flash应用程序首地址存储的就是栈地址。4 j: L( ]  M# r$ R7 D
  第44行,这个设置在RTOS应用程序中比较重要,因为基于Cortex-M内核的RTOS任务堆栈基本都是使用线程堆栈指针PSP。但系统bootLoader使用的是主堆栈指针MSP,所以务必要设置下,同时让M内核工作于特权级。此寄存器的作用如下:
) \0 x6 m& q# p# P! G# s  Z! ]$ R$ b' t1 X+ y$ u" }/ S# f1 g
b00b09a901596bcedb07c31790d8d3d9.png

; ?  a- \( h% n2 X: k6 o6 V; D3 D* u0 c- N1 O- h' Z  w* H
  第47行,跳转到系统bootLoader。8 P& c  N% C! e/ f6 B0 G# A/ Y  O0 H

! H7 F  k: L! I82.4 QSPI Flash的APP应用程序说明' ?0 z+ A0 r( |- ^) l; {2 v
APP应用程序是由第53章配套例子:V7-033_LCD的汉字小字库和全字库制作 简单修改而来,主要修改如下两个地方:
. ]9 T5 I3 P: J5 V8 m  O( i  H7 K8 I. @
82.4.1 设置Flash地址
% q9 {* C$ A. A/ H2 E& O- H设置Flash地址为QSPI Flash首地址0x90000000:
# p) Y0 O. V! t4 j2 v& n& j8 e+ s1 l; h& J: ^
75afb2342189857e8fa086fc0af08462.png

2 R/ t6 ?$ Q/ L2 _8 G+ ^# _+ h/ q" _2 y
82.4.2 设置中断向量表! U2 R4 D. n( e# y( Q
在main函数最开始就设置中断向量表到QSPI Flash首地址0x90000000,也可以按照本教程第28章的说明,将中断向量表设置到DTCM里面。& \) f/ ~. G# e8 S
) M9 f7 k: k9 y+ d
  1. int main(void)- ~( o3 C4 Y* C0 }2 S
  2. {3 Z* q, m+ F8 ~" M
  3.     uint16_t ucBright;           /* 背光亮度(0-255) */& ^: g& r! u" i$ p/ P' J
  4.     uint8_t ucKeyCode;        /* 按键代码 */9 a2 s% V+ l* h* U6 E1 ?# [" m
  5.     uint8_t ucStatus;        /* 主程序状态字 */
    0 T$ J4 v; |% _4 h5 i
  6.     uint8_t fRefresh;        /* 刷屏请求标志,1表示需要刷新 */
    * \# L7 {! N! y) F& Y/ f! U
  7. # ]. X8 J5 j0 o5 F+ G
  8.     SCB->VTOR = 0x90000000; /* 设置中断向量表地址 */- g* c1 q' r& n( v5 E( ~% R8 s. m
  9. . I8 k" S+ j) c$ j% @, Q
  10.     bsp_Init();    /* 硬件初始化 */( P- l. b2 ^& p4 v
  11.     PrintfLogo();    /* 打印例程名称和版本等信息 */
    - B# C/ ~4 E2 _6 n# X
  12.     PrintfHelp();    /* 打印操作提示 */
    , n8 E7 y8 t% J( ^

  13. 6 v$ e2 A1 }- z; f  f
  14. 省略未写
    5 g8 s! }" `! M3 \

  15. % G, y' O* q4 l5 e
  16. }
复制代码
* G( @' ^  N/ T+ u% t7 G& P: c
82.5 QSPI Flash的APP应用程序调试下载配置
# ?4 L1 T% O# Z6 L0 G1 b, K将下面两个地方配置后,就可以像使用内部Flash一样使用QSPI Flash进行调试了。
( I3 r+ K! j; k; X2 g1 y3 A0 ?+ S' e2 s
82.5.1 下载配置$ l4 D( l  W& z
注意这里一定要够大,否则会提示算法文件无法加载:" f9 S* e; M6 f! }

6 W$ o; d5 q+ @* t
96d039e1657c72042027eb7e46ffc33a.png
7 f; B4 K8 J1 y6 i3 _0 M
, a" P! K1 L6 N2 S! F2 @6 J+ B+ ^; N
我们这里是将其加到DTCM中,即首地址为0x20000000,大家也可以存储到任意其它RAM地址,只要空间还够加载算法文件即可。推荐使用AXI SRAM(地址0x24000000),因为这块RAM空间足够大。
( t$ [( v' }8 O5 c6 `. J, L% D& a8 h+ p6 @4 t0 m% Z
如果要下载程序到QSPI Flash里面,需要做如下配置:
3 [5 O: U0 E0 C5 L/ Q- R  C" u/ u0 P  s+ ?' K" o# G1 s1 r7 F% l' |9 x
5c95b0f51dbecf9eac259ddcf6b3da55.png

; M4 G# H' h# L0 t8 J6 @
, L$ C0 E. q) e5 b# \82.5.2 调试配置; H7 f5 o' I- c
注意这里一定要够大,否则会提示算法文件无法加载:
/ t* B& s. O  d, _1 p6 f( h  u0 A: e, g9 K: a  ?: W3 G
6b0758d3dd4db39b7189a03d59f0eca0.png
3 q' j1 F1 S. u0 A7 Q
5 u. u- @" v( y& b5 ?  l* E* U
我们这里是将其加到DTCM中,即首地址为0x20000000,大家也可以存储到任意其它RAM地址,只要空间还够加载算法文件即可。
8 F% O$ \! l; ^
: A4 [. S' f. [9 x$ N, H+ @如果要做调试下载,需要做如下配置:" V8 v1 J$ M1 G
" b( O* n/ y3 L& h5 f
927401ada0fef49a78ac8029e372a755.png
) C7 d. b/ U/ m+ Q
" A7 C- i% {  c% E. d- I8 j
: j: Z7 M- J9 F
82.5.3 程序调试效果
6 v7 m  o6 x3 }9 v: W5 [, d# ^APP应用程序调试效果如下:: H; @- @. g$ o3 m( I/ }: l6 N% U
# H6 f, D( j: [1 M$ t& P+ I
681a23ba44bd11addce0fa9aae797dbd.png
1 t" ]0 O" R  e
) |9 h3 V- G; j* e
82.6 实验例程说明

0 X9 b2 l2 t: ?# V) t" B$ w- z6 }3 r, ?本章配套了两个例子:) O' @% F2 D/ V- F# Z) o
+ B' j6 h) Q8 C( u8 y# u- K# H
  V7-062_QSPI Flash运行程序(Bootloader)。
( T+ q5 x, o( ~4 J3 b6 ?% P  V7-063_QSPI Flash运行程序(用户APP)。: p4 P- j+ {# q: v

, F9 Q0 W9 Q0 c( f2 m7 j/ e, B. B# D; w
Bootloader例子需要大家先下载到内部Flash里面,然后按照本章第5小节的说明配置后,就可以像使用内部Flash一样调试下载QSPI Flash了。+ `# Q6 |' L+ [7 t: b
9 w; l7 N  B6 V: r; Z
82.7 总结
# q# O6 b2 _+ M7 W本章节就为大家讲解这么,为了熟练掌握,建议大家是操作练**。
0 K% a' D9 i9 g& r1 t/ _
  u) N5 g; L  Y# @" g( }9 C0 H: I! |2 e
5 t- t; u' H) a- I$ O0 P
收藏 评论0 发布时间:2021-12-21 23:21

举报

0个回答

所属标签

相似分享

官网相关资源

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