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

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

[复制链接]
STMCU小助手 发布时间:2022-2-22 18:48
前言# N- F+ |0 ~$ d5 I' I
STM32 提供了灵活多样的外扩存储器访问实现。本文中,介绍如何利用 QSPI (QuadSPI) 外扩串行NOR Flash 存储器。首先对 QSPI 接口功能特性进行介绍,然后分别介绍硬件设计和软件开发。并基于 STM32CubeMX,提供访问 MICRON N25Q128A13EF840F 的实现参考。
$ b7 U5 S5 [& t9 D/ M  s
, c6 \9 e* g0 b* t/ t) p一 实现环境
$ ~; {1 `. @6 [" O开发板:STM32F469G-DISCO/ U- Q3 D1 \+ G# ]  T
开发库:STM32CubeF4 v1.16.0
2 `7 _- v( j& w7 W) b) LSTM32CubeMX: v4.22.0
/ f4 ~! t- [2 K1 \$ s集成开发环境:IAR v7.70.1.114862 E0 ?4 o/ \- S- F" w3 `) c3 O: x

( A: Q9 K- ~- F  @- N实现过程在 STM32F469I-DISCO 板上展开,利用板上已有的串行 NOR Flash 存储器(MICRONN25Q128A13EF840F)。呈现整个开发涉及环节。在本文中,首先根据 QSPI 接口,介绍 QSPI 与外扩串行存储器硬件连接。另外,Cube 软件包中包含 QSPI 实现例,在本文对库中实现的 QSPI 例不做讨论,读者也可参考这些 QSPI 例进行设计。本文围绕由 STM32CubeMX 生成的工程,介绍如何实现对外扩串行 NOR Flash 存储器的访问。
- I6 J1 _. C* p. O1 N
; o! z3 y# ^( X0 u" L* c: B! q: E; J" L
二 QSPI 介绍
. g8 z. h. E3 m" y3 U在呈现 QSPI 访问外扩 Flash 的实现例前, 需要对 QSPI 有一定的了解,在此对 QSPI 进行简短的介绍。更多内容请参考AN4760。2 y# N3 L4 r8 j0 V+ k# h' W

) }6 ~4 [  m; y% J& c8 X
. B! i: T8 S) G9 b4 p' rQSPI(Quad-SPI)支持四线串行访问形式。同时,QSPI 支持传统 SPI 和 Dual-SPI 模式,Dual-SPI 模式支持两线串行访问。与 FMC/FSMC 比较,QSPI 支持更低成本、更小封装外部串行 Flash 存储器,更少的 IO 引脚占用,有效减少 PCB 面积,降低 PCB 设计复杂度。& _* S# y) v) a0 }: j9 i
QSPI 在不同系列 STM32 产品线的支持情况(仅部分罗列,未涵盖所有支持型号)。
3 S4 C& q. Q1 b2 ^
, Y. g+ P' m; K6 I4 w {ZD9YHG}M$K_WY{}P38O6.png 0 U7 v- p+ v" r8 A/ Q% ?+ b
# d7 D8 Y! C, {- x, h
QSPI 接口提供了灵活可配置的 5 个阶段,如下图所示(仅用于理解阶段构成,时序图根据配置不同存在差异)。分别是命令阶段、地址阶段、复用字节阶段、Dummy 阶段和数据阶段。可以根据外扩 Flash 中命令时序对不同阶段进行配置。后续会以实例进行呈现。更多内容请参考 AN4760。
( e8 y9 W9 k6 Y6 n% O/ {: z2 d, i$ g6 l( U  S5 Z" G
G(43Z~J%M3`)LTRK~Y2U@[X.png % S/ S# Y$ H1 x4 D) H$ T  z0 V7 l
1 ^- n' S. w: r; u2 j! ^
QSPI 支持三种模式,分别是:
& o$ R& R! `; k' ?5 `7 [; ^1 ]间接模式  所有操作通过 QSPI 寄存器实现,类似于传统 SPI,可以使用阻塞模式、中断模式或者 DMA 模式进行读写等访问。本文中提供的实现例为间接模式下的实现。; h1 _  B6 J( \8 b+ @" y. i( Y
状态轮询模式  接口自动轮询指定寄存器,直到回读寄存器内容与指定条件匹配。可应用于状态检测,从而实现忙等待等效果。本文不对此模式进行实现介绍,应用实现可参考 Cube 软件包中 QSPI 例程。
) X6 N6 b, w1 Z' @0 `& p存储器映射模式  外扩 Flash 被视为内部存储器,支持 AHB 主器件直接访问,CPU 能够直接运行位于 QSPI 存储器的执行代码。内部系统架构如下图所示(以 STM32F469/F479 为例)。本文不对此模式进行实现介绍,应用实现可参考 Cube软件包中 QSPI 例程 QSPI_ExecuteInPlace。
# A% U* L" T/ d0 g" v6 J7 d7 Z7 G; ~  {
@2GQ%0WHO]3V789F0GKH{BH.png ( t; B* i4 Y8 V8 B: w

9 N+ T7 v+ e/ u0 Y+ A+ e3 F/ I% N1 G. c" C) x  j5 i* T
三 QSPI 外扩串行 Flash 实现例' B3 Q  V3 Y5 H$ E
3.1 串行 Flash 介绍6 x: E" g, ^, Y: q2 U/ O& A: ~% G+ A
以 MICRON N25Q128A13EF840F 为例,更多细节请参考存储器手册。N25Q128A13EF840F 引脚图、时序图和电气参数来源于 N25Q128A13 手册文档。
4 J/ p; F) V2 F2 N支持协议: SPI, Dual I/O(对应 Dual-SPI), Quad I/O(对应 Quad-SPI)1 M9 N2 T+ j# N+ E0 ]; w
支持访问模式: 单线访问、双线访问、四线访问,得益于 QSPI 接口的灵活可配性,三种访问模式全部支持。9 F+ G7 T* [" |8 g- N4 @
供电电压范围: 2.7 ~ 3.6V
# d; l0 F8 [1 Y+ R最大时钟频率: 108MHz  j$ K" }) n8 _$ Y9 _
存储空间: 128Mb (16MB)
1 x$ }; a& L% J6 x, r2 _器件引脚示意图如下所示。由两根电源引脚和六根 QSPI 信号线构成。9 _/ i! z5 V! f

# g; P& }& H  l% q ZMJB2(7FWD5OZ0`4[0J~J[N.png & n: i9 ]% h+ {+ _9 d. ]
% N8 h8 o0 I, a
下表为存储器 N25Q128A13xxx 命令(未列出全部命令)。通过下表可知,存储器提供了灵活的访问实现形式,而结合同样灵活可配的 QSPI 接口,能够实现存储器命令全支持。而本文仅为提供设计思路,呈现了部分命令在 QSPI 上的实现。5 Z( @) f* A" j; B! m
/ Z% i# d# x* e8 y) M
P~~V0$N(6V_$_G3A6XAJ(7K.png - T& D  p0 N& m5 f% x
1 d* u1 @; c/ P' O
其中,默认读写默认 3 字节地址,四线快速读命令默认 Dummy 周期数为 8。
- U4 Z+ Z8 O6 G7 T7 |' D& J; R* a3 k4 k7 D7 t9 ]7 q
3.2 硬件设计
7 x- `- d1 e# {( y; L7 j涉及到的信号线少,硬件设计简单,只需直接将 QSPI 的六根信号线与存储器连接即可。考虑到可测性,可以增加串行电阻或者测试点。硬件电路图如下所示。7 z0 K. k9 \; K( s3 v- z

$ B( V; M6 Q( C! y3 f6 m; T! J Q{OUTZO[02XZ{L7_@%F)7O5.png
$ F. {4 h: L( b: x# S* e! ^) y1 l1 M, @/ |/ ^! Q
QSPI 接口 PCB 设计遵循如下几点,更多硬件设计内容请参考 AN4488。
2 w" I* T1 F% x+ d$ wa. 线阻 50Ω ±10%* e  E  u1 m8 d6 O8 }
b. 最大线长 < 120mmc. 避免在不同信号层走信号线
8 {- c8 Z. m) [/ kd. 时钟线至少离其他信号线 3 倍线宽距离, b# g5 W0 f5 f# P3 v) J
e. 数据信号线长差 ≤ 10mm
8 _' P" S1 g; n& Q" Z& Yf. 避免时钟线采用蛇形走线,同时尽量减少数据线上过孔。
* V3 L3 Z: a+ W% E. d. V- Z6 w+ R
6 m7 }- A" L+ s3 ^9 w) d9 v
% i% Z8 v* T1 \! X3.3 软件开发流程
/ \3 O) |. f( @; v. |9 M
# O8 S4 y: U3 Q Q6H]N_YL1]8O)6`AQWOC$H8.png
% N0 n4 x  }; _% R- d0 _! s- N( E3 q/ L1 g
3.4 软件实现例
% |# ^' t/ p* ~* }& j4 f1 ~* Z在环境搭建完成后,就可以利用 STM32CubeMX 根据硬件连接情况,进行 QSPI 配置,获取 IAR 工程。具体软件实现流0 Z! {7 V2 k3 I  M) q
程如下。4 Z# b) o) }! y
# q  A1 n4 z/ a* M8 T; U

& g4 {; @: T7 T ~LQVQPWMRM80Y]~5FDOGOQ1.png " B: Y# @2 p& X/ V

- P7 q% Z3 [& b: p6 Z) o! L2 @! k$ q1 O* c  u
a. 利用 STM32CubeMX 生成 IAR 工程
4 L1 v/ o. t7 E% Y# z打开 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 引脚,进行硬件开发) 。& i( ~4 @/ b. i
注: 在如上选择后,右侧引脚图中 QSPI 对应的引脚会呈现绿色显示。需要根据电路图中所连接的 QSPI 引脚,进行复用引脚确认。例如,在默认情况下,QSPI IO0 对应到 PC9 引脚,而 STM32F469I-DISCO 板上的 QSPI IO0 与PF8 连接,并非 PC9。所以,需要在右侧引脚图中,按住 Ctrl 键,左键在 PC9 引脚按下,拖动至 PF8 处,松开左键和 Ctrl 键,实现 IO0 引脚的关联。
$ K5 f- ~1 u  P选择“High Speed Clock(HSE)”为“Crystal/Ceramic Resonator”。5 T& v% z* y+ p- V% f" I9 A
选择”Debug”为”Serial Wire”
/ |( C1 [5 x! n# @8 s
+ m1 Z% Z9 k4 ^9 ^  K- n, m0 [6 L
7 K  o+ |/ f& J& e C23EP4AS9T7W`[OA%5S18`Q.png ) z. t" x/ P4 E* u6 p

: ~. A! G+ E5 h* A时钟配置如下图所示。设置输入时钟频率为 8MHz - 选择”HSE”做为 PLL 倍频时钟源 - 选择”PLLCLK”做为主频时钟源 - 设置 “HCLK”为 180MHz (FAHB 为 180MHz)- 点击 Enter 键,自动生成对应主频的时钟参数(仅提供时钟配置参考,并不限制一定要设置 180MHz 主频)。1 t9 j8 p/ s" Y3 k8 W/ _

+ e9 {9 `8 `. |3 z( I, x4 O
& f2 e# p% e1 ]# E# G# z& A% C1 _' T %9`PUO)YAL~PXHD(E4H4_TB.png
" Q  {7 c. M: k$ y9 _5 v2 M/ K& |. A" U
QSPI 配置如下图。参数的配置需要与存储器参数匹配。; @- x' O& h* {0 U+ @' o
• FIFO Threshold(FIFO 阈值) 配置为 4,并不严格要求。) k' V% t" l% M# m# h9 x% F+ H
• Smaple shift 选择“Sample shifting half cycle”。延后半个时钟,获取数据线上数据。可以使用在由于线路设计,数/ j) s  r1 `( [+ T6 |3 Y
据信号存在较大延迟的场景。7 o* a( \" K" a8 i, `1 R& G+ W

7 j/ X7 }" Y+ O  @
. i$ J7 i3 X( I* }2 r8 w8 N RQHJOG_`HZJN1HZD@)57FFX.png
' ~+ X0 d" v5 H: e2 G0 F2 t
& g6 K8 \. M( [1 L; `; i9 U1 b& z使能 QSPI 中断。
$ x  S/ ]' t7 a7 p! |
) |0 v6 A/ Y# w! K- |' B! L MY%W~@29U]WE69[]U4MJ~7Y.png
9 o9 ~* e7 i) Y2 X  @$ b1 i/ F4 ^9 J0 A+ ~. o/ o" Q
点击菜单栏”Project” - “Settings” - 设置”Project Name” , “Project Location” 和 “Toolchain / IDE” 。其中“Toolchain/ IDE”设置为 EWARM 以便生成对应 IDE 的工程。其他选项保持默认。; X" ?5 W" b4 `& m! d7 H2 |
点击菜单栏”Project”  “Generate Code”  等待 IAR 工程生成,出现”Code Generation”界面 - 点击”Open Project”打开工程。
/ C1 M& h: A! C4 K: x8 `7 o: |2 Q9 Z% K# q
b. 完善工程。6 M/ O* D& r. B$ F" I+ q
由上述步骤获得的 IAR 工程中,包含了时钟配置及 QSPI 接口的初始化。对于外扩 Flash 的操作,还需要 添加外扩Flash 支持的命令进行操作。N25Q128A13EF840F 支持的部分命令可参见本文 3.1 小结。
1 R6 }  m, [: _# }在这里出于简化考虑,仅提供了阻塞式读取 ID,擦除 Flash,块写和快读操作的实现。更多实现模式,可以参考Cube 软件包中提供的 QSPI 例程。: N* K1 J. m' F, S) Y- c8 o
在 N25Q128A13EF840F 手册中提供了读 ID 命令时序,如下图所示。
. h+ M# |$ s1 a) Y$ H: r# K# A
4 o; }- E/ m  x PV{B8I~5GR7NA2~US_OS2T3.png
3 K. T4 y% i1 ^; O* }. w! q" o: s& Y5 _; o' W% v( p3 V
由时序图可知,读 ID 时序构成: 命令阶段 + 数据阶段。命令阶段和数据阶段线宽都为 1,读 ID 命令码为 0x9E 或者0x9F,ID 数据长度为 17 字节。
1 ^$ h! F5 `. y在 N25Q128A13EF840F 手册中提供了写使能命令时序,如下图所示。
6 R+ X3 b# t% C" i4 \' z7 ~; N% @! h7 x) k( p9 T4 u3 ^

& T. b& R; p+ u2 W- D5 c' k GCO@4Y}W4V@@XJW4S3CH_3Q.png
: t0 C6 a1 t+ ]/ `# t2 W0 ^, C" J4 H) }/ {* S9 H4 E; l
由时序图可知,块擦除时序仅有命令阶段。命令阶段线宽为 1,写使能命令码为 0x06。(注:这里仅呈现了单线命令模式的实现。除此之外,STM32 QSPI 接口和外扩存储器支持双线、四线模式)。9 E, L  I# _! ^* V8 I; T
在 N25Q128A13EF840F 手册中提供了扇区擦除命令时序,如下图所示。
. v7 d$ |' R- \1 D3 K# v# R# D. }& H" {/ \
7Y(S}25F84FHD[Y@OV58]ID.png
1 |' Q" c4 s+ ]2 {: p$ H- J) w& |" m, L, F; T* J$ g, l% i+ W
由时序图可知,扇区擦除时序构成:命令阶段+地址阶段。命令阶段和地址阶段线宽为 1,扇区擦除命令码为 0xD8。其中地址为 24-bit,任一位于需要进行擦除操作的扇区范围内地址都有效。在此简单选择扇区 0 进行擦除,选择地址为 0。(注:这里仅呈现了单线命令模式的实现。除此之外,STM32 QSPI 接口和外扩存储器支持双线、四线模式)。在 N25Q128A13EF840F 手册中提供了四线快速写命令时序,如下图所示。
/ r; h  B9 c; R
( E% j0 b6 v# S( x1 V  W PJL4TD`8P)2AEWOOG04QLI2.png ( Y  C6 p5 g2 K

9 D# J) Z; B+ F1 I! Y" x- N- T, T. F由时序图可知,四线快速写命令时序构成:命令阶段+地址阶段+数据阶段。命令阶段和地址阶段线宽为 1,数据阶段线宽为 4,四线快速写命令码为 0x32。其中地址为 24-bit,对应写入起始地址。(注:这里仅呈现了单线命令模式的实现。除此之外,STM32 QSPI 接口和外扩存储器支持双线、四线模式)。( \4 ?* F1 B9 T- v7 `: W7 C( q* f0 u
在 N25Q128A13EF840F 手册中提供了四线快速读命令时序,如下图所示。  R4 d% c' b: m# Z5 I! t
; A( z7 n8 ]# B9 M) v
K4~X}UFP]K)_{D~PF$KU{BS.png
: G) S% Y# f$ \( `4 k" \8 ]+ o2 b% P. |0 f* a/ T
由时序图可知,四线快速读命令时序构成:命令阶段+地址阶段+数据阶段。命令阶段和地址阶段线宽为 1,数据阶段线宽为 4,四线快速读命令码为 0x6B。其中地址为 24-bit,对应写入起始地址。四线快速读命令默认 Dummycycles 为 8。(注:这里仅呈现了单线命令模式的实现。除此之外,STM32 QSPI 接口和外扩存储器支持双线、四线模式)。
8 b. s2 W: D7 u6 ~在 main.c \ main 函数中,增加代码如下。
0 X2 W! e% S1 W$ B' t
: e  f1 R: U; c5 C7 D+ X- K
  1. … //系统、时钟、IO 和 QSPI 初始化
    9 z% [6 u+ i$ d2 R" ]4 y' t
  2. /* USER CODE BEGIN 2 */
    1 U# {' Z7 ^+ V* G
  3. QSPI_CommandTypeDef sCommand;# m# \) X+ D; Y* a
  4. static uint8_t Buf_ID[17] = {0};
    : ?: `- m( c# H
  5. static uint8_t TxBuf[0x10] = "Ext Flash", RxBuf[0x10] = {0};
    * q: X8 w6 G  T6 ]% ~

  6. 0 h; E. }* V: j/ m
  7. sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; //DDR 模式失能- V- q3 C2 A4 P* x9 K- Z+ I, `' Q( {( q
  8. sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; //DDR 模式下,数据延迟输出, X2 u- q: s; p# O( K
  9. sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; //每次发送都包含命令阶段$ B- R, a. i% e- g  V
  10. /***** 读 ID 操作 *****/+ X. a# q6 }* ~7 h, J: w
  11. sCommand.Instruction = 0x9F; //READ ID 命令码
    3 ~$ a% e" ~3 b% x
  12. sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; //命令线宽
    " [( v% y% I  ]) k# i
  13. sCommand.AddressMode = QSPI_ADDRESS_NONE; //地址线宽。无地址阶段3 f0 z: Q6 |% J4 l
  14. sCommand.DataMode = QSPI_DATA_1_LINE; //数据线宽
    , {9 Z+ h% E. g" J
  15. sCommand.NbData = 17; //读取数据长度。ID 长度为 17 字节# i( v/ U% N% s6 Y! d! C2 j5 }$ T# D
  16. sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //无复用字节阶段
    5 C& \9 z8 v0 }
  17. sCommand.DummyCycles = 0; //无 Dummy 阶段% k6 {2 e- j+ Y. H1 S* g  X' i
  18. //配置命令(在有数据阶段时,命令在后续发送/接收 API 调用时发送)
    ! w8 _* Q6 F+ |
  19. if (HAL_QSPI_Command(&hqspi, &sCommand, 5000) != HAL_OK)/ [6 }1 t) y0 D3 R, L, w0 M0 a3 l
  20. {+ r3 o1 m) W* w2 o- M1 S+ M
  21. Error_Handler();+ E; E9 P. a. C2 r; F+ B
  22. }
    / r8 b! D2 q. z" P
  23. //执行 QSPI 接收
    ! o' O! E# |3 L2 i, W8 M
  24. if (HAL_QSPI_Receive(&hqspi, Buf_ID,5000) != HAL_OK)( Y5 \- ?- g9 \- }, H* }5 S
  25. {  H3 m$ Q0 l0 ~4 z
  26. Error_Handler();6 l$ g$ A1 n' b7 q
  27. }
    , d  Q! ?7 Z# r+ ^" y- B% h" e  ?
  28. HAL_Delay(1); //延时 1ms. 单位为 SysTick 定时中断周期! ?: J7 ]$ s! o

  29. : x$ W; h6 |3 w* S
  30. /***** 写使能操作(需要在块擦除之前,使外扩存储器处于写使能状态) *****/
    # Y8 J/ H! X8 C2 y' C
  31. sCommand.Instruction = 0x06; //写使能 命令码
    ( A5 z3 B4 B1 X) w" O
  32. sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; //命令线宽
    4 z3 r5 r8 ?, C9 c8 D6 ^
  33. sCommand.AddressMode = QSPI_ADDRESS_NONE; //地址线宽。无地址阶段9 h* c7 |& s: c7 c1 w  M" [
  34. sCommand.DataMode = QSPI_DATA_NONE; //数据线宽。无数据阶段( m8 ?2 v9 {# a1 x) ^  R
  35. sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //无复用字节阶段& M# U4 ~, T9 L# {
  36. sCommand.DummyCycles = 0; //无 Dummy 阶段
    2 b( [! W" N. q! M" e+ L9 {
  37. //配置发送命令; g- r+ K5 O. b/ U. `0 N
  38. if (HAL_QSPI_Command(&hqspi, &sCommand, 5000) != HAL_OK)
    1 D; Y2 F0 R4 y
  39. {& `% z8 d, [, I; `
  40. Error_Handler();% k0 C8 ^* z* h4 v1 u: h
  41. }  f0 L# A! Z9 B6 a( M5 l+ a
  42. 6 i( Y) T) m: [2 C
  43. /***** 块擦除操作 *****/+ }! U) L; P, @7 Y2 r8 g# _
  44. sCommand.Instruction = 0xD8; //扇区擦除 命令码- E; e3 Y1 p# l1 b; a, R& W
  45. sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; //命令线宽# o! ?5 a2 Z8 X. _+ p; |
  46. sCommand.AddressMode = QSPI_ADDRESS_1_LINE; //地址线宽。无地址阶段
    " q0 T) ]7 E* i+ d
  47. sCommand.AddressSize = QSPI_ADDRESS_24_BITS; //地址长度6 D6 G" W1 }9 B
  48. sCommand.Address = 0; //位于所需擦除扇区内的任一地址。& z, @5 R' T/ F% e' n3 [1 u' P
  49. sCommand.DataMode = QSPI_DATA_NONE; //数据线宽。无数据阶段
    . a3 F( f( A: @3 {# v  |
  50. sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //无复用字节阶段! u( i- z# c! T0 D2 j  [  S
  51. sCommand.DummyCycles = 0; //无 Dummy 阶段
    1 y  f/ p; b# z1 L$ X; B4 r8 S
  52. //配置发送命令
    5 r! b' x& o9 Y* f! `
  53. if (HAL_QSPI_Command(&hqspi, &sCommand, 5000) != HAL_OK)
    ; V) T8 @) ~2 m! N+ A" ]
  54. {
      }0 `* d* |/ h1 O- @
  55. Error_Handler();
    $ ~* l3 s! @  e5 {
  56. }1 B2 a1 Z7 }3 K: \, |
  57. HAL_Delay(3000); //延时 3s. 单位为 SysTick 定时中断周期
    & v1 ~) l: ?: ~( x, Q  j/ M

  58. 3 Q8 y# m, f7 r2 y
  59. /***** 写使能操作(需要在块擦除之前,使外扩存储器处于写使能状态) *****/6 X# ?6 w' T0 D+ K) m5 D4 b
  60. sCommand.Instruction = 0x06; //写使能 命令码
    ( z; G* X, V+ ~9 h5 B
  61. sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; //命令线宽9 I4 o, ^4 \" P9 A9 w+ H- H
  62. sCommand.AddressMode = QSPI_ADDRESS_NONE; //地址线宽。无地址阶段
    2 d; a7 f/ @5 {: ~) N
  63. sCommand.DataMode = QSPI_DATA_NONE; //数据线宽。无数据阶段1 o7 @" B3 t  c
  64. sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //无复用字节阶段
    6 p( o4 k4 B; F
  65. sCommand.DummyCycles = 0; //无 Dummy 阶段  g" w" u7 x& k. e5 ?
  66. //配置发送命令
    : M/ l' C/ [+ f
  67. if (HAL_QSPI_Command(&hqspi, &sCommand, 5000) != HAL_OK)+ S1 p8 [$ j% S8 {
  68. {! l/ S0 c1 z9 m& w/ ^
  69. Error_Handler();
    - [3 j) w3 K0 R/ c* D4 G3 {
  70. }
    $ M& V% L5 L. C, y- _
  71. 1 W7 w3 A' T1 i" h
  72. /***** 四线快速写操作 *****/
    5 z- E* ~2 T6 q1 L, j+ d
  73. sCommand.Instruction = 0x32; //四线快速写 命令码' ]# {1 Y: \$ c6 P0 }8 ^8 S
  74. sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; //命令线宽: u3 w( l/ d: B5 R: Z2 @, ~9 k
  75. sCommand.AddressMode = QSPI_ADDRESS_1_LINE; //地址线宽
    1 e# X( O% g# p4 p& ~2 y7 l: |2 I
  76. sCommand.AddressSize = QSPI_ADDRESS_24_BITS; //地址长度% Z: i, m+ m; b# h% i/ R$ {& p
  77. sCommand.Address = 0; //写入起始地址/ {1 \& S1 W8 Z# l2 c* M
  78. sCommand.DataMode = QSPI_DATA_4_LINES; //数据线宽  ?' T$ G' S4 \) G0 D
  79. sCommand.NbData = 10; //写入数据长度
    " j$ ~1 K9 B& a7 _8 N/ k; F( H
  80. sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //无复用字节阶段! X" b9 J% \6 h. C- P  F
  81. sCommand.DummyCycles = 0; //无 Dummy 阶段
    2 w9 b* O. L: [3 f" Y% v1 m7 D4 ?
  82. //配置命令(在有数据阶段时,命令在后续发送/接收 API 调用时发送)" y4 s! k6 {: f9 O0 R
  83. if (HAL_QSPI_Command(&hqspi, &sCommand, 5000) != HAL_OK)6 {, v% {* D7 q7 e( u0 H+ {
  84. {6 ]( |6 f- z% F& j$ G- b6 h9 {
  85. Error_Handler();
      G7 X& u+ W' D: Y, [0 s. E: Y
  86. }
    0 }3 ]9 |" K9 e. p9 \" ?. B& ^
  87. //执行 QSPI 接收
    9 n1 z% _) P( p9 S: v( b
  88. if (HAL_QSPI_Transmit(&hqspi, TxBuf ,5000) != HAL_OK)$ W8 r4 a( Y: Q. c" p" m' Z. z
  89. {
    + _$ E. r+ @5 i
  90. Error_Handler();# m7 I( d8 |1 l1 n
  91. }
    ( Q3 u$ L/ P  o1 j) B/ Y! Q# L
  92. HAL_Delay(5); //延时 5ms. 单位为 SysTick 定时中断周期
    9 x- E  Q2 K; ~# u4 X  z5 {$ ]' ~

  93. / V5 o# `, W" q8 B8 U1 r$ L
  94. /***** 四线快速读操作 *****/0 p  N7 D( p) v5 w8 e6 Q3 r
  95. sCommand.Instruction = 0x6B; //四线快速读 命令码$ ]! Z7 T# g3 g3 Y
  96. sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; //命令线宽$ e# [; G; V4 h( d4 Y# V' E$ w$ f
  97. sCommand.AddressMode = QSPI_ADDRESS_1_LINE; //地址线宽0 f  n4 Z% V" c
  98. sCommand.AddressSize = QSPI_ADDRESS_24_BITS; //地址长度% }1 [8 `: f" B
  99. sCommand.Address = 0; //起始地址! R; J& X- z( \- ]4 d
  100. sCommand.DataMode = QSPI_DATA_4_LINES; //数据线宽
    " d/ _  r3 C2 m, V
  101. sCommand.NbData = 10; //读取数据长度) H! c7 |& }3 J0 ^( `
  102. sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //无复用字节阶段3 c  K# o. t9 B- N) m8 }
  103. sCommand.DummyCycles = 8; //Dummy 阶段。N25Q128A13EF840F
    . z# D" n6 Y2 G
  104. Dummy cycles 默认为 15; ?2 w2 x. X& ]
  105. //配置命令(在有数据阶段时,命令在后续发送/接收 API 调用时发送)" Z2 o3 {0 z& G9 ^2 }& u
  106. if (HAL_QSPI_Command(&hqspi, &sCommand, 5000) != HAL_OK)
    3 [- A0 F1 U/ z' u9 \
  107. {% B0 w9 }! {  ]0 o, x9 @
  108. Error_Handler();' V, ^. h7 z9 x1 }
  109. }
    % S% O9 l' ^' z( k; A- t
  110. //执行 QSPI 接收
    5 g4 t9 B* o* n) P" P/ Y5 u
  111. if (HAL_QSPI_Receive(&hqspi, RxBuf,5000) != HAL_OK)
    " k: [! a' E7 g
  112. {" t2 W0 r# {( q' m! r; A; g5 ^
  113. Error_Handler();  i" A. q# s! R6 u
  114. }: s" O7 K& z% `9 u5 m- t6 _
  115. /* USER CODE END 2 */
复制代码
. B- W$ G6 m6 p$ M6 K1 K7 Q
) z8 m. F6 n% T
四 小结
; b3 r( u! W& m6 y; c. ]STM32 的 QuadSPI 接口灵活可配,对于命令阶段、地址阶段、复用字节阶段、Dummy 阶段和数据阶段都可以进行配置。基于这种灵活性,能够实现市面上 SPI、Dual IO、Quad IO 的串行 Flash 支持。但出于简化考虑,QSPI 支持的中断访问及DMA 访问等更多功能没有在本文进行介绍,更多实现可以参考 ST 提供的 Cube 软件包中的 QSPI 例程。另外,不同厂家的串行 Flash 命令及操作实现略有差异,具体以采用的 Flash 文档描述为准。) w- f: J; t2 l* x  g4 I

5 x. W. h1 A/ |( |$ \4 l, G5 u& @# ~3 B
" ?1 J/ x  j1 `- l
& l8 h& Y& s) s, j4 p$ ]$ m

% K6 M7 e! m  p! s. Z& Z" n
1 I8 C  Q, W. p  j; r) C+ ?
+ ?; a$ m, ~" V
赞 收藏 1 评论0 发布时间:2022-2-22 18:48

举报

0个回答

所属标签

相似技术帖

官网相关资源

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