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

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

[复制链接]
STMCU小助手 发布时间:2021-12-21 23:21
82.1 初学者重要提示
2 d. k$ a' y7 @$ t" ^/ t  操作本章配套例子前务必先将QSPI Flash的下载算法放到MDK安装目录。
) H9 T! w2 U& k  J, b' s) Y6 ^3 Z0 e. s  QSPI Flash执行程序的BOOT和APP作用:
* i6 X8 f% E; b% Y- U/ {  BOOT程序需要下载到内部Flash。主要用于跳转到外部QSPI Flash执行程序。那么问题来了,我们可不可以不使用BOOT,上电就直接执行QSPI Flash的程序?不行,因为QSPI Flash不像内部Flash,无需初始化,上电就可以使用,而QSPI Flash不行。) |. T* M( U6 X
  APP应用程序要下载到QSPI Flash里面。APP应用程序可以在QSPI Flash里面执行主要是因为W25Q256支持XIP(Execution In Place),并且STM32H7的QSPI Flash支持内存映射。& J  D) `. X/ J/ w9 L9 B9 z; Q
82.2 下载算法存放位置( L$ b5 k# l( u( _% g
编译例子:V7-060_QSPI Flash的MDK下载算法制作,生成的算法文件位于此路径下:
* D. j4 c3 a9 X8 M9 d) E% z5 c8 |1 p" J- x% t, N9 |7 P
618b073cf66c2944fcdb610aef0e67ea.png

% v; v( u2 q: {! A$ H+ {/ ]& f7 F
* I7 U& Y. ?+ f* p4 I生成算法文件后,需要大家将其存到到MDK安装目录,有两个位置可以存放,任选其一,推荐第2种:
2 J- ^8 K2 m1 N0 \3 s! n
2 Y  }( Z; o8 ?. ~. [7 P$ d  第1种:存放到MDK的STM32H7软包安装目录里面:\Keil\STM32H7xx_DFP\2.6.0\CMSIS\Flash(软包版本不同,数值2.6.0不同)。
- x1 m, _/ s( V$ M. l: ]: u- X  第2种:MDK的安装目录 \ARM\Flash里面。- F" W! Q$ c6 x8 B! P: G7 f* u
2 g+ \5 K' H" V. Y; u
b192c51eb80b27959d7c06b80a142d6e.png
% a8 {/ \. n, M+ E4 z7 t. d" a
0 w& V  t; [$ i2 `
82.3 QSPI Flash的Bootloader说明
! H, r" ~' N% G# _& J3 |* l. g
Bootloader的实现比较简单,需要大家将其下载到内部Flash。程序实现上主要注意以下两点即可。
' [, k$ w/ G( L2 D, f" _2 S
" G# @7 A! R0 z! I7 Q82.3.1 初始化QSPI Flash并设置内存映射模式& |+ J7 T9 `5 y) [6 I" u
在bsp.c文件中初始QSPI Flash并设置为内存映射模式。0 ]( H0 M4 o: ]6 Q

" M2 u" L/ b; A  R" k
  1. /*% J4 U, G  z3 J& u+ J8 m( z4 D3 A
  2. *********************************************************************************************************
    6 Y7 r1 C) J# C" _7 R- T7 i
  3. *    函 数 名: bsp_Init
    7 [) F# J2 X2 [4 X/ l
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
    ( R+ H7 w; M1 L$ T2 x
  5. *    形    参:无
    0 ^! l' ?% X+ C) z# x% K1 M
  6. *    返 回 值: 无! ]) k+ g3 C, a- b; }  m
  7. *********************************************************************************************************
    " h6 \( B& _2 O( v
  8. */4 O( c* @! K8 d5 g& ]
  9. void bsp_Init(void)
    ) i1 f8 O, \: b; O9 r8 l
  10. {# I9 M) ~/ A+ B8 I3 d
  11.     /* 配置MPU */7 G, t( V% k& {5 Q! G
  12.     MPU_Config();% D* |6 f  |4 ?$ B9 W0 T) k. H
  13. ; [2 \. v* @$ w! F5 T
  14.     /* 使能L1 Cache */" Q6 C6 u5 a6 K) J$ I
  15.     CPU_CACHE_Enable();
    0 x" f1 P0 F0 t) m+ z  L: E

  16. / j" o+ K, w8 p
  17.     /*
    6 m* A( }# f9 \- t+ k* O
  18.        STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:) H: F. t* Q, {4 R+ c
  19.        - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。) {$ T4 j8 @. w9 g
  20.        - 设置NVIV优先级分组为4。4 r" H! T. c  A/ h+ y
  21.      */
    , \- u8 B3 @/ Z9 [- g9 B+ w
  22.     HAL_Init();2 Y5 [& f& N' S& c/ q; z& u+ j: a
  23. " h* W1 P; b% }" Z  k/ J' l
  24.     /* ) d! i8 R7 v7 ^8 D' c7 u5 t
  25.        配置系统时钟到400MHz
    # Y8 u* m& y# k; C
  26.        - 切换使用HSE。
    2 ?, R# Y0 k/ Z& L" V# Y
  27.        - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
    7 }; G6 R! b  i5 @8 ~/ B* Z
  28.     */* B5 }  ?* F- ?, y# H2 W
  29.     SystemClock_Config();
    ) F& }: Z- C, F7 w4 G( i8 `
  30. $ d4 f- N5 s& T+ L. ?6 O- l
  31.     /* 8 w9 [. W0 u& w; S9 [  Y  r
  32.        Event Recorder:
    3 m3 ]1 {5 T, H& f1 ]  C% v
  33.        - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
    2 f4 T$ I3 W7 ]  n
  34.        - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章8 o1 `+ c) \2 x
  35.     */    , ~; R, F" z' G3 d4 I/ f$ p
  36. #if Enable_EventRecorder == 1  3 A' v" y( S' a1 d% }. Q$ b
  37.     /* 初始化EventRecorder并开启 */
    % I  j; ~, `+ [
  38.     EventRecorderInitialize(EventRecordAll, 1U);5 z) _( S6 \2 j, w% L) |
  39.     EventRecorderStart();
    . I0 u! F: z& b
  40. #endif
    + g% ?! z" `! P

  41. ( {. ~* C2 t! [4 C/ \0 y
  42.     /* 针对不同的应用程序,添加需要的底层驱动模块初始化函数 */. T, a4 \2 w' \) l
  43.     bsp_InitQSPI_W25Q256();  /* 配置SPI总线 */   ! P6 o" k5 ]! g; [8 E: k
  44.      QSPI_MemoryMapped();
    * K" ^# Z+ D; Y
  45. }
复制代码
3 Z( ?$ d9 `9 w! z  B
82.3.2 程序跳转的实现
& z$ k. W( V) r0 O$ W4 s从内部Flash跳转到外部QSPI Flash的实现代码如下
9 _" y: Y6 D! z$ Y
; V* x) t2 V# O8 k7 C3 F
  1. 1.    /*/ L% d0 M6 ~8 y  R; B7 }
  2. 2.    ******************************************************************************************************4 C8 ^3 j' ?$ O& Y; H# Q5 u7 T
  3. 3.    *    函 数 名: JumpToApp' P; d# V8 C; f$ H8 S' E
  4. 4.    *    功能说明: 跳转到应用JumpToApp
    " i4 z- j4 t9 B8 C; ^4 j
  5. 5.    *    形    参: 无7 A. S2 `5 f0 K- P- S
  6. 6.    *    返 回 值: 无
    " @2 h6 B, O2 b2 s5 r+ j
  7. 7.    ******************************************************************************************************
    5 ?, s/ O2 x$ E
  8. 8.    */- G& b# V8 P% f8 w
  9. 9.    static void JumpToApp(void)4 c6 A, A5 ?/ C8 _
  10. 10.    {
    " h, _  f, r7 M( {5 w
  11. 11.        uint32_t i=0;
    8 p/ Y+ \, k* k' Y
  12. 12.        void (*AppJump)(void);         /* 声明一个函数指针 */
    * @: H' l& C* [
  13. 13.        __IO uint32_t AppAddr = 0x90000000;  /* APP 地址 */8 i! k0 W# S) F6 i7 K
  14. 14.        
    ! Q5 u6 q+ l/ x1 S8 ]) c
  15. 15.   
    & d( }- g* @- V6 _0 k: @" W/ ~
  16. 16.        /* 关闭全局中断 */( f' W: Z4 B+ r* F! N
  17. 17.        DISABLE_INT();   X* b' p/ x8 P2 b! N1 d3 U$ q
  18. 18.        ; w9 s3 R5 n; ^* R. J* Z1 q& ]
  19. 19.        /* 设置所有时钟到默认状态,使用HSI时钟 */4 G  _; K# y4 g6 @1 w. [3 s
  20. 20.        HAL_RCC_DeInit();* V" o9 T* a1 r5 P9 H( v
  21. 21.        ( V! F2 F7 s0 [, Z! i
  22. 22.        /* 关闭滴答定时器,复位到默认值 */1 E5 o* r# s1 v' _" o% d' ]; Y' {4 \7 e
  23. 23.        SysTick->CTRL = 0;! Q( e6 b4 |; P( a0 ^7 F3 g, V
  24. 24.        SysTick->LOAD = 0;# ]/ V0 \7 j4 K# H! q
  25. 25.        SysTick->VAL = 0;
    5 }( R: {1 t" t/ P
  26. 26.   
    ; ^, I- ^! c7 G5 a  ]+ M# Y
  27. 27.        /* 关闭所有中断,清除所有中断挂起标志 */
    1 b. o1 L5 g5 q' M5 U5 ]; ^0 ?
  28. 28.        for (i = 0; i < 8; i++)# z  I1 Z1 w" ]  m
  29. 29.        {  n* j3 ]( _$ l. _; r8 U  \
  30. 30.            NVIC->ICER<i>=</i>0xFFFFFFFF;
    * g" y7 E; p5 {+ F
  31. 31.            NVIC->ICPR=0xFFFFFFFF;
    0 D- r+ p9 I- Z" Z# T7 l: y
  32. 32.        }    + w- o+ x. H; p
  33. 33.    ' j& e5 K. o& x/ P. p8 x
  34. 34.        /* 使能全局中断 */) ]9 ]- Y3 }8 t, ]- I
  35. 35.        ENABLE_INT();
    ! A8 O( H) I; j, W5 W
  36. 36.    2 q! ]. ?: [7 D3 E8 B
  37. 37.        /* 跳转到应用程序,首地址是MSP,地址+4是复位中断服务程序地址 */+ L' H. l$ d% h; S8 C" h3 A
  38. 38.        AppJump = (void (*)(void)) (*((uint32_t *) (AppAddr + 4)));
    , \2 U, h+ g' i
  39. 39.      F" k7 Y7 {: e/ y
  40. 40.        /* 设置主堆栈指针 */: ]& h' \$ h: \; \$ S1 s1 n" K
  41. 41.        __set_MSP(*(uint32_t *)AppAddr);
    6 c6 v) o, {2 `4 w% u& D
  42. 42.        / G6 x2 R  m& G
  43. 43.        /* 在RTOS工程,这条语句很重要,设置为特权级模式,使用MSP指针 */
    7 T& s: @# K# x( i  ?
  44. 44.        __set_CONTROL(0);) f4 ]9 |- o! Y
  45. 45.   
    1 b. N1 I6 e2 X& l
  46. 46.        /* 跳转到系统BootLoader */
    . |1 w& c/ G$ }
  47. 47.        AppJump();
    ! S& D8 O! q# N. t- A0 ]
  48. 48.    * I* J& f5 v8 I" R. k. l7 q
  49. 49.        /* 跳转成功的话,不会执行到这里,用户可以在这里添加代码 */6 }9 z* I4 h# N/ y
  50. 50.        while (1); N3 F2 E! k/ E: x+ r3 a% _
  51. 51.        {
    ( }; }0 w; ]; C, e! I* A
  52. 52.   
    1 G% M  W) M6 D
  53. 53.        }
    ! K- t8 j% I9 ^9 h5 ^+ \
  54. 54.    }
复制代码
$ g: r3 t- Y6 W) d! X" U0 }' V
这里把程序设计中的几个关键地方做个说明:
$ ^0 K% [/ Z5 c' W! X+ d
' O  d3 }2 q9 ]  第12行,声明一个函数指针。2 X) Z# _* \! R( u
  第13行,QSPI Flash地址在0x90000000。
4 k" w  o8 U: S  第20行,此函数比较省事,可以方便的设置H7所有时钟到复位值,内部时钟使用HSI。
7 R# K/ y6 v) w- o, f7 S8 B: n  第23到25行,设置滴答定时器到复位值。" J" ?$ ^# I! S) e1 W
  第28到32行,清除所有中断挂起标志并关闭中断,这里是直接通过一个for循环设置了NVIC所有配置位,共8组。: t; ]+ D; }* m' s/ I$ N6 L
3 I* m4 o$ _% t4 f) C* O5 ]5 ?
bfe6b8c0ea19b535e2fb06c6618577f6.png
0 [. G6 f5 p; D# U
2 B8 w1 ~1 Q& M) y, b3 E: [
  第38行,将系统bootLoader的中断复位服务程序的入口地址赋给第12行声明的函数,用户执行这个函数时,就会直接跳转过去。, I; t1 f: }  D. Z% c+ _  |
  第41行,设置主堆栈指针位置,即QSPI Flash应用程序首地址存储的就是栈地址。2 S, x" J& v/ `( Z- [  W
  第44行,这个设置在RTOS应用程序中比较重要,因为基于Cortex-M内核的RTOS任务堆栈基本都是使用线程堆栈指针PSP。但系统bootLoader使用的是主堆栈指针MSP,所以务必要设置下,同时让M内核工作于特权级。此寄存器的作用如下:- M. }0 w  ~& J
0 i0 E( D- O3 k  {3 x/ y
b00b09a901596bcedb07c31790d8d3d9.png

3 a0 b( e3 b: l
  d2 M: K* d" I, `' J4 R' \  第47行,跳转到系统bootLoader。+ V& a) K4 Q% e  C
) v/ B0 [! k; N' ?% y
82.4 QSPI Flash的APP应用程序说明. y6 G: Y2 a3 ~. I
APP应用程序是由第53章配套例子:V7-033_LCD的汉字小字库和全字库制作 简单修改而来,主要修改如下两个地方:- W4 n" p- f# f& o

2 y6 D- ?2 R$ D9 H( p( R  @. A82.4.1 设置Flash地址
: t0 \+ U8 s7 d6 H设置Flash地址为QSPI Flash首地址0x90000000:$ B% p8 d& n7 x

8 P2 z% v9 T" {: s3 O! e
75afb2342189857e8fa086fc0af08462.png
4 c$ s9 ?; h% U7 y3 @7 y
$ H- h( u! V* v1 h6 O4 K
82.4.2 设置中断向量表. ~3 r( Z4 Y% c2 `+ i+ r
在main函数最开始就设置中断向量表到QSPI Flash首地址0x90000000,也可以按照本教程第28章的说明,将中断向量表设置到DTCM里面。4 Y/ D2 J# B) D) a2 l3 w6 J4 {

5 _( h- }  n+ }& S( G* p1 u
  1. int main(void)
    $ z' \$ A$ k2 a# B6 `$ W8 f, Z
  2. {
    9 X, R9 Q! Z% Q
  3.     uint16_t ucBright;           /* 背光亮度(0-255) */# R2 ^! F& j- x7 B% @6 q
  4.     uint8_t ucKeyCode;        /* 按键代码 */
    7 j  r8 q2 |0 v" `) y6 N
  5.     uint8_t ucStatus;        /* 主程序状态字 */
    ' \$ t( @' d$ u2 u) c- A3 x
  6.     uint8_t fRefresh;        /* 刷屏请求标志,1表示需要刷新 */
    $ [6 k1 p# V/ k4 T2 ~

  7. 9 i1 y6 ~* b$ \" R3 ~
  8.     SCB->VTOR = 0x90000000; /* 设置中断向量表地址 */0 O0 ?0 p+ W4 P
  9. 1 e: o, N' v! M0 o( A
  10.     bsp_Init();    /* 硬件初始化 */
    , |; K) ?' p# |0 u  P/ B
  11.     PrintfLogo();    /* 打印例程名称和版本等信息 */
    " q3 a6 j# h. J" \5 S& p6 z0 o; r
  12.     PrintfHelp();    /* 打印操作提示 */: {" ]/ Z! R2 |' D' a" N
  13. $ `. O$ N5 L3 C- g
  14. 省略未写
    $ G, e: A# F3 C" A. u% R0 ]

  15.   ]2 \1 c3 r6 u7 @  V& S
  16. }
复制代码
6 |; o1 Q, O6 T" l$ w3 Z( j& h
82.5 QSPI Flash的APP应用程序调试下载配置' h2 e' G- J/ y# t. i
将下面两个地方配置后,就可以像使用内部Flash一样使用QSPI Flash进行调试了。' l. l4 E6 v) A

  O( K! W- `9 f. M% V5 Q82.5.1 下载配置
5 z! d2 k4 l* i& u注意这里一定要够大,否则会提示算法文件无法加载:: G7 v3 ~9 ^5 U* X( f
( f: H& e, X- Z5 U+ @3 S
96d039e1657c72042027eb7e46ffc33a.png
5 F, I( v! H1 F: R9 ]
, L7 |; s( S6 z% Z; a
我们这里是将其加到DTCM中,即首地址为0x20000000,大家也可以存储到任意其它RAM地址,只要空间还够加载算法文件即可。推荐使用AXI SRAM(地址0x24000000),因为这块RAM空间足够大。
- h: v  l+ w  l7 _  u# K  Z; j& y" ]0 J# K# T' H: d
如果要下载程序到QSPI Flash里面,需要做如下配置:. ^) H4 h0 p6 p, ~% T1 X. J8 E
) p$ m0 P0 e) U7 F$ c, V: O+ O
5c95b0f51dbecf9eac259ddcf6b3da55.png
. L9 E( z0 w3 c  W, c) [/ i

4 h, H5 @9 `$ K( s( H2 b! J' T82.5.2 调试配置0 z+ F/ b& [" x' O# G3 j
注意这里一定要够大,否则会提示算法文件无法加载:* G7 _  l7 `: o. N. x1 U6 w' g2 a& ^- }
" {* o5 j6 o% b7 m
6b0758d3dd4db39b7189a03d59f0eca0.png

6 t2 E7 s+ _. Z: I& t
# B3 ~6 t/ z7 X2 i8 y我们这里是将其加到DTCM中,即首地址为0x20000000,大家也可以存储到任意其它RAM地址,只要空间还够加载算法文件即可。& y3 U# v7 k0 Y

' a; [" {" h2 \5 I, N5 |& e  V; a4 s如果要做调试下载,需要做如下配置:4 y, H  j5 f6 j, Q" }+ a& L" D

( V7 F. N$ R7 ?5 w  T# r
927401ada0fef49a78ac8029e372a755.png

+ d' m9 F& L7 B' c' ?2 G. S( p& {: B8 w2 I

) M( D* ^# ^2 [# C0 J; t5 v82.5.3 程序调试效果
8 u. ~6 L8 C/ Y& s* nAPP应用程序调试效果如下:
3 Y* a! k$ U! u' n
& v( Q( Z! D: Z' o5 P
681a23ba44bd11addce0fa9aae797dbd.png

5 N6 b7 }. l# y4 m% g
% K5 Z( B6 U2 r8 M' l/ o82.6 实验例程说明
2 u; z% |2 a4 V9 ?
本章配套了两个例子:
& J3 @8 r8 S/ N3 F3 x5 N, |% ~% \
  V7-062_QSPI Flash运行程序(Bootloader)。
7 E  a( |: q1 a7 S1 \  V7-063_QSPI Flash运行程序(用户APP)。
* ?) G! b- K6 e! z5 M2 X. X+ b: K, n, J6 W* |  C) h9 N/ c; Q* f

6 V) W: d. j5 ABootloader例子需要大家先下载到内部Flash里面,然后按照本章第5小节的说明配置后,就可以像使用内部Flash一样调试下载QSPI Flash了。
# v1 }" z5 e' {+ }+ ^6 t) U9 g$ D' F
82.7 总结2 _; s3 t" b2 n2 v
本章节就为大家讲解这么,为了熟练掌握,建议大家是操作练**。6 G% k3 V9 w* X* i+ o8 ^/ l9 o6 t
. y6 a3 I0 W+ y/ ?
" g; q4 M$ V8 M5 ~/ V5 h
$ C$ y' p: f0 B$ @7 m# g/ I$ h% D
收藏 评论0 发布时间:2021-12-21 23:21

举报

0个回答

所属标签

相似分享

官网相关资源

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