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

【经验分享】利用 QuadSPI 外扩串行 NOR Flash 的实现

[复制链接]
STMCU小助手 发布时间:2022-2-22 18:48
前言
# i( y0 ?4 q+ x; iSTM32 提供了灵活多样的外扩存储器访问实现。本文中,介绍如何利用 QSPI (QuadSPI) 外扩串行NOR Flash 存储器。首先对 QSPI 接口功能特性进行介绍,然后分别介绍硬件设计和软件开发。并基于 STM32CubeMX,提供访问 MICRON N25Q128A13EF840F 的实现参考。
* z/ e! z6 D9 R* B
7 {9 l" K. R3 C4 q1 w一 实现环境. X; N  M) Y9 W3 a* `9 I6 D# e& {8 o
开发板:STM32F469G-DISCO
- R( n% F9 M/ n7 `开发库:STM32CubeF4 v1.16.07 }- d3 t4 M! u  K8 [4 M4 F
STM32CubeMX: v4.22.0
% t% F; `! I" _- b集成开发环境:IAR v7.70.1.11486
0 k4 X/ H/ L0 F" a% `* d' k
& k2 u9 o" {, R2 U& w# n. q实现过程在 STM32F469I-DISCO 板上展开,利用板上已有的串行 NOR Flash 存储器(MICRONN25Q128A13EF840F)。呈现整个开发涉及环节。在本文中,首先根据 QSPI 接口,介绍 QSPI 与外扩串行存储器硬件连接。另外,Cube 软件包中包含 QSPI 实现例,在本文对库中实现的 QSPI 例不做讨论,读者也可参考这些 QSPI 例进行设计。本文围绕由 STM32CubeMX 生成的工程,介绍如何实现对外扩串行 NOR Flash 存储器的访问。( z; y1 e( h: s. K# B* L
& ^2 b( Y& T: W' k
, V: y3 f& E& G! ]. Z+ |% p
二 QSPI 介绍) k& d5 i: \$ l2 H7 ^( ^3 `
在呈现 QSPI 访问外扩 Flash 的实现例前, 需要对 QSPI 有一定的了解,在此对 QSPI 进行简短的介绍。更多内容请参考AN4760。
* t; u, C" y) V7 q
  O/ {; c% ^( P. U5 I2 E) W3 Q# x5 q6 B' _. G/ @
QSPI(Quad-SPI)支持四线串行访问形式。同时,QSPI 支持传统 SPI 和 Dual-SPI 模式,Dual-SPI 模式支持两线串行访问。与 FMC/FSMC 比较,QSPI 支持更低成本、更小封装外部串行 Flash 存储器,更少的 IO 引脚占用,有效减少 PCB 面积,降低 PCB 设计复杂度。
: ?; u5 R/ Y9 T) K& P# N, C% iQSPI 在不同系列 STM32 产品线的支持情况(仅部分罗列,未涵盖所有支持型号)。
9 x; o. L+ m7 h  `- X2 \3 S
! W4 O) U4 a' E& I$ R, P/ _9 @. r, r {ZD9YHG}M$K_WY{}P38O6.png
  D' l, @: d" G
. k$ {' O8 {4 H+ F4 eQSPI 接口提供了灵活可配置的 5 个阶段,如下图所示(仅用于理解阶段构成,时序图根据配置不同存在差异)。分别是命令阶段、地址阶段、复用字节阶段、Dummy 阶段和数据阶段。可以根据外扩 Flash 中命令时序对不同阶段进行配置。后续会以实例进行呈现。更多内容请参考 AN4760。
/ ^) m2 e  z$ _, z: J: Z0 s' H+ Y7 u2 u/ O9 Y9 @  [: \
G(43Z~J%M3`)LTRK~Y2U@[X.png
5 m3 N$ D' F' O
/ t* I5 U! C% U2 D6 P8 A5 G6 QQSPI 支持三种模式,分别是:
5 G& A" O0 A0 x$ o4 H# C1 J8 n间接模式  所有操作通过 QSPI 寄存器实现,类似于传统 SPI,可以使用阻塞模式、中断模式或者 DMA 模式进行读写等访问。本文中提供的实现例为间接模式下的实现。1 q2 L1 \1 {1 l: u4 o
状态轮询模式  接口自动轮询指定寄存器,直到回读寄存器内容与指定条件匹配。可应用于状态检测,从而实现忙等待等效果。本文不对此模式进行实现介绍,应用实现可参考 Cube 软件包中 QSPI 例程。$ m1 u' p( E+ u. V; n
存储器映射模式  外扩 Flash 被视为内部存储器,支持 AHB 主器件直接访问,CPU 能够直接运行位于 QSPI 存储器的执行代码。内部系统架构如下图所示(以 STM32F469/F479 为例)。本文不对此模式进行实现介绍,应用实现可参考 Cube软件包中 QSPI 例程 QSPI_ExecuteInPlace。, u% O2 ?" a5 Y5 M$ z( _) T: L! j
" F; o. b8 ~8 A' A" ]
@2GQ%0WHO]3V789F0GKH{BH.png 6 `1 K; T% a0 x: S

; g' O; m! S( E  w$ U$ _8 D( h: T. m" p
三 QSPI 外扩串行 Flash 实现例
  u# K" E- `7 _- B7 F7 v7 q3.1 串行 Flash 介绍$ F5 _: H5 B1 H; `
以 MICRON N25Q128A13EF840F 为例,更多细节请参考存储器手册。N25Q128A13EF840F 引脚图、时序图和电气参数来源于 N25Q128A13 手册文档。
3 ]5 F/ ]$ u  o% f! H2 Z支持协议: SPI, Dual I/O(对应 Dual-SPI), Quad I/O(对应 Quad-SPI)
/ T; P0 c$ y0 X4 S+ r! v( x  a支持访问模式: 单线访问、双线访问、四线访问,得益于 QSPI 接口的灵活可配性,三种访问模式全部支持。
% n; I0 `% O& `3 o供电电压范围: 2.7 ~ 3.6V
1 T* ?* W5 l! \; D# `最大时钟频率: 108MHz- W6 C, X0 w6 @* }1 z. q
存储空间: 128Mb (16MB)
0 m0 `2 f6 Z& ?  a; {- G. ~器件引脚示意图如下所示。由两根电源引脚和六根 QSPI 信号线构成。/ M% {: J8 t; f, n, u+ R# X

. m! k" [: R( K6 G ZMJB2(7FWD5OZ0`4[0J~J[N.png % t6 F* Y) B$ n1 N' n

' G5 V& ]) u' Y- y! z下表为存储器 N25Q128A13xxx 命令(未列出全部命令)。通过下表可知,存储器提供了灵活的访问实现形式,而结合同样灵活可配的 QSPI 接口,能够实现存储器命令全支持。而本文仅为提供设计思路,呈现了部分命令在 QSPI 上的实现。
8 z- J0 P! W5 g% t$ x# y- n% ]8 |- l# f8 b; j+ r# a5 E" `5 Q* `0 v$ Y" I
P~~V0$N(6V_$_G3A6XAJ(7K.png
* j# E5 P& X% V' ^9 S& i1 k5 H" b" n# B- Q9 b& C! i; J) N
其中,默认读写默认 3 字节地址,四线快速读命令默认 Dummy 周期数为 8。3 O; P' h* j2 n) U0 `- ], y: h7 A

4 V, I: b/ {. N2 ~# F/ ~3.2 硬件设计, j0 A' a# Y$ [: [: G
涉及到的信号线少,硬件设计简单,只需直接将 QSPI 的六根信号线与存储器连接即可。考虑到可测性,可以增加串行电阻或者测试点。硬件电路图如下所示。
5 l2 n) Z% @1 P/ e1 J9 i
5 k" @$ J( |8 N6 y1 l+ _; c Q{OUTZO[02XZ{L7_@%F)7O5.png
# ^( e" m4 Q. E+ Z1 s# z5 S2 ?% a" Q2 g
QSPI 接口 PCB 设计遵循如下几点,更多硬件设计内容请参考 AN4488。
+ z8 T4 s0 p  ~  l7 l0 Aa. 线阻 50Ω ±10%7 T. B. A$ I" ]' z
b. 最大线长 < 120mmc. 避免在不同信号层走信号线6 |1 H7 G0 U7 R
d. 时钟线至少离其他信号线 3 倍线宽距离4 t0 ]4 c% ?* F0 z
e. 数据信号线长差 ≤ 10mm- Z. t! P0 L0 s+ ~" l
f. 避免时钟线采用蛇形走线,同时尽量减少数据线上过孔。
+ v+ p1 a. G' G) `/ q( c
3 r- }  v3 x# m9 ^" [  I, T. Q( U3 a) \$ @
3.3 软件开发流程" d9 X+ V* w, v6 ~5 ~# i$ n% U  c4 ]
4 |+ T. T% ^$ R6 p. N
Q6H]N_YL1]8O)6`AQWOC$H8.png
; P- f( h2 b0 s
/ o+ z0 H9 L# y3.4 软件实现例
& h" ?2 I% ?# g. R9 f# ^- n- u6 W在环境搭建完成后,就可以利用 STM32CubeMX 根据硬件连接情况,进行 QSPI 配置,获取 IAR 工程。具体软件实现流$ n. d: ]. H0 G5 U) u$ P; x
程如下。
3 C* y& b" z! B& k4 o( }# d  V
9 e, l& T' |9 e+ O0 O7 f' C' P
$ E" P! Q7 S! r2 v1 A: b ~LQVQPWMRM80Y]~5FDOGOQ1.png
: s/ S( H- m* C; K* R1 y: V# T1 Y1 A8 [8 {7 ^# P

7 m/ U7 U& q! N# c& \/ |- O4 i( ^a. 利用 STM32CubeMX 生成 IAR 工程* i; h" T5 S7 H+ a- }) w, |
打开 STM32CubeMX - 点击”New project” - 在”Part Number Search’中输入 STM32F469NI - 点击”MCUs Liast”中出现的 STM32F469NIHx - 点击“Start Project” - 此时,基于 STM32F469NIHx 的 STM32CubeMX 工程被打开。如下,根据 STM32F469I-DISCO 板硬件连接情况(QSPI NCS, CLK, Q0, Q1, Q2, Q3 对应 PB6, PF10, PF8, PF9,PF7, PF6;外部高速晶振为 8MHz 无源晶振;调试接口采用 SWD 接口,其中 SWCLK, SWDIO 对应 PA14, PA13):选择” QuadSPI”为”Bank1 with Quad SPI Lines”(注:也可在开发过程中,先用 STM32CubeMX 查看 QSPI 接口对应的 IO 引脚,进行硬件开发) 。
, Q7 g9 e% \4 [# t( b3 F# r注: 在如上选择后,右侧引脚图中 QSPI 对应的引脚会呈现绿色显示。需要根据电路图中所连接的 QSPI 引脚,进行复用引脚确认。例如,在默认情况下,QSPI IO0 对应到 PC9 引脚,而 STM32F469I-DISCO 板上的 QSPI IO0 与PF8 连接,并非 PC9。所以,需要在右侧引脚图中,按住 Ctrl 键,左键在 PC9 引脚按下,拖动至 PF8 处,松开左键和 Ctrl 键,实现 IO0 引脚的关联。& a1 `8 u# |5 j0 e
选择“High Speed Clock(HSE)”为“Crystal/Ceramic Resonator”。
3 @/ s$ W5 e. w8 c0 q3 l选择”Debug”为”Serial Wire”
. b/ Y* m  W, m' A0 m; y; p; ~. y% w6 H6 \' c# w

+ `$ p7 c% z+ h* w, [6 v C23EP4AS9T7W`[OA%5S18`Q.png + X  O" a- Y& V6 }0 v
5 y* L* M4 H1 L! N7 p: }- j6 F& d/ y) g
时钟配置如下图所示。设置输入时钟频率为 8MHz - 选择”HSE”做为 PLL 倍频时钟源 - 选择”PLLCLK”做为主频时钟源 - 设置 “HCLK”为 180MHz (FAHB 为 180MHz)- 点击 Enter 键,自动生成对应主频的时钟参数(仅提供时钟配置参考,并不限制一定要设置 180MHz 主频)。
$ l6 A6 v* F9 w5 @2 g2 ?% x0 S4 K3 K; E& J" O
# d1 i. I$ e/ B
%9`PUO)YAL~PXHD(E4H4_TB.png * a  `5 F0 }: q9 Z
. g8 P0 x( U* c1 h
QSPI 配置如下图。参数的配置需要与存储器参数匹配。! c: j( C. _2 W9 ~
• FIFO Threshold(FIFO 阈值) 配置为 4,并不严格要求。0 Y! K" x9 w- P+ @" |
• Smaple shift 选择“Sample shifting half cycle”。延后半个时钟,获取数据线上数据。可以使用在由于线路设计,数
  s5 V* {5 _' E8 Y9 V据信号存在较大延迟的场景。! t! u8 P& d! G! z( \) Z, K( J
4 C! `% S9 n# @

8 R; m4 U& |$ P RQHJOG_`HZJN1HZD@)57FFX.png
6 I0 o8 ^4 A0 m( B  x9 C; j4 p4 s9 Z. Q
使能 QSPI 中断。
, ?9 C" o  A" U  O
) o( ^  r; L! \ MY%W~@29U]WE69[]U4MJ~7Y.png , j$ M3 Y) h* H( f

, Y3 P0 T/ a# g7 i8 R7 S% l点击菜单栏”Project” - “Settings” - 设置”Project Name” , “Project Location” 和 “Toolchain / IDE” 。其中“Toolchain/ IDE”设置为 EWARM 以便生成对应 IDE 的工程。其他选项保持默认。/ g+ P) w, |( |4 ]- j
点击菜单栏”Project”  “Generate Code”  等待 IAR 工程生成,出现”Code Generation”界面 - 点击”Open Project”打开工程。
3 h, Q( V1 ^+ G6 I  U0 g, c' o2 Z- ]2 R; E
b. 完善工程。) v- k' A; [. `8 ~/ d# Z, D2 }7 m+ o
由上述步骤获得的 IAR 工程中,包含了时钟配置及 QSPI 接口的初始化。对于外扩 Flash 的操作,还需要 添加外扩Flash 支持的命令进行操作。N25Q128A13EF840F 支持的部分命令可参见本文 3.1 小结。
; k/ a# Q5 N2 W/ N' A在这里出于简化考虑,仅提供了阻塞式读取 ID,擦除 Flash,块写和快读操作的实现。更多实现模式,可以参考Cube 软件包中提供的 QSPI 例程。! Z: j$ A8 k/ m9 ?1 K. y6 X2 R
在 N25Q128A13EF840F 手册中提供了读 ID 命令时序,如下图所示。9 V& X: B/ c& _9 k1 P  ^' ]# k5 W
8 ]) L' H6 Z& z$ l$ w: X! ?
PV{B8I~5GR7NA2~US_OS2T3.png 0 k, `5 V  Q( u2 \4 l* d
! a, d2 q/ ]% m, f& p4 e
由时序图可知,读 ID 时序构成: 命令阶段 + 数据阶段。命令阶段和数据阶段线宽都为 1,读 ID 命令码为 0x9E 或者0x9F,ID 数据长度为 17 字节。# W' g1 Z# l' F1 y* j
在 N25Q128A13EF840F 手册中提供了写使能命令时序,如下图所示。
( k6 M, S& M9 V2 k3 Y# ^4 |$ H
: r5 l. B: q+ @! N8 i' I
  d# a$ n  @+ s* T GCO@4Y}W4V@@XJW4S3CH_3Q.png
: l# j- U( ?& j5 i7 ?; k+ x3 E) w! j
由时序图可知,块擦除时序仅有命令阶段。命令阶段线宽为 1,写使能命令码为 0x06。(注:这里仅呈现了单线命令模式的实现。除此之外,STM32 QSPI 接口和外扩存储器支持双线、四线模式)。7 A' }, p+ r7 v& h4 a4 {, V
在 N25Q128A13EF840F 手册中提供了扇区擦除命令时序,如下图所示。8 y$ q8 F! s" W9 ?
- ^  ~; z0 Y& {- L( v. @5 R' g  k
7Y(S}25F84FHD[Y@OV58]ID.png
' @2 c0 M4 a2 F. |! s
2 @. W! A  I; q; z由时序图可知,扇区擦除时序构成:命令阶段+地址阶段。命令阶段和地址阶段线宽为 1,扇区擦除命令码为 0xD8。其中地址为 24-bit,任一位于需要进行擦除操作的扇区范围内地址都有效。在此简单选择扇区 0 进行擦除,选择地址为 0。(注:这里仅呈现了单线命令模式的实现。除此之外,STM32 QSPI 接口和外扩存储器支持双线、四线模式)。在 N25Q128A13EF840F 手册中提供了四线快速写命令时序,如下图所示。
1 s: m! X8 k: t! z, X% z5 w& r: O. Y' O1 [8 ~. W' Y
PJL4TD`8P)2AEWOOG04QLI2.png
2 A! |. Y! D+ ~) l, B7 F# y6 P1 j
4 j% R* Q* ^0 ~( P( D( e由时序图可知,四线快速写命令时序构成:命令阶段+地址阶段+数据阶段。命令阶段和地址阶段线宽为 1,数据阶段线宽为 4,四线快速写命令码为 0x32。其中地址为 24-bit,对应写入起始地址。(注:这里仅呈现了单线命令模式的实现。除此之外,STM32 QSPI 接口和外扩存储器支持双线、四线模式)。
/ {! J7 F0 G1 c1 c: d7 B# j; \0 r在 N25Q128A13EF840F 手册中提供了四线快速读命令时序,如下图所示。8 ]4 ]3 \9 q4 k; a% t3 Y
. Y. V- _3 Y" B; _
K4~X}UFP]K)_{D~PF$KU{BS.png
1 t9 K# x) P) ?# s( ^4 u4 q1 }; |" q7 u: i5 o6 ~2 u
由时序图可知,四线快速读命令时序构成:命令阶段+地址阶段+数据阶段。命令阶段和地址阶段线宽为 1,数据阶段线宽为 4,四线快速读命令码为 0x6B。其中地址为 24-bit,对应写入起始地址。四线快速读命令默认 Dummycycles 为 8。(注:这里仅呈现了单线命令模式的实现。除此之外,STM32 QSPI 接口和外扩存储器支持双线、四线模式)。9 u& w. @/ Y3 F2 G* {0 `
在 main.c \ main 函数中,增加代码如下。
2 s1 y: c- m3 u% c
/ f' A/ {5 j9 D( X- X4 H3 [* e  n
  1. … //系统、时钟、IO 和 QSPI 初始化
    % C; T: E1 b* {
  2. /* USER CODE BEGIN 2 */
      X" }+ P: }: j/ y+ F! P
  3. QSPI_CommandTypeDef sCommand;
    : I: Z' `5 V  B0 v( k
  4. static uint8_t Buf_ID[17] = {0};7 g  C3 J9 |1 L! M# ]3 j
  5. static uint8_t TxBuf[0x10] = "Ext Flash", RxBuf[0x10] = {0};
    ; c7 S% D" ?0 p! L) ]  ?6 F
  6. 2 d0 C- q! w$ C# G4 v' B
  7. sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; //DDR 模式失能
    ( g6 V0 ~+ J& M; Y& u& _7 R( ^0 e
  8. sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; //DDR 模式下,数据延迟输出
    & {4 M; a& F% U
  9. sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; //每次发送都包含命令阶段5 D  `1 r$ u" m7 R
  10. /***** 读 ID 操作 *****/
    + U  J( ]/ L6 i8 n/ h+ H% c. j, T
  11. sCommand.Instruction = 0x9F; //READ ID 命令码( x9 l- i( y$ w: K6 E
  12. sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; //命令线宽
    $ C; K! \) \  [! g. F/ L( t
  13. sCommand.AddressMode = QSPI_ADDRESS_NONE; //地址线宽。无地址阶段8 u/ N9 Y( a! W3 j) A1 P5 [4 y
  14. sCommand.DataMode = QSPI_DATA_1_LINE; //数据线宽
    # s- W, F' X1 U$ m! `* W$ a
  15. sCommand.NbData = 17; //读取数据长度。ID 长度为 17 字节
    ) S- @5 Z7 @4 F+ A! t
  16. sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //无复用字节阶段9 V7 j4 W6 q7 O% ~/ f8 M( }, q
  17. sCommand.DummyCycles = 0; //无 Dummy 阶段7 g4 a, e3 k3 |6 @0 M
  18. //配置命令(在有数据阶段时,命令在后续发送/接收 API 调用时发送)/ W4 u( U/ L- v$ N/ W6 V9 s
  19. if (HAL_QSPI_Command(&hqspi, &sCommand, 5000) != HAL_OK)2 ]7 `6 Y% P8 Z2 ?/ |' r' I
  20. {' u. d8 L/ v) k5 n
  21. Error_Handler();
    : D  }% r0 p! ]) \7 z5 L
  22. }
    6 ?$ s, ^5 H' g" U  {
  23. //执行 QSPI 接收
    / h3 l% q6 G7 ~9 A2 D- t2 P
  24. if (HAL_QSPI_Receive(&hqspi, Buf_ID,5000) != HAL_OK)0 U9 F0 n8 M, v. a& V; }
  25. {
    " Y! j" e2 A1 p
  26. Error_Handler();
    & h0 h0 s. N6 s  T  b) R5 D" G4 H
  27. }
    * v1 n" }# V0 X) H8 F: l" a: @8 t
  28. HAL_Delay(1); //延时 1ms. 单位为 SysTick 定时中断周期+ e; u. t& N2 d7 |

  29. ; _: M' M3 `. m* n2 `
  30. /***** 写使能操作(需要在块擦除之前,使外扩存储器处于写使能状态) *****/
    1 x* t% e+ D3 `6 `/ {
  31. sCommand.Instruction = 0x06; //写使能 命令码5 y0 z0 i  Z4 a; V
  32. sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; //命令线宽4 j7 W. ?6 M7 l3 ~4 b9 j! U
  33. sCommand.AddressMode = QSPI_ADDRESS_NONE; //地址线宽。无地址阶段
    2 ]8 e% M2 i5 |7 o
  34. sCommand.DataMode = QSPI_DATA_NONE; //数据线宽。无数据阶段  D% o( v/ P) C- K
  35. sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //无复用字节阶段8 |' y0 H% T0 m, b# O
  36. sCommand.DummyCycles = 0; //无 Dummy 阶段
    + X4 C3 [4 A7 M5 o
  37. //配置发送命令: }1 [2 x! {( ^# E, L; P  h
  38. if (HAL_QSPI_Command(&hqspi, &sCommand, 5000) != HAL_OK)
    5 t" K" b( [3 i
  39. {6 x* y. y( W+ {" p( [* f
  40. Error_Handler();* l1 L+ r8 Q- `( Q, n) C
  41. }9 L3 I0 i" }5 s) y+ `. ]

  42. 9 ^! f- \0 y4 L. U1 M4 |( }
  43. /***** 块擦除操作 *****/
    : P' o4 \/ I. d- m
  44. sCommand.Instruction = 0xD8; //扇区擦除 命令码
    ( G% Y7 F! R: j' j, B
  45. sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; //命令线宽
    0 U' F3 a: g9 v0 c' d0 E. `- B! D/ e
  46. sCommand.AddressMode = QSPI_ADDRESS_1_LINE; //地址线宽。无地址阶段
    - b. N  E* X! X
  47. sCommand.AddressSize = QSPI_ADDRESS_24_BITS; //地址长度, S% K% j+ b' n5 h; s. ]
  48. sCommand.Address = 0; //位于所需擦除扇区内的任一地址。
    : Y- U* [" m" Q# a+ Q. X
  49. sCommand.DataMode = QSPI_DATA_NONE; //数据线宽。无数据阶段
    2 Y7 p% m* d1 U, L' N# \& {
  50. sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //无复用字节阶段
    0 x: q9 n/ T1 u$ h2 u/ Y: c( s' l
  51. sCommand.DummyCycles = 0; //无 Dummy 阶段
    ( K; m- J+ F( N# c3 z
  52. //配置发送命令6 u! ]  k  Y2 Y% Y9 y$ J# x8 p+ B
  53. if (HAL_QSPI_Command(&hqspi, &sCommand, 5000) != HAL_OK)
    8 v4 s8 z3 V2 a/ R7 v1 y9 ~2 @! R
  54. {% X! `' N; i' U
  55. Error_Handler();
    2 ^7 O. w: ]5 t* g6 C
  56. }
    3 |3 ]  X$ }! q  K+ I
  57. HAL_Delay(3000); //延时 3s. 单位为 SysTick 定时中断周期8 s8 O. Q# |6 G/ R/ N9 u& e

  58. ' x6 S" a0 p2 r
  59. /***** 写使能操作(需要在块擦除之前,使外扩存储器处于写使能状态) *****/+ L1 ~- M  s: c) r% P" I
  60. sCommand.Instruction = 0x06; //写使能 命令码: p$ j' s4 ^1 X2 }' N5 H& Q
  61. sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; //命令线宽4 G# C6 A4 W7 A2 d4 Y
  62. sCommand.AddressMode = QSPI_ADDRESS_NONE; //地址线宽。无地址阶段) A7 C; @/ D* w- I
  63. sCommand.DataMode = QSPI_DATA_NONE; //数据线宽。无数据阶段4 u+ l9 o+ x/ J" C: h
  64. sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //无复用字节阶段3 o# v4 E4 ^# N; Q  O2 [9 V
  65. sCommand.DummyCycles = 0; //无 Dummy 阶段2 t; T3 w! h2 N( n; I7 h/ Y& A
  66. //配置发送命令
    6 s3 z4 ~' D( b) n5 ?7 ]& J/ n
  67. if (HAL_QSPI_Command(&hqspi, &sCommand, 5000) != HAL_OK)/ Y- |6 h+ L& e! q
  68. {
    4 e5 e7 M( m6 y4 E  w( t" T
  69. Error_Handler();. S4 D0 M3 N' j% w
  70. }
    7 S4 U+ M3 @9 y

  71. ) A; h" a: F0 j. }) }
  72. /***** 四线快速写操作 *****/
    / W( |6 v  m/ j7 C+ x7 `
  73. sCommand.Instruction = 0x32; //四线快速写 命令码& i! s1 F' U0 }4 m+ W! D  L
  74. sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; //命令线宽0 y+ V# l* w- t* {
  75. sCommand.AddressMode = QSPI_ADDRESS_1_LINE; //地址线宽
    , m; p- K2 G( c
  76. sCommand.AddressSize = QSPI_ADDRESS_24_BITS; //地址长度
    $ |9 u+ w& x! p* m: d" v- T
  77. sCommand.Address = 0; //写入起始地址
    * B' d- M+ h1 d/ D: q
  78. sCommand.DataMode = QSPI_DATA_4_LINES; //数据线宽" K4 a+ x) J$ m7 Z
  79. sCommand.NbData = 10; //写入数据长度( T9 E2 F8 Z5 N6 v: X* R
  80. sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //无复用字节阶段
    : X  Q7 l+ N6 D+ g
  81. sCommand.DummyCycles = 0; //无 Dummy 阶段
    ' v8 g! Q- _; T5 P" d# Q$ g/ M
  82. //配置命令(在有数据阶段时,命令在后续发送/接收 API 调用时发送)
    ! G& Q% m2 M7 Y. l2 k9 r9 r3 N
  83. if (HAL_QSPI_Command(&hqspi, &sCommand, 5000) != HAL_OK)
    # ?* ~* I) i0 u# f& C7 Y
  84. {
    # B7 h0 b8 c- ^& W+ ^4 ]
  85. Error_Handler();; i, b1 C. B# K) {: a
  86. }
    0 K; i7 W0 j3 V- Z2 R* [
  87. //执行 QSPI 接收; _7 O4 k0 B) O; W
  88. if (HAL_QSPI_Transmit(&hqspi, TxBuf ,5000) != HAL_OK)
    6 d+ y3 q9 l- L* T" I1 L
  89. {
    + d4 q  V8 }9 J4 O
  90. Error_Handler();
    0 X! q# f8 a4 E' B
  91. }& G# t" ]6 H$ r: H
  92. HAL_Delay(5); //延时 5ms. 单位为 SysTick 定时中断周期0 B! L* ~6 r2 [, f4 N: R, w
  93. " H- z( c$ \6 O4 Y, x' X1 a1 _) j/ v
  94. /***** 四线快速读操作 *****/
    5 M+ s2 ?3 [! U
  95. sCommand.Instruction = 0x6B; //四线快速读 命令码
    4 P9 x1 R0 R6 g4 |8 b
  96. sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; //命令线宽1 O" r0 T. L: I: [5 Z3 [
  97. sCommand.AddressMode = QSPI_ADDRESS_1_LINE; //地址线宽
    + D) a/ V5 j8 z& }( c" d# p) w
  98. sCommand.AddressSize = QSPI_ADDRESS_24_BITS; //地址长度9 n( U/ z3 g. a4 f
  99. sCommand.Address = 0; //起始地址, F2 i& F' g& Z! Z( n& K9 x
  100. sCommand.DataMode = QSPI_DATA_4_LINES; //数据线宽
    $ d7 ^6 t$ o' W8 K7 [8 x
  101. sCommand.NbData = 10; //读取数据长度/ C# G& U, d2 C( @7 G! K. m
  102. sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //无复用字节阶段
    7 J0 r8 a( G: x: q& }, j5 f
  103. sCommand.DummyCycles = 8; //Dummy 阶段。N25Q128A13EF840F) R! a/ [3 z+ c' V/ V
  104. Dummy cycles 默认为 15
    6 V3 y. L' A7 y/ @6 P3 _% l5 x& t
  105. //配置命令(在有数据阶段时,命令在后续发送/接收 API 调用时发送), q7 q* q, l. G& {0 y
  106. if (HAL_QSPI_Command(&hqspi, &sCommand, 5000) != HAL_OK)
    ' b+ c" ?! ?9 t+ W
  107. {5 N# K5 m; Q: K1 ~
  108. Error_Handler();
    * F4 w- ~3 R( S! l- c& F
  109. }
    / n  t' B, f: G% S4 I
  110. //执行 QSPI 接收
    + q- [% k( W/ J
  111. if (HAL_QSPI_Receive(&hqspi, RxBuf,5000) != HAL_OK)& W: K/ K" q/ z; y' ^- H: [  H! F
  112. {& `8 p, C5 F$ K2 E1 m
  113. Error_Handler();) U/ E. p/ W2 r9 N  R
  114. }
    ( O! S/ M9 _6 d) b+ _% E- {
  115. /* USER CODE END 2 */
复制代码

" w6 ]7 F, T% Z" C: x
- i+ r5 l$ j; d四 小结
) \+ }8 q" ~- B& B6 @4 ^. T3 d5 sSTM32 的 QuadSPI 接口灵活可配,对于命令阶段、地址阶段、复用字节阶段、Dummy 阶段和数据阶段都可以进行配置。基于这种灵活性,能够实现市面上 SPI、Dual IO、Quad IO 的串行 Flash 支持。但出于简化考虑,QSPI 支持的中断访问及DMA 访问等更多功能没有在本文进行介绍,更多实现可以参考 ST 提供的 Cube 软件包中的 QSPI 例程。另外,不同厂家的串行 Flash 命令及操作实现略有差异,具体以采用的 Flash 文档描述为准。
0 x4 b! d* _0 B" }% ?
- B+ @  d. |; `( R) z, B# r
! N' F6 ]- ^' L5 n! N$ ]. ]' F' G0 E

' E5 \' \* j3 P
4 d" t% X0 T! @: q+ W- ?# M0 ?4 U  `4 v# [
- `5 N4 R9 F- o3 v; z3 M
收藏 1 评论0 发布时间:2022-2-22 18:48

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版