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

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

[复制链接]
STMCU小助手 发布时间:2021-12-21 23:21
82.1 初学者重要提示0 o6 R7 y6 A3 J! h. m
  操作本章配套例子前务必先将QSPI Flash的下载算法放到MDK安装目录。6 Q/ P  {$ L  c1 z. _! ?2 s
  QSPI Flash执行程序的BOOT和APP作用:
) |0 r- O4 I% m( X. \7 j- z  BOOT程序需要下载到内部Flash。主要用于跳转到外部QSPI Flash执行程序。那么问题来了,我们可不可以不使用BOOT,上电就直接执行QSPI Flash的程序?不行,因为QSPI Flash不像内部Flash,无需初始化,上电就可以使用,而QSPI Flash不行。- M4 v8 N. Q* _3 Z$ E; }
  APP应用程序要下载到QSPI Flash里面。APP应用程序可以在QSPI Flash里面执行主要是因为W25Q256支持XIP(Execution In Place),并且STM32H7的QSPI Flash支持内存映射。
2 K9 J! E+ A" F82.2 下载算法存放位置# u: l4 [/ l4 P9 ]
编译例子:V7-060_QSPI Flash的MDK下载算法制作,生成的算法文件位于此路径下:
4 c  p# N+ l6 V" K9 |/ p. R! H! M% H# }$ u& C
618b073cf66c2944fcdb610aef0e67ea.png

7 K1 [/ ?$ P, k7 B
! b: o; }  s  x& s1 G生成算法文件后,需要大家将其存到到MDK安装目录,有两个位置可以存放,任选其一,推荐第2种:
2 s, D7 K1 h, v6 t" Y# J7 k; g+ r8 D
- @% z" w; Z, k& A" D2 m, \0 v. w  第1种:存放到MDK的STM32H7软包安装目录里面:\Keil\STM32H7xx_DFP\2.6.0\CMSIS\Flash(软包版本不同,数值2.6.0不同)。2 I1 b% C/ |9 T
  第2种:MDK的安装目录 \ARM\Flash里面。
0 _; c% T5 j3 c/ z  }5 d- E" Q" i. y0 N1 K7 b8 S( a
b192c51eb80b27959d7c06b80a142d6e.png
$ _: F* C! ]3 @/ B! `6 W

" P+ N2 f( O( B' A% v1 V3 f, o82.3 QSPI Flash的Bootloader说明
! u* ?2 M. ^! k" m3 u0 Q# s- w
Bootloader的实现比较简单,需要大家将其下载到内部Flash。程序实现上主要注意以下两点即可。3 D/ y- V" g7 x( \) g

% {- @0 O. S1 E6 A7 {82.3.1 初始化QSPI Flash并设置内存映射模式
/ W* k  M" `) z在bsp.c文件中初始QSPI Flash并设置为内存映射模式。9 S: q! H1 X& P

, ]. K' r/ p6 k$ R7 y' ~" s
  1. /*, A0 w, t/ O  O
  2. *********************************************************************************************************
    ! i3 c* h7 n% c; P& d. ~/ e2 L4 [' C
  3. *    函 数 名: bsp_Init
    " C6 u* P  E+ O2 j
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
    ! z1 T+ D0 L/ j5 `
  5. *    形    参:无
    % r3 a" G& ?! M5 c: D
  6. *    返 回 值: 无% F9 J6 a) |4 e. ~
  7. *********************************************************************************************************' j$ [: f5 C- S$ ?
  8. */% K  }% @% t' B  \, B7 y" c5 Z# E
  9. void bsp_Init(void)4 c/ Q" w" R) T$ F6 a
  10. {5 o# _: u1 M3 Y2 g
  11.     /* 配置MPU */
    , m) k$ j& x3 [0 k. _$ F  J
  12.     MPU_Config();3 l# {7 ~7 V0 H  b+ y) c) R$ I( |
  13. - B* v/ u# v* j7 N6 G& I1 c% q
  14.     /* 使能L1 Cache */
    6 w' l" s2 w( h% a! H# X' a! g, B
  15.     CPU_CACHE_Enable();6 G% F8 x& _5 V- P8 r) i! p

  16. + T- O2 E* Z3 p7 O8 q3 d5 r3 `7 A( I
  17.     /*
    % E5 i7 [9 {& v) Y8 u( R
  18.        STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:
    + F. i7 F  Z. K+ G
  19.        - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。+ W) b$ S* ^( h% s$ g0 B0 Z
  20.        - 设置NVIV优先级分组为4。
    $ e9 {0 ?+ O/ w7 ]1 T! g, E
  21.      */3 S  J% x' {+ u; m
  22.     HAL_Init();
    ; f7 h  z* c, F8 j* n

  23. & }7 o. X. N1 U! S# L- b' c2 W
  24.     /*
    4 m4 j/ }# n( l6 ?) {
  25.        配置系统时钟到400MHz" h7 M% p" u8 w/ }
  26.        - 切换使用HSE。* y' m  g4 S' S  Q4 f
  27.        - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。0 z% v& r6 j+ q" o, s% H$ p
  28.     */
    . {$ ~+ e1 a( @+ v' K
  29.     SystemClock_Config();
    / D2 h; L4 p9 J0 _1 [; X
  30.   e0 @1 A6 q& k7 e
  31.     /*
    7 F# m8 ]" G+ P* |
  32.        Event Recorder:
    8 T0 P) M4 r+ W( \) g/ k9 B
  33.        - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。% ]. J' S- x+ O% u$ g$ I
  34.        - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章6 H% m, k! a* B# P9 m
  35.     */    / C% X3 X5 F4 w$ J
  36. #if Enable_EventRecorder == 1  
    8 m* `. ?& I" m5 N/ W) m0 s" ^# ~# @
  37.     /* 初始化EventRecorder并开启 */5 z/ I+ Y  h( t: \
  38.     EventRecorderInitialize(EventRecordAll, 1U);* ]7 Z3 _/ e1 h! T5 ]$ J
  39.     EventRecorderStart();3 a( T# s/ d# w  L) j
  40. #endif
    6 g9 v  `2 H/ y- }$ P, C( t
  41. ) R- H+ J4 \1 x
  42.     /* 针对不同的应用程序,添加需要的底层驱动模块初始化函数 */4 _. l1 U# G' S
  43.     bsp_InitQSPI_W25Q256();  /* 配置SPI总线 */   
    % @, G7 u) I2 `/ P/ w# U
  44.      QSPI_MemoryMapped();
    9 I+ r/ I: ?0 a: H2 b/ W+ {: u
  45. }
复制代码

0 Q& y; ]2 a+ W82.3.2 程序跳转的实现
* B7 @' A4 r4 U! B% F从内部Flash跳转到外部QSPI Flash的实现代码如下. j! ^  w, Y$ }/ R5 k
* b, g5 s6 g' C9 V: T
  1. 1.    /*
    - ]  F. }  Q2 z. Y' b4 D6 G
  2. 2.    ******************************************************************************************************
    8 D3 c) E, {/ `, f/ c+ H; r0 M8 C5 m' ^
  3. 3.    *    函 数 名: JumpToApp
    + ?% j/ O; P' O) z
  4. 4.    *    功能说明: 跳转到应用JumpToApp
    # ~& j' R* W. u( c! ~
  5. 5.    *    形    参: 无
    : G6 `: v% _5 x7 P3 J0 }# {) {6 c
  6. 6.    *    返 回 值: 无
    . @% c. U# y& ?2 L  T+ H" y: h2 {
  7. 7.    ******************************************************************************************************
    + H5 |+ P) M" R
  8. 8.    */
    0 z  K  X2 w  r: G1 k! f
  9. 9.    static void JumpToApp(void); o# ^! C  v1 ?9 d) g5 v9 E
  10. 10.    {
    ! D8 m$ A3 E. S4 X8 }
  11. 11.        uint32_t i=0;# E4 S7 [8 D: x! H: I8 y# _
  12. 12.        void (*AppJump)(void);         /* 声明一个函数指针 */
    5 q* B8 t2 @7 G. t$ ^. m  ~5 m
  13. 13.        __IO uint32_t AppAddr = 0x90000000;  /* APP 地址 */
    5 Z/ {0 _" }: G: `1 K
  14. 14.        0 C# W9 E7 }9 G+ J
  15. 15.   
    ( @9 @; j& p2 f8 ~( V8 K9 K
  16. 16.        /* 关闭全局中断 */* N1 }' b0 w$ C' a
  17. 17.        DISABLE_INT(); . O% R; g& H6 z' w4 u/ u
  18. 18.        
    % C, ]; Z% z8 ^* @& c! e
  19. 19.        /* 设置所有时钟到默认状态,使用HSI时钟 */
    8 j+ ^$ G" A" P! B! `$ F9 ]
  20. 20.        HAL_RCC_DeInit();
    $ Z: s7 }" a  I1 T1 c  J
  21. 21.        - {- k' q5 p5 A: Q0 o. L. D$ D
  22. 22.        /* 关闭滴答定时器,复位到默认值 */
    $ e4 ~7 ^9 d+ f7 V8 O0 O
  23. 23.        SysTick->CTRL = 0;" d' W7 b. d3 O4 D7 B; `
  24. 24.        SysTick->LOAD = 0;
    3 U$ ~( B& r, ]/ |' f" k
  25. 25.        SysTick->VAL = 0;! C0 F4 a4 M/ k+ Z: C
  26. 26.    ) h5 X+ ]; V7 W+ @7 f
  27. 27.        /* 关闭所有中断,清除所有中断挂起标志 */. ^* N8 U9 S' `" j( y7 i
  28. 28.        for (i = 0; i < 8; i++)
    % L; ~/ @$ B9 l* ^: T# K7 f& [4 l
  29. 29.        {! P/ i' z( r, [' t, _6 Q
  30. 30.            NVIC->ICER<i>=</i>0xFFFFFFFF;6 T% V  F5 g! ^6 T2 K& G9 D4 F0 d
  31. 31.            NVIC->ICPR=0xFFFFFFFF;
    1 V6 z: c8 v3 [
  32. 32.        }   
    1 e8 g1 d0 K' V4 ^3 g. s3 \
  33. 33.    8 d! @7 v7 I7 g3 K
  34. 34.        /* 使能全局中断 */
    , m* G! `0 [. h
  35. 35.        ENABLE_INT();! a2 Z  l4 i- ?: g2 n. t# W# ~
  36. 36.   
    7 {) d& }8 s1 J* _3 s
  37. 37.        /* 跳转到应用程序,首地址是MSP,地址+4是复位中断服务程序地址 */
    ( ~. H" E3 M. @6 k& P5 \
  38. 38.        AppJump = (void (*)(void)) (*((uint32_t *) (AppAddr + 4)));
    ( Y( C4 K8 l$ U) c* y
  39. 39.    " \/ B3 l. ?% G- ]* p3 d5 s# T) l
  40. 40.        /* 设置主堆栈指针 */& o6 P3 u2 h/ o& {
  41. 41.        __set_MSP(*(uint32_t *)AppAddr);2 D0 I1 y6 n' d) Z( ~) j
  42. 42.        7 _& F5 ]7 \/ [# m6 A
  43. 43.        /* 在RTOS工程,这条语句很重要,设置为特权级模式,使用MSP指针 */
    ' k2 x# e- g3 S
  44. 44.        __set_CONTROL(0);
    $ n3 z7 O& p, {: q( b: _
  45. 45.    ( v* I$ n3 p) c* M7 y! w
  46. 46.        /* 跳转到系统BootLoader */8 P/ ]/ A8 n7 e  [& K& z
  47. 47.        AppJump();
    6 f, d) D/ \5 N/ b, r: _
  48. 48.    - T$ P1 a0 w, v
  49. 49.        /* 跳转成功的话,不会执行到这里,用户可以在这里添加代码 */
    + l+ G' {8 A) @1 R! S: s  D8 {
  50. 50.        while (1)% \1 C/ o9 H( w" B
  51. 51.        {
    . g8 x% N7 i0 D! ]
  52. 52.    7 d( l0 N7 [. L: `0 w) G" [
  53. 53.        }
    7 l5 X% V* Y% U
  54. 54.    }
复制代码
: F: x8 Z+ J  Q, \, M8 C
这里把程序设计中的几个关键地方做个说明:
/ P" n* x& B" I! O) ?$ T+ B+ Q8 d1 S. c0 D8 y8 R
  第12行,声明一个函数指针。
6 [8 _4 G$ ?* q% r3 f! O+ X  第13行,QSPI Flash地址在0x90000000。( n9 }6 a; C# W! R- i
  第20行,此函数比较省事,可以方便的设置H7所有时钟到复位值,内部时钟使用HSI。. G& x0 E& R1 @; _/ ]  x9 T* E2 C, l
  第23到25行,设置滴答定时器到复位值。" I9 \0 k; x' {; ^7 m( C( a0 e, s
  第28到32行,清除所有中断挂起标志并关闭中断,这里是直接通过一个for循环设置了NVIC所有配置位,共8组。
' W! m2 W. r6 _! m% D5 ~1 {9 l% Z1 r3 p5 i4 Y8 S0 U
bfe6b8c0ea19b535e2fb06c6618577f6.png

9 l$ ]& [0 ]$ I' G3 I" `) [+ q- F: u1 q* C0 t* u1 @
  第38行,将系统bootLoader的中断复位服务程序的入口地址赋给第12行声明的函数,用户执行这个函数时,就会直接跳转过去。
; ?& @6 e  k3 s0 z/ e* j  第41行,设置主堆栈指针位置,即QSPI Flash应用程序首地址存储的就是栈地址。! }" U8 g, D2 c* i! f& A
  第44行,这个设置在RTOS应用程序中比较重要,因为基于Cortex-M内核的RTOS任务堆栈基本都是使用线程堆栈指针PSP。但系统bootLoader使用的是主堆栈指针MSP,所以务必要设置下,同时让M内核工作于特权级。此寄存器的作用如下:( A9 [0 E! g3 A+ j  w5 T
$ ~( E! {' n/ ?& S0 n
b00b09a901596bcedb07c31790d8d3d9.png
! B! K$ r8 m: E/ n* e7 B* @( l

" n; ~. z4 K" x+ w2 Q$ ?) ~) P  第47行,跳转到系统bootLoader。
4 \% H/ @, k2 G6 g* ]* n0 ^9 m) h8 g( k( N" I$ Q
82.4 QSPI Flash的APP应用程序说明2 v0 [- g7 d2 g+ w) y
APP应用程序是由第53章配套例子:V7-033_LCD的汉字小字库和全字库制作 简单修改而来,主要修改如下两个地方:; W5 b4 X# j; Y2 {

1 I3 P8 S0 Y- T" {' u82.4.1 设置Flash地址% b; o, Q% L* M4 ^) T3 N
设置Flash地址为QSPI Flash首地址0x90000000:
( O: N, ]7 d- U0 z& J5 o3 a; w0 Y0 a5 i- d  h
75afb2342189857e8fa086fc0af08462.png
+ C" d5 t. c8 X4 ^: \  i8 r
7 Y$ b& H& B( }2 N6 ?! P
82.4.2 设置中断向量表
8 n: K6 I9 }( D在main函数最开始就设置中断向量表到QSPI Flash首地址0x90000000,也可以按照本教程第28章的说明,将中断向量表设置到DTCM里面。* f0 m& b# v1 m, N" }

; U7 [* a* R2 U% ^/ d6 B
  1. int main(void)) k8 e% \3 P, K9 g  m
  2. {/ x+ t/ p6 ]% t( A& o" b* [
  3.     uint16_t ucBright;           /* 背光亮度(0-255) */4 {' b# {# g+ i6 `! \
  4.     uint8_t ucKeyCode;        /* 按键代码 */( ]) t4 b( e7 V2 v2 q7 `, U  p$ c
  5.     uint8_t ucStatus;        /* 主程序状态字 */9 K) Y6 P; I0 V9 P, P
  6.     uint8_t fRefresh;        /* 刷屏请求标志,1表示需要刷新 */6 G' M- q8 X5 H6 C3 P" x( n2 p

  7. 4 x, O/ p8 x! ?1 w
  8.     SCB->VTOR = 0x90000000; /* 设置中断向量表地址 */! V- Z  p; C0 o: z" x/ u
  9. 0 X9 ~' E4 L4 E
  10.     bsp_Init();    /* 硬件初始化 */
    2 |  a7 L% U: f8 J# F/ T& T5 b
  11.     PrintfLogo();    /* 打印例程名称和版本等信息 */
    ! H; s: E- F8 |0 E, F0 Y
  12.     PrintfHelp();    /* 打印操作提示 */  l- r. W% M0 a2 [! U% K; B3 w
  13. % E, y' z# b# K9 E
  14. 省略未写
    7 f* a1 H6 [1 J; B. H7 g8 g* {; L

  15.   Q* D: R. z3 v/ ]" c# I
  16. }
复制代码
7 F  z7 ?$ g0 S) z# y
82.5 QSPI Flash的APP应用程序调试下载配置4 r1 T  Z2 E$ e4 h" |* l
将下面两个地方配置后,就可以像使用内部Flash一样使用QSPI Flash进行调试了。
! j8 T5 Z$ v; c( v, n5 \
8 Y* @. A6 I2 Y1 t2 B& v82.5.1 下载配置
& Y* z& V! X: E$ K" e" q) b$ E/ B" S注意这里一定要够大,否则会提示算法文件无法加载:
! ?- X3 V: A) V* C7 m
4 H& O" U* p$ ]; e+ S4 {+ N4 F
96d039e1657c72042027eb7e46ffc33a.png
: w9 s% R# ^! b

' \/ j1 t2 h4 q我们这里是将其加到DTCM中,即首地址为0x20000000,大家也可以存储到任意其它RAM地址,只要空间还够加载算法文件即可。推荐使用AXI SRAM(地址0x24000000),因为这块RAM空间足够大。
/ Z# H7 {* X: i7 w8 S
; ]8 t" I4 G5 {4 q: x7 S; l$ q8 }! t9 x如果要下载程序到QSPI Flash里面,需要做如下配置:
5 F2 p% T: X7 n7 v2 P6 k$ q8 _( F( S: X
5c95b0f51dbecf9eac259ddcf6b3da55.png

6 U/ p+ a( M2 r' V. ]* ]. r
; w, y# s2 i- \, y82.5.2 调试配置( O' j4 l0 X* N) H6 q
注意这里一定要够大,否则会提示算法文件无法加载:
' Y( J: B. K. R9 K, D" ]" f3 Z5 _
6b0758d3dd4db39b7189a03d59f0eca0.png
( {& }5 y- M2 F3 M% W% V

/ S+ U6 q: W% h! r我们这里是将其加到DTCM中,即首地址为0x20000000,大家也可以存储到任意其它RAM地址,只要空间还够加载算法文件即可。
5 R& Z( w0 A2 k) n
1 [6 A( J7 X. q' }5 [; W如果要做调试下载,需要做如下配置:# A9 k' \. R( M  W6 I

( e" C( ~% w7 C% D' A3 V2 W
927401ada0fef49a78ac8029e372a755.png

8 q2 R0 b; _. V. }0 |* l# a
0 W1 g) _5 d# ^, y  `+ B# J$ o4 u* O) s- P0 K" h% u2 h8 o5 R
82.5.3 程序调试效果9 u: I% p# v+ S& J/ G/ N
APP应用程序调试效果如下:
5 U9 t! g, v- x) A! q" M5 x
# I4 Z, n" B* ^) }# V
681a23ba44bd11addce0fa9aae797dbd.png

' {! r, o2 s9 i8 V7 `  I& w2 K& e, }( o+ i* ?) Q$ T# M
82.6 实验例程说明

9 a4 B& B* l! D% c本章配套了两个例子:6 P, ?8 ?' J! S! d

* Q+ `6 _) u) s+ L/ I  V7-062_QSPI Flash运行程序(Bootloader)。
/ b& Y- n( V- x& `  p/ P# b; @3 B  V7-063_QSPI Flash运行程序(用户APP)。
/ F8 |7 v9 h$ Y( X
6 y5 p% j) e# R1 T5 T$ v2 p
( H' u4 K8 y" V. dBootloader例子需要大家先下载到内部Flash里面,然后按照本章第5小节的说明配置后,就可以像使用内部Flash一样调试下载QSPI Flash了。0 ~- V# M0 o  X# j2 T- A2 ?

" k3 v' b9 h* p" r; t82.7 总结' h; ]. x1 N# N9 |9 _
本章节就为大家讲解这么,为了熟练掌握,建议大家是操作练**。
$ g' `0 F+ T" u9 d6 Y1 f6 X# V9 e# p+ M* M3 e( m

8 Q, i' M7 }8 m) z9 @, ]
* O5 S7 E% M* x8 |: Q* C2 R& z9 t
收藏 评论0 发布时间:2021-12-21 23:21

举报

0个回答

所属标签

相似技术帖

官网相关资源

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