一、W25Qxx系列芯片----简介8 A# d6 B! i- t7 I( [
W25Qxx 系列 Flash 存储器可以为用户提供存储解决方案。擦写周期多达10W次,可将数据保存达20年之久,支持2.7~3.6V的电压,支持标准的SPI,还支持双输出/四输出的SPI,最大SPI时钟可达80Mhz。
; j6 ^" S; Q/ }8 _W25Qxx 系列 Flash 存储器是为系统提供一个最小空间、最少引脚,最低功耗的串行Flash存储器,比普通的串行Flash存储器更灵活,性能更优越。! R( S1 x7 D# Q v9 e; \) E
功耗低,正常工作状态下电流消耗0.5mA,掉电状态下电流消耗1uA。 S# Y* C' y) M9 D3 T, Y& g
) T. J& C0 K: Z1. 存储结构: U7 f, t8 C. l) K3 P; C( z
W25Qxx 系列 Flash 存储器的存储结构0 m- J: R3 x0 q' m9 q' @& n
相同点:& z9 [% [0 X/ h" q! T& D
. k) Q/ J* x+ y- b& d1块 = 16扇区 = 64k字节,1扇区 = 16页 = 4k字节,1页 = 256字节。
0 i' o. Z. D" O/ X) s5 I, _只有三种擦除方式:扇区擦除 、 块擦除 和 全片擦除。
: L9 F0 b. A# Q% v- n写操作一次可以写1~256字节,最多一次写一页256字节。
/ [1 G8 R1 F- Z不同点: 容量和内存空间地址不同,具体如下表所示:
- D! d6 R" ^. o0 B O: x
9 _5 g$ M9 P: t2 @6 q7 u
1 o% @0 A$ q5 _! d; r1 Y7 u
! S3 C' B! f! a2. 引脚接口% \6 X- I" a# E0 a$ w5 {8 Z
下面只介绍标准SPI接口,接口如下图所示:; D" Q* M! k9 Z6 D2 _
& ]. H2 ^ X, n# `
/ _7 _5 u! u$ @3 ?/ O
, \4 n0 W$ A) F- I9 f# S$ ~
片选引脚:/CS( U0 ~- d% P0 e% U, i9 C) F
(1)当CS引脚为高电平时,芯片被禁能,DO引脚高阻态,不能进行读写操作。
9 h) S4 k& o$ Z; B- l. A: ^9 b(2)当CS引脚为低电平时,芯片被使能,能进行读写操作。
$ J! |; J* X! y& F3 \ 上电后,执行一条新指令之前必须使CS引脚先有一个下降沿。- e+ y J S9 d8 n% E- g
( R' J- H5 h! l3 z$ i' ~7 X1 P+ ~数据输出引脚:DO(IO1)6 I0 z% E' ~/ r% @. H% z' X, `, w1 a
标准SPI模式: CLK上升沿捕获地址和命令,下降沿输出数据。4 c- M9 s; J `0 K" a
QSPI模式: 双向数据传输 IO1。" x& D. G/ t, I9 r$ g& B1 d
9 P/ N+ u) u- P$ Y. f8 a. H
写保护引脚:/WP(IO2)+ L* E% P0 `/ P) @4 G/ B( w+ ?
标准SPI模式:( B4 g( p2 v% }1 f
写保护引脚可以被用来保护状态寄存器不被意外改写。6 R, E- r6 c; k" `, A, o
(1)当WP引脚为高电平时,芯片写保护失能,可以正常写入数据。! z# y* t& z# R9 h8 m2 _. B6 y: @
(2)当WP引脚为低电平时,芯片写保护使能,不可以正常写入数据。
* P' p5 S5 c6 r1 z- S! Y+ nQSPI模式: 双向数据传输 IO2。( W$ G9 A# Z/ i* {% r( d. U a
4 Q8 f; Y9 O5 Z1 e2 I地:GND
& o8 `8 ?! B3 Q) r8 e* k电源地) x. ?/ k# X' ?( R- ?- W! Z
1 H! s$ U. J! {5 B0 K9 l8 b数据输入引脚:DI(IO0)
: }0 ?* t" \/ f: s% y标准SPI模式:9 z. U3 `4 f$ @2 M1 c" ?
数据、地址和命令从DI引脚送到芯片内部,在CLK引脚的上升沿捕获。
0 i! j0 g% v' Y y9 J W" tQSPI模式: 双向数据传输 IO0。0 |) g7 r9 V7 v4 P H
6 H9 _* e. K& l' u, c
串行时钟引脚:CLK
! o& g& Z) o: j7 f- \1 p; GSPI时钟引脚,为输入输出提供时序。
. x; [* ^% q& P! p' d
( {" M* I& D: z+ \; x7 l/ w保持引脚:/HOLD(IO3)2 |; L2 C; v! x2 b8 `' z5 A, F
标准SPI模式:
1 e, Y6 s; Q/ u' e- |# e当CS引脚为低电平时" J) m% S. e/ _: n: F' _: l
(1)当HOLD为低电平时,DO引脚处于高阻态状态,而且也会忽略DIO和CLK引脚上的信号。5 t7 ^. a) E: ?. ~' Y
(2)当HOLD为高电平时,芯片恢复正常工作。; T0 d* A" y$ l' K' p
QSPI模式: 双向数据传输 IO3。/ Z/ t' j" U- g: q: H
+ _1 w& J+ @! U& C* c
电源:VCC; i) ^* {. l$ J0 r3 {7 R' p
电源正极
) O* C8 i2 c' x4 D4 u" |0 H% _# S- p# \; q6 w8 x
3. 原理图9 S1 E/ G. l% P
* v; i4 ]( A) N
. `4 N; m5 l! w9 \2 Z3 h! [2 }
: V. ^4 D" f( X7 F4 c2 q+ O4. 内部结构框架图. q; \9 B3 U2 u& a$ I( V0 @: F
. V i! n% ?! O
$ S+ a' ^; @ H: X* w! `
3 B; e7 K& ^* K# @6 B6 u, b
5. 型号ID
& @9 ~: y* m0 M% P- s2 Q+ \! t( hW25Qxx 系列 Flash 存储器支持 JEDEC 标准,具有唯一的 64 位识别序列号,方便区别芯片型号,具体如下表所示:
; Q7 h5 J: |8 m) `& p( J+ {
; ^1 k: [5 v* L0 f, m/ t
$ O9 {+ B5 x4 G) v, w8 p8 ]* e5 N g3 r' z* N
二、W25Qxx系列芯片----工作原理
2 D( I" a `" e/ _% H3 D e1. SPI 运行方式
6 R3 I1 d; N. W* I/ v7 j rW25Qxx系列芯片支持以下两种SPI通信方式:
- H6 |2 n6 }3 q3 V3 t5 g模式0: CPOL = 0,CPHA = 00 I$ t. N& F$ \) T$ t
模式3: CPOL = 1,CPHA = 17 ?' s# T% |8 U Y9 M: l) x
/ W8 m5 ~4 |' w+ I3 ]6 F/ q2. W25Qxx系列芯片----状态寄存器
1 y Z0 X0 }! v/ D& E2 n注:这里是记录所有W25Qxx系列芯片的状态寄存器,有些型号的状态寄存器,没有全部功能。
# O6 u4 _ K; B
' Z* G$ X5 {. S7 t( {3 V% H) ^状态寄存器14 J! ~5 H* c4 Y% a) c. `+ F2 u
h$ Y* R2 y$ Q/ Q0 h& d' G
% i6 t& s4 g& i
9 R9 J7 N; K8 w
S0----总线忙标志位(BUSY)6 ^) A& d; Z% ]' }) T
在执行页编程、扇区擦除、块区擦除、芯片擦除以及写状态寄存器指令时,该位被硬件自动置1。这时候,除了读状态寄存器指令外的所有操作指令都会被芯片忽略。
0 i+ G! K- v! q% K; M当芯片执行完这些指令后,硬件会自动将该位清0,表示芯片器件可以接收其他的指令。3 U; s& Y8 _0 E
# S. j, `) c( t' K W: T, T y
S1----写保护位(WEL)
9 A: a+ f4 {9 E- Z( \. \1 c执行完写使能指令后,该位置1
% e6 [+ [+ Y% s# R/ z当芯片掉电后和执行写禁能、页编程、扇区擦除、块区擦除以及芯片擦除指令都会进入写保护状态,该位置0" |. a% g7 {" S4 w0 P. I4 T7 b
) m% b1 p1 {& ?" GS2、S3、S4----块区保护位(BP2、BP1、BP0)6 M8 m- [5 @) d! e7 d$ D' d
这3个位默认状态为0,即块区处于未保护状态。可以利用“写状态寄存器”指令对这几个位进行置1来达到块区保护的目的。块区保护状态为:没有保护、部分保护和全部保护状态。. P1 N/ X0 _' B
当状态寄存器的SRP位为1或读写保护管脚(/WP)为低电平时,这3个位不可被更改。
+ f4 i5 D" j: { q) @# w7 ? B6 t1 B& e4 i% @9 a8 D: G
S5----底部和顶部块保护位(TB)
$ q/ r, \6 M5 I; m此位默认值为0,可以利用“写状态寄存器”指令对这个位进行置1或清零。
" Q7 R% o8 `6 Q6 E- p当TB = 0时,表示保护位从顶部开始;
- s Z0 Z% j" b& {当TB = 1时,表示保护位从底部开始。
2 ^: @% ^, e* w4 P w& g8 C当状态寄存器的SRP位为1或读写保护管脚(/WP)为低电平时,这个位不可被更改。
. W$ i3 u) Y, I8 G7 l6 j
. m& u$ R* f! j4 N' sS6----扇区/块保护(SEC), I& B! M8 Q! y, F7 ^8 Z1 {3 v$ `
此位默认值为0,可以利用“写状态寄存器”指令对这个位进行置1或清零。
* [2 Z9 W; T; i6 T, W) ^6 r当SEC = 0时,表示每次保护的区域大小为4K;
o8 z: r! N6 g# {2 t7 j; B当SEC = 1时,表示每次保护的区域大小为64K。
# V/ r* W7 O6 @- v! @. a9 x
, a; k/ a3 `: l7 \) W8 k状态寄存器2
/ b. b4 |5 P$ {9 e5 w3 U! _# B& ]% ^. ~8 P/ m
: P) E9 M0 U. ^% G2 L% p7 B( t+ \" N, E; T
S7、S8----状态寄存器保护位(SRP、SRL)/ U" q) E+ U0 |9 N% D- n& T
这两个位的默认值为0,可以利用“写状态寄存器”指令对这个位进行置1或清零。5 f+ c0 g" W; ?4 ^$ a1 p+ l
这两位和读写保护管脚(/WP)决定了状态寄存器写保护的方式。
: M3 e8 S; S0 ?, b状态寄存器写保护的方式有:软件保护,硬件保护、电源锁定或一次性可编程(OTP)保护。
* [- _3 |& d+ j) h$ V/ C9 z
7 n9 X' F) `8 kS9----快速SPI通讯使能(QE)
. x& [- ^- d) z Z4 f% h. Y) I此位默认值为0,可以利用“写状态寄存器”指令对这个位进行置1或清零。7 I8 L8 ~" }5 e' x6 G
当QE = 0时,设置为标准速度模式或快速模式,保持管脚(/HOLE)和读写保护管脚(/WP)启用;
1 o# ~2 K1 T! v& _当QE = 1时,设置为高速模式,保持管脚(/HOLE)和读写保护管脚(/WP)被设置为IO2和IO3功能使用。 M9 Y' J: X4 }' b( x- X
* v4 ~ r$ N$ ` yS10、S11、S12、S13----安全寄存器锁位(LB3、LB2、LB1)
; w; ]' a% @7 D+ \1 n6 g: o# `LB3-1的默认状态为0,安全寄存器被解锁。
& _) y6 _ X2 n- `4 S+ h7 X可以使用写状态寄存器指令将LB3-1单独设置为1。
6 R" n" [/ y& Y uLB3-1是一次性可编程(OTP),一旦它设置为1,相应的256字节安全寄存器将成为永久只读。- U Q% |2 Q; Y$ m0 v: f
% K- b" H+ t; O/ v. e4 X g
S14----补码保护位(CMP)
) y( _% A+ @7 K1 d! V u它与SEC、TB、BP2、BP1和BP0位结合使用,为阵列保护提供更大的灵活性。! @- W& D3 f& m! y8 t1 {% B X) b1 W
一旦CMP设置为1,之前SEC、TB、BP2、BP1和BP0设置的阵列保护将被逆转。例如:8 J# P$ K+ ^1 [. b( j1 H- J! ` e0 h
当CMP=0时,一个最高64KB的块可以被保护,而数组的其他部分则不受保护;
: f1 M# Q/ |" K/ |当CMP=1时,最上面的64KB块将成为不受保护的,而数组的其余部分将成为只读的。2 i( ~$ |" c# M3 D8 u
默认设置为CMP=0。( m# z" _ n8 \: R
5 p6 }& t& b: P) ?6 j* M; d0 SS15----暂停状态位(SUS)
% O7 `+ {: r4 f$ F: m在执行**擦除/程序暂停(75h)指令后设置为1。
2 W# K/ P! x/ N2 C! w0 v8 E通过擦除/程序恢复 (7Ah)**指令以及下电、上电周期将SUS状态位清除为0。
3 D) y- A3 V) X0 ]6 i& j8 F5 o% T& X' S% x# \ u1 q
状态寄存器3
8 ]& O! \8 f, f% `! p9 S" f2 ^/ y8 B+ M( r7 s" k
* C# }4 J7 c5 F7 d+ T0 |' L, ~. c2 J' E/ J$ i; s4 M
S16----当前地址模式(ADS)6 e' e2 z& g' k
表示设备当前运行的地址模式。 E/ M$ Q0 M$ X0 N, }
当ADS=0时,设备处于3字节地址模式,3 i# k% M8 K+ D& f( O) Y
当ADS=1时,设备处于4字节地址模式。3 I: B7 E3 o* V" S" h( _
- h+ j$ L% b; _, l4 pS17----启动时地址模式(ADP)2 s& b4 `. n( K8 D4 H, ]
决定设备上电或复位时的初始地址模式,该位仅在上电或设备复位初始化期间使用。0 k2 Z* o* [/ J" _; ^) ^' |
当ADP=0(出厂默认)时,设备将启动到3字节地址模式,扩展地址寄存器必须用于访问超过128Mb的内存区域。当ADP=1时,设备将直接启动到4字节地址模式。# v- f) }3 V% o6 f/ i
3 F8 K( {# Q& u0 ^* l& n
S18----写保护方案(WPS)
2 a" q: x3 U; L$ G r/ z8 Z当WPS=0时,设备将使用CMP、SEC、TB、BP[2:0]位的组合来保护存储阵列的特定区域。' h( I9 J* z' g1 v
当WPS=1时,设备将使用单独块锁来保护任何单独的扇区或块。
' F& o& z7 x( }! a设备上电或复位后,所有单个块锁定位的缺省值为1。
3 T1 h4 b. \0 ^6 C# L0 z6 Q; J n$ ]& d/ }* r# L
S22、S21 ---- 输出信号强度(DRV1、DRV0)7 M) Y: r+ `8 o
% _! ^9 u! X) M1 W+ P5 a/ V' ^
3 u* |/ G! B" y2 {6 _* F# \9 K8 M- }+ E
S23----HOLD/RST引脚功能选择
. t. u1 ]7 R$ V当HOLD/RST=0(出厂设置)时,引脚为/HOLD。5 x" T, s5 Y" {1 B$ U! O2 i7 t
当HOLD/RST=1时,引脚为/RESET。: L+ K8 y: A# z% Y
但是,只有当QE=0时,/HOLD或/RESET函数才可用。% m) d$ U8 f9 x, L9 ~2 v
QE设置为1时,关闭/HOLD和/RESET功能,引脚为专用数据I/O引脚。
, i# m: {- s' U! t. h& E" t! z7 [7 `; Z3 Z& K( G$ M
3. W25Qxx系列芯片----常用操作命令
( r$ v; [! M. H% Z: z(1)单字节操作 Y8 n" m) \ _/ t. j; K! s) X
单字节操作,只往芯片中写入1字节的操作命令,具体代码如下:/ h* ]) U9 H8 w9 @6 \
: p h# L0 \; N& e. k! x- void W25QXX_Write_Enable(void) //写使能 + {! i, E7 ?# A1 [* t$ }; I
- {5 `# U3 t' g0 O0 z0 s j$ \
- W25QXX_CS(0); //拉低片选CS引脚---使能芯片: |1 e8 x. t; Q
- W25QXX_ReadWriteByte(0x06); //写入1字节操作命令+ M/ G% V/ X4 E6 I- i! N
- W25QXX_CS(1); //拉高片选CS引脚---关闭芯片 5 a: d1 _2 T5 }
- }
复制代码 . T- A1 I' |% ~0 i
操作命令 如下表所示:( C1 f( K) I' A
9 }' d1 s7 Y: H0 f
) Q2 h' k# ?0 P9 T
% r; n! P# |3 N: H
% a5 }0 l0 ~1 U1 x注:如果想要实现其他功能,替换操作指令数据,便可实现功能。
" r& k* Q/ |1 G1 V$ q0 k: K# Z! z1 t
(2)双字节操作. J' b9 p" c( S( H
双字节操作,先往芯片中写入1字节的操作命令,接下来是读取/写入的字节数据。
. T8 l: | k3 s具体代码如下:
$ M# m4 s: U; a4 T# r2 N$ Y" g2 @' l8 Q4 T
- //读取1字节数据' F8 N: w# H4 \- p
- uint8_t W25QXX_ReadSR(void)//读取状态寄存器
. |1 A5 Q1 i) y3 Q' L - {
$ S6 W! E* P1 ~0 }& g' E5 V" A - uint8_t data=0;9 V1 Z( a9 Q+ P/ K+ K$ T( m# c+ ?
- W25QXX_CS(0); //拉低片选CS引脚---使能芯片 y+ O" v9 _. S4 r
- W25QXX_ReadWriteByte(0x05); //写入1字节操作命令
/ {7 X" A; A' Z b - data=W25QXX_ReadWriteByte(0Xff); //读取1字节数据
2 {% K$ {; j4 w; o% }/ \ u - W25QXX_CS(1); //拉高片选CS引脚---取消片选
3 j! u) f c: A, k/ a! } - return data;
" w9 k. w& V4 Y/ Y" ]8 | - }
6 ~! A& O2 u: k' Q: g, b
3 N% q2 r) @0 k- R- //写入1字节数据
. z# n2 I, F. L0 |2 M; M& G - void W25QXX_WriteSR(uint8_t data)//写状态寄存器
( x2 M+ O' y* p8 \; d9 d - {0 Z3 D. m9 f- C( @* q* V
- W25QXX_CS(0); //拉低片选CS引脚---使能芯片
. i: l+ P6 \" i [ - W25QXX_ReadWriteByte(0x01); //写入1字节操作命令
! L" M* X4 z/ B, u! V - W25QXX_ReadWriteByte(data); //写入1字节数据; w; m6 A5 s1 f% S% h
- W25QXX_CS(1); //拉高片选CS引脚---取消片选
, k8 G( c+ ?9 V - }3 [5 o+ i# Z& J* f3 d
复制代码 3 R' \' v( x' P* N
操作命令 如下表所示:
! w) j" l1 m) S9 L+ }. S& v# w7 n: @ O$ D, r
) k- Y2 w1 W( d8 e) X9 ]: @
! C3 ^+ x7 Q' o- u
注:如果想要实现其他功能,替换操作指令数据,便可实现功能。
. D5 o1 s% a2 Y
) e+ ?$ P% t' k0 C2 S; f8 {9 I(3)读取ID操作4 a, d# O: F) m3 R8 e) w
具体代码如下:
; U, a# d0 S9 W, F
# j+ T' c8 J; @" ?0 V' i- uint16_t W25QXX_ReadID(void)//读取芯片ID" ^! i/ R5 y5 J4 E1 j C, e
- {
" d8 r+ Z7 S( L3 f$ s4 c - uint16_t ID = 0; . Z- i2 F$ f1 ^- ~5 p% T+ w
- W25QXX_CS(0); //拉低片选CS引脚---使能芯片
; z. c" z1 e1 J; L+ @* |+ L - W25QXX_ReadWriteByte(0x90); //发送读取ID命令 & d6 ]% n1 \1 T, M" }/ z
- W25QXX_ReadWriteByte(0x00); 2 ~7 M) ?' L1 e q& |
- W25QXX_ReadWriteByte(0x00); + O3 [% f% I3 G+ ~: ~, u
- W25QXX_ReadWriteByte(0x00);
+ T8 x3 j+ ?$ u$ M - ID|=W25QXX_ReadWriteByte(0xFF)<<8; : m/ C$ Q- L% V7 [
- ID|=W25QXX_ReadWriteByte(0xFF);
: Y1 j- r, ]8 ^# j; u' d - W25QXX_CS(1); //拉高片选CS引脚---取消片选 ' Q0 v: \1 P; p3 b( J/ J( {
- return ID;. p. E" _5 l. {. d- Z0 v
- }
复制代码 # B7 a( Y( Y0 C% f- j# W
操作命令 如下表所示:
1 B" O& B* z v7 B4 L5 F
8 A! m! s# T$ i9 W3 _3 `3 t
& u& w1 ?1 |2 V/ G: N( k2 s8 l1 k! R* H4 @. A0 ?2 L
指令名称 指令数据(hex) 字节1 字节2 字节3 字节4 字节5 功能
! z+ }" }5 R* B- _! j4 KDevice ID 0xAB 0x00 0x00 0x00 (ID7-ID0) 读取设备ID
2 \: S9 O ?- N" E3 Z# ^ ZManufacturer/Device ID 0x90 0x00 0x00 0x00 (MF7-MF0) (ID7-ID0) 读取制造商+设备ID4 |- y: j3 E5 N6 i1 |' r5 v8 W
JEDEC ID 0x9F (MF7-MF0) (ID15-ID8) (ID7-ID0) 读取全部ID
* t8 I$ x I) T \2 u0 J) H# h% M2 }Read Unique ID 0x4B 0x00 0x00 0x00 0x00 (UID63-0) 读取唯一ID号
% {6 k9 K! d2 w注:如果想要实现其他功能,替换操作指令数据,便可实现功能。
" ]3 g6 c5 l# }( G7 I z; R8 m8 H( Q) L* ?# x
(4)带地址操作 ^' b! H& Y0 ]( Z. B- ?; |& D$ S6 M
带地址操作主要分两种:! ~0 ~& v1 H% ~* Z7 s! @
3字节地址:W25Qxx系列芯片都可以使用。
$ `9 V X. p9 k/ q, G0 o- s1 V4字节地址:只有W25Q256和W25Q512可用。6 y* b; p/ W! `$ W
# g8 Y5 H9 X7 W' f$ V2 I8 A9 |3字节地址, ]/ S6 Q$ r5 R5 u" y4 o. m) k! o
具体代码如下:
7 b: Q+ |0 h- H0 \0 M- //读取数据
# K2 k9 E8 O) U/ C! y5 h - void W25QXX_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead) 3 g. d9 s+ ?8 }5 c
- {
; Y" K" T" \" w9 d - W25QXX_CS(0); //拉低片选CS引脚---使能芯片
$ `2 F# k: P$ o$ p A0 a$ o$ c - W25QXX_ReadWriteByte(0x03); //发送读取命令
& v+ {- f$ C. P1 o0 c0 A! y - W25QXX_ReadWriteByte((uint8_t)((ReadAddr)>>16)); //发送24bit地址 4 k- D, `& C2 ]- U6 a
- W25QXX_ReadWriteByte((uint8_t)((ReadAddr)>>8)); 9 ^8 f2 e4 p& ]; {% j6 g% L/ M' z* d* }
- W25QXX_ReadWriteByte((uint8_t)ReadAddr); 6 ]+ I6 |/ o0 i! Y2 ^& e
- for(uint16_t i=0;i<NumByteToRead;i++)//可读多个数据) L! F! |: X: O! q2 l
- {
" b+ K5 \. S7 R$ Q3 P$ \# O& b - pBuffer<i>=W25QXX_ReadWriteByte(0XFF); //循环读数
/ U" o7 {9 G& ^ N, @+ t - }
; C2 x; C2 ]5 ^ - W25QXX_CS(1); 6 e- E5 s$ I* G: x6 x- V( ~
- } 6 ?/ \6 h* J% Y
+ B+ q# F) H6 p, }" P& d/ w/ X1 s- //写入数据
6 D6 s4 J- P' ]6 I3 R5 c - void W25QXX_Write_Page(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)5 d" t: r3 o4 z- V
- {' C$ I* ~3 P& W: U# K% f$ j$ g# L
- W25QXX_Write_Enable(); //写使能1 [8 e# Z/ _+ V. r, r3 W
- W25QXX_CS(0); //使能器件 ; I+ J) F! t, k: o7 [
- W25QXX_ReadWriteByte(0x02); //发送页写命令
4 Z; O8 Y$ h& z% d! A - W25QXX_ReadWriteByte((uint8_t)((WriteAddr)>>16)); //发送24bit地址
* W+ G- X* i5 c" r - W25QXX_ReadWriteByte((uint8_t)((WriteAddr)>>8));
" A t8 M2 c' v2 g; c C - W25QXX_ReadWriteByte((uint8_t)WriteAddr); ; n) b, y* {6 z0 J5 w
- for(uint16_t i=0;i<NumByteToWrite;i++)//可写多个数据,最多256个字节一页数据
, f) O2 ]. E. a - {5 ?" N9 w5 n C- H
- W25QXX_ReadWriteByte(pBuffer<i>);//循环写数
9 F* q. h3 E* `3 g6 Z( I/ ?! m3 y# o - }5 N( A0 `) v5 J# g; ?- z
- W25QXX_CS(1); //取消片选 + @- U3 W5 C) b* M' \8 Y+ |
- W25QXX_Wait_Busy(); //等待写入结束
6 S# _( J. H+ O: I - } </i></i>
复制代码
1 ^% C6 W8 R" Y- \& h' b7 Z) u操作命令 如下表所示:
$ f7 A1 }$ W8 s) K
, C+ }' p# h9 a9 b- o* K
7 I* G* U7 ^7 [) c% S
7 a7 E) @; F6 r S8 g9 d! a1 K( C, n4字节地址8 R& z, \! t6 [( U- U; ^
具体代码如下:7 }; M/ g3 @4 c) o; ?, d9 b
- //启用4字节地址模式 9 g" S ], n6 e4 g- g
- void W25QXX_Enter_4Byte()
2 v2 @/ d5 \6 s3 \0 U - {
3 X' @: g9 m* { - W25QXX_CS(0); //拉低片选CS引脚---使能芯片
2 n/ y) G# E( K( c4 E+ O - W25QXX_ReadWriteByte(0xB7); //写入1字节操作命令
7 p7 E' C8 r! N" |5 | - W25QXX_CS(1); //拉高片选CS引脚---关闭芯片
9 Q1 \" D/ M$ g2 ?- c - }
0 G4 z0 O2 M; u$ }# @9 u- M - ( J/ W Z0 n: {) \7 L$ O; W2 `/ E
- //退出4字节地址模式 ) e3 ~/ r& |2 }6 t
- void W25QXX_Exit_4Byte()6 e! L+ W3 p7 X
- {
r9 h. R/ e# D' u% d$ J# @! V - W25QXX_CS(0); //拉低片选CS引脚---使能芯片
x- |% q+ a8 h( k& y) m: F0 F - W25QXX_ReadWriteByte(0xE9); //写入1字节操作命令
5 B) X$ }0 P) x6 ^2 l+ L# ^ - W25QXX_CS(1); //拉高片选CS引脚---关闭芯片
7 i* F0 p% {3 S1 X1 p! U- X1 p - }
+ \! N2 Q( D& z2 y; Z7 O9 T
5 I$ K# t+ p) N' J- {- //读取数据9 e! Y3 W/ o+ U/ u/ B" y; g* X& {
- void W25QXX_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead) # e/ a* Y. |, U# |# u3 B' Q
- { 7 }* U% `# O8 _' C
- W25QXX_CS(0); //拉低片选CS引脚---使能芯片$ Y# q5 _5 _5 q' k2 Q. z- v4 a
- W25QXX_ReadWriteByte(0x13); //发送4字节地址读取命令
4 U/ R; x0 Y+ l O+ g! N0 E: C' f+ b" w - W25QXX_ReadWriteByte((uint8_t)((WriteAddr)>>24));//发送32bit地址 1 V L2 m; T: e% n
- W25QXX_ReadWriteByte((uint8_t)((ReadAddr)>>16));
* |) I' W& }2 W) c" F" g$ l - W25QXX_ReadWriteByte((uint8_t)((ReadAddr)>>8));
" f( I8 k. L" g - W25QXX_ReadWriteByte((uint8_t)ReadAddr); - t3 R! Y; r& B3 {
- for(uint16_t i=0;i<NumByteToRead;i++)//可读多个数据
4 r; ^0 z/ A7 u0 V - { 7 r$ t% x: w4 l5 M% d+ |
- pBuffer=W25QXX_ReadWriteByte(0XFF); //循环读数
/ L( W, ]$ O' w7 b7 F0 }+ O4 a' R - }
9 E* }( s( ?* C" I6 i0 h - W25QXX_CS(1); : p. f% C2 t* L A5 k8 f5 K/ q
- }
4 ?) G9 A7 @3 d Q5 s K
/ e4 C% ^- L+ b: U$ G- //写入数据" B$ h& Z$ X+ I
- void W25QXX_Write_Page(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
- n) [8 q6 s" q# o - {
S7 h* y. }. Y" L9 U/ k - W25QXX_Write_Enable(); //写使能8 {/ b8 {% r1 a, E" U$ G% {+ \
- W25QXX_CS(0); //使能器件 % R( ^7 E/ ^& A8 V/ S
- W25QXX_ReadWriteByte(0x12); //发送4字节地址页写命令
8 q/ y1 t; ^9 b% ` - W25QXX_ReadWriteByte((uint8_t)((WriteAddr)>>24));//发送32bit地址
! h; B. e/ _. k7 C& { - W25QXX_ReadWriteByte((uint8_t)((WriteAddr)>>16)); ! Z3 E' m* m8 F+ ]1 k1 g4 F4 Z7 v
- W25QXX_ReadWriteByte((uint8_t)((WriteAddr)>>8));
( f( s. w0 R7 x) y; P& H) m - W25QXX_ReadWriteByte((uint8_t)WriteAddr); ' A) B8 n- [ y2 ]
- for(uint16_t i=0;i<NumByteToWrite;i++)//可写多个数据,最多256个字节一页数据$ R+ n/ ^* o& R( g+ Z
- {1 _& M9 @% X# ^7 `
- W25QXX_ReadWriteByte(pBuffer);//循环写数
! G5 j; F. g. s7 M/ C/ F. e) T2 m - }
+ A& A- C5 h0 v1 Z. l - W25QXX_CS(1); //取消片选
' }( ?% B# D" V, y% g - W25QXX_Wait_Busy(); //等待写入结束6 O8 U% b; i1 I1 t, M# g
- }
复制代码
/ p; o7 r; m- @5 B注:如果想要实现4字节地址,需要启用4字节地址模式。
! q0 k3 M7 R2 u# P* z. j+ K9 w; i6 a) n/ M8 O+ g3 S& Z
操作命令 如下表所示:
& ?, _- u1 r6 R% {/ Q; I/ p' s' E/ s9 d7 E6 K, N0 }! Y8 U1 C
, ]- [' V+ @7 g2 X3 \2 H; m, ?8 D) ?. d1 M8 S3 o. j, ]
————————————————
, r! [5 t7 l5 O( j K% a版权声明:根号五- \% w! Y6 P u* _
' }* L' C, P1 M3 Y' {
# k3 y0 Y; E4 y( D2 r1 \' `3 A: q& w1 G0 Z2 i
|