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

【经验分享】STM32H7的QSPI总线基础知识和HAL库API

[复制链接]
STMCU小助手 发布时间:2021-11-4 18:44
78.1 初学者重要提示
* `: W) [5 S9 U2 n' n  QSPI接口,可以做1线,2线或者4线使用。
6 h4 D# I3 P! ?  注意,QSPI接口不分主从,QSPI仅用于主控。
: g1 b2 l$ S4 x; s  可以单独使用BANK1外接一个Flash,也可以单独使用BANK2外接一个Flash,不可以BANK1和BANK2同时独立使用。但可以两个BANK合起来做双BANK(也称双Flash,即dual flash)使用,即8线模式。
$ V" p/ Q. Q' X  STM32H7可用的单线,双线,四线和八线SPI QSPI OctaFlash等涵盖各大厂商
& A+ r% `0 d& y( s78.2 QSPI总线基础知识5 G$ c% F* A  S
78.2.1 QSPI总线的硬件框图& }0 F: W6 |, w, |4 N& ]
认识一个外设,最好的方式就是看它的框图,方便我们快速的了解QSPI的基本功能,然后再看手册了解细节。
$ h% k# o' ?2 R9 o  W' u. d: G
- Z7 |0 B0 Q8 j( \4 h8 VBANK1外接Flash4 Z$ m( w% H4 f7 `% ^

" u& O% U* u5 Q+ A( n- _$ U
f04c8d70b5dfdaf87e9a1a4f54b38e55.png

7 p- J$ M0 W7 }4 e
( E: M. ^) `  Q! \$ o3 EBANK1和BANK2都外接Flash:! f9 n' y: F# b4 D5 f; H, f8 l
+ z# n" n: w" j7 t
60f4042c5098f3ba9a7e40219c023175.png
' V( S' g& G5 o& v1 s
; W$ r/ B1 m; n* F; |
通过这个框图,我们可以得到如下信息:
+ l6 \. d6 n* A
% ]! X3 |2 v- x0 m  quadspi_ker_ck时钟输入
# L5 Y; x* o5 Y: g3 a内核时钟。6 G# q6 ^1 g- a& {) i
5 J9 O! @9 l, m  _9 A$ X
  quadspi_hclk时钟输入3 y/ _" V  c  M" [1 f
为寄存器提供时钟。( R& ?5 a7 ]. L6 \1 d/ Y& ^1 c

% ?% X1 c: P1 b  quadspi_it输出信号
# V$ H+ r) I  S  T8 K  A* FQSPI全局中断。
2 p9 ~- k' M, r: X$ q: T
* a5 _% U8 T. F8 m: S& |- t0 w" a  quadspi_ft_trg输出信号* O4 ~) |" S. D2 K/ V8 i: ?
MDMA的QSPI FIFO阀值触发信号/ E5 C1 \( d4 c5 ^

! X3 f& d4 s  U1 b" q  quadspi_tc_trg输出信号  l" K" S! I$ r# u
MDMA的QSPI传输完成触发信号1 p$ a' r6 n# |9 H/ P+ R7 [

5 @1 H5 Z) T+ G4 G  CLK& _: `, N# F+ S2 S) H) c
为外接Flash提供的时钟。为外接的两块Flash同时提供时钟。0 H" ]5 k  _; p& Z

# p" }7 d- l) g7 Q* I5 y+ i& {( g  BK1_IO0/SO  H! d1 O! Y0 r
在2线或者4线模式中作为双向IO,1线模式作为单向输出,供Flash1使用。- E3 C8 [. ~/ y' d
4 ]8 }1 P- S4 L' x1 b1 b/ f
  BK1_IO1/SI, h5 _$ Q  h6 [0 D7 w4 ^7 S" [& M
在2线或者4线模式中作为双向IO,1线模式作为单向输入,供Flash1使用。  b) Q9 \2 C5 [% y1 @- o' `. k
) ?/ l! A5 P' Y0 P
  BK1_IO2
) v+ `( m! u; x2 t在4线模式中作为双向IO,供Flash1使用。' R# w- x8 W/ e0 C2 J, |7 S
7 W8 X: {' k/ Q. \: N
  BK1_IO3' Q0 y3 k; h. }
在4线模式中作为双向IO,供Flash1使用。
. H' U  S* g/ g; h% r" Z; V0 B6 @2 B6 a! E* M
  BK12_IO0/SO
2 B4 \! R6 z4 B% b9 F在2线或者4线模式中作为双向IO,1线模式作为单向输出,供Flash2使用。% G1 x2 ?0 Z, x" L/ {# P! F
& A7 _' v6 D1 l+ I+ u9 c0 [% h
  BK2_IO1/SI
! n  U( q8 ]2 [3 L% q) n在2线或者4线模式中作为双向IO,1线模式作为单向输入,供Flash2使用。% v0 \7 T$ w  \' {" U

9 H3 W7 N: o6 e0 d  BK2_IO28 g2 r9 _) S2 L3 U
在4线模式中作为双向IO,供Flash2使用。- t$ q$ f/ S" L' b$ X3 [: s0 V
0 l0 C# B# k( f' ~# ]( K& W4 t2 Y; l
  BK2_IO3
# t5 o: t* L- I+ {在4线模式中作为双向IO,供Flash2使用。9 P+ r% A% I; h
# x: P0 u# M, y8 q! i+ t9 U
  BK1_nCS
( g% h; o; M- k片选信号,低电平有效,供Flash1使用。如果工作在双bank模式下,也可用于Flash2。; H9 C. L- V8 \" o8 e8 |# o& T+ I6 h& G
' T- A( Z0 |! D
  BK2_nCS5 u' W5 S. u& M/ l; N1 }5 S7 {) s
片选信号,低电平有效,供Flash1使用。如果工作在双bank模式下,也可用于Flash1。
' u- ~! P% L9 v$ Z' |1 K- Q
2 C8 @6 r9 }' M) r& w" A78.2.2 QSPI的时钟源% F+ O+ V  ?8 w  j- A
这个知识点在初学的时候容易忽视,所以我们这里整理下。
4 [  O9 F8 h! J/ g# ^1 u3 }3 i# e
3 s) U+ Q  f0 K3 `! n1 e7 Q. lSTM32H7主频在400MHz下,QSPI的最高时钟是200MHz,可以选择的时钟源如下:% C# B2 `2 `$ t& I4 E8 w, M+ }

8 [- r2 M7 U6 H
60a21420cdf6bbfc171b77ef44ebcf28.png
3 F8 Q1 K8 L1 s5 W, P& t. @
7 Y8 c- }) B; O* h3 z7 ?( V: K
12523b301f01c6108162699ca2ad5685.png
  j3 J' q( r$ ~6 B9 ^9 k" B
2 S- a  V! ~" x2 }8 ^5 v
9 x- @% X3 s( l
我们的程序中默认是采用的HCLK3作为QSPI时钟。! `/ q) r+ a) Q4 }  U7 A

1 n6 s( Z8 E! |/ a$ s. Z78.2.3 QSPI 命令序列
# e- n+ s7 P; a* u: H$ Q: rQSPI的命令序列主要包括以下几个阶段:指令阶段、地址阶段、交替字节阶段、空指令阶段和数据这五个阶段,任一阶段均可跳过,但至少要包含指令、地址、交替字节或数据阶段之一。- q: ?4 N5 q0 K+ c( l

& f6 Q5 x+ H! G6 W6 `, G
2cb087bbc794898408c6160acfd426e4.png
2 m0 _! r$ s4 N) V3 \
$ c8 k* m1 k; Z6 {2 N- u" ^+ @: |
  指令阶段; r# @, W2 j! L" P$ f9 ~  H% i
在此阶段,将命令(8位指令)发送到Flash,允许发送任何值。用户可以简单地将所需的命令写在指令字段中。根据软件和硬件配置,可以1线,2线或者4线方式发送。在某些只发送地址的案例中,指令阶段可以跳过。
0 Z  q$ U! O; J$ ?+ K8 ~
/ P0 t' L2 P1 Y 地址阶段
1 m' @0 M4 F% \8 K在此阶段,将地址发送到Flash,从指定的地址读取或写入数据。 地址阶段是完全可配置的,允许发送1、2、3或4个字节的地址。在间接模式和自动轮询模式下,用户可以简单地将所需的地址写入QUADSPI_AR寄存器。据软件和硬件配置,可以1线,2线或者4线方式方式发送。 在一些不需要地址的情况下,可以跳过地址阶段。
- |  {, w" s! l) [/ w( \
8 g3 m% l' ^) U: V4 ?+ T  交替字节阶段
; B% D  Z: [1 h5 j/ Y( p% h* `' c- h  aQSPI接口支持的一个额外阶段,具有更大的灵活性。它是通常用于控制操作模式。交替字节阶段是完全可配置的,并允许发送一,二,三或四字节。
0 a; x9 B4 d" p+ _; f
. w! P4 o' a& x/ B: @2 X. c  空周期阶段
8 V) s, ]5 W9 H: n+ J, q, ?在高速时钟下运行时,此阶段可以确保有足够的“周转”时间从输出模式切换到输入模式。
% w5 ^: J+ j4 \3 F# p5 K6 I4 Q& N' U3 P9 ]* R/ F+ E' A
  数据阶段
, ^2 d* o* s: o9 r这个阶段实现数据的收发。9 W/ u( z& N" p1 _
: i$ u! `) ]5 `
78.2.4 QSPI的1线,2线,4线,SDR和DDR模式# r6 S) A. K/ j5 c& X1 f
这里所说的线是指通信阶段使用的数据线个数。9 c1 l' X/ R) H
4 ?: p2 f9 @( m7 E% q
213a38369fe04824fa8640f515beb2fc.png

3 x: Y/ ~+ I  k4 l% z" w/ k2 o0 g2 a. M6 S% q) K! G- H
1线(SingleSPI,虽然是一发一收,但属于1线方式)  U; H! Q9 E( @; {, U
发送用的数据线BK1_IO0/SO(BK2_IO0/SO),接收用的数据线BK1_IO1/SI(BK2_IO1/SI): @( g. r- o! c, ^3 k8 Y

) Q" r; f" s! t) s& C1线模式下,所有线处于的状态:  W4 _7 C: H8 v. w8 r/ N! F
) a7 o# o: h; u" k/ m7 p" X
(1)  BK1_IO0 / SO(BK2_IO0 / SO)处于输出模式。
. g8 A6 G' `! v' r! x" B0 w
( C* R. }8 @( k. E; X (2) BK1_IO1 / SI(BK2_IO1 / SI)处于输入模式(高阻抗)。
( y. P) U( i9 r* G! F
9 _  ?1 o7 K# W9 p3 i (3) BK1_IO2(BK2_IO2)处于输出模式并强制置0。
# ?  J8 g3 ^9 ^/ B8 n1 T% p4 Q5 G! O
(4)  BK1_IO3(BK2_IO3)处于输出模式并强制置1。
; ]( H5 P' p1 E8 ^& M
$ C. T5 u& @% A3 X& e
7c6105bc6d18539b680aeeed7ec93aed.png

% V, C2 p8 ~$ V: e: r( w
9 x5 X2 m8 u3 j  2线(Dual-SPI)0 w: I2 E9 W3 B6 K
同时使用BK1_IO0(BK2_IO0),BK1_IO1(BK2_IO1)做输入输出。- m, v( G9 V% y) D' g1 g3 a
3 X8 Y( L1 {* w( R; e1 G  g
2线模式下,所有线处于的状态:) Y% J1 ~& N' i6 i/ G0 ?

& w+ A6 U! g( k& g; g1 T5 l% Z' t (1) BK1_IO0 (BK2_IO0 )和BK1_IO1(BK2_IO1)读取时处于输入(高阻)。其它情况下为输出。) \) {) Y6 Q9 {5 }7 J$ T
) y4 f; ~) C& B
(2) BK1_IO2(BK2_IO2)处于输出模式并强制置0。
9 [6 \" G9 N( w6 \8 C6 D& c5 O- l8 L2 |( `5 w
(3) BK1_IO3(BK2_IO3)处于输出模式并强制置1
2 r8 i& h5 D6 |6 V7 r  s- i: p2 @' ~3 T/ s3 e2 \! z
* y' H! R0 e  l0 w

$ Z1 i; b. z6 E. u% m/ N+ l4线(Quad-SPI)+ a* K0 B- Z& Q: X) i( H
同时使用BK1_IO0(BK2_IO0),BK1_IO1(BK2_IO1),BK1_IO2(BK2_IO2),BK1_IO3(BK2_IO3)做输入输出。
2 v( B; }8 L+ O/ {  R) J# S6 ]" _4 g) g0 k- |' P/ X! ?
4线模式下,当读取数据时,所有线处于输入(高阻),其它情况作为输出。
1 L. I0 C! F1 I: ]
0 t1 i; J/ o5 n1 J
9d022cbcfd5fb3f3950421c3312e505f.png
5 F# g/ v6 h( N6 v
, q1 v$ o9 M6 M1 w
  SDR
1 a! m, }4 M7 u/ V9 T  H9 l在 SDR 模式下,当QSPI驱动BK1_IO0(BK2_IO0),BK1_IO1(BK2_IO1),BK1_IO2(BK2_IO2),BK1_IO3(BK2_IO3)信号时,这些信号仅在 CLK的下降沿发生转变。: `. D$ ]$ t- d7 Z
( R/ q' X4 J) F4 ~. q" X
  DDR& C  F% V: p( c6 A& q- F
在 SDR 模式下,当QSPI驱动BK1_IO0(BK2_IO0),BK1_IO1(BK2_IO1),BK1_IO2(BK2_IO2),BK1_IO3(BK2_IO3)信号时,这些信号在CLK的上升沿和下降沿发生转变。
: L: P' t2 G9 c* M) E: f( V4 M6 N* C
  双BANK(双Flash)
2 Q6 {- L0 B1 r/ ^$ B% }双闪存就是将QSPI的两个BANK分别接一个QSPI Flash,然后时钟公用,片选公用(也可以不公用),从而实现8线模式。
% P' q# U- u$ x
/ E* J% b% [, d0 D3 T
d28d743492529e4d88e9b64567fe52b4.png

0 [* v. w' `  z, L/ F) A
( f9 f4 W; x0 O; o( K0 Y78.2.5 QSPI间接模式,查询模式和内存映射
4 K( l& `; y- `QSPI支持在以下三种模式下工作:
) e* t3 {- m0 v6 Y% N/ ]3 v. X. d5 V7 h: P2 k8 R8 S
1、  间接模式:
4 d' z; y. |0 e- S  ?$ @/ F2 M
) c: \% p, r/ s1 E& ?& H9 i这里所谓的间接模式是指寄存器方式访问外设,就跟我们操作串口外设一样。间接模式主要用于以下场合:" h8 l6 n! P; e
$ X" s( a& p( L, b2 h; G: d5 ?
  用于读取,写入,擦除和配置QSPI Flash。
2 Y" }  B+ T( K3 q3 A" j& b  如果不需要AHB总线访问 QSPI Flash(在内存映射模式用)。1 D% z9 v+ [! E, p  J7 [) ?
  CPU或者DMA通过QSPI数据寄存器执行所有操作。
+ {5 k3 F0 m1 y  o0 u- A9 q+ H" b0 R5 f- d  U/ C; \; G
! b* y% l2 t  G3 l: ]0 @: e
在间接模式下,所有操作均通过QSPI寄存器执行,含读取和写入操作都由软件管理。 QSPI接口类似于经典的SPI接口。传输的数据通过数据寄存器与FIFO。在在此模式下,可以从大容量的外部Flash读取数据或向外部Flash写入数据,可以支持到4GB容量。
, `# s* a1 l8 X% Z% E  s) X" {) U/ d& r+ o, Q
如果进行擦除或编程操作,则必须使用间接模式,并且所有操作必须由软件处理。在这种情况下,建议使用状态轮询模式,然后轮询闪存内部的状态寄存器以了解何时编程或擦除操作完成。2 M. b$ h" n& h) R" B% k2 [" M
7 n6 ?+ B, \$ l: Y8 \
9 [. {! K" X% Y  H6 \
  Y* v% X7 \% m: J" G9 I
2、  状态轮询模式9 o( T8 V7 Y) z. f" J. g
& G/ r7 ?% p& l. J6 z9 {% F1 |
在以下情况下使用状态轮询模式:
# x' {) e" E; c# A) f
9 \2 y1 B4 U3 I; ?8 X  读取QSPI Flash状态寄存器。) C9 b; X: M0 l+ j, A, l
  在操作结束时自动轮询状态寄存器。
) T/ ]5 R( \0 G可以自动轮询内存中的指定寄存器并减轻CPU负担,例如检查擦除操作何时完成。QSPI也支持定期查询QSPI Flash,并且可以屏蔽返回的数据位,将所选位与所需值进行比较,结果比较可以通过下面两种方式处理:; A+ [# O) W) W. J' z/ j" L4 t

4 ~+ @0 s! J' }  l( \* Q  AND与操作模式:如果所有选定位都匹配,则产生中断。  j4 V) u6 C7 h/ B
OR或操作模式:如果所选位之一匹配,则产生中断0 T; b  H; D; i& s1 C' a

  K3 x5 r$ `% {" ?$ Z, [+ C, |# l" K, {- y5 I
发生匹配时,QSPI可以自动停止。3 o2 a4 o# R' c, S% ~
& m, e; }9 Q# S" D$ n4 o

; C8 V' h6 u/ L, G0 [
* \! S! n5 D) Y8 s4 C# F2 G3、  内存映射模式
$ O5 M, G$ m6 P, x
+ x1 v, Z; A  e' \$ ~* R在以下情况下使用内存映射模式:7 F1 u% g1 r2 ]* K: M- @6 A' V+ a- A! ]

( r) R, n+ Y) M# h1 L  用于阅读操作。
6 W: P+ a5 _4 @. u# D% i  像使用内部Flash一样使用外部QSPI Flash, 任何AHB总线主控都可以自主读取数据。
( ?9 u5 n& W. Z* q9 z8 k! G! \, K  用于从外部QSPI Flash执行代码。! ^* b. p  b7 `& r* A. b* O" a! v
- t( E! [. S7 h" N

4 z% a0 b  G# k" V5 c: w& ^- m/ @QSPI接口能够管理多达256 MB的内存,在内存映射模式下地址范围是0x9000 0000到0x9FFF FFFF。
# ]$ v, C( \7 Z- ?2 S
5 t" a$ d; C1 x" V1 `9 N78.3 QSPI总线的HAL库用法
$ v, v# i. m4 X, t  r/ \4 d78.3.1 QSPI总线结构体QUADSPI_TypeDef
5 ~& J. L- x. CQSPI总线相关的寄存器是通过HAL库中的结构体QUADSPI_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:
5 k1 h; o7 x1 B6 r5 Z- u8 O3 J3 b# Z( s( l
  1. typedef struct
    ( S+ H  C2 R( w- e* Y
  2. {
    . o8 ^- l3 x; l' f
  3.   __IO uint32_t CR;       /*!< QUADSPI Control register,                           Address offset: 0x00 */
    $ J. M) D" z" u5 f, N5 Z
  4.   __IO uint32_t DCR;      /*!< QUADSPI Device Configuration register,              Address offset: 0x04 */
    ) i4 R6 U/ F/ e5 z
  5.   __IO uint32_t SR;       /*!< QUADSPI Status register,                            Address offset: 0x08 */
    ! K+ {9 h8 [% [; I% b
  6.   __IO uint32_t FCR;      /*!< QUADSPI Flag Clear register,                        Address offset: 0x0C */
    : U  [; o$ N' A  R
  7.   __IO uint32_t DLR;      /*!< QUADSPI Data Length register,                       Address offset: 0x10 */
    , m, C5 _1 n1 F4 F5 h
  8.   __IO uint32_t CCR;      /*!< QUADSPI Communication Configuration register,       Address offset: 0x14 */) G9 Z9 {. R" W( y9 C. Y
  9.   __IO uint32_t AR;       /*!< QUADSPI Address register,                           Address offset: 0x18 */
    * h$ e/ J' e% H0 \5 T' S
  10.   __IO uint32_t ABR;      /*!< QUADSPI Alternate Bytes register,                   Address offset: 0x1C */
    8 s4 U2 `* c- W" o, B9 D
  11.   __IO uint32_t DR;       /*!< QUADSPI Data register,                              Address offset: 0x20 */; ?7 y6 t' Z0 u) P. u% M& I
  12.   __IO uint32_t PSMKR;    /*!< QUADSPI Polling Status Mask register,               Address offset: 0x24 */' A- v8 ~  V6 K4 S$ U5 r& \
  13.   __IO uint32_t PSMAR;    /*!< QUADSPI Polling Status Match register,              Address offset: 0x28 */1 p- J5 A  `/ S( c, b
  14.   __IO uint32_t PIR;      /*!< QUADSPI Polling Interval register,                  Address offset: 0x2C */
    4 G! @2 ~8 ]3 a/ m& r& [9 W' [
  15.   __IO uint32_t LPTR;     /*!< QUADSPI Low Power Timeout register,                 Address offset: 0x30 */4 C' T+ s6 T8 D
  16. } QUADSPI_TypeDef;
复制代码
3 t0 B1 E& j8 B1 }) k
这个结构体的成员名称和排列次序和CPU的寄存器是一 一对应的。
' }6 }) d9 [0 n" S9 l, p8 x2 _
: n) ^2 c( d5 B__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:
$ K6 J5 G7 z* ^. y+ c8 t  m
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */
    8 g, J4 L3 T& N: \6 F) a
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码
) `) o' _! m- G/ Q" h
下面我们看下QSPI的定义,在stm32h743xx.h文件。
8 b* b# e/ `$ d" c) s) n' f4 P6 b
7 T1 f# v/ x2 ?
  1. #define QSPI_BASE ((uint32_t)0x90000000) /*!< Base address of : QSPI memories  accessible over AXI */
    & K. M( g0 j8 R, w/ h

  2. : R* p6 o& a( S2 I2 v4 J0 d
  3. #define PERIPH_BASE           (0x40000000UL) ( R5 \$ H' ~3 U/ F" h9 Y# ]
  4. #define D1_AHB1PERIPH_BASE    (PERIPH_BASE + 0x12000000)
    " A6 i+ j4 k4 ~7 v9 {) V- v

  5. 4 C2 @, {3 \) M; j/ u
  6. #define QSPI_R_BASE           (D1_AHB1PERIPH_BASE + 0x5000)
    ! _; l  ]( U; P6 D  o4 J6 \7 p
  7. #define DLYB_QSPI_BASE        (D1_AHB1PERIPH_BASE + 0x6000)
    1 L0 Q% R$ E" S$ W: l- t1 |" C

  8. + C4 L8 U! X! o
  9. #define QUADSPI               ((QUADSPI_TypeDef *) QSPI_R_BASE) <----- 展开这个宏,(FLASH_TypeDef *)0x52005000- [' b! f! U) C: K
  10. #define DLYB_QUADSPI          ((DLYB_TypeDef *) DLYB_QSPI_BASE)
复制代码
( u# E* a( ]; J  ~' \/ d9 V
我们访问QSPI的CR寄存器可以采用这种形式:QUADSPI->CR= 0。$ S- c, u& L0 U1 F* ?* F" G1 O

2 c1 \( N  R/ w78.3.2 QSPI总线初始化结构体QSPI_InitTypeDef
7 _2 ?/ c" U# K下面是QSPI总线的初始化结构体:4 {  |7 |& \+ k+ @- g, G

! U' F' J- X( w0 v
  1. typedef struct/ \2 S2 h6 a" |1 d' D+ a1 \
  2. {% X9 h4 v( U: R" D# ^
  3.   uint32_t ClockPrescaler;     
    ! r# F0 b. k* t& i3 I: f* f  w) |
  4.   uint32_t FifoThreshold;      7 y5 D5 V% O6 x% ^1 o7 t/ o( m/ u
  5.   uint32_t SampleShifting;   
    8 r, |% x3 @6 O0 r( t* r
  6.   uint32_t FlashSize;         
    . c7 S/ i1 ^; Y- Z
  7.   uint32_t ChipSelectHighTime;
    1 C4 ]+ x% _$ W2 W% g7 ]
  8.   uint32_t ClockMode;         
    . r% H1 {" v, z) m- U1 F8 g
  9.   uint32_t FlashID;           
    8 \& ]5 }3 o+ B& {; b6 ?3 Q" B2 m
  10.   uint32_t DualFlash;                                           # r0 \1 p) I* z
  11. }QSPI_InitTypeDef;
复制代码
9 I) N7 t# O% K' U- _6 X+ J: _6 N8 Q
下面将结构体成员逐一做个说明:8 |, ^) N4 D6 ~; j
2 @1 h3 |7 x' M: E/ I, G$ Q5 ^3 y
  ClockPrescaler
8 ^3 E- q3 u. X" r" {" w( X: P4 f设置时钟分频,参数范围0到255。特别注意,这里是针对HCLK3作为QSPI时钟来说的。
; r% j( H3 F0 v7 x0 z* `6 I
! r9 H  S$ E/ q' ~2 y8 S# T  FifoThreshold
7 I, B/ o# d  ?  i. z" h: y用于设置FIFO阀值,仅用于间接模式,参数范围1到32,单位字节。
/ k: b: ^8 i8 W+ z3 @( E0 T1 }, v- O6 X) a
  SampleShifting: J9 H$ X  B: y) t: w) Y0 O
QUADSPI在FLASH驱动信号后可以选择再过半个CLK周期后才对FLASH数据采样,这有利于推迟数据采样。支持的参数如下:
. H& G9 B, P4 ]& o" f5 ^* f" n* F+ X2 ?
#define QSPI_SAMPLE_SHIFTING_NONE      ((uint32_t)0x00000000U)      
2 U  m- X; i8 K% I#define QSPI_SAMPLE_SHIFTING_HALFCYCLE ((uint32_t)QUADSPI_CR_SSHIFT); L$ I( M) @$ z0 S5 N# K1 J
  FlashSize
$ b& u& y$ U6 ]2 ?Flash大小是2^(FlashSize + 1),单位字节。
: D/ ]6 h8 E2 k. X, v) T7 @0 \% h& g2 i/ t  B/ z: e( T
间接模式下,最大支持的Flash大小是4GB,内存映射模式,最大支持256MB。. Q  B( j# k+ {1 s

, T% c1 ?7 b* ^$ S- ~' [8 i
  1. #define SPI_POLARITY_LOW       (0x00000000UL)$ ]2 j8 B: }& n8 S- ]
  2. #define SPI_POLARITY_HIGH      SPI_CFG2_CPOL
复制代码

% d7 M# X1 R; e5 F) H  ChipSelectHighTime
1 B, |' W- s+ _+ h' A) n) R命令之间的CS片选至少保持的高电平时钟周期ChipSelectHighTime+1。支持的参数如下:6 B9 q* j9 I4 w+ K& ~

0 S# ^/ z$ W5 g- j# i! R# \7 L
  1. #define QSPI_CS_HIGH_TIME_1_CYCLE      ((uint32_t)0x00000000U)                             
    ! T/ R" h5 D) D$ i4 i
  2. #define QSPI_CS_HIGH_TIME_2_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_0)                     
    / x! c7 [5 {/ f5 m8 b8 _
  3. #define QSPI_CS_HIGH_TIME_3_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_1)                      % b$ e6 Z1 B+ A) w' T  t8 g6 h. i
  4. #define QSPI_CS_HIGH_TIME_4_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_0 | QUADSPI_DCR_CSHT_1)   Q6 w* i# P# L! u1 b& A8 O4 ~
  5. #define QSPI_CS_HIGH_TIME_5_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_2)                     & s) S- J2 Z3 [# h0 K) ?, l
  6. #define QSPI_CS_HIGH_TIME_6_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_2 | QUADSPI_DCR_CSHT_0)
    1 Q' a) t6 T  b& Q2 N8 s
  7. #define QSPI_CS_HIGH_TIME_7_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT_2 | QUADSPI_DCR_CSHT_1)
    & z3 n& x5 w2 v% ^. L; h! v
  8. #define QSPI_CS_HIGH_TIME_8_CYCLE      ((uint32_t)QUADSPI_DCR_CSHT)   
复制代码
                6 q9 u/ {4 V& F, ~8 m3 F3 Q
  FlashID
' w5 f: ?: U4 g$ a, `( |, z& X) C用于选择要操作的BANK,即用BANK1还是BANK2操作Flash。0 d- J. D; r6 W0 e

  U- @' W. c" J! \
  1. #define QSPI_FLASH_ID_1                ((uint32_t)0x00000000)      , }' H+ z& Q: J& j5 ^
  2. #define QSPI_FLASH_ID_2                ((uint32_t)QUADSPI_CR_FSEL)
复制代码

* S/ k, l# q6 n  DualFlash
" M# X& \5 H: I用于选择是否使用双BANK。4 N  j2 M- A2 ^/ n$ h# v, |* j
, [7 k! g4 D8 n1 M
  1. #define QSPI_DUALFLASH_ENABLE          ((uint32_t)QUADSPI_CR_DFM) /*!<Dual-flash mode enabled*/
    0 [" G- t" ?$ P9 {
  2. #define QSPI_DUALFLASH_DISABLE         ((uint32_t)0x00000000)     /*!<Dual-flash mode disabled*/
复制代码

' b' }2 S+ L  I1 f) W78.3.3 QSPI总线句柄结构体QSPI_HandleTypeDef
/ A7 S: V! s# Q+ n下面是QSPI总线的初始化结构体:8 o9 K' z3 D6 _5 f* s3 I
( Z6 v3 d" x! h0 K! o5 y
  1. typedef struct
      l, t, x; a' [( b( C
  2. {
    ; E% R- {9 T6 T' @) g& v
  3.   QUADSPI_TypeDef            *Instance;        /* QSPI registers base address        */
    * _6 F1 o& E$ V! I% S- H( k; V
  4.   QSPI_InitTypeDef           Init;             /* QSPI communication parameters      */  n2 X3 s+ w, h
  5.   uint8_t                    *pTxBuffPtr;      /* Pointer to QSPI Tx transfer Buffer */
    3 M+ j: V' g- T! E+ P: V
  6.   __IO uint32_t              TxXferSize;       /* QSPI Tx Transfer size              */
    - Z+ C1 d) Z# B! {! F3 S
  7.   __IO uint32_t              TxXferCount;      /* QSPI Tx Transfer Counter           */) Q* r$ Z' p. \) x+ `
  8.   uint8_t                    *pRxBuffPtr;      /* Pointer to QSPI Rx transfer Buffer */
    / N) r: f3 Q% \, r) h8 B5 x
  9.   __IO uint32_t              RxXferSize;       /* QSPI Rx Transfer size              */2 U) ~- e% ]/ f" i" g: q* ?" A$ Y
  10.   __IO uint32_t              RxXferCount;      /* QSPI Rx Transfer Counter           *// @8 R' z7 `" \
  11.   MDMA_HandleTypeDef         *hmdma;           /* QSPI Rx/Tx MDMA Handle parameters  */
    - `' ~$ p+ t" G' j: J/ a, z
  12.   __IO HAL_LockTypeDef       Lock;             /* Locking object                     */& F+ \1 y4 i7 j! d5 V
  13.   __IO HAL_QSPI_StateTypeDef State;            /* QSPI communication state           */& I- ]3 [. `. w, O% i
  14.   __IO uint32_t              ErrorCode;        /* QSPI Error code                    */: U! r; h# c) O
  15.   uint32_t                   Timeout;          /* Timeout for the QSPI memory access */
    : T7 n, j& y0 T. ]- [( L% Z# Q  [
  16. }QSPI_HandleTypeDef;
复制代码
, K1 `1 K0 \* `$ n% c5 L
下面将结构体成员做个说明:+ n& ^8 y0 x4 |' @5 j
1 C; Y' s6 j0 n$ K/ W1 ^" D
  QUADSPI_TypeDef   *Instance
: u  }- u& e1 u1 ]6 r$ j这个参数是寄存器的例化,方便操作寄存器,比如使能QUADSPI。% Y& l1 i' f( U4 ^" m% k' M7 R

  B& Q+ c! g* y! P, @1 uSET_BIT(QUADSPI ->CR,  QUADSPI_CR_EN)。! x, y# {- U6 C4 Y, K

& a! i0 r% B' S  QSPI_InitTypeDef  Init
* |, v+ `  Q9 @  E这个参数是用户接触最多的,在本章节3.2小节已经进行了详细说明。
7 b) s: Z' c9 k! o1 {, {& r0 h) Z0 h9 A% I1 ]- i
  MDMA_HandleTypeDef          *hmdma
. ?/ |9 C& ]0 c' Q; D$ d' I用于QSPI句柄关联MDMA句柄,方便操作调用。5 y2 @7 T' g" Z; r( _6 x
+ B" ]6 w$ ?! [* C: {
  其它参数
; ~) W8 h( \" z9 A; z) _6 e其它参数基本都是在函数内部调用,用户基本不用管。
1 m, Z9 C3 |6 K' P7 E' Y" |1 J! X9 F( o4 r' X' g
78.3.4 QSPI命令结构体QSPI_CommandTypeDef: u  G1 \9 ]% k* ~
下面是QSPI总线的命名结构体:: o2 o% Z7 ~6 B) @$ R& Z, i
4 L# L/ H1 ^$ N( N2 u% q
  1. typedef struct
    : d. q3 q/ G' F- o  u: l
  2. {
    % ?* Y. U* m6 c# x0 W3 i% i
  3.   uint32_t Instruction;        3 S+ E# s, J0 p2 l& p1 H: u/ C2 C
  4.   uint32_t Address;           $ M& E0 s+ i- M- E8 I: x2 h
  5.   uint32_t AlternateBytes;     
    & }+ N; s5 M; x3 p  Q6 T) u8 d  D
  6.   uint32_t AddressSize;      
    ! e/ l5 \0 O6 E6 h6 g
  7.   uint32_t AlternateBytesSize; / T* |6 |4 n, {
  8.   uint32_t DummyCycles;      / D6 m7 L$ Q' S/ T# o3 V9 y
  9.   uint32_t InstructionMode;  " f* b0 B" a; I3 A5 v. M0 K
  10.   uint32_t AddressMode;       + u( y0 }# T% t) |+ U1 C
  11.   uint32_t AlternateByteMode;
    " F* Z. u  L  j( L0 O8 w9 N0 K
  12.   uint32_t DataMode;         - ^" d; Y! o7 N9 @
  13.   uint32_t NbData;          % s# f% A  W, A
  14.   uint32_t DdrMode;           ( |' U6 v( i* e; R
  15.   uint32_t DdrHoldHalfCycle;  
    ! V+ }, e% o( I1 I( {! R
  16.   uint32_t SIOOMode;         * \5 A% m; M  p+ \7 o# [
  17. }QSPI_CommandTypeDef;
复制代码

% }" G4 B* _9 q下面将结构体成员逐一做个说明:+ B: x5 e3 |9 }. n: G
# l7 Z- q9 |6 U- @- p3 I, ~' {  @
  Instruction
- q/ H# z' f- x( F( e$ K设置要发送的指令,参数范围0x00到0xFF。( d' u7 r. s6 m& ?3 d) A% _2 X( U
" H! ~  u! T% Z- D; f* M
  Address
7 N/ ]3 {' L. N- V# `7 A" }2 k& f设置要发送的地址,地址由是1个字节到4个字节来表示,参数范围0x0 到 0xFFFFFFFF。
" t- N  h3 Y! e: f5 ]' y/ _
2 C# N4 F# K% C  m/ a( g  AddressSize
4 `1 J; n) V3 [, k$ n+ _地址大小,即表示此地址需要的字节数,支持的参数如下:( r$ v! b  y$ n- h/ e7 b
. u$ E% j* |' z% n  b* c
  1. #define QSPI_ADDRESS_8_BITS            ((uint32_t)0x00000000)           /*!<8-bit address*/
    0 s: U& D, @- {' f" k! }5 D
  2. #define QSPI_ADDRESS_16_BITS           ((uint32_t)QUADSPI_CCR_ADSIZE_0) /*!<16-bit address*/
    / K' y% {+ y  f4 ~8 _$ O6 Y
  3. #define QSPI_ADDRESS_24_BITS           ((uint32_t)QUADSPI_CCR_ADSIZE_1) /*!<24-bit address*/. l  V  B8 I# f) k' K3 a4 G( d  u
  4. #define QSPI_ADDRESS_32_BITS           ((uint32_t)QUADSPI_CCR_ADSIZE)   /*!<32-bit address*/
复制代码

' s/ A4 Y/ F5 E2 I: P: K  AlternateBytesSize
4 H) ?9 a5 {- V* X; X6 K交替字节大小,支持的参数如下:) Q. K5 z' N. y2 j  A) ]
) R# ^( t, R: b7 G! i2 q2 r
  1. #define QSPI_ALTERNATE_BYTES_8_BITS    ((uint32_t)0x00000000)           /*!<8-bit alternate bytes*/2 t" k7 d8 f- x, z( A3 r9 `" G
  2. #define QSPI_ALTERNATE_BYTES_16_BITS   ((uint32_t)QUADSPI_CCR_ABSIZE_0) /*!<16-bit alternate bytes*/! ]0 I( O$ |0 A( ~( {
  3. #define QSPI_ALTERNATE_BYTES_24_BITS   ((uint32_t)QUADSPI_CCR_ABSIZE_1) /*!<24-bit alternate bytes*/
    0 |, _, _, O1 s
  4. #define QSPI_ALTERNATE_BYTES_32_BITS   ((uint32_t)QUADSPI_CCR_ABSIZE)   /*!<32-bit alternate bytes*/
复制代码
1 U/ c$ y" @2 F4 p
  DummyCycles$ j% j3 M+ ?7 T
执行空周期个数,参数范围0到31:
; k) F. l9 W& k1 a
0 @( K: W& Q( s' l7 I' d* S$ O1 K  InstructionMode
1 ]" V% i3 @% @- j指令阶段需要几线模式:; p  x3 n" r7 E0 Q" V3 \) s

. _0 B: V4 H8 ]9 K2 w
  1. #define QSPI_INSTRUCTION_NONE          ((uint32_t)0x00000000)          /*!<No instruction*/$ ~7 t2 b4 g+ I4 \3 f/ U
  2. #define QSPI_INSTRUCTION_1_LINE        ((uint32_t)QUADSPI_CCR_IMODE_0) /*!<Instruction on a single line*/
    ) q" z, a1 ~7 ~  e' o2 ~+ i
  3. #define QSPI_INSTRUCTION_2_LINES       ((uint32_t)QUADSPI_CCR_IMODE_1) /*!<Instruction on two lines*/
    6 ?: ?( j7 C/ @! m& T' e; l. {' R
  4. #define QSPI_INSTRUCTION_4_LINES       ((uint32_t)QUADSPI_CCR_IMODE)   /*!<Instruction on four lines*/
复制代码
" q: m  S0 _# E0 m2 |/ @0 S/ }
  AddressMode
0 q# E  ]6 K( M" m: Y. P" M/ a地址阶段需要几线模式:' W. Z, c6 x' X5 C

1 j  }6 B- S) s: k- P
  1. #define QSPI_ADDRESS_NONE              ((uint32_t)0x00000000)           /*!<No address*/
    6 v4 {+ A: ^) o- i# T
  2. #define QSPI_ADDRESS_1_LINE            ((uint32_t)QUADSPI_CCR_ADMODE_0) /*!<Address on a single line*/" a! _# [' f: X) B2 i! n
  3. #define QSPI_ADDRESS_2_LINES           ((uint32_t)QUADSPI_CCR_ADMODE_1) /*!<Address on two lines*/
    " u; y) J. h4 Y: c
  4. #define QSPI_ADDRESS_4_LINES           ((uint32_t)QUADSPI_CCR_ADMODE)   /*!<Address on four lines*/
复制代码

: s+ A0 v: B( ^/ K. _; h+ O6 p6 D  AlternateByteMode3 o% d. m  l5 U# n& @' E
交替字节阶段需要几线模式:/ j, [6 ~( N" `
. }* I; y. v3 S9 f5 x
  1. #define QSPI_ALTERNATE_BYTES_NONE      ((uint32_t)0x00000000)           /*!<No alternate bytes*/
    3 }. a- }: e4 Y: P
  2. #define QSPI_ALTERNATE_BYTES_1_LINE    ((uint32_t)QUADSPI_CCR_ABMODE_0) /*!<Alternate bytes on a single line*/2 `( s' a( P/ ?0 V$ B3 }
  3. #define QSPI_ALTERNATE_BYTES_2_LINES   ((uint32_t)QUADSPI_CCR_ABMODE_1) /*!<Alternate bytes on two lines*/
      {" r6 b: n" V0 y9 z' E9 }8 H" w+ \
  4. #define QSPI_ALTERNATE_BYTES_4_LINES   ((uint32_t)QUADSPI_CCR_ABMODE)   /*!<Alternate bytes on four lines*/
复制代码

1 d. }8 h0 v2 J& ^$ ]& q$ K  DataMode( m" F, {. a0 ]) t2 P( M
数据阶段需要几线模式:; z2 W) d0 K7 l) M
) O& |: u: A  I
  1. #define QSPI_DATA_NONE                 ((uint32_t)0X00000000)           /*!<No data*/
    9 ?% L" A2 k' B0 Y& J; h
  2. #define QSPI_DATA_1_LINE               ((uint32_t)QUADSPI_CCR_DMODE_0) /*!<Data on a single line*/2 w% ]# N3 J# v3 v7 q
  3. #define QSPI_DATA_2_LINES              ((uint32_t)QUADSPI_CCR_DMODE_1) /*!<Data on two lines*/
    + ?8 k9 g, w" [* o( C; B2 u1 f  d  y
  4. #define QSPI_DATA_4_LINES              ((uint32_t)QUADSPI_CCR_DMODE)   /*!<Data on four lines*/
复制代码

8 {* N9 D) {0 T6 V! p  NbData) B  O0 o* U" k& y3 t
要传输的数据大小,参数范围0 到 0xFFFFFFFF,如果设置为0表示不定长,直到存储器末尾。) b6 U: a5 q  e1 v8 e5 s$ Q

; c4 W  `5 u- U& @7 o7 ~  DdrMode) R+ Q1 w0 c1 O# w/ v9 n1 @& H
用于设置是否使能DDR模式。数据阶段,交替字节阶段和数据传输阶段可以使用DDR模式。支持的参数如下:
+ H) F3 f, u0 b- T9 w1 |7 a' g1 W% U0 f; m- q& f
  1. #define QSPI_DDR_MODE_DISABLE          ((uint32_t)0x00000000)       /*!<Double data rate mode disabled*/
    5 e8 g. o: ?- l6 O4 a
  2. #define QSPI_DDR_MODE_ENABLE           ((uint32_t)QUADSPI_CCR_DDRM) /*!<Double data rate mode enabled*/
复制代码
6 C# X  e  l) R! Q" H/ [
  DdrHoldHalfCycle, f% V4 e* E; [
DDR模式下,用于设置延迟半个时钟周期再做数据输出。
1 c4 }  B& }% j0 J3 i* H6 A
. A5 ?8 h) ]; c$ Y8 E( X
  1. #define QSPI_DDR_HHC_ANALOG_DELAY      ((uint32_t)0x00000000)      9 \' U: t5 H( h6 j8 R9 E
  2. #define QSPI_DDR_HHC_HALF_CLK_DELAY    ((uint32_t)QUADSPI_CCR_DHHC)
复制代码

! U: s/ f. I- i  SIOOMode4 h- d! w* r; u8 T/ D( L
设置仅发送一次指令还是每次操作都发送指令,支持的参数如下:# i2 ]- }, d. s3 a1 h
! f  Q/ l1 K* n+ E7 Y2 {
  1. #define QSPI_SIOO_INST_EVERY_CMD       ((uint32_t)0x00000000)     
    ' G$ \5 W& Q1 e$ X
  2. #define QSPI_SIOO_INST_ONLY_FIRST_CMD  ((uint32_t)QUADSPI_CCR_SIOO)
复制代码
7 E7 N. b' f7 O+ e( R8 k
78.3.5 QSPI自动查询结构体QSPI_AutoPollingTypeDef
# t1 i4 q8 ]' P. j% ^& @3 Q4 l* ?下面是QSPI总线自动查询结构体:
9 B5 R# l! z, |4 w- W! F4 E9 u
- ?' h) p+ u4 ^& ?& `
  1. typedef struct0 @6 V! a- w" b' ]9 U+ m
  2. {
      v  H+ V. p9 S& c9 Q0 E
  3.   uint32_t Match;            
    ' m. L* [; L9 f3 U9 v
  4.   uint32_t Mask;             ( k$ M7 V$ e* U. O* z
  5.   uint32_t Interval;         9 g0 p- x$ p* s" X- J. L
  6.   uint32_t StatusBytesSize;   
    4 s9 T, n2 D. I2 K- h
  7.   uint32_t MatchMode;       % Y$ A; \) n' p. @! D% t1 E
  8.   uint32_t AutomaticStop;     3 c' k- S! V  n
  9. }QSPI_AutoPollingTypeDef;
复制代码
. F1 \; u' c3 j' z# p
下面将结构体成员逐一做个说明:* w* s  N. S: o! X: H

& j+ J" D3 K* L9 B* H. X* ]! C  Match
2 Y9 B; L4 h* u3 [: O* _参数成员Mask屏蔽了状态寄存器的某些位后,状态寄存器的值与此参数成员值做匹配。参数范围0x0 到 0xFFFFFFFF。
7 o" z& y" s+ a" h" z) w) U
) n: K1 O" ]  C6 E, X" S% k  Mask& h9 P# \( |4 H" T7 A% r
用于设置屏蔽位,比如Mask = 0x01,表示仅保留bit0的数值,其它bit忽略。参数范围0x0 到 0xFFFFFFFF。
3 P+ U8 U- u1 {3 i1 Z9 s  h
: U2 M$ p' ]  m7 F* o6 \  Interval
' H" ~! a0 h" U, Y+ E指定自动轮询阶段两次读取之间的时钟周期数。参数范围0 到 0xFFFF。
% Z4 G' U( j( }! Y9 ]+ X9 K2 e5 r) |6 {! b' L$ ]9 c7 C, \3 b. c
  StatusBytesSize+ |+ c) |5 n( ?8 N- g1 X+ q1 H
用于设置状态寄存器大小,参数范围1到4个字节。. ^4 b5 e% W% w1 r; K4 A' U& G
; ^: H0 H9 z7 D4 t
  MatchMode0 k7 M& L9 R' }6 s8 U" M9 P
参数成员Mask屏蔽了状态寄存器的某些位后,状态寄存器完全与参数成员Match一样(与操作的含义)或者任意一个bit的值与参数成员Match中一个bit的值一样(或操作的含义),比如Mask = 0x01,Match=0x00,MatchMode=与操作,表示不断查询状态寄存器bit0,等待其为0。3 X  F( ^( @" H7 m4 |

- D" l2 M  M6 a9 H* cMatchMode支持的参数成员如下:$ w- {3 R# K$ H) K( ]( Z# X3 j) ]

/ D0 e' }0 m: P) N, {: ~+ I
  1. #define QSPI_MATCH_MODE_AND            ((uint32_t)0x00000000)     /*!<AND match mode between unmasked bits*/# u9 m# c- i" x8 F5 _0 H4 D
  2. #define QSPI_MATCH_MODE_OR             ((uint32_t)QUADSPI_CR_PMM) /*!<OR match mode between unmasked bits*/
复制代码

2 ~* H' I6 _+ o! A. p7 G" x6 U( N5 k  AutomaticStop
! x, R5 T& P! c! f; S; g& D当与参数成员Match匹配时,自动停止检测。
- {4 N9 b& `  Z
7 o" @5 O* B( x; B7 M6 V78.3.6 QSPI内存映射结构体QSPI_MemoryMappedTypeDef, Q; `9 |1 p( w% g, o
下面是QSPI总线的内存映射结构体:
( p0 L! W+ c) x* j6 A7 `
9 A/ h. G& y) }$ a& u
  1. typedef struct' X" H+ x1 `$ S
  2. {
    ' _, J) h5 S! y
  3.   uint32_t TimeOutPeriod;   
    : \; z7 f% G% C7 m
  4.   uint32_t TimeOutActivation;  : W* I% `8 C$ h7 {
  5. }QSPI_MemoryMappedTypeDef;  
复制代码

3 d4 W& W1 _7 V; M下面将结构体成员逐一做个说明:" z% s- u8 |) B" R
8 X* B- b1 n- H3 r$ A
  TimeOutPeriod
2 n" F5 S! W  V3 C% A1 K( T( L) ?" [. qFIFO满时,释放芯片选择之前要等待的时钟周期数。参数范围0到0xFFFF。
. W' P( g1 p5 x# j7 o$ R& s9 ?7 M3 N6 o0 i- y8 g0 r: C" w& V
  TimeOutActivation- ]8 x! I  U$ r) d6 B" o
指定是否启用超时计数器以释放芯片选择,支持的参数成员如下:  j9 i2 B0 i3 B5 H$ Q* T( k/ N, J

6 I. C/ Z& Y& l+ `! m" ^
  1. #define QSPI_TIMEOUT_COUNTER_DISABLE   ((uint32_t)0x00000000)     & p- i( U; [; v# f# B5 }7 r# w: L2 O
  2. #define QSPI_TIMEOUT_COUNTER_ENABLE    ((uint32_t)QUADSPI_CR_TCEN)
复制代码

7 v( r: f6 Z9 h8 ?5 [78.4 QSPI总线源文件stm32h7xx_hal_qspi.c: m7 ?" R1 m6 C/ w
此文件涉及到的函数较多,这里把几个常用的函数做个说明:$ M9 p3 c5 A6 j! j- i
- ]" N. H% s5 j8 k% L5 h2 C; ~4 `# `7 E
  HAL_QSPI_Init
$ O& S8 L( h' R2 q/ t' g  HAL_QSPI_DeInit
9 P4 t  ~8 U' E, @* I9 L  HAL_QSPI_Command
, f  m8 u! ~0 a  HAL_QSPI_Command_IT
  P5 P& U1 s' T( T7 }( D& }  HAL_QSPI_AutoPolling9 J2 o4 I7 s' a, I2 p5 X6 ?
  HAL_QSPI_AutoPolling_IT
; N( s" H, q* y6 I; \# |) c  HAL_QSPI_Transmit
4 S# |6 P2 m8 t( u/ l  HAL_QSPI_Receive
7 M' ]% ]# X. T/ L) f  HAL_QSPI_Transmit_DMA# m: `8 J1 R1 }4 p  M" A4 A
  HAL_QSPI_Receive_DMA
( X* N3 M& v; I. i  HAL_QSPI_MemoryMapped
6 f3 ^6 ?8 J" w$ x78.4.1 函数HAL_QSPI_Init+ C: O: a: i0 a8 o/ \# A
函数原型:
- f) m! \- U! F$ s) ^6 Z: H; V  m6 r4 e0 D% p0 Q
  1. HAL_StatusTypeDef HAL_QSPI_Init(QSPI_HandleTypeDef *hqspi)
      N/ b; I( f  m4 f5 n0 V' E
  2. {
    1 q& W, N  u9 Q7 M& p2 P
  3.   HAL_StatusTypeDef status;3 i: i' Y1 o6 t
  4.   uint32_t tickstart = HAL_GetTick();
    4 Y6 o4 m, W. z$ I# j$ r# z5 a
  5. , G& g1 P9 s9 t$ T  Q
  6.   /* 检测句柄是否有效 */
    & a5 u0 F7 r* ?- w
  7.   if(hqspi == NULL)+ h! }$ r( c# _( \% ]0 h2 ?0 h/ |
  8.   {
    7 e) @' C% T- B# O$ S
  9.     return HAL_ERROR;" S, w" l. |6 p4 z$ I
  10.   }
    3 [  ]4 ]: F  |) e5 s, ~# K
  11. " V- n# n, I1 i7 Q, M: @( L, f
  12.   /* 检查参数是否有效 */
    ( m/ G+ H8 i+ A1 k5 T( u/ ?# `
  13.   assert_param(IS_QSPI_ALL_INSTANCE(hqspi->Instance));
    0 R! ?* _7 V' {# t
  14.   assert_param(IS_QSPI_CLOCK_PRESCALER(hqspi->Init.ClockPrescaler));
      w6 {: u3 g5 B
  15.   assert_param(IS_QSPI_FIFO_THRESHOLD(hqspi->Init.FifoThreshold));& c' y8 e  s) h3 f
  16.   assert_param(IS_QSPI_SSHIFT(hqspi->Init.SampleShifting));% r  }- W" A# [* i$ A0 O2 M
  17.   assert_param(IS_QSPI_FLASH_SIZE(hqspi->Init.FlashSize));
    & B) d& `/ o; H* s5 b, D
  18.   assert_param(IS_QSPI_CS_HIGH_TIME(hqspi->Init.ChipSelectHighTime));, ^. V& x( q( J
  19.   assert_param(IS_QSPI_CLOCK_MODE(hqspi->Init.ClockMode));0 a! r3 P5 z+ B! t+ P0 ~: l
  20.   assert_param(IS_QSPI_DUAL_FLASH_MODE(hqspi->Init.DualFlash));  {7 Q( n" O. ~0 |

  21. 1 _, E. A. ~; r' J' w
  22.   if (hqspi->Init.DualFlash != QSPI_DUALFLASH_ENABLE )
    5 }5 b- H5 U- m' ]
  23.   {
    / M* W: R( A' Q, `! R
  24.     assert_param(IS_QSPI_FLASH_ID(hqspi->Init.FlashID));1 d+ m1 _9 d. N; c9 D
  25.   }
    / J. S7 p" L4 w' |
  26. 8 Q' j3 e- u8 E" c& f; |
  27.   if(hqspi->State == HAL_QSPI_STATE_RESET)6 l. |& H+ @% T# U, P9 \6 N
  28.   {
    * L& L# X: y. e: G
  29. 8 r/ }7 r1 G; ~& r
  30. #if (USE_HAL_QSPI_REGISTER_CALLBACKS == 1)
    $ N' \5 [- t, u* ?; c, Q  V4 P
  31.     /* 复位状态,设置默认的回调 */8 j1 a1 p6 s. l. L0 |6 m
  32.     hqspi->ErrorCallback         = HAL_QSPI_ErrorCallback;1 }+ }0 |# P, H* m
  33.     hqspi->AbortCpltCallback     = HAL_QSPI_AbortCpltCallback;! a2 V* G( i3 H
  34.     hqspi->FifoThresholdCallback = HAL_QSPI_FifoThresholdCallback;
    3 y6 A9 }9 |! Z+ \5 S5 R0 {, I% C
  35.     hqspi->CmdCpltCallback       = HAL_QSPI_CmdCpltCallback;
    3 s$ n+ r2 N" V0 d; V: G
  36.     hqspi->RxCpltCallback        = HAL_QSPI_RxCpltCallback;
    ! g$ s/ v* @$ u. P$ r# c
  37.     hqspi->TxCpltCallback        = HAL_QSPI_TxCpltCallback;7 o8 [- S/ ?0 K" n4 z% G
  38.     hqspi->StatusMatchCallback   = HAL_QSPI_StatusMatchCallback;
      e' u! M; }+ @% u/ N7 T( G, j& v) K
  39.     hqspi->TimeOutCallback       = HAL_QSPI_TimeOutCallback;3 h: M' s' \5 G  J- H& s) f
  40. ; }2 E8 z* }5 I' `
  41.     if(hqspi->MspInitCallback == NULL)$ c- Z+ F# L! S5 ^8 [5 V  l# Y/ i
  42.     {+ a/ a" n& x+ T- G9 }" A
  43.       hqspi->MspInitCallback = HAL_QSPI_MspInit;2 F* U! E$ ~% _3 m4 ?
  44.     }
    , `; o+ ]% ^! Y: l6 T! B6 q* f1 a* Z

  45. : p/ O( ^8 c  d7 ?: I
  46.     /* 初始化底层硬件 */0 z) u. [7 b$ l  E. |; k0 H$ a* F
  47.     hqspi->MspInitCallback(hqspi);
    % n1 O( @7 J: v- {) v# c- Z% h/ ~
  48. #else& W1 W3 p6 Q, y" I6 w
  49.     /* 初始化: GPIO, CLOCK */5 u" n% F4 d* r( L* n) o0 L* I' e
  50.     HAL_QSPI_MspInit(hqspi);
      _* M' W  z- f  Y1 R7 _6 ]# \
  51. #endif
    5 k7 J+ |, m  b; H

  52. 2 [0 C" M. ~; j
  53.     /* 配置QSPI内存访问默认的溢出时间 */
    " r, F0 I% a7 V* }" {/ o- o
  54.     HAL_QSPI_SetTimeout(hqspi, HAL_QSPI_TIMEOUT_DEFAULT_VALUE);
    ) d' }2 V7 I) V# z( Y& X* V+ [( F
  55.   }3 o! l+ R( T  J4 M

  56. 6 {  s+ T( H, u0 D
  57.   /* 配置QSPI FIFO阀值 */  X4 h8 C  ]9 k( B4 [
  58.   MODIFY_REG(hqspi->Instance->CR, QUADSPI_CR_FTHRES,
    ! K& w3 q0 U3 F& p( x5 R' O3 v
  59.              ((hqspi->Init.FifoThreshold - 1U) << QUADSPI_CR_FTHRES_Pos));
    4 \' u0 }- D$ u- j, P# l

  60. : \# Q: g8 r% S5 B
  61.   /* 等BUSY标志复位 */
    5 D" @$ A4 N: i$ H) J' r
  62.   status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, hqspi->Timeout);/ Q$ J1 Q: |9 O* \5 E( \
  63. $ `0 D: X8 o7 ~7 R  h2 @
  64.   if(status == HAL_OK)+ @4 k! C$ K- O4 s7 J* }% J
  65.   {8 W! D+ s/ v* _( x( @6 e$ H
  66.     /* 配置QSPI时钟分频和采样延迟 */
    0 n7 A. _2 s! k/ O" `
  67. MODIFY_REG(hqspi->Instance->CR, (QUADSPI_CR_PRESCALER | QUADSPI_CR_SSHIFT | QUADSPI_CR_FSEL |3 O3 F2 T/ `8 _, t* r
  68. QUADSPI_CR_DFM),% }3 B) I. |& H4 [7 Y5 t/ K
  69.                ((hqspi->Init.ClockPrescaler << QUADSPI_CR_PRESCALER_Pos) |
    : V& @6 S! F) m
  70.                 hqspi->Init.SampleShifting  | hqspi->Init.FlashID | hqspi->Init.DualFlash));
    , T6 v/ y; j- |) ?2 J/ j$ n

  71. * Q, b' J$ N7 _: ~4 X1 l7 d
  72.     /* 配置QSPI Flash大小,CS片选高电平时间和时钟模式 */
    ( v. }9 f6 q2 w4 @2 t
  73.     MODIFY_REG(hqspi->Instance->DCR, (QUADSPI_DCR_FSIZE | QUADSPI_DCR_CSHT | QUADSPI_DCR_CKMODE),( M) j; ^" V6 y3 D7 Z
  74.                ((hqspi->Init.FlashSize << QUADSPI_DCR_FSIZE_Pos) |
    1 {. p8 D5 C8 |  A
  75.                 hqspi->Init.ChipSelectHighTime | hqspi->Init.ClockMode));
    : a( G6 p# W/ N7 e$ P- R
  76. ! ^6 E2 [, D+ n3 u& f0 Y
  77.     /* 时钟QSPI外设 */
    & X! l. {5 Z: a6 t" z9 S  {! O6 W1 H
  78.     __HAL_QSPI_ENABLE(hqspi);5 u- h& |9 |$ @, G7 b

  79. . _; K" k& b$ Z6 G
  80.     /* 设置QSPI无错误代码 */
    ; i# z# x( n! {1 ~9 l4 N
  81.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
    , [6 ^- _5 i& @

  82. - ~2 I& I4 w% j3 d3 g( P
  83.     /* 初始化QSPI状态就绪 */  q5 r: _  u7 W- ^6 y
  84.     hqspi->State = HAL_QSPI_STATE_READY;5 M: V& R- \% t8 {1 t' J
  85.   }
    4 K8 t. [' G3 l0 H( H, i

  86. . L/ c5 W3 [0 O9 R5 C- l
  87.   /* 返回状态信息 */
    2 ]+ w; B2 Z0 o$ J! K* l
  88.   return status;! m; G9 L; \& o2 u! [: o1 ?
  89. }
复制代码

( c  p. M/ Y  \+ o' n4 {& U6 E函数描述:3 }8 x/ C2 l% H$ N* r4 V
' L+ _$ r* N, H- U4 g! V" n9 B) j$ b
此函数用于初始化QSPI。
/ h" k' r) d. ?! \0 v/ Q+ G/ S. ~& P( X9 C
函数参数:
, O- \4 N& n+ Q. Z7 w" K; H5 u
* G9 g  {# d" W  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,详见本章3.3小节。
/ m4 h2 H8 V% Y- c  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
/ r, _% Q' T* d; q注意事项:6 W* u" ^) N& R' ]0 [/ a$ z
6 _+ o" Z) K1 r4 C
函数HAL_QSPI_MspInit用于初始化QSPI的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
( P. C& J4 v' [7 ~1 x8 a如果形参hqspi的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量QSPI_HandleTypeDef SpiHandle。, ^! F$ {3 P$ q% ~
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_QSPI_STATE_RESET  = 0x00U。
* }; {5 i0 D, U" A' W! |1 b4 m+ s. N* \2 l% f* Q. L
解决办法有三* p/ \/ V! F5 I3 J1 ]4 E+ f

9 S$ X4 c8 k4 w) B* X方法1:用户自己初始化QSPI和涉及到的GPIO等。
1 i% v' c- \6 ]% X* T
3 W# `( _. k6 V( D0 G* S  s( A方法2:定义QSPI_HandleTypeDef QspiHandle为全局变量。: x; H( k! O" N# b

6 J  r7 u0 g9 ]; C8 I2 R& L. g$ E方法3:下面的方法' D" @1 p2 {! V9 @
, U* d6 M" S, j% ?
  1. if(HAL_QSPI_DeInit(&QspiHandle) != HAL_OK)
    - v1 E" P. s% w0 ~& K
  2. {
    ' k1 ~3 T' M9 _4 v( s- M
  3.     Error_Handler();5 E3 |% \% o/ }$ n2 w
  4. }  5 F: t' ^- T5 P6 J
  5. if(HAL_QSPI_Init(&QspiHandle) != HAL_OK)" l$ M4 l- Y6 O8 E0 O$ a5 C4 q
  6. {
    * ~5 D1 F+ y! X0 [/ _( \: g7 O3 X& K6 d
  7.     Error_Handler();
    . \& z/ b0 o/ c+ ?& o) r# ?
  8. }
复制代码
: z) v6 C; t8 i# E5 U. g
使用举例:
0 ^, B9 P, G* F3 l: z7 I0 V& h' A) U+ {) o+ c- y6 ~) u
  1. /*
      Q( R2 e' F$ K$ S" M+ p  |
  2. *********************************************************************************************************
    : ^6 x9 O7 q. h* C  Z, `
  3. *    函 数 名: bsp_InitQSPI_W25Q256, }% K/ H4 U3 i5 r
  4. *    功能说明: QSPI Flash硬件初始化,配置基本参数
    9 M9 ^7 i3 F0 Q  k
  5. *    形    参: 无; ~% T/ M* s9 N$ r6 }6 c
  6. *    返 回 值: 无1 H1 ~6 E. O  E9 m3 D7 ?& ]! N& ^! h
  7. *********************************************************************************************************7 f- ]5 r8 p. _" }
  8. */
    ( Q5 R( l$ G' `! N( {3 e) t6 [
  9. void bsp_InitQSPI_W25Q256(void)4 I" y# x1 o2 H8 R1 U
  10. {
    / S4 F! N! G% ]- Q  F3 |
  11.     /* 复位QSPI */' e4 M, p3 B# R
  12.     QSPIHandle.Instance = QUADSPI;
    4 y+ ?$ h$ V" k0 N& s- b! ^. O
  13.     if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK)3 q8 v. G$ p% C  ?% z+ ]/ b% i
  14.     {" r. Z9 S; I" s7 f5 o; P
  15.         Error_Handler(__FILE__, __LINE__);
    ) S; Q: O; ^9 ~: P) k/ S
  16.     }
    * g+ y/ @. V7 b! i8 @

  17. ' P5 m+ L! N5 g8 X& w
  18.     /* 设置时钟速度,QSPI clock = 200MHz / (ClockPrescaler+1) = 100MHz */
    + M) E2 M0 ?! @  N2 ^
  19.     QSPIHandle.Init.ClockPrescaler  = 1;  
    5 s1 N1 k  a- z: W- t5 z5 h
  20. ) R. k' S, o: k: r8 \/ c
  21.     /* 设置FIFO阀值,范围1 - 32 */
    . ^+ E7 h; \8 L1 r
  22.     QSPIHandle.Init.FifoThreshold   = 32; % U, [8 H0 `9 p% R, f/ B0 V
  23. 6 O, g. Q( I8 M- t. D2 v" L
  24.     /*
    . a8 A2 C6 \) R' @/ z
  25.         QUADSPI在FLASH驱动信号后过半个CLK周期才对FLASH驱动的数据采样。
    9 ?4 X; Q  @/ P) i' T" V7 S
  26.         在外部信号延迟时,这有利于推迟数据采样。4 B, {  r0 X) R# g# ~" ~+ U
  27.     */0 A' |- Z4 \% `* f& I
  28.     QSPIHandle.Init.SampleShifting  = QSPI_SAMPLE_SHIFTING_HALFCYCLE; 2 V/ Y- T9 r; X

  29. 5 P  a& C/ V, G6 B
  30.     /*Flash大小是2^(FlashSize + 1) = 2^25 = 32MB */
    $ V- H- R8 f4 R2 ]
  31.     //QSPI_FLASH_SIZE - 1; 需要扩大一倍,否则内存映射方位最后1个地址时,会异常。) h" I" y. x% g( v, s
  32.     QSPIHandle.Init.FlashSize       = QSPI_FLASH_SIZE;
    ) Z3 W8 N# ~3 I0 u; A" U
  33. 7 x* o5 y* b# q/ I7 t
  34.     /* 命令之间的CS片选至少保持2个时钟周期的高电平 */
    . f- C6 |7 N1 h7 r* [; A9 k
  35.     QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_2_CYCLE;
    + [2 o, i% X8 J3 C9 |1 S+ v

  36. ' x' U; Z% E. y5 [
  37.     /*6 l( Y5 X3 L3 F' R
  38.        MODE0: 表示片选信号空闲期间,CLK时钟信号是低电平
    ( i* E8 s# v5 i
  39.        MODE3: 表示片选信号空闲期间,CLK时钟信号是高电平
    % j8 S6 t, u, A7 C8 I: c
  40.     */3 k5 j7 o" ?, i$ @
  41.     QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0;
    & C+ a0 e% A: W7 h' N) G7 H
  42. 3 ^/ s4 a! E; t* N
  43.     /* QSPI有两个BANK,这里使用的BANK1 */, q2 M+ ]3 k; ^$ c' T
  44.     QSPIHandle.Init.FlashID   = QSPI_FLASH_ID_1;  A: O7 j5 k8 Y

  45. 7 M, M/ t2 J% x" S! r5 L% }: }
  46.     /* V7开发板仅使用了BANK1,这里是禁止双BANK */
    8 G2 X" o, h& o9 ~/ ]3 N: d
  47.     QSPIHandle.Init.DualFlash = QSPI_DUALFLASH_DISABLE;  M  R; W# h+ [8 f. _. m0 }! |

  48. 8 Q8 a& k; p* s3 O4 _
  49.     /* 初始化配置QSPI */
    / n* f# G0 o  _; O
  50.     if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK)& ]% ]3 N5 }* O/ {$ T+ `+ e$ N# H" L
  51.     {
    3 X3 R* @) V% ?# ]' A/ H$ I6 k; `/ n
  52.         Error_Handler(__FILE__, __LINE__);3 q" ^8 S& b2 }+ z$ l' I2 E
  53.     }   
    % E/ s5 k# [) p5 @! D3 A
  54. }
复制代码

3 ~2 x; O  R* M7 S; Z78.4.2 函数HAL_QSPI_DeInit$ _: i2 C7 v6 Z) r; \; ~
函数原型:
( _+ O7 M6 N5 X. w( E) j: u0 J( j% P8 I! b  x! {: ~; ^
  1. HAL_StatusTypeDef HAL_QSPI_DeInit(QSPI_HandleTypeDef *hqspi)
    2 U- e- O5 \0 u( g
  2. {9 |' Z* x4 ^& v+ \9 \3 T" G3 p
  3.   /* 检测QSPI句柄 */
    2 b/ k' o8 q) ~) N; M# {
  4.   if(hqspi == NULL)
    . L* V1 g8 z* }- P1 P# p
  5.   {" l4 w) s$ @5 J' F7 l# ~- u
  6.     return HAL_ERROR;
    & n2 O2 ^' Z5 b3 R4 ]* Y
  7.   }
    7 E/ D7 v. ~. N7 D9 H9 _6 \

  8. 7 t, s$ X9 |7 H
  9.   /* 禁止QSPI外设时钟 */
    ; F2 o& `; b6 A
  10.   __HAL_QSPI_DISABLE(hqspi);
    4 @" V3 F+ l% |! }" S. @  p

  11. ) E. c0 [; Z7 q( q3 k) g  F
  12. #if (USE_HAL_QSPI_REGISTER_CALLBACKS == 1)
    2 C) H5 z: ?- v: o
  13.   if(hqspi->MspDeInitCallback == NULL)
    $ k3 s( l! K( A& p8 q+ e( _6 w
  14.   {
    % e; K9 }3 S$ U6 {1 D
  15.     hqspi->MspDeInitCallback = HAL_QSPI_MspDeInit;
    3 x& W( n1 v& D
  16.   }
    ; i6 o. i0 [, H" e# x  N

  17. ; n; x" v+ Y* Q+ g
  18.   /* 复位硬件底层 */4 s4 o& D+ X1 ^  t1 Y
  19.   hqspi->MspDeInitCallback(hqspi);' _; G0 `7 q* b- ^! n2 ]5 A
  20. #else
    3 e2 z) }' ^7 Z1 L' A  a
  21.   /* 复位: GPIO, CLOCK, NVIC... */+ v  _3 j8 H; r  L6 m8 \7 L# \- {
  22.   HAL_QSPI_MspDeInit(hqspi);- i( g; L+ g0 S, z1 E7 I
  23. #endif3 A0 K  o7 R( D" i

  24. 8 V, |3 A# F# W/ s) w- M! w+ F1 }5 ^
  25.   /* 设置无错误 Set QSPI error code to none */
    * x3 x2 `* t8 G! h$ X  F2 H5 T/ p
  26.   hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
    1 D  F- _: n- u9 _/ n2 @8 F. X

  27. # \- V! K# ]7 C5 A; l, A" L6 L9 \
  28.   /* 设置QSPI状态为复位 */" n% @0 B( F1 X0 ^6 c  a$ I  Y5 O, P
  29.   hqspi->State = HAL_QSPI_STATE_RESET;7 |  v' [' V; |3 o$ ?4 T+ f# i9 V

  30.   ]4 {" }. Z8 b0 `
  31.   return HAL_OK;( \" B( W5 D# L1 }% ]  l
  32. }
复制代码

5 e" h, H. A& |, I2 }7 H函数描述:: ~9 X/ t3 |1 Y: x9 {: I+ E; y
, i4 S: s% i6 U' V- S
用于复位QSPI总线初始化。
9 H# D3 I3 D3 {) @# l
* a7 y! h* I! ?6 _9 z函数参数:7 t$ B' {/ p/ x0 e% P

  R5 M, g  K* r" _3 a( M- f  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。, r( I$ ?0 |2 I& o- |! m
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。) i. S/ _/ X0 X* O' Z* o. Q1 }
78.4.3 函数HAL_QSPI_Command
; r" x( \' @- d函数原型:; l; }. `& y( H
8 k$ \: p- k% ~% J1 s% h, S; Y
  1. HAL_StatusTypeDef HAL_QSPI_Command(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, uint32_t Timeout)
    8 h3 ]6 p% t0 I. b  `0 U) V, H
  2. {4 P' O& \+ t  M- H  r7 i
  3.   HAL_StatusTypeDef status;( |/ R" Q, W$ Z, c6 l$ w0 C
  4.   uint32_t tickstart = HAL_GetTick();/ Y0 Y* }: x% t, K4 p/ n9 v  }
  5. ( C7 f" @: w/ n* O6 m' o6 {
  6.   /* 检测参数 */; Y2 P! L  E- l. o6 @
  7.   assert_param(IS_QSPI_INSTRUCTION_MODE(cmd->InstructionMode));
    ! D5 a: t5 i! `0 M+ M7 g
  8.   if (cmd->InstructionMode != QSPI_INSTRUCTION_NONE)' G! Y- z: y  M
  9.   {1 r+ j. U+ t2 B( t6 _
  10.     assert_param(IS_QSPI_INSTRUCTION(cmd->Instruction));
    1 k. f1 H- ]' X0 n! ~& c
  11.   }  u4 B8 b/ Z$ j5 l8 Y
  12. + p9 r5 u7 i. S) K. M
  13.   assert_param(IS_QSPI_ADDRESS_MODE(cmd->AddressMode));
      e( O1 l& s" d
  14.   if (cmd->AddressMode != QSPI_ADDRESS_NONE)! X5 L8 v; P- u
  15.   {' |( e1 }* u: p! `6 R5 j
  16.     assert_param(IS_QSPI_ADDRESS_SIZE(cmd->AddressSize));' \% r( T! u) r$ l7 y' f; u, Y. N
  17.   }/ a2 g/ S. t' x9 v5 h$ E% ], u
  18. 8 y1 j4 w7 E5 E# }6 d5 U
  19.   assert_param(IS_QSPI_ALTERNATE_BYTES_MODE(cmd->AlternateByteMode));
    # P7 D6 U/ n$ q
  20.   if (cmd->AlternateByteMode != QSPI_ALTERNATE_BYTES_NONE)
    2 m$ A/ u8 Z( K+ h; S5 l
  21.   {" A) y% h/ u) F5 y3 O
  22.     assert_param(IS_QSPI_ALTERNATE_BYTES_SIZE(cmd->AlternateBytesSize));! |0 R, y# x+ [! r' a
  23.   }4 `* r# g! p4 C4 @- f* I4 O
  24. 7 b" q  c' K  @1 t) P1 A; V3 l' n& S
  25.   assert_param(IS_QSPI_DUMMY_CYCLES(cmd->DummyCycles));
    6 s: x1 k5 x0 E3 s
  26.   assert_param(IS_QSPI_DATA_MODE(cmd->DataMode));
    9 G$ [1 j7 L5 U0 d, ]" |% n

  27. " f/ G2 \4 t/ v; F; i7 V
  28.   assert_param(IS_QSPI_DDR_MODE(cmd->DdrMode));
    + x& }& T' Z3 x# m
  29.   assert_param(IS_QSPI_DDR_HHC(cmd->DdrHoldHalfCycle));
      b% S& O7 x8 Z& I5 k7 }& M
  30.   assert_param(IS_QSPI_SIOO_MODE(cmd->SIOOMode));' y7 C- t+ Y2 [. p- D! J! t/ {

  31. - b/ y$ ~- @9 H: F2 O& s
  32.   /* 上锁 */
    6 T5 e8 M$ @1 m8 @( B% z
  33.   __HAL_LOCK(hqspi);
    ; X* X) {. H. g) D7 n. K) b9 e7 O5 @
  34. ; ]( ]4 _+ [: [! [6 z$ M' F; r
  35.   if(hqspi->State == HAL_QSPI_STATE_READY)
    ' V4 S7 ?6 |  ]( ?
  36.   {
    3 F' g7 l* T3 x/ J7 [  y
  37.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
    4 j* k& C& h/ P/ O$ g0 r
  38. / y+ |4 a" n* }' i6 E8 w$ T
  39.     /* 更新QSPI状态 */- J- V" D0 x' E, Y, Q3 M% L& r
  40.     hqspi->State = HAL_QSPI_STATE_BUSY;1 b# ^4 X. b: q" z; r

  41. * M  R+ L2 K1 u& D$ |% y
  42.     /* 等待BUSY标志复位 */
    5 B0 a4 f! q* W, O0 ~) ]
  43.     status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, Timeout);, q' w! J$ l; O# i" s6 u
  44. 0 ^, a" `: x; o3 D8 A0 ~
  45.     if (status == HAL_OK); V% F" P# `6 N
  46.     {7 p( R; L  e# J: N8 d
  47.       /* 配置QSPI  */
    ! [* i* Z3 V' a  O5 H+ [" I! S' T
  48.       QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_INDIRECT_WRITE);
    ) E( V. I$ Z% S3 ]

  49. ) n3 L, U; `! V7 J3 q+ @0 A! K
  50.       if (cmd->DataMode == QSPI_DATA_NONE)
    . U/ N4 l* x7 D: L- d) d
  51.       {
    7 j/ Q) d3 t/ ], {) @2 W5 W
  52.         /* 没有数据阶段时,配置完成后立即开始传输,所以请等到TC标志设置并返回到空闲状态 */# t6 p$ y) [0 S& o1 j
  53.         status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_TC, SET, tickstart, Timeout);
    . c& L5 ]3 D. g/ F  C* U9 M

  54. : o/ x* K( l& j) [. ~
  55.         if (status == HAL_OK)
    / K! L2 q2 l: ^. w& Y3 \! n6 l% K
  56.         {$ ~0 S* P( D  t, J* t6 q
  57.           __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TC);( g# z  s8 m7 d) |$ u. Q

  58. / L* J' o' V7 R! {
  59.           /* QSPI就绪 */# e8 V/ H3 V8 O2 Y( ?
  60.           hqspi->State = HAL_QSPI_STATE_READY;% V5 R! d  p; R* s0 w( {
  61.         }# a6 F! C, a0 f) r# r$ l9 I, h
  62.       }0 E( p" W) _  l1 ~; H+ c
  63.       else
    ) I0 i* U$ r; V/ ~
  64.       {
    1 i  `1 F" n  C# k1 y
  65.         /* QSPI就绪 */) q# U6 c. y0 p0 T1 _# W
  66.         hqspi->State = HAL_QSPI_STATE_READY;, Q# R1 |% u; R# E+ b3 b, S1 j
  67.       }- ?+ w  c# O' e3 J) d4 E2 J
  68.     }
    * |0 J0 @  E' G( ^
  69.   }9 n9 o, G& B2 ]# G, o1 s
  70.   else
    * _) }9 v  d: |' w# d
  71.   {( l  p1 w& \7 B8 a8 G7 {( H; m% k
  72.     status = HAL_BUSY;$ Q- |5 U" C! [  P( p
  73.   }. X! g) ^1 J" P8 L( o

  74.   z! k' @. i5 ^+ N0 Q" v
  75.   /* 解锁 */
      |+ m7 p. Q. ^8 x& x' `
  76.   __HAL_UNLOCK(hqspi);
    $ }5 g' M& D& S& I5 n) @* E5 _. g4 C
  77. - b, O0 Y( T# o
  78.   /* 返回函数状态 */3 y; v! _) g. D# w( ]# x7 j" n5 h" _
  79.   return status;1 ]0 A, G9 `4 M7 g( @3 F, c
  80. }
复制代码

* l$ f9 l$ ~: g8 m函数描述:4 H  T* o1 S( `) F1 y  ]% ~) o

3 x6 ~# I6 ?! S/ l! Y- o/ [! u2 U( s此函数主要用于为QSPI Flash发送操作命令,查询方式。
7 B# _# \" w# v0 A! S/ _8 ^5 r
2 f0 e2 ]4 m7 p( f函数参数:2 u7 l. v+ P  L1 G) w5 [. h6 @
& H# o0 U/ O# C& C% l+ d; |0 I
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
# C/ Q% V, k+ c  第2个参数是QSPI_CommandTypeDef类型结构体变量,详见本章3.4小节。
( A: i. U4 [; Y+ D& b  第3个参数是溢出时间,单位HAL库时间基准,一般我们设置的是1ms。
, J, s( M; d9 F/ v9 Y9 T7 f  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。0 L( u( o. ~; w# d
使用举例:
1 v" H% C0 c2 I  L% A, s& j2 N! u: N2 H! k" ^  C4 E% L
  1. /*
    1 T: N, R2 M( I% ~/ f
  2. *********************************************************************************************************
    1 d( I/ L, v/ a2 U
  3. *    函 数 名: QSPI_WriteEnable
      E, J3 Z% B1 O2 W8 Q3 {
  4. *    功能说明: 写使能
    ; j2 A6 G( g& A/ S1 c: _
  5. *    形    参: hqspi  QSPI_HandleTypeDef句柄。
    5 p# q, ~3 ]& _4 k4 ~7 W- N; d/ R: p
  6. *    返 回 值: 无
    6 g/ |: e* h; j9 c8 C- H3 }" {0 h  c
  7. *********************************************************************************************************
    + r8 [) w9 y0 E( l. C. a2 s
  8. */
    $ k5 t' ~% Q6 _$ p/ l0 r
  9. static void QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi)
    % ]! J/ Z* l, {) ~" \
  10. {
    8 ~) J4 S* M  v  J6 B
  11.     QSPI_CommandTypeDef     sCommand = {0};
    9 r6 o6 ?: F- I
  12. ! m- \3 w) U. k/ _& [& J
  13.     /* 基本配置 */
    ) N9 H, G$ Z# U: x6 B: T/ i
  14.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */# v# a1 _# O; p
  15.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */
    2 v1 D) B# f# {2 i5 c& k
  16.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */- ^9 N2 C) [, u# p# q" ]8 G
  17.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */) G8 [3 U) E7 ~7 f3 T/ v
  18.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */
    5 S5 ]8 p0 y* n% g2 X5 v0 @
  19.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;     /* 每次传输都发指令 */
    ' w: ]; P, ^! {! q* H) D1 E

  20. ! h( U1 _: X7 v' S
  21.     /* 写使能 */2 @4 y" u& ^) ^: U* A/ q/ ~, S5 g
  22.     sCommand.Instruction       = WRITE_ENABLE_CMD;  /* 写使能指令 */  m0 f4 B2 u+ X2 a. M
  23.     sCommand.AddressMode       = QSPI_ADDRESS_NONE; /* 无需地址 */& Y$ _( K9 V: ]' Z+ x0 `" h
  24.     sCommand.DataMode          = QSPI_DATA_NONE;    /* 无需数据 */
    * s- d( O! b. |8 u
  25.     sCommand.DummyCycles       = 0;                 /* 空周期  */* K& z9 J  i$ ~. n

  26. 8 J+ P  i5 z/ ^: d3 S( Z6 t' ~8 m( f
  27.     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
    ) E! v/ q# _7 Z! e
  28.     {
    8 p6 I3 L8 [6 _. v! {0 E, x
  29.         Error_Handler(__FILE__, __LINE__);
    # ^+ i6 k% W) V9 r& b
  30.     }    % g2 b2 f7 O' p7 Q: O- c
  31. }
复制代码

7 w8 }$ y' A5 F+ b$ [. s78.4.4 函数HAL_QSPI_Command_IT
3 V! A. E8 T0 m9 B) X# @4 C7 V函数原型:' q* A7 Y& c+ K& Y6 _* V

, F$ M7 C* \8 t& L# X5 b
  1. HAL_StatusTypeDef HAL_QSPI_Command_IT(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd)6 G! x& F1 F: v7 z9 d
  2. {
    * H, e+ T1 z2 H! }
  3.   HAL_StatusTypeDef status;6 l1 O4 A1 g- K, @1 K
  4.   uint32_t tickstart = HAL_GetTick();
    4 W* d8 D, Z0 q% V

  5.   o) k, o: {4 n4 p
  6.   /* 检测参数 */" C) \) f7 U1 Q
  7.   assert_param(IS_QSPI_INSTRUCTION_MODE(cmd->InstructionMode));
    $ i% Z; y- ~* o/ w- w$ M( O6 G
  8.   if (cmd->InstructionMode != QSPI_INSTRUCTION_NONE)
    % ]: e: M  j( |- K
  9.   {
      Y5 F. _& V. A9 {- V$ |* P
  10.     assert_param(IS_QSPI_INSTRUCTION(cmd->Instruction));% F+ Y4 c' V3 J& r2 N
  11.   }, y3 W8 g# B" l; J
  12. ) j* g( s* ?: e
  13.   assert_param(IS_QSPI_ADDRESS_MODE(cmd->AddressMode));4 p0 }" f1 S& t: J% A1 q  n
  14.   if (cmd->AddressMode != QSPI_ADDRESS_NONE)3 \+ z( `9 Z1 k, k7 {! t
  15.   {
    8 A: S- J5 o2 \# i1 ?
  16.     assert_param(IS_QSPI_ADDRESS_SIZE(cmd->AddressSize));/ t2 u5 l; H+ o! V; N4 y8 w& S
  17.   }' J: m% Q4 M) L( s
  18. ( b1 q% D& Z! E2 n7 [
  19.   assert_param(IS_QSPI_ALTERNATE_BYTES_MODE(cmd->AlternateByteMode));) C5 n) Y1 u$ q. W1 x! m5 m
  20.   if (cmd->AlternateByteMode != QSPI_ALTERNATE_BYTES_NONE)
    1 y7 s# `# S5 A6 ?+ m+ F! W
  21.   {6 T+ R% t6 T+ K  ^+ ~: P
  22.     assert_param(IS_QSPI_ALTERNATE_BYTES_SIZE(cmd->AlternateBytesSize));0 L9 B- N3 G' R, P# o
  23.   }
    6 `" U5 O3 `- g: L7 p2 g" H

  24. % _5 |1 e1 W& [) A8 ]8 K. G& I
  25.   assert_param(IS_QSPI_DUMMY_CYCLES(cmd->DummyCycles));
    9 L5 a0 q1 i" ]# E
  26.   assert_param(IS_QSPI_DATA_MODE(cmd->DataMode));
      S" C9 C7 o* |* @) @! `5 ?

  27. 2 y" }# n! ~$ q- L2 u4 H6 \8 z
  28.   assert_param(IS_QSPI_DDR_MODE(cmd->DdrMode));- i! d3 N1 Z4 f' X/ P; s- W
  29.   assert_param(IS_QSPI_DDR_HHC(cmd->DdrHoldHalfCycle));
    ; e8 d1 C9 S/ X
  30.   assert_param(IS_QSPI_SIOO_MODE(cmd->SIOOMode));
    5 z+ E4 Y5 ?& s5 U5 H  i. c

  31. ! k( F3 _" x, Z7 ?$ p
  32.   /* 上锁 */
    : f% s  }0 V0 J# _3 |; |$ z
  33.   __HAL_LOCK(hqspi);
    + k8 }& N1 u: `! [; e2 V" o
  34. ! Q* x1 N' F; N( L. T1 C$ m
  35.   if(hqspi->State == HAL_QSPI_STATE_READY)
    & X2 c; r% t0 E9 p0 @
  36.   {% j' T; n" X$ k5 w
  37.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;+ u+ T% e" m& Z! |% j2 i2 k3 O
  38. . I. Z: y7 X. l/ U
  39.     /* QSPI忙 */: y$ [4 d) ^: ^8 I
  40.     hqspi->State = HAL_QSPI_STATE_BUSY;% B' G- Z, a) l* v

  41. % D" Y4 T- }* F7 x& j, m! F
  42.     /* 等待BUSY标志复位 */
    7 E- w+ P  F8 _# i& M
  43.     status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, hqspi->Timeout);
    - _) B0 J( K& J/ c7 {
  44. + f7 P: p5 j; [. N9 M& F
  45.     if (status == HAL_OK)  r0 J0 g* U% i7 L4 A. E
  46.     {
    0 [) f$ z  @8 Q$ z) V/ R) ~
  47.       if (cmd->DataMode == QSPI_DATA_NONE)
    ; @0 m8 }9 I; h: t, h& n
  48.       {3 I4 o* k% j: Q4 {' Y+ A% Q
  49.         /* 清除中断 */( {5 V" `# h7 n% u! j$ F! G
  50.         __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TE | QSPI_FLAG_TC);
    & j4 I* J7 k; Z; S5 {9 o
  51.       }" T% l; P$ V* a
  52. , k/ |9 T/ G/ A& u: @! v4 d( F
  53.       /* 调用所有配置函数 */
    , g8 x& I' D- a  s
  54.       QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_INDIRECT_WRITE);
    9 `% R8 @8 b# ~" s/ `# V5 m( J& g
  55. ) x& `7 {' z# H& ]+ a6 l
  56.       if (cmd->DataMode == QSPI_DATA_NONE)
    6 v! A, X- w, b  Q
  57.       {
    . v) _0 z/ S6 a* A6 y. T
  58.         /* 无数据阶段,配置完毕后,立即开始传输,所以机会TC和TE中断 */
    + Q1 \# y, P2 a+ v  I$ l2 j
  59.         /* 解锁 /
    9 f. E) }# K# n1 o3 ^/ D
  60.         __HAL_UNLOCK(hqspi);
    ) h, ~! m  a9 z6 j
  61. ( |, y. j1 w  Q* k" Z" a
  62.         /* 使能TE(Transfer Error)和TC中断 */$ B* @: K8 N$ B! I  r$ k$ D& V
  63.         __HAL_QSPI_ENABLE_IT(hqspi, QSPI_IT_TE | QSPI_IT_TC);+ L& m7 }7 w8 Z5 Z! ~6 l3 _6 @" \
  64.       }
    + _# |) q: c# M7 _* X/ b
  65.       else
    # ]: D4 R+ U$ Y3 Q5 u
  66.       {7 p4 v$ J5 ?; r, i, s
  67.         /* 更正QSPI状态 Update QSPI state */  s8 w* F' _3 l; w2 X
  68.         hqspi->State = HAL_QSPI_STATE_READY;5 ~9 K2 h' O* Y! Z8 S; T6 E
  69. ! Y8 I0 T8 x1 o' i
  70.         /* 上锁 */! |- H$ i, R# q' y" ?" T
  71.         __HAL_UNLOCK(hqspi);. A+ L3 i5 Q& m
  72.       }
    . P+ m2 {9 ~2 L, m: g# J
  73.     }
    * k, t1 v) ~  L6 ~. n% Q
  74.     else
    % w+ m2 _  r$ ?! H) r1 O
  75.     {
    ( G2 z# j/ ?1 z5 T/ r$ @
  76.       /* 解锁 */
    & `3 D$ Q0 l7 M! p5 p6 M9 T/ A
  77.       __HAL_UNLOCK(hqspi);: `" y( R! A4 g4 Z& k: M& z$ |
  78.     }$ L/ o0 m/ S) e5 }: p
  79.   }
    , j3 B, [  d0 a& H6 k
  80.   else
    & F4 i5 }9 Q% G  y& w) F+ M1 N
  81.   {
    . B* J* P1 O5 U3 m  g  Q
  82.     status = HAL_BUSY;
    . K) @1 x' i( E( N/ L3 ]

  83. . p* z9 W  g& B  q: U" d" r
  84.     /* 解锁 */
    : z) N" Q1 O" D; S% _5 W! n
  85.     __HAL_UNLOCK(hqspi);) E6 D3 R% P) E/ H7 b' z3 y6 P/ D
  86.   }0 t/ [' U7 M* x3 S* m/ D% c
  87. $ `  [% h2 J7 Z1 x$ w5 P9 R
  88.   /* 返回状态 */& v% _( n9 L! N
  89.   return status;0 z4 i2 g9 B+ g# I
  90. }
复制代码

3 _# C8 T' K. D5 l! z9 a$ C函数描述:
) j! b) u: i( w4 T( b  Y& z* r" p& a' Y. t6 p. J: |; \0 L
此函数主要用于为QSPI Flash发送操作命令,中断方式。( B- f7 f. X4 z( V# u1 |
4 F3 K" }* m3 [0 _
函数参数:
/ M9 v9 ^) |' D1 c2 x* D+ l6 o$ A5 P, V+ H# z" n
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
, Z# Y( u8 L9 j- i7 T  第2个参数是QSPI_CommandTypeDef类型结构体变量,详见本章3.4小节。/ D% k6 g$ Z2 f/ y  ]1 M3 H9 R
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。9 G* g8 s0 X1 Z7 `7 r
使用举例:$ F2 ?9 w* v5 O; l9 k) W
, Z# |$ F& x$ ~9 ~; r; v
  1. /*
    " g. ?+ `8 N- D9 Q+ U
  2. *********************************************************************************************************1 p: s: h3 p3 n) g# h( k2 b$ L
  3. *    函 数 名: QSPI_WriteEnable0 P* {# g) x7 O- x( a0 f
  4. *    功能说明: 写使能7 S( X$ N/ F: w- V( a8 J; \- n1 K
  5. *    形    参: hqspi  QSPI_HandleTypeDef句柄。' U% c! M' k7 i7 d5 b/ ^
  6. *    返 回 值: 无
    0 M4 K: a/ n* I
  7. *********************************************************************************************************
    ( \3 u6 r: P5 g$ B! S; ]2 A# F
  8. */
    ; ]: V8 r6 A8 Q# X
  9. static void QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi)
    6 h* O2 @( m* f, |
  10. {
    6 O# Q: \& {9 a# p
  11.     QSPI_CommandTypeDef     sCommand = {0};
    & b! o9 B8 i1 ]. C: b

  12. 6 x, r$ l+ d& j) {
  13.     /* 基本配置 */
    4 n0 Z: z) R- q- N+ c0 m
  14.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */
    / F9 F7 L0 a) {- E9 C2 r
  15.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */' q: ]1 f5 L7 S1 u4 {+ p4 d+ z6 m
  16.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
    6 b( i9 O) r0 E& s* B5 J$ ?/ P
  17.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */! l" E9 `' r( C0 |
  18.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */- J4 n; y+ w! r! l
  19.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;     /* 每次传输都发指令 */
    : i5 w! O! L& Z6 G/ ]

  20. " K7 b. m. ^/ }! F3 L0 N7 k% F
  21.     /* 写使能 *// ^$ I# \6 |! l) q/ e% {
  22.     sCommand.Instruction       = WRITE_ENABLE_CMD;  /* 写使能指令 */
    5 B1 ]9 q; h& R# `) |% Z
  23.     sCommand.AddressMode       = QSPI_ADDRESS_NONE; /* 无需地址 */% R% t# t& ^$ [, o( X) F
  24.     sCommand.DataMode          = QSPI_DATA_NONE;    /* 无需数据 */
    0 y9 [$ @% R" H* v, U3 r" G
  25.     sCommand.DummyCycles       = 0;                 /* 空周期  */
    * L6 m- W% D0 Q4 i, U% u# X; t- b( D

  26. , F( r# }0 X1 Y7 P4 H* v6 f
  27.     if (HAL_QSPI_Command_IT(&QSPIHandle, &sCommand) != HAL_OK)7 z" j0 Y$ u* a" B6 @
  28.     {
      d  K8 b& z, O" o/ O6 p
  29.         Error_Handler(__FILE__, __LINE__);1 m2 N& `, t7 E
  30.     }    ( T8 W2 ~) t2 ~+ a* e$ Z
  31. }
复制代码
* Q8 H7 D; J# F, }1 {
78.4.5 函数HAL_QSPI_AutoPolling. ]) Z/ t5 H  e& Q: b
函数原型:  g4 a# H% b5 q4 y. u

3 m0 O& C  ~, H0 D8 q! o
  1. HAL_StatusTypeDef HAL_QSPI_AutoPolling(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, QSPI_AutoPollingTypeDef *cfg, uint32_t Timeout)
    % z$ }# t( P4 e+ P, j9 {' I
  2. {) o. J! H6 R, A* H
  3.   HAL_StatusTypeDef status;
    / m# _* Z! y% ~: a% f! Q2 b
  4.   uint32_t tickstart = HAL_GetTick();( ]0 C, D' u+ H( U5 }( r8 z

  5. # V; J4 c: @. h8 u7 q3 t
  6.   /* 检查参数 */" E# Q: x: b, O7 Z' ]* o# X$ J! C) Z
  7.   assert_param(IS_QSPI_INSTRUCTION_MODE(cmd->InstructionMode));) R7 |" q5 V0 x$ T9 ?
  8.   if (cmd->InstructionMode != QSPI_INSTRUCTION_NONE)
    % i% \2 |4 M2 H1 m8 s0 q
  9.   {
    2 o  K: @$ ]3 z) y
  10.     assert_param(IS_QSPI_INSTRUCTION(cmd->Instruction));
    - k  P7 _4 n7 \% L8 T' Z" n
  11.   }. _% ~( Z' R4 z

  12. / o( O8 a) @. O% k! W& M5 l
  13.   assert_param(IS_QSPI_ADDRESS_MODE(cmd->AddressMode));
    / N1 A& b, r! e( X* s: Z2 D
  14.   if (cmd->AddressMode != QSPI_ADDRESS_NONE)7 ]* n+ K! l; n1 F- _5 C; j9 k2 b
  15.   {+ P) n, c' h. N: b7 S& A
  16.     assert_param(IS_QSPI_ADDRESS_SIZE(cmd->AddressSize));
    8 x; m* S7 C, {" u3 }; `
  17.   }
    * s' ]3 m& k# x/ o: \

  18. $ e$ w2 h( |( G0 k6 v
  19.   assert_param(IS_QSPI_ALTERNATE_BYTES_MODE(cmd->AlternateByteMode));
    ) f3 t6 v" G  a: o8 x9 ?* X+ @
  20.   if (cmd->AlternateByteMode != QSPI_ALTERNATE_BYTES_NONE)
    # w. O2 b! Y" y1 j
  21.   {8 i" m0 f5 B/ k# x1 N- o' C
  22.     assert_param(IS_QSPI_ALTERNATE_BYTES_SIZE(cmd->AlternateBytesSize));
    ! ~3 |2 X$ J* a4 J- G# u4 c
  23.   }0 x8 s% p5 ~( k6 l' u

  24. , C5 r) v- `' e, G5 v/ |
  25.   assert_param(IS_QSPI_DUMMY_CYCLES(cmd->DummyCycles));
    3 o7 ?9 \2 t, t4 p6 C8 j* _
  26.   assert_param(IS_QSPI_DATA_MODE(cmd->DataMode));' H8 a8 g! W* ~4 W5 A: H

  27. 9 [% K# D, m3 e3 r6 \6 `$ E
  28.   assert_param(IS_QSPI_DDR_MODE(cmd->DdrMode));
    ; D6 q# p6 j, s1 W9 K7 G
  29.   assert_param(IS_QSPI_DDR_HHC(cmd->DdrHoldHalfCycle));
    5 M  i) E$ S" \1 v2 @) {
  30.   assert_param(IS_QSPI_SIOO_MODE(cmd->SIOOMode));
    & y3 `; W! f9 }% _: o2 @7 y
  31. ; w  M. J& f* [8 o8 m& |& R7 N/ v' n/ j
  32.   assert_param(IS_QSPI_INTERVAL(cfg->Interval));0 r$ v' ~" f# {( l! e
  33.   assert_param(IS_QSPI_STATUS_BYTES_SIZE(cfg->StatusBytesSize));" W) p2 B2 y! q& R
  34.   assert_param(IS_QSPI_MATCH_MODE(cfg->MatchMode));
    ) \0 |# {) w3 d$ r( @. j' E
  35. % C5 |! w1 d! [" O: a4 d: z
  36.   /* 上锁 */% R& _+ |7 `! ]! `
  37.   __HAL_LOCK(hqspi);2 i, R4 M  o, d4 O4 E
  38. % I7 o3 Z% ^6 _6 e
  39.   if(hqspi->State == HAL_QSPI_STATE_READY)
    4 o: b4 Q8 W6 U; n- y  ~' ~
  40.   {7 T9 s3 A+ V$ j* `  j+ ^
  41.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
    ' W$ Z1 S( }$ j: `
  42. : J" Q* O4 ^4 I$ Z
  43.     /* 更新状态 */: L* O% n; e- ~- `7 y) ~  i* i
  44.     hqspi->State = HAL_QSPI_STATE_BUSY_AUTO_POLLING;
    * C) I4 g) u8 i$ d& ^0 E

  45. 6 r# |' E- Y; H9 S5 R
  46.     /* 等待BUSY复位标志 */2 u. `9 Q$ v. r; {2 J& w! B
  47.     status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, Timeout);
    ' Z1 J" E- d# s( `) U

  48. ! v. }' ?$ X6 I
  49.     if (status == HAL_OK)
    6 E2 V0 U4 [8 ~) m) b9 I. l  C0 p3 ~
  50.     {3 q9 {" \$ e( q- P; Z% r0 k7 J/ _
  51.       /* 配置QSPI匹配位 */
    # l4 k% z8 t+ _% v
  52.       WRITE_REG(hqspi->Instance->PSMAR, cfg->Match);+ g. y9 D3 e) K& ?+ K- }; x! R6 f

  53. ' W* I! k  y. X* t5 `' G
  54.       /* 配置QSPI屏蔽位 */
    3 e9 \2 @, E3 p* f) J
  55.       WRITE_REG(hqspi->Instance->PSMKR, cfg->Mask);5 G, D3 `, u* X; R9 J) y

  56. 9 A9 |2 b5 x" O" L% f) `
  57.       /* 配置查询时间间隔 */
    % r* u: s4 v& x
  58.       WRITE_REG(hqspi->Instance->PIR, cfg->Interval);
    / r5 w" N2 m- R- ?- P  z" A8 {. S

  59. 2 d0 V. y* D* l$ N! r+ w
  60.       /* 配置匹配模式,使能自动停(否则阻塞方式无限等待) */# w9 e6 X: K4 Q
  61.       MODIFY_REG(hqspi->Instance->CR, (QUADSPI_CR_PMM | QUADSPI_CR_APMS),7 Q: W5 u5 F( R% a# C7 H
  62.                (cfg->MatchMode | QSPI_AUTOMATIC_STOP_ENABLE));
    / {4 `; H' _5 P* Y

  63. ; `, n* w" T8 X# D6 Y1 T9 N
  64.       /* 调用配置函数 */7 m! ?0 z, [" _1 E6 F
  65.       cmd->NbData = cfg->StatusBytesSize;5 N+ p' o9 |, A
  66.       QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_AUTO_POLLING);3 _% G$ Z$ u1 t9 p$ E5 l
  67. ( @% u+ f/ j3 c/ w
  68.       /* 等待SM标志 */# M$ W5 S$ N4 O7 c1 E+ ]: M# j
  69.       status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_SM, SET, tickstart, Timeout);. j3 _) B; x4 {* q, z3 i" p

  70. & E3 {6 u2 }! i+ t
  71.       if (status == HAL_OK)( K  }6 L  ?2 [7 f: {2 @! Y% g
  72.       {9 p% d" ^9 p" x. c8 ^
  73.         __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_SM);
    ; w. _1 a( G3 h' b% `. M8 ~# f
  74. ; N; a2 W9 P9 {
  75.         /* 更新状态 */
    2 r5 X) r! {* \$ \$ h6 J* i
  76.         hqspi->State = HAL_QSPI_STATE_READY;
    5 b3 [* G; [4 a" _0 p: M1 v4 a% k/ Q
  77.       }/ r: r9 k0 K3 c* s# v
  78.     }
    1 y& h. c, U; |& J$ n4 Y
  79.   }8 b3 u* ~& b& w5 p2 y$ {7 z
  80.   else
    ; P; x3 M# s" m0 x% g
  81.   {
    3 K, P3 a- }* r) ^# L
  82.     status = HAL_BUSY;
    ' `* E7 k& E/ b" ?6 g1 l0 u
  83.   }% B% \0 f1 N$ m- d
  84. 0 ^4 A; ?' D- h
  85.   /* 解锁 */
    1 F# T8 i. C. w% _+ X6 B3 s* G3 H
  86.   __HAL_UNLOCK(hqspi);
    , V0 s3 m( _& G& Y/ b
  87. * j( g" P; g: u& R7 I$ n
  88.   /* 返回状态 */
    + X! F& k! j% C3 g% I" t' \: p0 @
  89.   return status;4 D$ ?2 a+ k9 Y6 r
  90. }
复制代码
9 ~2 g6 T; S0 D& F' S. j  F5 s
函数描述:
' c( k" X7 N$ N4 g& K) T& w/ Z( q/ t: q  K/ t/ M/ r% `% q
用于状态标志查询,函数采用的查询方式。& {0 h9 U( L+ C
" J- S- L5 P( g3 x
函数参数:
7 d% @( e3 X9 H7 \% o! @, B7 `8 C* l# {, t/ w) }; n& o2 k
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
# I! p% F8 s0 o! W! {; A  第2个参数是QSPI_CommandTypeDef类型结构体变量,详见本章3.4小节。4 J, p& a% R( @  o) D8 C8 s
  第3个参数是QSPI_AutoPollingTypeDef类型结构体变量,详见本章3.5小节。+ F3 Q+ d4 z, V) u: m/ A' E
  第4个参数是溢出时间,单位HAL库时间基准,单位1ms。: \+ M9 l4 L. ]: {' S2 N
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
$ R4 E) j; {  o3 C- z+ J( G使用举例:/ [: p/ Y* |: o0 W
) D0 n' O9 V8 L0 l, @: S8 e$ X
  1. /*2 m# _$ I2 J" @" g5 i
  2. *********************************************************************************************************2 i* S+ k/ W) R& T1 E7 k' O# T8 H
  3. *    函 数 名: QSPI_AutoPollingMemReady9 A8 n  D/ R) M7 m/ b/ ^1 _! B
  4. *    功能说明: 等待QSPI Flash就绪,主要用于Flash擦除和页编程时使用$ a  [' H. q( L1 Q
  5. *    形    参: hqspi  QSPI_HandleTypeDef句柄! @. p, O7 D0 I, Y, e( F( W0 p
  6. *    返 回 值: 无
    ) z7 P- W" K) @5 f; ~
  7. *********************************************************************************************************6 w1 J. V' C# K9 a- B3 n0 V* R
  8. */# ^" }% f4 @# R7 p7 n
  9. static void QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi)* B$ z4 g3 a+ P9 \; e
  10. {
    7 r2 v% T2 h# r- t
  11.     QSPI_CommandTypeDef     sCommand = {0};% ^. J' k# f* }$ Y9 V
  12.     QSPI_AutoPollingTypeDef sConfig = {0};
    2 G. V2 g$ p2 C# l

  13. : w+ O' i$ N8 y
  14. $ @8 u: t, x# Q) i$ S3 b8 K
  15.     /* 基本配置 */
    + ]" n  F+ d1 Z4 j  S
  16.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */
    - e7 F; j7 k+ u; q4 @
  17.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */
    % D: J* C, P7 {+ Y. Q1 _
  18.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */2 {' T) V$ E2 V6 A
  19.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */6 y- e( M) P% W* J% H+ l" i
  20.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */
    * a) t2 I' p& a. a6 s8 I
  21.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;     /* 每次传输都发指令 */+ M# O- U2 ]& U9 z3 h5 f  C' h

  22. 9 a9 u( }6 y8 a& T1 f4 U& b/ z
  23.     /* 读取状态*/
    3 ?7 U7 ?- ?2 q& I) e
  24.     sCommand.Instruction       = READ_STATUS_REG_CMD; /* 读取状态命令 */
    2 ^! Z; B" M. b! p7 b. Q7 a* u' |
  25.     sCommand.AddressMode       = QSPI_ADDRESS_NONE;   /* 无需地址 */
    ' R# e$ s+ d- B7 [% O
  26.     sCommand.DataMode          = QSPI_DATA_1_LINE;    /* 1线数据 */+ [* }( l0 v7 \  y6 ]: v
  27.     sCommand.DummyCycles       = 0;                   /* 无需空周期 *// q* w1 J/ ?/ t, @. g" _

  28. 4 i0 f9 Z7 K) j7 w, N2 }
  29.     /* 屏蔽位设置的bit0,匹配位等待bit0为0,即不断查询状态寄存器bit0,等待其为0 */
    ' L! b- B9 W1 F5 A- R
  30.     sConfig.Mask            = 0x01;, O: P: e- X$ p
  31.     sConfig.Match           = 0x00;
    + \/ L5 R4 ]0 g# M) R( O, z6 n7 i
  32.     sConfig.MatchMode       = QSPI_MATCH_MODE_AND;
    1 X8 j/ R# C0 }3 _4 V5 K
  33.     sConfig.StatusBytesSize = 1;
    9 S# b) n; C2 q& S  U- ~
  34.     sConfig.Interval        = 0x10;* W' N: I, z5 b
  35.     sConfig.AutomaticStop   = QSPI_AUTOMATIC_STOP_ENABLE;
    1 s5 {$ V: n- ]- R' [4 ]# M: H

  36. ' {- u4 _3 [' |+ t9 @
  37.     if (HAL_QSPI_AutoPolling(&QSPIHandle, &sCommand, &sConfig, 10000) != HAL_OK)  ^( O, ^+ F0 b
  38.     {2 z0 |4 b9 q2 K1 Y
  39.         Error_Handler(__FILE__, __LINE__);
    ! q6 ^) I6 j2 @2 n3 L8 a+ O
  40.     }
    1 u7 S- J! n' y# t9 n, o
  41. }
复制代码

3 Q: E6 q) O9 z78.4.6 函数HAL_QSPI_AutoPolling_IT
# ?: N4 ]) n* h3 q( e7 z函数原型:( m9 \: E4 V/ P; b  x1 O: Q2 ?, Z
3 ^! M* i' l, X  H
  1. HAL_StatusTypeDef HAL_QSPI_AutoPolling_IT(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, QSPI_AutoPollingTypeDef *cfg), Z# Y1 }# [% _9 F' ?) \
  2. {2 q; z: s7 K  X2 S) ^0 u
  3.   HAL_StatusTypeDef status;$ u, p5 I# B9 A9 _
  4.   uint32_t tickstart = HAL_GetTick();; y# i: ]$ s/ ?- e. }
  5. ; o" v2 m) m% k$ ]1 o! Y. O
  6.   /* 检查参数 */$ ~  T$ n' Z8 o# F
  7.   assert_param(IS_QSPI_INSTRUCTION_MODE(cmd->InstructionMode));
    ) F" w3 R6 p# ~% [$ g
  8.   if (cmd->InstructionMode != QSPI_INSTRUCTION_NONE)
    , ^# e- t# |; _8 ~2 a2 m& b& J
  9.   {
    - ^0 t3 z! x2 P. Z
  10.     assert_param(IS_QSPI_INSTRUCTION(cmd->Instruction));7 a& ^( K, X- m1 M8 l
  11.   }5 k& M2 Z/ z3 j% g: D
  12. / @  j& v8 o. Y' s
  13.   assert_param(IS_QSPI_ADDRESS_MODE(cmd->AddressMode));% d2 W1 R6 V+ U0 L
  14.   if (cmd->AddressMode != QSPI_ADDRESS_NONE)
      V2 p7 ]0 Z7 V) ~, [, w0 h
  15.   {
    & L- c; ?( D+ ^, K8 ]% G6 F0 J5 w
  16.     assert_param(IS_QSPI_ADDRESS_SIZE(cmd->AddressSize));
    0 a+ p- t/ _" t. O  N
  17.   }
    % E( r5 H# ]/ j/ O4 H

  18. 0 E% z/ n9 w( V+ e" P: g9 v$ _
  19.   assert_param(IS_QSPI_ALTERNATE_BYTES_MODE(cmd->AlternateByteMode));
    ' Z. O( V; K9 L7 V  c
  20.   if (cmd->AlternateByteMode != QSPI_ALTERNATE_BYTES_NONE), J2 ]6 b, C4 F- w+ i
  21.   {4 j; Y' n3 n& o2 b- j
  22.     assert_param(IS_QSPI_ALTERNATE_BYTES_SIZE(cmd->AlternateBytesSize));1 ^  N4 M, W* ~0 P, g1 v
  23.   }
    * t" a  p& c" z7 W7 [

  24. 5 F6 u4 h7 X4 m; c7 r) H8 A3 x
  25.   assert_param(IS_QSPI_DUMMY_CYCLES(cmd->DummyCycles));
    ; u! a! N. M1 v4 `* [/ j
  26.   assert_param(IS_QSPI_DATA_MODE(cmd->DataMode));
    ) i8 n/ u- k, N$ ?
  27. 4 x; k$ }1 U2 |2 g# F: A0 i
  28.   assert_param(IS_QSPI_DDR_MODE(cmd->DdrMode));
    ) F9 E  t: a& V: {
  29.   assert_param(IS_QSPI_DDR_HHC(cmd->DdrHoldHalfCycle));3 O# G- V' l* z0 {  ]% U
  30.   assert_param(IS_QSPI_SIOO_MODE(cmd->SIOOMode));( A3 F' D4 i7 B* T) Y+ F

  31. ; p: h# E7 G4 p0 w# L
  32.   assert_param(IS_QSPI_INTERVAL(cfg->Interval));/ S4 n- _  F! w0 ~" N& A! ~9 H
  33.   assert_param(IS_QSPI_STATUS_BYTES_SIZE(cfg->StatusBytesSize));$ G; ~1 y7 z9 w9 u
  34.   assert_param(IS_QSPI_MATCH_MODE(cfg->MatchMode));
    1 u& t# ]8 V& H. X
  35.   assert_param(IS_QSPI_AUTOMATIC_STOP(cfg->AutomaticStop));
    5 e6 T; C- ]7 l; \

  36. 9 M+ X6 Z6 G: K% e5 \' e' `/ _0 f
  37.   /* 上锁 *// c4 _3 z9 e; A4 W1 e2 W
  38.   __HAL_LOCK(hqspi);
    8 c6 B- K/ a5 i
  39. , e' I7 K- ~3 I$ m
  40.   if(hqspi->State == HAL_QSPI_STATE_READY)
    5 |0 {" H7 X1 b8 r" K
  41.   {3 V5 f0 u- G$ _; b0 k, W
  42.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
    1 F9 G- A/ M, \0 s" p

  43.   s' J( v  @( E, b3 \/ \
  44.     /* 更新状态 */' q, X6 H) u! V; `
  45.     hqspi->State = HAL_QSPI_STATE_BUSY_AUTO_POLLING;
    + T& q6 B# J) [: ]% ?! r) U5 M
  46. 7 I' |- w. d. i  g6 \
  47.     /* 等BUSY标志复位 */
    / f9 W5 j0 S& O3 S
  48.     status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, hqspi->Timeout);
    9 \. e* z$ l- U0 k  f. E8 \8 z
  49. ( A- }" S& j+ G. i% z2 H2 e
  50.     if (status == HAL_OK)5 V- H9 V4 }; s) O/ S
  51.     {
    ( u6 Z2 L: @8 x- Y
  52.       /* 配置匹配值 */, K/ |, B$ m- Q7 T. i4 ^6 B! R
  53.       WRITE_REG(hqspi->Instance->PSMAR, cfg->Match);
    3 P3 }# a3 H: R* F' ?9 @" O+ m
  54. $ `1 h9 Q: m# h, F
  55.       /* 配置屏蔽值 */1 e4 m) h; E! \7 s, s
  56.       WRITE_REG(hqspi->Instance->PSMKR, cfg->Mask);6 P( L- N3 Y7 ^/ _

  57. ! F2 H& A9 H8 o" P& S4 w% R
  58.       /* 配置查询间隔 */
    6 v5 R3 b' ]2 T/ O1 [
  59.       WRITE_REG(hqspi->Instance->PIR, cfg->Interval);% N& I+ R0 P: W  n- e: U# J6 L8 ]7 |
  60. # V/ m9 L& c8 m5 d" g/ |* s
  61.       /* 配置匹配模式和自动停止位 */
    4 e& T9 P# R6 h4 t1 k, _
  62.       MODIFY_REG(hqspi->Instance->CR, (QUADSPI_CR_PMM | QUADSPI_CR_APMS),& ~4 P3 L8 J9 {* b2 I# N! B
  63.                (cfg->MatchMode | cfg->AutomaticStop));! Z- F: V1 M+ L. [' R6 |

  64.   k1 O$ T- G5 U
  65.       /* 清标志 */3 X! n. N( Y5 A7 B9 l& j
  66.       __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TE | QSPI_FLAG_SM);
    / P% Z3 n6 Q9 S3 V7 \. Q

  67. 4 t- [5 B* l  G. A8 k; K" S
  68.       /* 调用配置函数 */; V, z( ~/ n( y5 m# ^8 q
  69.       cmd->NbData = cfg->StatusBytesSize;6 I& O9 |; m9 o) s. t: q; d
  70.       QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_AUTO_POLLING);5 d6 D5 e& R5 J
  71. % H. E4 g* _1 @9 @. \9 `9 e
  72.       /* 解锁 */
    ) v1 b4 F' M4 ?2 q) ~2 i
  73.       __HAL_UNLOCK(hqspi);4 O9 I9 B' e* M# U2 ]
  74. * j1 k, y/ w7 Z# v2 S
  75.       /* 使能SM(status match)和TE(Transfer Error)标志 */
    % K; [: ]: l0 Y% T9 t# Y- J
  76.       __HAL_QSPI_ENABLE_IT(hqspi, (QSPI_IT_SM | QSPI_IT_TE));6 x' E8 y; G; l1 ~' R: D

  77. 5 J3 V& ?2 k! h( `8 M4 d0 _
  78.     }: L/ d! O; Y% r; ]. e* ?
  79.     else* c4 g2 P+ q8 A6 g8 K7 ^5 f
  80.     {# V+ _9 q: Y! t" b5 R) V' D
  81.       /* 解锁 */
    ) {3 Q3 E- o8 |. g: G: \4 i. V
  82.       __HAL_UNLOCK(hqspi);5 A' [$ e% m% M/ Y
  83.     }
    5 u% P% l" ]; D$ H9 r
  84.   }
    2 S1 l' C& I6 W. _& ]# O
  85.   else
    ( t( B  x; j% H" K! t
  86.   {
    0 @0 \3 m) _* c) Q4 Y& ]
  87.     status = HAL_BUSY;
    # s+ Q  i5 G, K) O: E

  88. # B0 A* w# K6 ^( I% F6 A; Z
  89.     /* 解锁 */
    7 V+ T; c3 _& F' A+ i* H+ ~
  90.     __HAL_UNLOCK(hqspi);) y2 l  S. z/ h% }. C* t# o/ K
  91.   }) g) A! Q. D- a, U& `3 B

  92. 1 u, m% K# N9 `: F/ j6 n2 e: k
  93.   /* 返回函数状态 */6 E& g" Y- z$ H  m/ r7 O
  94.   return status;
    ! S* [5 u* U1 y6 b% D6 R( w# p
  95. }
复制代码
+ R2 W: O' l" h; U$ E/ }$ g; W. c
函数描述:
1 J' h9 z$ u! v' u+ i0 c2 ~7 R7 E/ \) g4 z. A, s
用于状态标志查询,函数采用的中断方式。, V0 D* k* j$ ^/ N; c

3 G, I: w: v. Q函数参数:
. i- b  f3 S$ U8 f( [, e& k$ C9 E0 G1 R
' v$ h/ t- a+ M& P4 R! ^  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。4 O. U' ?  [" t% I- o" K9 X1 K' j
  第2个参数是QSPI_CommandTypeDef类型结构体变量,详见本章3.4小节。1 X6 h5 D7 L9 d6 ?* x- p/ k
  第3个参数是QSPI_AutoPollingTypeDef类型结构体变量,详见本章3.5小节。
) u, _8 B( p! N4 K  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。$ J! K$ T% i9 e, \' b
使用举例:* d" T  K. U) t1 O
: y8 k1 }9 f1 b* a# E5 c
  1. /*! Q8 r2 S1 I9 O
  2. *********************************************************************************************************
    ' w* h0 S# A$ `* X. c
  3. *    函 数 名: QSPI_AutoPollingMemReady
    + u  B3 V3 V# r
  4. *    功能说明: 等待QSPI Flash就绪,主要用于Flash擦除和页编程时使用0 Z  D  v+ t. G& \! k) `
  5. *    形    参: hqspi  QSPI_HandleTypeDef句柄
    # k/ ]) a. _- f- D3 R# P4 B4 T: ~, o  C
  6. *    返 回 值: 无
    - H0 w5 B/ D) V6 W1 |
  7. *********************************************************************************************************/ t' U9 V" ?$ H1 T
  8. */
    ! w) p% N0 A( Z5 I5 L$ E
  9. static void QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi)
    ( `9 {0 g+ z; ~
  10. {
      {4 O% A5 Q4 {  m$ g% Z' \, g) k( {* l
  11.     QSPI_CommandTypeDef     sCommand = {0};
    : m! E) ]: c+ b" a: \! V# U
  12.     QSPI_AutoPollingTypeDef sConfig = {0};
    7 O2 f# f3 S+ B0 j* {7 F

  13. - X- y, O7 r" J; r8 d6 T

  14. * ^3 f3 N6 E8 o1 R: s
  15.     /* 基本配置 */0 P# g% \4 G) P% b  Y4 o
  16.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */, m. u: z/ n4 h/ L
  17.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */
    . V- Z% W/ R$ S& w6 @& y
  18.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
    + M2 @5 u  X0 C) a0 n9 `* t7 L
  19.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */, b& ~, T( W2 u' q+ O0 ^
  20.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */2 I- P! u7 c6 S! ^( I
  21.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;     /* 每次传输都发指令 */
    , ^9 P( z7 S3 G8 ?6 B3 X& F; k8 `
  22. 2 ]. T$ N$ ?, v7 |% J+ ~- m
  23.     /* 读取状态*/
    3 N7 m7 ?: K& L8 J/ v" d
  24.     sCommand.Instruction       = READ_STATUS_REG_CMD; /* 读取状态命令 */
    0 X% z' u/ @9 r5 B, J
  25.     sCommand.AddressMode       = QSPI_ADDRESS_NONE;   /* 无需地址 */
    ; X8 Q0 F, j" z; K- H' ~
  26.     sCommand.DataMode          = QSPI_DATA_1_LINE;    /* 1线数据 */
    - O0 M4 D' O8 P- l' }) `
  27.     sCommand.DummyCycles       = 0;                   /* 无需空周期 */
    & R1 A5 y/ P' x

  28. ; g+ N2 ^7 D( J0 q0 J) E: U0 ^
  29.     /* 屏蔽位设置的bit0,匹配位等待bit0为0,即不断查询状态寄存器bit0,等待其为0 */
    ; u5 s2 W% D. c# }1 ~
  30.     sConfig.Mask            = 0x01;
    + `2 A& q$ C8 z( H
  31.     sConfig.Match           = 0x00;
    : }3 J6 D3 G2 {# W5 h2 e8 o
  32.     sConfig.MatchMode       = QSPI_MATCH_MODE_AND;& E$ V8 ]# n1 p" K
  33.     sConfig.StatusBytesSize = 1;8 `6 p1 f& D7 d5 ^
  34.     sConfig.Interval        = 0x10;
    : t# I" K+ X. c2 F
  35.     sConfig.AutomaticStop   = QSPI_AUTOMATIC_STOP_ENABLE;
    ; b! t" ?3 p( ?

  36. 6 e2 c4 N( f( I" c
  37.     if (HAL_QSPI_AutoPolling_IT(&QSPIHandle, &sCommand, &sConfig) != HAL_OK)3 G: A' w* s# j" u; Y
  38.     {
    # ]: X( o" k- J0 o/ c( S
  39.         Error_Handler(__FILE__, __LINE__);3 e+ W6 p! u: p& ?# ]: G1 J; e+ K
  40.     }
    - h) C8 o, z5 P  r
  41. }
复制代码

2 h. [( V4 D7 F; ?; k3 j78.4.7 函数HAL_QSPI_Transmit
! i: z8 c. Q0 [- X' W- R  e& n函数原型:
2 o! w3 K9 u( f) g7 P  d* j  v, ]# s+ w
  1. HAL_StatusTypeDef HAL_QSPI_Transmit(QSPI_HandleTypeDef *hqspi, uint8_t *pData, uint32_t Timeout)
    * @2 P* u8 g9 n/ z6 Z; Z$ H( y. }
  2. {# L0 s+ S0 ~) T" Q
  3.   HAL_StatusTypeDef status = HAL_OK;
    # ~1 Q: p/ a5 V  O1 F+ t+ Y$ q
  4.   uint32_t tickstart = HAL_GetTick();! z9 {, f( {" R
  5.   __IO uint32_t *data_reg = &hqspi->Instance->DR;
    8 k9 w! m4 x4 R0 H9 K2 H# e  e
  6. % S5 ~( C/ e" @0 K
  7.   /* 上锁 */
    9 y# D8 b  ^' l* B( x2 e
  8.   __HAL_LOCK(hqspi);
    ) [, Q9 p3 l) ^, l& y

  9. , U6 m2 G9 r1 Q( w
  10.   if(hqspi->State == HAL_QSPI_STATE_READY)
    - f4 C# i- m$ U; y
  11.   {
    3 R. W2 q$ I( k0 J( o
  12.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;) t2 k6 B/ \$ R' O" v8 L
  13. $ `9 {) y( Q9 P4 r# W3 w
  14.     if(pData != NULL )
      S! [' W3 C$ R0 v3 a
  15.     {3 A$ R' N# K: b% ?! b4 k
  16.       /* 更新状态 */
    * r5 h1 a  Y$ b8 P
  17.       hqspi->State = HAL_QSPI_STATE_BUSY_INDIRECT_TX;
    / R; S: Z) a' u4 j

  18. , e, S) x$ ]$ r1 s. {
  19.       /* 配置发送 */
    9 U; w7 O  b+ T& X) Q
  20.       hqspi->TxXferCount = READ_REG(hqspi->Instance->DLR) + 1U;
    : N3 `1 q$ n5 d6 T. _& R
  21.       hqspi->TxXferSize = READ_REG(hqspi->Instance->DLR) + 1U;& O4 E+ k3 g# T* j; }, N  {
  22.       hqspi->pTxBuffPtr = pData;
    8 ~5 S& ~; Q3 z. a
  23. # n) r. [; v! }2 ?# B# T
  24.       /* 配置QSPI,间接模式 */
    ) H, G8 w" ~. r, `
  25.       MODIFY_REG(hqspi->Instance->CCR, QUADSPI_CCR_FMODE, QSPI_FUNCTIONAL_MODE_INDIRECT_WRITE);
    ( H4 ]! O0 a! z, m4 l) O% d
  26. ( T' O7 y' a7 j" b5 k
  27.       while(hqspi->TxXferCount > 0U)  B+ B: }- Z0 a# e0 R$ z
  28.       {
    ; D9 Z3 C' h- z
  29.         /* 等待FT标志 */9 x, [- W& n; L8 s
  30.         status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_FT, SET, tickstart, Timeout);
    9 Y9 C& ^' o; u

  31. / @0 C# X- K2 j
  32.         if (status != HAL_OK)
      l" M$ e* Y: N- ~" Q) t
  33.         {, ^* l7 z0 c$ G. R8 d
  34.           break;0 }( p( E" [1 M- S6 s! w: p
  35.         }* ^2 M5 Q( o4 {2 x) X4 z
  36.   v0 q# K; ^9 H. [8 ?# g
  37.         *((__IO uint8_t *)data_reg) = *hqspi->pTxBuffPtr;
    ! c- p+ J2 r( X0 x, e! j! |4 I: h
  38.         hqspi->pTxBuffPtr++;
    ) `8 P! S5 r) {, {3 T" G% w
  39.         hqspi->TxXferCount--;
    , f) |% g4 r8 r6 @1 u  Y9 o
  40.       }
    5 P0 `0 S* ?" m* y

  41. & K$ W& B3 `# N
  42.       if (status == HAL_OK)
    4 J# O& {' w- v' y- e
  43.       {: U( V) _# v7 H. Q# w, B
  44.         /* 等待TC标志 */
    ) u$ K8 q- M$ n5 t3 ~, J0 S1 V8 Z
  45.         status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_TC, SET, tickstart, Timeout);
    4 q# }8 F6 X* g: \' i3 Q

  46. + L/ b3 E( i4 Y  K: }; `
  47.         if (status == HAL_OK)0 s2 R+ l, T3 u, \
  48.         {
    . h7 n7 A5 b4 d3 W! ~
  49.           /* 清楚传输完成 */
    4 `* B* u( Z1 i# x$ ~+ ~) l
  50.           __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TC);
    6 ~8 P1 n& g1 g7 e

  51. , P' m' [/ x3 [, Y. e5 A
  52.         }: d$ X/ n. S; [; g, N
  53.       }: J( C* e6 E3 g% G& }9 K' K
  54. 1 A/ u: u5 Z- V  A2 l
  55.       /* 更新 */
    ; t7 y* c2 q8 A6 r  C2 n) I# x
  56.       hqspi->State = HAL_QSPI_STATE_READY;" G$ d# w. w# s4 m& ?6 X
  57.     }
    5 t, V5 n) r0 r2 y" r/ g& g
  58.     else
    ( x  c) f3 H# Z" l! E) U
  59.     {
    1 z3 e% X% \/ ^1 J
  60.       hqspi->ErrorCode |= HAL_QSPI_ERROR_INVALID_PARAM;. d; i$ y1 ]* r$ L9 v
  61.       status = HAL_ERROR;$ S  W9 `0 K: Y, {% d
  62.     }1 G1 p: I0 Z& f
  63.   }9 J- |9 f4 `: o3 T. L2 S
  64.   else; t+ T$ Z  w5 z1 d+ x0 F
  65.   {
    7 y* H& F" K4 J; @
  66.     status = HAL_BUSY;
    ) s2 Q% b' p& ~* N4 S4 D5 p6 l
  67.   }- }" _) q9 J/ Y9 i  q  E

  68. . s6 j; R) A  J* }  T1 M
  69.   /* 解锁 */2 z% Z! G8 _% _
  70.   __HAL_UNLOCK(hqspi);
    - n" B1 o) k5 C9 J- j2 I5 y& V

  71. 3 l# w+ Z- p8 o( f6 d
  72.   return status;
    7 c4 `7 J; E+ S3 Y: h
  73. }
复制代码

1 K/ C  ^: c: g$ g$ m函数描述:6 W, v" Q# [3 [1 L* x, {
, S5 U' s) k7 d1 x" G
此函数用于QSPI接口数据发送,函数采用查询方式。
1 e6 b- m' H4 p/ O6 Z4 q
3 N' p+ a* I7 U; X# i) J函数参数:
3 ~: q) {) @' W% Y8 P$ A) K; `% E: H
2 Z/ d8 T$ j% P( N3 w- V  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。$ d, h8 u3 ]& T; B" k% ^! k
  第2个参数是要发送的数据地址。. {; \+ v* {/ e$ v! w9 `: h# f7 o
  第3个参数是溢出时间,单位HAL库时间基准,我们一般设置的是1ms。/ E* `' Z. p5 z8 h' P
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
/ V8 v2 v( Z  p# P$ \1 N3 h4 ?使用举例:7 Y6 ], B0 n. z* x

/ |- |  M8 s8 {* ]
  1. /*
    + m' {1 {5 K; ?" z3 h
  2. *********************************************************************************************************
    ' f& _; _% s% R5 ]& l$ [  \
  3. *    函 数 名: QSPI_WriteBuffer
    ) ], C  R/ W7 x+ }& T* ?4 q
  4. *    功能说明: 页编程,页大小256字节,任意页都可以写入
    : k0 O1 k1 c# }4 A
  5. *    形    参: _pBuf : 数据源缓冲区;
    * _1 q8 q1 A. `8 N) z' }3 Z
  6. *              _uiWriteAddr :目标区域首地址,即页首地址,比如0, 256, 512等。" L1 [  Z; y6 v  Y& @. k
  7. *              _usWriteSize :数据个数,不能超过页面大小,范围1 - 256。! ]: p" g, ^9 k+ R
  8. *    返 回 值: 1:成功, 0:失败8 ~) H( B2 L; A; D9 `; i) x; y
  9. *********************************************************************************************************
    2 f7 J& a. T4 Z; y8 j% c  w
  10. */) N. p) }, _% f  q, `& ^
  11. uint8_t QSPI_WriteBuffer(uint8_t *_pBuf, uint32_t _uiWriteAddr, uint16_t _usWriteSize)
    & R/ _1 w& Q8 P  X2 E. D" p
  12. {
    " H/ f- j  G0 @4 Q1 |! x% H
  13.     QSPI_CommandTypeDef sCommand={0};
    ( ^- a* `. x! G% k5 o1 C
  14. " O: @. Y# q1 S, V. O. c  P
  15.     /* 写使能 */- f2 w0 r$ d# h& {! i
  16.     QSPI_WriteEnable(&QSPIHandle);   
    ' k/ g% f9 ]' [% _! l
  17. 4 j: ^8 m7 P7 |( f
  18.     /* 基本配置 */
    - ]! Y1 e/ q* h* w$ E% s' R5 k
  19.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 *// r3 O9 N$ f$ K
  20.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */% i0 x# h/ h6 }/ H
  21.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
    7 Z& [' \( L6 H
  22.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */
    , l! A* J6 u5 f% S! X5 r
  23.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */
    . F. b  ^7 O7 f( T
  24.     sCommand.SIOOMode          = QSPI_SIOO_INST_ONLY_FIRST_CMD;     /* 仅发送一次命令 */    " o% x% X; g, c: D) }0 z

  25. & F3 r0 R" f; Q3 S
  26.     /* 写序列配置 */
    ; I: M' G& W  D% L' v' D8 n" Q0 w
  27.     sCommand.Instruction = QUAD_IN_FAST_PROG_4_BYTE_ADDR_CMD; /* 32bit地址的4线快速写入命令 */
    - }, n# O1 S7 q( |) v7 R
  28.     sCommand.DummyCycles = 0;                    /* 不需要空周期 */" }6 K# x% b% H
  29.     sCommand.AddressMode = QSPI_ADDRESS_1_LINE;  /* 4线地址方式 */
    2 E8 v- n+ a5 W8 P2 q4 A0 I
  30.     sCommand.DataMode    = QSPI_DATA_4_LINES;    /* 4线数据方式 */
    6 b" u" E: Y  I4 M
  31.     sCommand.NbData      = _usWriteSize;         /* 写数据大小 */   
    % L. Y' e9 J& f1 C6 i) s! f
  32.     sCommand.Address     = _uiWriteAddr;         /* 写入地址 */
    ( ~8 b' \) l/ i  G: s* e# K

  33. ) s; d# `/ C/ o6 [
  34.     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 10000) != HAL_OK)1 K8 `9 Z( j2 q
  35.     {. N' m$ C! F( U) k" U
  36.         //return 0;3 N! h# c! `4 ~, S4 O8 Z
  37.         Error_Handler(__FILE__, __LINE__);
    6 J3 V3 h8 m5 O* b; ?4 H8 w
  38.     }
    & B: z9 c: }2 f/ X, e
  39. , c. N2 W4 O5 ~
  40.     /* 启动传输 */, V4 }' }3 q0 S2 o
  41.     if (HAL_QSPI_Transmit(&QSPIHandle, _pBuf, 10000) != HAL_OK)
    $ V/ P4 m# r% {1 m3 ?
  42.     {
    : e. s; B& P& Z- J5 B- u! o2 Q
  43.         //return 0;
    # Y0 J) N) Q. s! q2 o" J
  44.         Error_Handler(__FILE__, __LINE__);: j% @2 L5 c7 O: S. {& F* t# u
  45. & N2 j0 H) v( ]! L* \: l
  46.     }9 I# }0 A4 Q5 {3 O9 [

  47. ; K1 J2 R* Z: h
  48.     QSPI_AutoPollingMemReady(&QSPIHandle);    3 b* {9 P) m5 |$ j6 _' ?1 s

  49. 1 `# B  i( a8 D+ }
  50.     return 1;% W4 r$ {& l) g3 y
  51. }
复制代码

+ {4 k, N/ J2 h78.4.8 函数HAL_QSPI_Receive
5 }7 L' L5 ?. x; {# O, B( c函数原型:% X) Q( ]5 P0 i: g

. \" {6 x9 V* V2 ?/ L$ u
  1. HAL_StatusTypeDef HAL_QSPI_Receive(QSPI_HandleTypeDef *hqspi, uint8_t *pData, uint32_t Timeout)
    # y) |5 J# V! r% a( a; M* Q+ [
  2. {
    * d6 `3 F: p" K6 l
  3.   HAL_StatusTypeDef status = HAL_OK;* t( d1 y! g& K0 f+ N. L+ i  {0 G, W
  4.   uint32_t tickstart = HAL_GetTick();1 R; e- m- F! ?2 u6 ?( [
  5.   uint32_t addr_reg = READ_REG(hqspi->Instance->AR);1 L' y# e% L0 Z
  6.   __IO uint32_t *data_reg = &hqspi->Instance->DR;
    . p& p" X3 q) N" I8 k( V" X+ k/ v/ Y

  7. 0 }5 d3 P! B3 b! `) S
  8.   /* 上锁 *// Z; n) w: U, [0 s8 ^7 j6 J
  9.   __HAL_LOCK(hqspi);$ {7 `6 d1 y8 z* @; S% \6 G

  10.   b+ u& D$ ]4 f2 I4 d6 [$ ]1 q
  11.   if(hqspi->State == HAL_QSPI_STATE_READY)
    9 a) V' @, h1 C
  12.   {, h& q) X( U2 _
  13.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;6 J; w: l; j8 k4 v7 ?) v) J4 g" j
  14. . [+ N2 n2 b/ s$ P
  15.     if(pData != NULL )
    ) h) V: E) P4 o/ W4 U, N
  16.     {1 S, B6 U  y, g8 ?" g  Y
  17.       /* 更新状态 */
    ( K" ~. S% f2 @
  18.       hqspi->State = HAL_QSPI_STATE_BUSY_INDIRECT_RX;
      R) F' A( Y8 g

  19. ; Q/ j- v' ^8 I6 ^! p8 j
  20.       /* 配置接收 */! w; R, E5 Q. E7 g8 V; e
  21.       hqspi->RxXferCount = READ_REG(hqspi->Instance->DLR) + 1U;
    " r# A/ i: d8 |; G. Z& h" j
  22.       hqspi->RxXferSize = READ_REG(hqspi->Instance->DLR) + 1U;
    3 n4 b4 k/ m1 E& k2 q0 s- ]
  23.       hqspi->pRxBuffPtr = pData;4 u1 u  ~# K% t3 [! t

  24. " h) @' j% Q9 d! B6 \5 k# ^+ v
  25.       /* 配置QSPI,间接模式 */) q' C  J8 |! v8 j8 r1 K
  26.       MODIFY_REG(hqspi->Instance->CCR, QUADSPI_CCR_FMODE, QSPI_FUNCTIONAL_MODE_INDIRECT_READ);
    # h. j, C3 w/ I- K0 ^' g

  27. , q0 J3 R% c( d; N
  28.       /* 启动传输 */
    & m8 n0 e3 X& u
  29.       WRITE_REG(hqspi->Instance->AR, addr_reg);
    ) m4 n# P; Y; B# F( l

  30. 1 V$ p- s; [7 D9 `
  31.       while(hqspi->RxXferCount > 0U)+ `; y! l2 [- {* I" \1 D
  32.       {
    5 _# L, z4 }' J
  33.         /* 等FT和TC标志 */
    : ?* H3 V+ j! ~' c
  34.         status = QSPI_WaitFlagStateUntilTimeout(hqspi, (QSPI_FLAG_FT | QSPI_FLAG_TC), SET, tickstart, Timeout);' L& |) }% u+ ]4 m
  35. * r! R0 e* X5 g) \7 x
  36.         if  (status != HAL_OK)3 u/ Y9 Q1 {5 D# g( L
  37.         {
    . h% e" M6 y3 r7 G) l
  38.           break;# ?& Y, R- @7 N% C; E
  39.         }( o$ U" a; C! y- v! j* r. x# h# u! e
  40. 0 M( v/ y" G3 M9 W- m- c, V/ ^
  41.         *hqspi->pRxBuffPtr = *((__IO uint8_t *)data_reg);
    : _8 T! }. M  Q
  42.         hqspi->pRxBuffPtr++;
    6 y* V  t: z" @4 X: u0 r  F  i
  43.         hqspi->RxXferCount--;
    ' J7 a- \6 X- ?) B
  44.       }2 r- }3 \0 N. }- U! G
  45.   K2 c. Y# J6 r) H0 F
  46.       if (status == HAL_OK)
    1 E2 r+ c+ E6 m' ]! h4 p
  47.       {% S, S3 T# K/ B% j
  48.         /* 等待TC标志 */
    2 ?# b; E5 @" F; V& j
  49.         status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_TC, SET, tickstart, Timeout);
    # `; C% `8 B1 Q
  50. 5 h( T8 O* m& ?+ d4 Q$ [
  51.         if  (status == HAL_OK)
    8 d+ Q) h* _( ^# v
  52.         {
    $ W. n; |) o3 s) V& j
  53.           /* 清楚传输完成bit */  T' m3 @% J- r6 q6 g1 ^) |4 F
  54.           __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TC);" p- B' `. F' j* b: S/ o' [
  55. ' P! l- W) y1 ?# h# D
  56.         }* d: w* f, Y! f4 l
  57.       }
    . W& J) ?' X$ d" |

  58. 5 ]' P1 b( U* @
  59.       /* 更新QSPI状态 */
      q  |+ @6 F, T# W1 w' Z% V
  60.       hqspi->State = HAL_QSPI_STATE_READY;, S! O# K! L. j/ D) s9 y0 A
  61.     }  [; {' V% E0 C8 S! z7 L5 p: }  A
  62.     else; J  F& g* T9 W& d# L3 \% S
  63.     {
    9 @( C/ ]/ H+ z! O  I
  64.       hqspi->ErrorCode |= HAL_QSPI_ERROR_INVALID_PARAM;! ~+ k( f+ k* _9 }
  65.       status = HAL_ERROR;  g$ \( d% q. l' v. V
  66.     }6 B  z: k  x/ {" i' Z, ?" N
  67.   }
    6 B1 g+ N6 z0 M/ J
  68.   else+ D6 L& W3 @4 A" ?, R+ D
  69.   {
    # T0 V) Z# Q' e7 M9 Y1 z& r
  70.     status = HAL_BUSY;
    # }  i: [1 e0 B2 T% ^$ w
  71.   }
    ; T! b' `6 V. @- c' `1 X7 Y
  72. 0 B. Y+ d8 ~% V6 s- d) r
  73.   /* 解锁 */, ^& U+ Z, |" {; A9 Q: I9 B
  74.   __HAL_UNLOCK(hqspi);: A' z1 m! ]) i1 h& L! J0 _* H
  75. # k5 d6 b( S0 y
  76.   return status;" ?8 Y+ w  m3 K8 ~3 Q# ^
  77. }
复制代码
7 d- b& N) W! `) K
函数描述:
6 X5 g" K. p5 J: [. P) R& y6 h3 c4 `  M  x
此函数用于QSPI接口数据接收,函数采用查询方式。' O' M! J5 v# m5 h6 h
. z; [6 H: d% v
函数参数:
: [( ]4 O3 u. b9 o# b: N- S0 D6 @; [/ c: M7 n
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
0 l% A. a: ]0 D* e# T  第2个参数是要接收的数据地址。
9 b/ f0 l5 _. P9 d1 T% K  第3个参数是溢出时间,单位HAL库时间基准,我们一般设置的是1ms。
" O9 t4 W2 Y  v7 \  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
: i, a# s, F! m, [; q! Z9 }# @使用举例:
( g6 x/ F7 G+ M9 d$ l5 R) ]
) p) z5 t/ p1 h( t1 K2 \9 S5 g7 S
  1. /*
    ' O' |. W: D& l1 Q" X  f+ g# w- O
  2. *********************************************************************************************************
    + Q7 K0 m, o# Y1 e
  3. *    函 数 名: QSPI_ReadBuffer+ g7 [" l8 F! i4 W' I! d
  4. *    功能说明: 连续读取若干字节,字节个数不能超出芯片容量。0 d) d: o4 Q9 u, j
  5. *    形    参: _pBuf : 数据源缓冲区。5 J- D# u9 _, F# i  _
  6. *              _uiReadAddr :起始地址。: b! b; ~3 P* E1 [' K
  7. *              _usSize :数据个数, 可以大于PAGE_SIZE, 但是不能超出芯片总容量。! z! k9 J5 l5 x$ F$ |
  8. *    返 回 值: 无3 s' U3 {9 P: Q  L- ]
  9. *********************************************************************************************************4 {/ L* n, {( p7 r
  10. */
    ; ^9 W+ P$ U! b# N: c
  11. void QSPI_ReadBuffer(uint8_t * _pBuf, uint32_t _uiReadAddr, uint32_t _uiSize)
    ' s! q$ U% t5 I( ~. D- D
  12. {
    2 @  r" b4 A" [' i' x

  13. * j0 I5 {5 P9 e. w- }. V, N
  14.     QSPI_CommandTypeDef sCommand = {0};8 k8 S/ _; k* Q% T' v

  15. 7 t- q  b; v' Y' q* O2 n2 S

  16. 6 x% t& C0 V+ L7 A3 E
  17.     /* 基本配置 */
    4 d! _% t  i8 W
  18.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;        /* 1线方式发送指令 */
    & h+ R  m$ }) M- {: k8 O9 X+ @0 }
  19.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;          /* 32位地址 */
    8 o* Y9 |& u/ `9 p1 n" _
  20.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;      /* 无交替字节 */
    % d# p. e/ C( J1 r% f
  21.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;          /* W25Q256JV不支持DDR */+ t; M5 w+ \5 r5 p% W+ H$ Y5 _
  22.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;      /* DDR模式,数据输出延迟 */" F6 [7 L* H% m+ M' K
  23.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;        /* 每次传输要发指令 */   
    4 E$ n. \: U: K# ]! A% Y# l) ^
  24. 2 n' ?' G, G- R- f6 C; Q
  25.     /* 读取数据 */9 p! v- _) A7 h% U: e) }
  26.     sCommand.Instruction = QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD; /* 32bit地址的4线快速读取命令 */# f) ~6 \# x6 e! }+ n% c
  27.     sCommand.DummyCycles = 6;                    /* 空周期 */2 l  [- S2 c2 v  j) p
  28.     sCommand.AddressMode = QSPI_ADDRESS_4_LINES; /* 4线地址 */6 K. W3 B. g( s# ^. M
  29.     sCommand.DataMode    = QSPI_DATA_4_LINES;    /* 4线数据 */ & s: I# `( n# M- \  ~
  30.     sCommand.NbData      = _uiSize;              /* 读取的数据大小 */ " N+ ?1 ?. ?: G8 z
  31.     sCommand.Address     = _uiReadAddr;          /* 读取数据的起始地址 */ 3 J( W6 `9 R2 w: J6 ~( [, U& \& x

  32. 5 W( i3 A9 h8 {  @0 g* {3 I2 Q' G* ?; T
  33.     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 10000) != HAL_OK)! n6 N% r) M: g) e8 q8 _" i
  34.     {0 e' O/ |) G  m8 r% d) O
  35.         Error_Handler(__FILE__, __LINE__);
    2 o. A; P7 Y( g8 w7 m
  36.     }
    ! a2 C4 I$ f3 S9 h5 M% o5 b
  37. - W$ [/ V" a* F' p: j7 ?) N
  38.     /* 读取 */
    # y9 T( Y. P( g6 d& M$ t
  39.     if (HAL_QSPI_Receive(&QSPIHandle, _pBuf, 10000) != HAL_OK)
    * D6 ?4 N) y& c& f6 I
  40.     {
    9 W, r4 V" d8 \7 J) P' Q/ @
  41.         Error_Handler(__FILE__, __LINE__);# O9 m( [# s" ~: b2 Y& }
  42.     }    . J5 F' s6 {2 P! b) r( ]5 O
  43. }
复制代码
+ Z" a) A0 s! c8 x) Y( H
78.4.9 函数HAL_QSPI_Transmit_DMA
- r* H0 Q& W6 q: |函数原型:  c2 f% _: {/ R' N

, q" P% K. ]& a, b- i
  1. HAL_StatusTypeDef HAL_QSPI_Transmit_DMA(QSPI_HandleTypeDef *hqspi, uint8_t *pData)) S* u# F, u- X7 M8 ~  X, G
  2. {3 r, X, C5 B/ e3 c" [
  3.   HAL_StatusTypeDef status = HAL_OK;
    " S5 Y) r. n8 z
  4.   uint32_t data_size = (READ_REG(hqspi->Instance->DLR) + 1U);
    9 R" c  }* l* J- a" L5 H) k

  5. 6 D9 ~* o2 e4 a$ P
  6.   /* 上锁 */
    / y% ]* A$ X  a
  7.   __HAL_LOCK(hqspi);
    1 y  V6 |3 r% w2 ?1 {2 ~) C& e
  8. # d2 Z7 z2 b, {' p& k2 @
  9.   if(hqspi->State == HAL_QSPI_STATE_READY)% Q% u- ]3 {4 x
  10.   {4 I4 l( H% i- r7 B% t( x
  11.     /* 无错误 */
    0 S5 ~1 e$ b+ {( [( o
  12.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
    , D) n4 v0 @4 M3 t% p* g

  13. ; |5 Q* s, j/ Y) p& P. V2 S/ c
  14.     if(pData != NULL )
    - D( V3 i. Z# {$ f% T8 f
  15.     {! t% T. @0 O1 a; K: r) R- [
  16.       /* 配置发送字节数 */% ~  O% N. y9 E
  17.       hqspi->TxXferCount = data_size;7 L. w7 |1 k- H% M& B5 L

  18. ; u* w- F5 ]+ v. n2 D2 U" f
  19.         /* 设置QSPI状态 */7 s  [3 @+ ^, m  p& C5 l( J9 d
  20.         hqspi->State = HAL_QSPI_STATE_BUSY_INDIRECT_TX;- N* b5 z5 I2 S/ ?% o

  21. & J# v" i) F0 k3 L7 t/ f# w
  22.         /* 清除中断标志 */4 Z- f6 P6 h2 V  O- |
  23.         __HAL_QSPI_CLEAR_FLAG(hqspi, (QSPI_FLAG_TE | QSPI_FLAG_TC));0 i& U9 U( C9 X

  24. " r& F# l% G8 D3 m4 {9 x+ f+ b
  25.         /* 配置发送 */
    ' n: P$ O: l' H- H2 \9 H
  26.         hqspi->TxXferSize = hqspi->TxXferCount;
    ' r' }) {" R  z, ?! b6 }% d6 o0 J
  27.         hqspi->pTxBuffPtr = pData;
    * K9 {3 W' S% L

  28. $ x# K0 B3 A) M) J) P
  29.         /* 配置间接写模式 */
    ( K* C) n4 h5 q. t7 {* i5 F& g. ]0 ]& I
  30.         MODIFY_REG(hqspi->Instance->CCR, QUADSPI_CCR_FMODE, QSPI_FUNCTIONAL_MODE_INDIRECT_WRITE);
    ) ?: v( N1 s5 j; A" Z' u
  31. # W0 o' M- E# h6 \7 c2 c9 B
  32.         /* 设置MDMA发送完回调 */0 l. i' ?- g5 V  Y  e2 f
  33.         hqspi->hmdma->XferCpltCallback = QSPI_DMATxCplt;  ?* X2 ^$ _+ O0 W

  34. * d: C2 T, C& y& L2 U- O- M% ]
  35.         /* 设置MDMA错误回调 */9 m$ Z9 o) z9 G5 x% M
  36.         hqspi->hmdma->XferErrorCallback = QSPI_DMAError;
    . M6 m7 r& N8 V/ i

  37. * w3 j  g" h4 y( x- Z2 E% Y7 o
  38.         /* 设置MDMA终止传输回调为NULL */3 a- ?, ~- ^9 c. ]
  39.         hqspi->hmdma->XferAbortCallback = NULL;
    3 |& ^3 H% `! q3 `0 R# ]* j, n* N9 D  P

  40. $ J* _  I6 U2 @0 s4 a1 J
  41.         /* MDMA的目的地址是QSPI DR寄存器,设置禁止递增 */+ D& x" r8 M8 I) C
  42.         MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_DINC | MDMA_CTCR_DINCOS) ,MDMA_DEST_INC_DISABLE);' K5 l' D- E; s" u
  43. % j/ j# Y: [% l. K1 n  |6 {6 L
  44.         /* 更新MDMA源地址配置 */$ }0 H; x% v0 B1 _6 @
  45.         if (hqspi->hmdma->Init.SourceDataSize == MDMA_SRC_DATASIZE_BYTE)
    6 w7 |) c; w* K) P
  46.         {
      f- A9 Y9 f( u
  47.           MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_SINC | MDMA_CTCR_SINCOS) , MDMA_SRC_INC_BYTE);
    4 m9 _& C3 @. u
  48.         }. V' z8 Z% K1 n+ N0 O9 E
  49.         else if (hqspi->hmdma->Init.SourceDataSize == MDMA_SRC_DATASIZE_HALFWORD)9 V8 F: T5 Y$ z- Q  n
  50.         {
    0 r' c4 K5 J, p6 s; \7 \% J% p- k
  51.           MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_SINC | MDMA_CTCR_SINCOS) ,& V9 X+ t" z( ]! F
  52. MDMA_SRC_INC_HALFWORD);. e+ {1 f, \* M$ X
  53.         }4 o  U5 E+ k' ?! M1 Y5 c* T2 R
  54.         else if (hqspi->hmdma->Init.SourceDataSize == MDMA_SRC_DATASIZE_WORD)2 c1 ?% W/ }4 S2 d0 p" L
  55.         {/ y1 M" ~! e$ e. G5 n$ c
  56.           MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_SINC | MDMA_CTCR_SINCOS) , MDMA_SRC_INC_WORD);
    9 p: i% s; s9 [( C) {8 }" m
  57.         }
    8 E/ W6 j+ }. K- P' h9 X3 P- S8 ^! l
  58.         else
    $ T6 }7 b* W# m8 F
  59.         {. Q5 S7 Y. H2 `/ x  |
  60.           /* 配置错误 */
      B; L) q3 ~' ]; y% s( A
  61.           hqspi->ErrorCode |= HAL_QSPI_ERROR_DMA;9 ~3 l4 v* J: K& |- k( L* A9 L
  62.           status = HAL_ERROR;- M8 Q; j  p" I" S
  63.         }1 x& h! u9 L3 L& O$ Y, W
  64. - E* ^* w2 \! P0 B$ Z
  65.         /* 使能QSPI MDMA发送 */
    , z: J" b1 k( n2 c# ^2 {
  66.         if (HAL_MDMA_Start_IT(hqspi->hmdma, (uint32_t)pData, (uint32_t)&hqspi->Instance->DR,: s, |, ]. ^5 Z( D9 I. y* p, y
  67. hqspi->TxXferSize, 1) == HAL_OK)& L+ U7 ?7 K. J+ n
  68.         {, u, o: @% X: e1 |1 K4 y( k1 k
  69.           /* 解锁 */' B& `/ m, S: \4 c7 @( ~/ Y
  70.           __HAL_UNLOCK(hqspi);' J  @$ o& _; X: z: K3 H
  71. # x4 A7 k; z# n" B
  72.           /* 使能QSPI传输错误中断 */+ q+ G3 [2 ~! W. `2 I
  73.           __HAL_QSPI_ENABLE_IT(hqspi, QSPI_IT_TE);- f8 v( V- C9 ?6 q
  74. . Y) `7 }) U8 E6 \. X! l6 g
  75.           /* 使能MDMA传输 */9 b( n! d  O" L' }, z% W$ C/ x
  76.           SET_BIT(hqspi->Instance->CR, QUADSPI_CR_DMAEN);
    # I1 r0 E6 a3 b' {4 @1 i
  77.         }' t/ T. n$ I* X# Y: K0 l0 Q/ _
  78.         else/ R# w* t* [+ ^. C
  79.         {4 j. P# E& w, ]+ o% a+ O) q8 o. F
  80.           status = HAL_ERROR;
    3 u; ?: z3 U/ ~; W) T
  81.           hqspi->ErrorCode |= HAL_QSPI_ERROR_DMA;
    2 s2 H. S* L- t% _  s0 P# M8 P
  82.           hqspi->State = HAL_QSPI_STATE_READY;! A. ^; q* X6 A9 D

  83. / a; C$ d8 Q/ V
  84.           /* 解锁 */
    ; L( E7 i; F) J) f- K
  85.           __HAL_UNLOCK(hqspi);
    3 M, U& X  _; J) a  _& W- O
  86.         }
    1 q& m1 y; z$ c; B& `' r# I+ b
  87.     }
      I1 H7 C" ~) H
  88.     else' T9 x( p. x: [8 E+ K2 T  Q% P7 e+ t
  89.     {5 ^; I+ a0 F! K' T, g- i/ m0 o
  90.       hqspi->ErrorCode |= HAL_QSPI_ERROR_INVALID_PARAM;
    - H; o( E. G+ I
  91.       status = HAL_ERROR;% x8 H) \4 ?1 f) J/ C5 O+ v
  92. $ O. @. l' F" W5 b5 _/ t
  93.       /* 解锁 */
    , k# Z/ J6 A0 J9 X8 I. L6 x
  94.       __HAL_UNLOCK(hqspi);
    ( I5 H4 K9 G% ^' i
  95.     }
    # h9 _: o: i( H" c6 p& H$ y
  96.   }
    : C% I$ ?) U8 |2 L
  97.   else
    1 e% C& |% ^2 U% K
  98.   {
    0 A7 C$ P* \% b1 N% M8 _  \; O
  99.     status = HAL_BUSY;" Z6 O; Z! v. m3 N) H$ h

  100. ; W6 A: R4 ^) f4 [' l; U" d, C/ d
  101.     /* 解锁 */
    4 u0 o/ d  e; W/ N
  102.     __HAL_UNLOCK(hqspi);8 K2 ^- B/ ]) M; [
  103.   }+ s4 J2 ?; Z9 ]) S4 b& `# M3 ?
  104.   e2 e6 j: |/ y2 B, c6 b  y
  105.   return status;; V# W) c0 g% Q% W9 ?9 K
  106. }
复制代码

3 v1 j  X& l$ ?. i- O函数描述:
+ W5 B# v# _" O5 J/ t& X% D
( H0 E3 V3 \" {% S, B/ `% i此函数用于QSPI接口数据发送,函数采用DMA方式。
' z. w: p4 g: ~3 s0 Q3 p8 Q0 t4 _, w" v+ `
函数参数:
* f. f6 S6 o' g* N4 m6 l, `8 _* _* l" A
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。% D. o& l; C) _
  第2个参数是要接收的数据地址。, h8 ^5 l1 o* C# G- `
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。( W. b4 b# b. u, i/ s9 [, L
使用举例:4 A" x& b8 T) t* S6 K% \9 i8 y
- @) W" q! i' a' Q: n% m$ N
  1. /*4 d8 y' K& y1 W, N
  2. *********************************************************************************************************
    * R6 X: w# a9 {' f2 u
  3. *    函 数 名: QSPI_WriteBuffer
    : I2 B' l& V* K$ x
  4. *    功能说明: 页编程,页大小256字节,任意页都可以写入
    8 J- Y: V6 N7 Y# _- s
  5. *    形    参: _pBuf : 数据源缓冲区;
    & C- v/ l* o7 L
  6. *              _uiWriteAddr :目标区域首地址,即页首地址,比如0, 256, 512等。
    : G0 F2 {* q* m: U! N  Y
  7. *              _usWriteSize :数据个数,不能超过页面大小,范围1 - 256。
    9 Y/ Q! u+ U% p0 d( R
  8. *    返 回 值: 1:成功, 0:失败
    # D$ M1 C( g' i, E: |
  9. *********************************************************************************************************
    % u) n: h8 s6 \' |# a: f% E' S
  10. */
    4 q# v, a1 }7 o7 c/ r/ f4 z* @% a) t3 `
  11. uint8_t QSPI_WriteBuffer(uint8_t *_pBuf, uint32_t _uiWriteAddr, uint16_t _usWriteSize)
    6 |5 X( D5 E. P: u& W' W5 L
  12. {+ W( N' O8 T. G" x
  13.     QSPI_CommandTypeDef sCommand={0};
    & e9 p: x5 }. o& D" I. \% t% Z

  14. & [" O4 {8 f3 s
  15.     /* 写使能 */
    3 @. f1 e- l; M8 w
  16.     QSPI_WriteEnable(&QSPIHandle);   
    4 e( e) J+ s9 ^* l9 ^

  17. . A( q* q% z6 J4 r& s* l% G+ R4 P
  18.     /* 基本配置 */% Z' {6 `( B/ W' y- N6 q7 X
  19.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */
    2 Y+ M, G( g* ]( d* M
  20.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */5 \2 n, p/ F5 L
  21.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
    1 o+ |' K- h+ ]6 j
  22.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */+ c, d; V9 E  S" E6 Z) G& ^' r
  23.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */7 y0 A( B# A& R7 ]9 W% y1 M( O. F
  24.     sCommand.SIOOMode          = QSPI_SIOO_INST_ONLY_FIRST_CMD;     /* 仅发送一次命令 */   
    $ J0 w$ U- }# O, l
  25. # ]" H3 k: Z2 Q) B* Y+ p, b
  26.     /* 写序列配置 */6 y+ V) A/ R: p
  27.     sCommand.Instruction = QUAD_IN_FAST_PROG_4_BYTE_ADDR_CMD; /* 32bit地址的4线快速写入命令 */3 K7 v9 j8 M' d  d% }* [% W
  28.     sCommand.DummyCycles = 0;                    /* 不需要空周期 */8 @) y/ [5 y* ~5 C9 I
  29.     sCommand.AddressMode = QSPI_ADDRESS_1_LINE;  /* 4线地址方式 */; C( D! Q. _) @. \) q7 `
  30.     sCommand.DataMode    = QSPI_DATA_4_LINES;    /* 4线数据方式 */
    3 Q' B' N# o9 O7 j6 t: @
  31.     sCommand.NbData      = _usWriteSize;         /* 写数据大小 */   : C* h" _% e1 N( p3 `* l
  32.     sCommand.Address     = _uiWriteAddr;         /* 写入地址 */
    - c7 z+ U9 R& V+ X7 M
  33. " ]5 {5 K" b5 n) I
  34.     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 10000) != HAL_OK)) M; J. Z4 m7 ~2 V4 m+ m- b8 \6 p: o; k
  35.     {
    3 S! T7 I# c, I( h
  36.         //return 0;/ [- }+ q9 g: W; u( `- Y/ H
  37.         Error_Handler(__FILE__, __LINE__);
    / m9 y4 ?; Z2 F+ r' E% E
  38.     }
    , t# a3 @% g: ^

  39. 8 l) v' i4 Y& \9 n8 g4 O# b% _
  40.     /* 启动传输 */
    , m' F- E& A; v7 }5 g7 Q9 n
  41.     if (HAL_QSPI_Transmit_DMA(&QSPIHandle, _pBuf) != HAL_OK)
    # p3 Z$ F& T8 N
  42.     {
    $ Z& t' b6 k! b$ e" l' h& P* G9 c
  43.         //return 0;% {% Y+ k4 g+ F- d$ z! {
  44.         Error_Handler(__FILE__, __LINE__);: j" d4 \2 B: W
  45.     }7 V* p/ |: L+ e! D, t& }, N3 C
  46. " {1 u2 ^5 V& Q: c( g8 G- c
  47.     QSPI_AutoPollingMemReady(&QSPIHandle);   
    0 l# F5 m/ f* W8 d  {$ y5 z# \

  48. # p( S& k" d( G( ]: t5 x0 z
  49.     return 1;7 u" |  Y$ O& Y! t
  50. }
复制代码
7 X2 X. ?+ }9 x5 Q
78.4.10   函数HAL_QSPI_Receive_DMA
6 Z* D5 u+ X, N  ~函数原型:3 {% J& N( d, ~1 u- K

! f3 K, k# `- a9 R9 r; p% C9 C
  1. HAL_StatusTypeDef HAL_QSPI_Receive_DMA(QSPI_HandleTypeDef *hqspi, uint8_t *pData)' J6 a! W) r, c5 J" {
  2. {
    + ?# e0 o! g" c, S/ t
  3.   HAL_StatusTypeDef status = HAL_OK;
    : `. K% P7 U8 v& F8 `6 o
  4.   uint32_t addr_reg = READ_REG(hqspi->Instance->AR);, N* s0 L& r* |7 |% R
  5.   uint32_t data_size = (READ_REG(hqspi->Instance->DLR) + 1U);5 a# M6 A* x& O3 F& T0 D1 ]! |0 ?

  6. ; W4 V) G( E# j3 C; V
  7.   /* 上锁 */% ]- [" n1 P, k2 s4 p. [
  8.   __HAL_LOCK(hqspi);
    $ c9 ~" y9 ]  ?8 g6 n! T) j
  9. + {4 L' F: L  [5 c8 N0 p( ]
  10.   if(hqspi->State == HAL_QSPI_STATE_READY)
    & L. W# E: V# Y( N  s
  11.   {
    2 P/ ^" p% {" ^# ~. [) t' U+ u
  12.     /* 无错误 */
    ' V0 H  z" l& {* w
  13.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
    ( O9 _7 P) n/ W% d

  14. / C1 f% M) B4 \' {
  15.     if(pData != NULL )/ s# s  a  @) _* c  x: U- ]
  16.     {7 j, c: o; ^0 M2 \6 ], m9 j
  17.       /* 配置接收 */! S. x0 I; X# r" K
  18.       hqspi->RxXferCount = data_size;
    " P  m& o# _# U& l) Y( S8 `
  19.         /* 更新状态 */: T: H$ O: N, C! c; t
  20.         hqspi->State = HAL_QSPI_STATE_BUSY_INDIRECT_RX;
    ' D6 \1 S* G' D) H$ z0 w5 n. K
  21. : H" o& n% P7 @4 W! J  z
  22.         /* 清除中断标志 */) O* H) }- B) l- D4 J' _# A" t
  23.         __HAL_QSPI_CLEAR_FLAG(hqspi, (QSPI_FLAG_TE | QSPI_FLAG_TC));" H: k, p) M  S+ e
  24. + Z+ _" B& k! x" @9 _# t
  25.         /* 配置接收 Configure */$ g( V' d* F7 A! X6 B9 Y5 K, E
  26.         hqspi->RxXferSize = hqspi->RxXferCount;& }! T6 J. t" j" B+ N& x& v" t
  27.         hqspi->pRxBuffPtr = pData;: n! D/ \" X+ y( u8 y( f
  28.   {( a$ k  |, R" m
  29.         /* 设置接收完成中断 */
    / A" i, K) S7 x
  30.         hqspi->hmdma->XferCpltCallback = QSPI_DMARxCplt;
    . A6 w: i. R- ~& u6 m9 j

  31. 8 t) ~4 j* v9 B# ?8 H4 f* Q6 m
  32.         /* 设置MDMA错误回调 */
    4 }6 v5 W: d" h5 H9 `( b' G
  33.         hqspi->hmdma->XferErrorCallback = QSPI_DMAError;# A( [. M' {" l2 E8 W" I6 g: t

  34. 2 A4 p$ N- w1 R% w/ M4 [
  35.         /* 置空MDMA终止回调 */( T3 n. Z/ ?5 R! R6 ^" x  `
  36.         hqspi->hmdma->XferAbortCallback = NULL;) h9 c+ k. n$ U* i9 z- d6 \3 ^
  37. 8 q8 m' Z1 n0 `/ L5 [( ?
  38.       /* 接收模式下,MDMA的源地址是QSPI DR,要禁止地址自增 */
    ) Z: o# p5 V, Y, B; f9 }
  39.       MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_SINC | MDMA_CTCR_SINCOS) , MDMA_SRC_INC_DISABLE);5 |2 b9 [" P; n8 ]2 k! k$ [! z
  40. . G: A6 p6 k; o  m  \
  41.       /* 更新目的地址配置 */+ m: y$ a0 z4 F& a9 ^1 l1 G
  42.       if (hqspi->hmdma->Init.DestDataSize == MDMA_DEST_DATASIZE_BYTE)
    1 {6 I0 }! M* x& U1 G
  43.       {$ h& ?! s/ r: ]6 f6 m* ?
  44.         MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_DINC | MDMA_CTCR_DINCOS) , MDMA_DEST_INC_BYTE);6 s3 [' x/ P( k
  45.       }1 u* S3 }7 T; R" w# V
  46.       else if (hqspi->hmdma->Init.DestDataSize == MDMA_DEST_DATASIZE_HALFWORD)$ C2 T8 f1 o  |, A$ R: a
  47.       {
    / ]7 e* e7 X' P" g6 r$ h" F
  48.         MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_DINC | MDMA_CTCR_DINCOS) , + y( w3 M* V" [% r7 W' a
  49. MDMA_DEST_INC_HALFWORD);
    # T  _# B9 _/ R: M- f' x
  50.       }! j, _' {4 z1 `& J1 q, l" f
  51.       else if (hqspi->hmdma->Init.DestDataSize == MDMA_DEST_DATASIZE_WORD)
    5 {& y5 a- n0 d) n% b
  52.       {/ P7 \8 W) q% u# m) m* Z
  53.         MODIFY_REG(hqspi->hmdma->Instance->CTCR, (MDMA_CTCR_DINC | MDMA_CTCR_DINCOS) , MDMA_DEST_INC_WORD);
    ) p5 D5 k" N( ^/ W
  54.       }5 t- {7 Y4 a" m
  55.       else
    & R: I  N  N# e$ n2 S4 P' p: @& s
  56.       {0 D( b7 p9 _$ U& n" R$ @  o# j3 n& E8 M
  57.        /* 配置错误 */' @  g# _  }1 H: W8 D
  58.         hqspi->ErrorCode |= HAL_QSPI_ERROR_DMA;7 ~5 h3 d( v& v+ @0 E: V
  59.         status = HAL_ERROR;
    " v( w4 S1 c. B9 v
  60.       }# \6 ~/ D4 l2 N& o! N
  61.           /* 配置CCR寄存器,间接读 */9 V/ d, m5 `% `4 v1 X) O
  62.           MODIFY_REG(hqspi->Instance->CCR, QUADSPI_CCR_FMODE, QSPI_FUNCTIONAL_MODE_INDIRECT_READ);* G7 B' X, ?  m6 i# E6 S% d% H
  63. 5 v! H0 ~; e# e, W& q
  64.           /* 启动传输 */
    / U' ]6 C5 n2 D9 r, ^# H) T
  65.           WRITE_REG(hqspi->Instance->AR, addr_reg);
    ! s9 e: G' @$ B0 f( A" o( T7 Z8 m4 J# m

  66. * y2 m" i1 t1 l; G! k# t* v1 y
  67.         /* 使能MDMA */
    # y! M$ Z' _( k. i- h" r4 \/ M; q
  68.         if (HAL_MDMA_Start_IT(hqspi->hmdma, (uint32_t)&hqspi->Instance->DR, (uint32_t)pData,
    % F( t' q3 [5 y/ p
  69. hqspi->RxXferSize, 1) == HAL_OK)  R! ~. w; C- e0 P
  70.         {
    9 Y" |% X8 [' Y  S) _  Q
  71.           /* 解锁 */
    . Q3 l1 q- R8 N9 V
  72.           __HAL_UNLOCK(hqspi);
    8 b& Y4 M/ w% M8 Y# h: x! B, v
  73. 4 V8 A+ c# z' F: U0 _
  74.           /* 使能传输错误中断 */- N5 D( V& H/ G2 F1 G& ]
  75.           __HAL_QSPI_ENABLE_IT(hqspi, QSPI_IT_TE);! L1 z5 {9 ~  P( X2 h: M: z
  76. 1 E. O% u9 b! x1 {) P
  77.           /* 使能MDMA传输 */7 ~& a" N! C" D1 J: q. J$ b9 {
  78.           SET_BIT(hqspi->Instance->CR, QUADSPI_CR_DMAEN);
    5 A8 n- v' `0 D! Q2 m6 n
  79.         }
    3 L) Z3 J) D/ F) V+ X6 `$ U
  80.         else
    ' l1 H+ }8 G9 n1 h# c: e8 @* l
  81.         {
    1 W! k8 F% N2 z+ {
  82.           status = HAL_ERROR;
    5 P' F: b. e( S- m) |$ B
  83.           hqspi->ErrorCode |= HAL_QSPI_ERROR_DMA;/ U2 w! ~+ L1 V% [/ Q, @8 `* b
  84.           hqspi->State = HAL_QSPI_STATE_READY;. Q) \  D& o7 O8 X4 i& }8 Y2 Z

  85. 9 {$ z2 z5 L. F( l( q6 f0 u% w
  86.           /* 解锁 */
    % r  Q% j3 ~7 ]; G* Z, [; g
  87.           __HAL_UNLOCK(hqspi);
    , d9 H  n3 T' a8 h! s6 z
  88.         }0 N/ B! i; I! @& D8 b
  89.     }
    2 L' O& r, Y# |# a5 C0 X
  90.     else
    6 K8 H/ I" v) _
  91.     {
    9 X* {8 R) p! q( y# C9 Q
  92.       hqspi->ErrorCode |= HAL_QSPI_ERROR_INVALID_PARAM;/ Q! I; \0 X' q2 n- F
  93.       status = HAL_ERROR;
    : k* k# {" ]" h, Q7 i4 M
  94. 6 N- U& q" P$ F% B- L
  95.       /* 解锁 */
    3 K! L, p, Z3 J
  96.       __HAL_UNLOCK(hqspi);
    " W& b% I; @+ ^! ~9 `& c6 K
  97.     }
    6 g! I' Z6 L9 f! W$ M2 g
  98.   }; F) ]% s8 O3 v- S! e
  99.   else$ b* L9 t, h: f2 x9 ~
  100.   {
    % C! o* n$ t9 L8 ^. i7 V
  101.     status = HAL_BUSY;, X' T9 m# M1 I2 |! G* l. A. M, v
  102. 9 S3 r# [9 H7 o/ Q  Y' V6 R
  103.     /* 解锁 */. v7 W: w! @6 d
  104.     __HAL_UNLOCK(hqspi);
      A" u; Y8 q( S5 W
  105.   }
    * j* ?/ m; E1 f

  106. 0 r* Q( ^' G1 f0 R# I5 M
  107.   return status;
    $ ]9 Y+ h( |6 [
  108. }
复制代码
2 }4 B/ j2 O& `
函数描述:$ N1 p* t3 n& f! v+ y; D; e! ^' I0 i

, V; i2 g- e  X( p& u此函数用于QSPI接口数据接收,函数采用DMA方式。
) J; }7 O3 C; n6 ^# |7 s1 |  d* _6 @0 `4 F4 I* C- p- y0 ~, }' b
函数参数:
7 Y; }, Q+ V) s* M4 j, L1 `: M4 ?- I% R9 a9 U# M9 `. P- f8 h3 s" y2 \
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
, b- c; V+ f4 M: o2 F  第2个参数是要接收的数据地址。" h: ^( z. y, t
  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。" D. a8 i; O- N$ a) c
使用举例:
+ j, @9 \; p  ~& G
! O  F6 A) s; N5 x0 A) y
  1. /*
    # m7 y* G' h/ g
  2. *********************************************************************************************************
    , a- v0 R# T0 N' Y
  3. *    函 数 名: QSPI_ReadBuffer
    " o3 i) S. ^9 _" C
  4. *    功能说明: 连续读取若干字节,字节个数不能超出芯片容量。
    ( @* O3 z/ }8 R2 l7 }) p
  5. *    形    参: _pBuf : 数据源缓冲区。
    7 m' `1 w3 L9 A, p% f
  6. *              _uiReadAddr :起始地址。
    3 _- k8 }# y4 I
  7. *              _usSize :数据个数, 可以大于PAGE_SIZE, 但是不能超出芯片总容量。
    0 I+ u! g3 V( W! a: o7 ~3 V
  8. *    返 回 值: 无
    4 E5 @  R+ }. v6 L( V% |( \* z7 T
  9. *********************************************************************************************************
    % s2 N2 U) o% l. }3 v
  10. */& c  ?+ c) E: c. h: T
  11. void QSPI_ReadBuffer(uint8_t * _pBuf, uint32_t _uiReadAddr, uint32_t _uiSize)
    0 @: c& S4 l/ ]( w8 J. c
  12. {! j+ Y2 p5 c, ~5 J
  13. ! J8 Z& p' r( _( n; }) P
  14.     QSPI_CommandTypeDef sCommand = {0};
    6 j1 M( W+ Y* O; W8 W" i
  15. + e8 T1 P5 [; o6 g
  16. , W) o8 q: [( j0 w
  17.     /* 基本配置 */
    6 Z& X: E- p( [) z+ T: ~& d$ t
  18.     sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;        /* 1线方式发送指令 */1 ~/ P4 p( ^! \& J8 V% b
  19.     sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;          /* 32位地址 */
    . s  `( g4 P, Z( X( E
  20.     sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;      /* 无交替字节 */  N, }! ]2 E; x
  21.     sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;          /* W25Q256JV不支持DDR */
    ' y6 f' L5 w; W% k
  22.     sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;      /* DDR模式,数据输出延迟 */
    $ T$ N- _1 V; w, B/ Y! @6 i
  23.     sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;        /* 每次传输要发指令 */   
    6 k% Q/ H5 c6 d4 o) B0 B
  24. 7 N# R: C% ^' g
  25.     /* 读取数据 */4 \+ n  W2 ?/ h8 S7 X# S
  26.     sCommand.Instruction = QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD; /* 32bit地址的4线快速读取命令 */; \/ I% p4 S( ?7 x7 ?
  27.     sCommand.DummyCycles = 6;                    /* 空周期 */6 n. b" [! d9 r* T6 w2 h
  28.     sCommand.AddressMode = QSPI_ADDRESS_4_LINES; /* 4线地址 */
    + e, N; e  t6 N# r( i
  29.     sCommand.DataMode    = QSPI_DATA_4_LINES;    /* 4线数据 */
    3 J5 C: Y- `8 P6 B4 T6 B+ K0 z
  30.     sCommand.NbData      = _uiSize;              /* 读取的数据大小 */
    4 B6 S2 O8 a8 @- _6 j
  31.     sCommand.Address     = _uiReadAddr;          /* 读取数据的起始地址 */
    ) U- [, D' X3 x% y! E- T9 ^' f
  32. 1 l+ `1 |* C2 e6 c# Q: f% H
  33.     if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 10000) != HAL_OK)
    8 t) x9 T5 y0 D6 B0 ]$ C
  34.     {
    0 i: W1 r1 B, ~5 k4 z& W. O
  35.         Error_Handler(__FILE__, __LINE__);& q0 P& V( o1 k; J8 j  ]4 y1 A
  36.     }; s% o+ E) V# T. h: h) O
  37.   w" v% Y* o) f* W6 m
  38.     /* 读取 */
    0 E( [9 c$ H) k. {: i
  39.     if (HAL_QSPI_Receive_DMA(&QSPIHandle, _pBuf) != HAL_OK)
    * p+ U- K$ S% C, A9 h# K
  40.     {
    ) H$ ?; X1 E8 V7 J) w; A
  41.         Error_Handler(__FILE__, __LINE__);
    0 g* a2 L6 _; z3 Z4 f& J
  42.     }    # O$ T* i: m, n( z" Y" s! f
  43. }
复制代码

. V% h6 z  O" Z) @; a9 v: v78.4.11   函数HAL_QSPI_MemoryMapped4 M- F# q, ^! ]! F- ^  a1 k) k
函数原型:
% m8 {' R& z3 G2 d+ w- x
# I, ~, X* N9 {% y
  1. HAL_StatusTypeDef HAL_QSPI_MemoryMapped(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, QSPI_MemoryMappedTypeDef *cfg)
    & s- Z: x, W# \& ?7 f
  2. {
    3 }5 H6 e7 W8 f: [
  3.   HAL_StatusTypeDef status;, j, O4 T& b- q5 P- P# l- a7 y
  4.   uint32_t tickstart = HAL_GetTick();) ]1 l0 [/ S' |* a7 e7 H  ?' k8 H
  5. / m- T7 Y) b' H4 P+ |
  6.   /* 检查参数 */" w; R, q% k' g
  7.   assert_param(IS_QSPI_INSTRUCTION_MODE(cmd->InstructionMode));
    ) L+ L0 S+ Q* o5 m/ ^) D: U
  8.   if (cmd->InstructionMode != QSPI_INSTRUCTION_NONE)7 I. Q: k+ x  G' }
  9.   {9 ^) j3 E# r! e3 t
  10.   assert_param(IS_QSPI_INSTRUCTION(cmd->Instruction));
      y, v) C) y1 t
  11.   }
      u- l0 @5 ?. h3 b- Z

  12. ( H! F2 P4 v* m* f' l" N
  13.   assert_param(IS_QSPI_ADDRESS_MODE(cmd->AddressMode));+ A+ t5 h( ~6 h9 p" s( n' ?
  14.   if (cmd->AddressMode != QSPI_ADDRESS_NONE)
    : B* R% g$ l& L4 e
  15.   {8 j' [1 l, E) U0 ^/ p0 Z
  16.     assert_param(IS_QSPI_ADDRESS_SIZE(cmd->AddressSize));
    . b& M# s( u. ^7 X! M* w  J
  17.   }1 b) T$ a; `& m0 N
  18. 3 c5 h0 Y+ u& n" J
  19.   assert_param(IS_QSPI_ALTERNATE_BYTES_MODE(cmd->AlternateByteMode));
    . [" Q8 w( g+ e
  20.   if (cmd->AlternateByteMode != QSPI_ALTERNATE_BYTES_NONE)9 X9 v$ G" g( @% w  K1 D
  21.   {
    ; A- l, e- K# T# \
  22.     assert_param(IS_QSPI_ALTERNATE_BYTES_SIZE(cmd->AlternateBytesSize));# o/ t# Z/ d- j. C6 ~
  23.   }1 g9 J: w7 O4 i" L" X, B9 a
  24. , @0 }  f- S+ {; v3 U" M
  25.   assert_param(IS_QSPI_DUMMY_CYCLES(cmd->DummyCycles));
    8 {; k3 _. e* B1 O4 `; q
  26.   assert_param(IS_QSPI_DATA_MODE(cmd->DataMode));+ K2 p" M  l8 V  u

  27. , `, ]( u( T9 `( N1 F* J
  28.   assert_param(IS_QSPI_DDR_MODE(cmd->DdrMode));
    ' w9 {8 A6 Y9 @8 i4 o& _; f
  29.   assert_param(IS_QSPI_DDR_HHC(cmd->DdrHoldHalfCycle));+ L2 f6 @! g4 {9 v' l8 Z
  30.   assert_param(IS_QSPI_SIOO_MODE(cmd->SIOOMode));
    * [/ c6 c/ g. g, z" ^
  31. " G: I8 m( L6 `
  32.   assert_param(IS_QSPI_TIMEOUT_ACTIVATION(cfg->TimeOutActivation));# i  Y1 f) t. m. w

  33. ( F7 S5 }; o# q$ M9 N8 Q
  34.   /* 上锁 */
    ) Y$ c0 ]: x0 W2 a; n, x4 r! P5 Q
  35.   __HAL_LOCK(hqspi);; d' \+ t' M, G

  36. 1 q& ~- [$ [! Q
  37.   if(hqspi->State == HAL_QSPI_STATE_READY)
    " N- l7 F- A: D4 A" q
  38.   {8 e$ Z* ^7 l/ z" S
  39.     hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;) ^6 g% ?7 C6 R0 `- g- J

  40. 1 b% [; x7 G9 Z4 ^" y6 g$ x
  41.     /* 更新状态 */
    6 j0 u! r% F1 l/ p! }5 T  T
  42.     hqspi->State = HAL_QSPI_STATE_BUSY_MEM_MAPPED;
    3 V& W1 h0 c  m, b
  43. + O& ]( \2 z0 u7 s
  44.     /* 等待BUSY标志复位 */" L9 F) e, M0 n6 j$ F
  45.     status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, hqspi->Timeout);
      C/ S" r6 p8 ^& I: \  c

  46. ! C" o8 d( ?4 e9 O. k
  47.     if (status == HAL_OK)
    % |5 Y: E1 r5 g* H
  48.     {
    0 W' B) K6 ?5 p0 d, I% i; [" D7 D" {
  49.       /* 配置QSPI CR寄存器溢出时间计数 */, ^& `6 v8 t/ a9 \; Z: l6 a3 y) J
  50.     MODIFY_REG(hqspi->Instance->CR, QUADSPI_CR_TCEN, cfg->TimeOutActivation);
    2 Y! _4 C4 Q* T; J8 c7 ]

  51. 2 L5 ~# D2 J, n2 v
  52.     if (cfg->TimeOutActivation == QSPI_TIMEOUT_COUNTER_ENABLE)0 h& j: N( ^: L$ a$ a* E1 x0 s
  53.       {
    9 d2 |* f6 a" ~9 F$ Z7 u
  54.         assert_param(IS_QSPI_TIMEOUT_PERIOD(cfg->TimeOutPeriod));  G0 |: v- v# w  F- s

  55. 9 Q, R. P/ H" n: }
  56.         /* 配置溢出时间 */% F: h% G* @+ O( u; `9 f% I; a: s
  57.         WRITE_REG(hqspi->Instance->LPTR, cfg->TimeOutPeriod);
    ! x  {$ d" Y; v

  58. 0 W- p# j; L8 r4 _8 o
  59.         /* 清楚中断标志 */
    9 U' U6 e3 o; D# y0 e3 B7 i
  60.         __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TO);
    1 M* j) m4 k' q- d
  61. 1 P* U  Z1 @* u
  62.         /* 使能QSPI溢出中断 */
    5 V9 V, C9 [" x% T1 Z1 J
  63.         __HAL_QSPI_ENABLE_IT(hqspi, QSPI_IT_TO);
    8 f4 S+ @8 D% {" A
  64.       }2 O: X4 e2 m+ U' R; o: @
  65. : _3 G( m, U! d; g; O& n
  66.       /* 调用配置函数 */4 I0 I5 R. g  T8 @  R2 {
  67.       QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_MEMORY_MAPPED);
    ; v8 Y3 p5 d% v& Z8 `6 Q3 G# N
  68.     }& ]1 s- j: E! M7 q% G/ }% P" ~" s
  69.   }
    8 F1 Z0 i/ @' @! X! j8 e
  70.   else
      k5 _$ F! z$ c  I* A" B# t
  71.   {& f1 m9 ~) j# m9 {
  72.     status = HAL_BUSY;5 l  \8 r; a9 l1 E; n0 Z- O3 Q
  73.   }
    1 Y( C$ \/ T2 e( L7 w' E2 m/ k
  74. : }" A; e5 y; h5 A( ]
  75.   /* 解锁 */
    8 {6 X$ U, D3 V+ U
  76.   __HAL_UNLOCK(hqspi);
      Z1 q- h' T( o
  77. 0 q2 |7 m; S; j0 b4 }
  78.   /* 返回状态 */
    ; W/ v8 g- D6 a, }) C2 P( H& F
  79.   return status;
    & Z8 ^; i$ ?2 W& e9 ?
  80. }
复制代码

/ T* Q4 ^5 s& ?2 I函数描述:$ H- S( N  }* O- F6 ~' C( {

& a: v" n9 Q8 g6 `7 f2 @& g) o用于QSPI内存映射设置。
4 H/ X7 c& B: q! ~/ `" m4 M1 t* A4 ^. H: B  a
函数参数:" u3 S3 ]; K& B9 k& I
. G1 D  q- B. D, {* \( h0 i
  第1个参数是QSPI_HandleTypeDef类型结构体指针变量,详见本章3.3小节。
6 M5 l+ L. r& o1 ~2 V  第2个参数是QSPI_CommandTypeDef类型结构体变量,详见本章3.4小节。
) ]: z8 k: }4 Z# C& l# u  j  第3个参数是QSPI_MemoryMappedTypeDef类型结构体变量,详见本章3.6小节。
2 B5 P) t, L& P; m4 p* ^6 ?# S# x  返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示串口忙,正在使用中。
# p5 G8 C" k. l  ^" |+ ~使用举例:. a$ B! Q% G) l5 K9 {; Z
7 q& D0 \: @6 ^0 K, {7 A5 @" T9 H# R
  1. /*- o+ y$ r/ C' Q6 \# L8 T
  2. *********************************************************************************************************
      |( _( ~6 S, ~" |, _9 A
  3. *    函 数 名: QSPI_MemoryMapped6 @: D) C. R. g: b6 m
  4. *    功能说明: QSPI内存映射,地址 0x90000000
    ) r1 O9 f  N" ]+ {
  5. *    形    参: 无: q8 r7 q: e4 i0 O  I
  6. *    返 回 值: 无
    " K+ F$ t! L8 B4 ~' r
  7. *********************************************************************************************************
    ( o: S+ L% E' y6 U
  8. */) s) v7 n- J9 p2 H
  9. void QSPI_MemoryMapped(void)
    4 z/ d, H! d: v. }7 T. I
  10. {3 z4 S2 B6 h' o8 s  Q, ]: ?+ m% H
  11.     QSPI_CommandTypeDef s_command = {0};
    - q( k9 t6 |+ X( [. d5 F; `
  12.     QSPI_MemoryMappedTypeDef s_mem_mapped_cfg = {0};
    2 t; r4 X* ~& }$ P
  13. / N: P4 _* v" k: \+ v
  14.     /* 基本配置 */
    ( S. l# v7 c( m& g5 f! ~+ {' @
  15.     s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;      /* 1线方式发送指令 */
    1 ]3 a. C. E" q9 b7 |
  16.     s_command.AddressSize = QSPI_ADDRESS_32_BITS;             /* 32位地址 */4 z$ |: X; z1 f0 J; E& g: J  L4 B
  17.     s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
    ; P  r" E+ o$ Z
  18.     s_command.DdrMode = QSPI_DDR_MODE_DISABLE;                /* W25Q256JV不支持DDR */+ P  |/ m# z1 \% m2 x  K
  19.     s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;   /* DDR模式,数据输出延迟 */
    - o6 m( e7 v7 O- W1 y0 d
  20.     s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;            /* 每次传输都发指令 */4 @* W9 M% \5 [- c: a1 s/ v' s
  21. ' @6 r( v  d. g  q/ m/ Z5 t8 i
  22.     /* 全部采用4线 */9 @3 V6 K: ~7 {" `0 s0 \( J
  23.     s_command.Instruction = QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD; /* 快速读取命令 */
    / g5 p9 X- r$ [" Z. q1 b
  24.     s_command.AddressMode = QSPI_ADDRESS_4_LINES;                 /* 4个地址线 */
    8 z5 I/ ]3 h$ O/ N" m. J
  25.     s_command.DataMode = QSPI_DATA_4_LINES;                       /* 4个数据线 */5 J( `4 E. c3 r" E
  26.     s_command.DummyCycles = 6;                                    /* 空周期 */
    # ^6 ~- }( o( L3 K$ [
  27. 4 g! {) h0 J8 Z0 H
  28.     /* 关闭溢出计数 */' h) T0 z  A- s8 h
  29.     s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;8 B2 @2 m$ [1 W2 N! N+ F
  30.     s_mem_mapped_cfg.TimeOutPeriod = 0;# Y0 r5 N% w/ |$ G+ v# }/ N0 D
  31. 2 Q* ?: O; J8 C0 f2 N
  32.     if (HAL_QSPI_MemoryMapped(&QSPIHandle, &s_command, &s_mem_mapped_cfg) != HAL_OK)
    9 A5 d# t$ ]  h* E: M7 _. R$ |
  33.     {
    ' O" D8 F8 H  Y0 u
  34.        Error_Handler(__FILE__, __LINE__);: q5 U3 _# y3 h7 s  x
  35.     }
    & B# o0 I: M* L, {3 l
  36. }
复制代码
. F: t+ z/ u+ d6 F
78.5 总结! Z$ U1 a$ S" c$ |# g$ J* T: a
本章节就为大家讲解这么多,要熟练掌握QSPI总线的查询,中断和DMA方式的API用法。8 R1 V4 t7 g, r2 G. [

/ z4 d7 Y" H* k1 o2 M0 ?: [. l- |. S, \5 X+ Q
74f88e781c0aa6369a48d73fb7dbe7d9.png
收藏 评论0 发布时间:2021-11-4 18:44

举报

0个回答

所属标签

相似分享

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版