1、模拟SPI方式的IO配置
! N$ x# @! ^# u0 F6 |0 @/ J) t/ j5 p9 a: N3 {
& t. Q7 g( P" s
6 R3 o, ^% Z% A
2、驱动代码
3 s9 ^& Z$ X, ~/ m5 p; u2.1 头文件2 E) @1 F. o+ b' \8 F7 G. Y7 ^
- #ifndef __W25QXX_H
7 L1 d$ K- P) q - #define __W25QXX_H ; C5 k @9 z g
- #include "main.h"
3 m% s1 `1 ]4 }% S& o: x - " P! i3 }& u) `
- //W25X系列/Q系列芯片列表
3 T& g9 @/ S% Q6 ] - //W25Q80 ID 0XEF13
: D. ]; [8 d5 U" t' c, g - //W25Q16 ID 0XEF14
# M* r Q6 b6 q1 D1 k2 [ - //W25Q32 ID 0XEF15. e+ o) i8 L' q8 `0 d2 t4 l- c
- //W25Q64 ID 0XEF16
/ [7 w. |/ r( H+ A - //W25Q128 ID 0XEF17 6 T. J- }) { ?. O/ @
- #define W25Q80 0XEF13
' P- j! v) R' T) A# W) z - #define W25Q16 0XEF14! K9 {; n) _6 `8 E' e3 v6 I4 R9 V
- #define W25Q32 0XEF15
6 g, j b+ X) K# ] - #define W25Q64 0XEF16
- f4 f( P& A( U" h - #define W25Q128 0XEF17( @0 Z; s5 e% F3 c q& R
- 3 D* Q% W2 l, w* M# ^, A8 i
- extern uint16_t W25QXX_TYPE; //定义W25QXX芯片型号 * n4 n3 S2 f9 a% K' T' W' T$ ~, z2 d
- extern uint32_t W25QXX_SIZE; //容量3 |0 `- z* F* E7 a. M
- extern uint8_t W25QXX_UID[]; //唯一ID7 _" x- {3 j4 T
- 5 n- M/ z! d2 x/ G O
- //
# b; W, M! u2 T+ u - //指令表! A4 n% @* W% _1 D3 d
- #define W25X_WriteEnable 0x06 * d. k$ U7 {. o! c$ _1 ~
- #define W25X_WriteDisable 0x04
/ z% f# j& Y" @: N( ^! a - #define W25X_ReadStatusReg 0x05
* p" D3 \' Q9 S+ Q8 \; u - #define W25X_WriteStatusReg 0x01
! f" [' X0 q z9 p- a g4 Q - #define W25X_ReadData 0x03
' ]: c" l! D* T1 x8 T - #define W25X_FastReadData 0x0B
5 G% r* Q( r* O2 }2 F4 S) A - #define W25X_FastReadDual 0x3B
( r( t6 U# i) Q- R$ Z - #define W25X_PageProgram 0x02 5 B4 d- _# D1 T+ T
- #define W25X_BlockErase 0xD8
" N8 d; b; `3 y$ u - #define W25X_SectorErase 0x20
9 k* j' o3 F; |0 m - #define W25X_ChipErase 0xC7 ! F6 w( R; @7 u" \& g; U
- #define W25X_PowerDown 0xB9 6 ^- `0 y. g* r& S
- #define W25X_ReleasePowerDown 0xAB : M9 H! E& x J" \+ m0 `4 G$ D) D/ z& L
- #define W25X_DeviceID 0xAB $ M& v- T4 h: s
- #define W25X_ManufactDeviceID 0x90
6 `3 |' P$ k8 D7 O' E! c - #define W25X_JedecDeviceID 0x9F $ p9 ]$ X3 A7 d* ?" }
/ A) k+ C1 A3 H6 b3 v- @- void W25QXX_Init(void);
) H6 d9 l$ l8 n/ K$ S5 X# W+ K$ u - uint16_t W25QXX_ReadID(void); //读取FLASH ID" L. M: v, {! y$ a* ]
- void W25QXX_ReadUniqueID(uint8_t UID[8]); //读取唯一ID5 r2 Q8 R3 J& J3 p( p# N
- uint32_t W25QXX_ReadCapacity(void); //读取容量" H& i5 P3 w. {( f$ [/ S
- uint8_t W25QXX_ReadSR(void); //读取状态寄存器
! ~) R2 E3 _6 o* @% h9 u - void W25QXX_Write_SR(uint8_t sr); //写状态寄存器1 U3 C; {" E- P: ^4 U5 G; y
- void W25QXX_Write_Enable(void); //写使能
) ]2 \- q: Y% w9 t. ~7 \6 N( X - void W25QXX_Write_Disable(void); //写保护
1 t: J) p6 A" x0 e/ X7 R0 `! _ - void W25QXX_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);
1 I0 Q# C9 B$ J8 m! \* O. Q - void W25QXX_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead); //读取flash
8 v7 |" r9 ]( t - void W25QXX_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);//写入flash
4 W6 O" r# H- i, N9 a - void W25QXX_Erase_Chip(void); //整片擦除* g: V, {- H0 N( T. h5 ]! X2 W7 v! O
- void W25QXX_Erase_Sector(uint32_t Dst_Addr); //扇区擦除
1 P% g8 k( _2 L. U: M, z z - void W25QXX_Wait_Busy(void); //等待空闲; Q+ ]& h3 S+ I# {: y
- void W25QXX_PowerDown(void); //进入掉电模式
# o6 ^5 m) R) a: n - void W25QXX_WAKEUP(void); //唤醒
$ _& |: ^* E. s' c3 @, J9 T4 E) M8 K0 V - 9 N K/ F2 f1 g+ y+ ` k( R% p2 }
- #endif# e z4 t5 y! z4 o' C: L1 e
复制代码
5 ^. X$ M+ A- h' v% E2.2 源文件
2 i. r1 E# N7 N7 I+ b1 v5 M- #include "w25qxx.h") k8 W- q& x4 w6 I6 G& ?. |
- 1 i4 U8 q; p. `" M }- h
- " X" u/ R' H/ \( c; P
- uint16_t W25QXX_TYPE = 0;4 a: w K0 x& @8 b( o6 }: ^
- uint32_t W25QXX_SIZE = 0;
% U5 x" |0 ] s0 D+ E - uint8_t W25QXX_UID[8] = {0};) X" j* `: O2 ~& t
! D: ~4 K% @/ x% C2 n# ^
! W: Y/ h. O: a% S1 j4 ~- 0 Z. Y3 p9 y2 {
7 k' t0 D) a& P! m7 o% e- ///
- h5 \+ i& T9 M. G' d" T) l8 l - /// 移植修改区* p& U" ], m/ D1 ^. a: {2 y
- ///
3 l k# @% K' V+ H$ Z# U% P& t - ///
5 V9 _ c' Y/ \ - 9 i! i4 C7 B2 R( l
- #define W25QXX_CS_H() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_SET)) X: h- p/ h: a4 W
- #define W25QXX_CS_L() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET)
* M5 t4 _- n+ y( ]
0 m6 d& B2 E/ y" N1 q- #define W25QXX_SCK_H() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET)& E0 c5 X4 ^. I8 _# ^% x, Q2 }( i
- #define W25QXX_SCK_L() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET)! F$ r$ D. a0 l/ Z
4 G# j# o1 o0 x' |. H- #define W25QXX_MOSI_H() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET)
- U; X& i7 r# E; j. P - #define W25QXX_MOSI_L() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET)
8 |9 i% e D( ` - 9 T+ F0 u8 @2 h6 d) }# e) I' F; W
- #define W25QXX_MISO_GET() (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4) == GPIO_PIN_SET ? 1 : 0)3 O9 X7 l# r% m5 W. z
- ( z, | ^; i( b2 g* ^
- static void delay_us(uint32_t us)( U# d i. `! H4 y
- {* u/ |! L9 ], ?( M6 ^, u. h
- uint32_t delay = (HAL_RCC_GetHCLKFreq() / 4000000 * us);
f' O! @' `/ I - while (delay--)$ W3 z/ [3 f8 ~9 V' V
- {9 x7 n$ w; T l# v4 L7 z. [4 S
- ;7 c7 M' [, n: O8 L d
- }
9 t. X0 O# D% P - }
/ }4 H( x9 a8 r: U0 x! h - 6 Y0 [' w5 u% Z: m6 _' _* V
- static uint8_t W25QXX_SPI_ReadWriteByte(uint8_t TxData)& ~- [1 Y8 X% }9 U$ ?3 T4 a& L
- {
5 K" j" I* t3 h% ]3 o - int i = 0;
9 L8 J0 ?6 l& P; ^ - uint8_t RxData = 0;
@* n" O7 [9 t1 k7 b - W25QXX_SCK_L();
2 U# u4 F' O9 a3 D - for(i = 7; i >= 0; i--)" _/ h. V U u( }; C" K0 d
- {
% T, {3 U6 T2 g3 A - W25QXX_SCK_L();# Y( k B6 U s1 E4 k& H7 S
- if(TxData & (1 << i))7 Q5 P4 _" ~( H
- {) `& R7 b. p: Y# r2 F) @6 X) m
- W25QXX_MOSI_H();
- j+ [5 y: l0 D3 q& c/ A: O3 _ - }6 y1 o# Q8 F9 |; r# ^- F) t5 v7 L
- else
: Z4 N# ?, A6 z/ T - {1 U+ c9 P8 i! Z4 A' z- ^
- W25QXX_MOSI_L(); o |# m' }: u2 M
- }3 E$ k |' n( K+ e) r2 K( G7 U9 }
- delay_us(1); t2 x% n$ P" W+ d: P5 X/ {
- W25QXX_SCK_H();6 _# s3 {8 _: v6 b( R% Z
- RxData <<= 1;
3 d. ?& S5 z L' x - RxData |= W25QXX_MISO_GET();
" P$ D4 x/ `$ `6 k( u. Y8 R - delay_us(1);
8 G4 K9 _$ W/ b - }# T- Z7 @# E. e. D3 A- }
- W25QXX_SCK_L();. F. n# }: Q7 A
- return RxData;8 ]8 R$ L6 {4 n
- }
& G7 h3 L& @# P
: r/ @. U3 H4 K/ {- static void W25QXX_SPI_Init(void)
7 N) U' F8 `5 T6 C/ z- ` - {
W2 K- Q: V: C: o. [/ N - // 这里添加初始化IO的代码
( K9 Z1 \# T4 U5 P8 y - }/ G* i5 L4 M: B( g
- ' e/ c& O$ Z9 j! \; N8 j
% \% p* L+ J0 k2 X. p- 2 }, K$ v3 I( F/ M& a; e5 l
- ///
% I4 x3 d, g7 f: m3 l - /// 驱动代码8 Q- l/ D6 f: O% s
- ///! I7 L% @; R$ @ e. }1 K
- ///
1 P) ] v" M- \, B( z - 5 Q8 L' E, @; e: J
- % Q' l, }7 I) A6 Z
- //4Kbytes为一个Sector& b) V/ R" q1 A/ x p! g) u Y
- //16个扇区为1个Block
$ l ^4 H6 J/ s7 @' p$ R' l - //W25Q128& |) M: O6 S6 l
- //容量为16M字节,共有128个Block,4096个Sector
' U* L) R$ w9 m T0 }. |- b
" ^% N0 v7 z0 Y9 Q- //初始化SPI FLASH的IO口
& E' y. k: L* V& p% ^ - void W25QXX_Init(void)% V: ? H0 }7 I& `6 v) `
- {$ }6 y8 D" k0 Y5 i2 p+ r1 x% g
- W25QXX_SPI_Init();) ?5 i; W6 a: X. @$ m* h/ {
- W25QXX_CS_H(); // 取消片选* L( U: W; |3 W2 d+ B# o& r; g3 `
- W25QXX_SCK_L(); // 时钟空闲为低电平7 _+ @, I' t1 C3 m
- W25QXX_CS_L();6 l6 k2 [) P+ Q8 ^! I
- W25QXX_SPI_ReadWriteByte(0XFF);1 a( s( e; m$ f g- s' Y, F. v
- W25QXX_CS_H();2 N7 T" ~- X) x) X% o- O
- W25QXX_TYPE=W25QXX_ReadID(); //读取FLASH ID! j3 l* y# J! F
- W25QXX_SIZE=W25QXX_ReadCapacity(); //读取容量
6 `5 k3 W6 D7 Q! I7 y& ^/ ?1 ? - W25QXX_ReadUniqueID(W25QXX_UID); //读取唯一ID& R3 U* P& |7 q% V0 Y- i X7 c
- } y2 ]( x4 ~3 W4 h
: B, E( A+ V( \2 v: c- uint32_t W25QXX_ReadCapacity(void)
+ E) j) y/ D+ f: @+ d4 {( j - {
' @8 P$ i& i4 K - int i = 0;0 }9 I! f0 k: p' R" Y
- uint8_t arr[4] = {0,0,0,0};: r. y! _+ a# L7 |+ w
- W25QXX_CS_L();
' w/ v, B% d5 i9 u, F2 D - W25QXX_SPI_ReadWriteByte(0x5A);6 H. G' z' e3 R6 l- I- y& c' a! o
- W25QXX_SPI_ReadWriteByte(0x00);3 L/ z) m) w% w, h
- W25QXX_SPI_ReadWriteByte(0x00);
' [7 _. t1 S7 I4 b+ M - W25QXX_SPI_ReadWriteByte(0x84);
) c2 c4 x7 r" }+ P. z% |+ O8 s - W25QXX_SPI_ReadWriteByte(0x00);
1 G9 A3 {1 H" w. ^) r - for(i = 0; i < sizeof(arr); i++)1 o3 Y/ o: _4 y3 M3 Z- j3 h
- {
" ?2 d1 w( s) X6 k% v. b0 o - arr<i> = W25QXX_SPI_ReadWriteByte(0xFF);
8 {% a4 ?( |0 v - }5 o" `9 u6 e# _4 q' S I+ p: Y3 f
- W25QXX_CS_H();
; \, |0 D0 G& ]1 Z9 g* `% R - return ((((*(uint32_t *)arr)) + 1) >> 3);
: |) p/ l+ I5 n: S# v - }2 q L5 o1 H+ Z! g7 x
- 2 A) ?, n0 ~) Q& d$ B# i
- void W25QXX_ReadUniqueID(uint8_t UID[8])* v7 v& P+ z* }, F2 ^. N; d
- {
) T, V3 |7 t! @" {6 f1 m: h9 F - int i = 0;
9 i' @: j: b+ K5 _6 T' |. L* N. v - W25QXX_CS_L();
, a2 `4 U& _4 D8 t0 s - W25QXX_SPI_ReadWriteByte(0x4B);5 {. }/ [0 C5 t9 |" f" ]- ?+ h- p
- W25QXX_SPI_ReadWriteByte(0x00);
0 S' X6 {) b6 { - W25QXX_SPI_ReadWriteByte(0x00);+ X! V4 R; x$ s2 H, u2 E
- W25QXX_SPI_ReadWriteByte(0x00);
& j' [0 R6 z# k2 Q3 a7 H3 _ - W25QXX_SPI_ReadWriteByte(0x00);
4 C0 k, }1 ? {; v3 W7 G7 i! q- C - for(i = 0; i < 8; i++); ~# J4 D" Q6 U' m9 I
- {
y2 E% Z% z1 A: w1 v) `7 F - UID<i> = W25QXX_SPI_ReadWriteByte(0xFF);
/ f s0 {1 P8 n" u, h - }$ l* I" {. d6 g
- W25QXX_CS_H();$ a% B+ ?5 n% S) v# j. D
- }- M3 D0 e9 d' Y9 d4 E1 X0 q! b* u
5 B$ P7 V# Q. B: g- //读取W25QXX的状态寄存器4 B" I/ o5 S5 {! C$ D
- //BIT7 6 5 4 3 2 1 0/ U7 R# Q7 s& w6 f+ G
- //SPR RV TB BP2 BP1 BP0 WEL BUSY
$ M2 ?* j. |9 v" i% s- ^- b$ l - //SPR:默认0,状态寄存器保护位,配合WP使用; b* o! i. q5 j7 X
- //TB,BP2,BP1,BP0:FLASH区域写保护设置/ O* L' ~+ [) F4 t0 U+ f
- //WEL:写使能锁定
( ?+ H. A9 @' d7 a* ?, K0 J - //BUSY:忙标记位(1,忙;0,空闲)% m2 O+ A( M# ?3 J- ]
- //默认:0x00
% Y) g( Q" |6 i6 h; G - uint8_t W25QXX_ReadSR(void)4 B3 G! p) V9 p& h3 ]! ]$ I; O" j
- {
! M4 h0 i6 U! r) d# S- @ - uint8_t byte=0;: {% R8 J9 ]) R1 ]/ y& j4 E
- W25QXX_CS_L(); //使能器件
3 u4 a! c t F$ v( ]6 T( J2 [ - W25QXX_SPI_ReadWriteByte(W25X_ReadStatusReg); //发送读取状态寄存器命令
+ x4 j" L9 C- H. T3 p; p/ T! g) K - byte=W25QXX_SPI_ReadWriteByte(0Xff); //读取一个字节( r/ d" K4 |2 C) t' m. r
- W25QXX_CS_H(); //取消片选% ^4 F3 B9 I3 g; \
- return byte;6 a$ g1 K: a6 @' S2 B, n: y
- }( s4 d" D4 [1 \# E: i& H
- //写W25QXX状态寄存器
% L/ F' z) j6 P9 u6 p - //只有SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)可以写!!!- V; V) N: H( `
- void W25QXX_Write_SR(uint8_t sr)* b: f# R b+ d
- {- b0 U" i& r" z/ d* [8 S9 g
- W25QXX_CS_L(); //使能器件( y, M( g: |& Z4 H
- W25QXX_SPI_ReadWriteByte(W25X_WriteStatusReg);//发送写取状态寄存器命令
( f L, q' f2 H2 x - W25QXX_SPI_ReadWriteByte(sr); //写入一个字节
7 W$ O; L9 G1 ?8 U5 Q - W25QXX_CS_H(); //取消片选# n/ W7 l( \! ~' ~) R3 ~
- }+ S. i( J# i5 G3 _7 ]
- //W25QXX写使能; ^4 s+ i. U4 G7 Y- y
- //将WEL置位# l% [) F V; b* s: ]! _, M
- void W25QXX_Write_Enable(void); ]1 C* L" K7 {+ z& W
- {2 L$ }4 f# c3 U1 `1 @( R
- W25QXX_CS_L(); //使能器件
" H9 i/ b' N4 n' m2 q9 X& [" z - W25QXX_SPI_ReadWriteByte(W25X_WriteEnable); //发送写使能
- @. u _- s6 |+ T" X! a2 A - W25QXX_CS_H(); //取消片选
( H8 g/ I& b% e0 c7 Z - }+ K, h. \/ h- @# e$ r& J
- //W25QXX写禁止. X8 a) \0 f' U7 i1 V( C( Q
- //将WEL清零, K! Y/ R: D; ~+ J0 W
- void W25QXX_Write_Disable(void)
7 U6 t0 b9 r2 ?! v% D/ D1 N" B - {3 x g2 Z5 S: B
- W25QXX_CS_L(); //使能器件
' @4 m; e3 B% u6 t$ o) d - W25QXX_SPI_ReadWriteByte(W25X_WriteDisable); //发送写禁止指令% {4 z/ m8 S- E [$ P
- W25QXX_CS_H(); //取消片选2 _# W. k ^- `
- }6 U$ e8 i7 V ?
- //读取芯片ID
) B! C0 c- D* B, h& b9 F - //返回值如下:
; ~0 H" S) o1 q! x8 V, F" P - //0XEF13,表示芯片型号为W25Q80
* S. q: Q, y" M! W2 F5 E$ X- _+ a - //0XEF14,表示芯片型号为W25Q16% _1 U! b8 q* H0 ~# F
- //0XEF15,表示芯片型号为W25Q321 p, J c5 E5 p- J7 J3 J
- //0XEF16,表示芯片型号为W25Q64
: q& p6 }) e" y% e4 G, N - //0XEF17,表示芯片型号为W25Q128( _9 v8 m$ H5 w3 P9 G
- uint16_t W25QXX_ReadID(void)
, G( ~: d2 {/ |/ X - {
8 B, t; f( V8 d/ j# s4 H7 a6 w - uint16_t Temp = 0;
! g# w9 }+ y. }' P - W25QXX_CS_L();1 J- ?. }" o( i1 E& E
- W25QXX_SPI_ReadWriteByte(0x90);//发送读取ID命令
8 j% q/ s% k, A - W25QXX_SPI_ReadWriteByte(0x00); z! r5 m3 y. x" ?: G( h1 ]; W
- W25QXX_SPI_ReadWriteByte(0x00);
( T1 b9 h% p5 j6 X/ E& B - W25QXX_SPI_ReadWriteByte(0x00);1 Z* K" s5 e4 ?% h
- Temp|=W25QXX_SPI_ReadWriteByte(0xFF)<<8;6 }. D" r3 F" C- |0 R4 y; y' Q
- Temp|=W25QXX_SPI_ReadWriteByte(0xFF);, r: K+ D. a: D0 S& S" Q$ ^
- W25QXX_CS_H();2 |) M1 c* k: V$ Z5 B# v& K
- return Temp;; V8 B' r/ k6 [/ X1 d
- }8 `6 o: ?. ~9 W- D+ \9 f
- //读取SPI FLASH" Z& O- L/ Z! T
- //在指定地址开始读取指定长度的数据
5 D; [' S7 w" k - //pBuffer:数据存储区
z9 r# O! g1 z8 i1 p5 ?; }1 L - //ReadAddr:开始读取的地址(24bit)3 Q7 O' j7 x6 l6 Y, }5 \
- //NumByteToRead:要读取的字节数(最大65535)
0 o9 f5 H, | m9 S. L) u - void W25QXX_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead)/ z% P L i7 A. }+ \
- {0 |" v' ?% E, N
- uint16_t i;7 L: C4 Y/ L, e
- W25QXX_CS_L(); //使能器件
& w' Q" i+ z g" d; b$ t - W25QXX_SPI_ReadWriteByte(W25X_ReadData); //发送读取命令7 J( _" f, V7 Q+ [
- W25QXX_SPI_ReadWriteByte((uint8_t)((ReadAddr)>>16)); //发送24bit地址
9 U j) t3 I7 H X; j. y - W25QXX_SPI_ReadWriteByte((uint8_t)((ReadAddr)>>8));. `/ d. e8 j% j/ o6 A
- W25QXX_SPI_ReadWriteByte((uint8_t)ReadAddr);
# u8 M' t v/ B6 }- X+ ^ - for(i=0; i<NumByteToRead; i++)
2 z- `. ^8 m% ^( p, m' y6 w6 I9 i" | - {
+ _% u' ^( x( K - pBuffer<i>=W25QXX_SPI_ReadWriteByte(0XFF); //循环读数
! k* b$ K U' j, }1 z - }! z/ w" h, E3 y- E+ @9 ~% J
- W25QXX_CS_H();5 w+ S; y8 c) h8 S% Z; p
- }
) v: A- x6 M- h7 G' `) d - //SPI在一页(0~65535)内写入少于256个字节的数据7 U0 i* l% |! Z" c
- //在指定地址开始写入最大256字节的数据
! g' V8 c* h4 `" J9 ` - //pBuffer:数据存储区0 I% Q; o9 e0 ]" ]5 u
- //WriteAddr:开始写入的地址(24bit): n; S5 g+ A4 _2 V+ N: J+ P% }3 s
- //NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!* B* p/ ]7 L/ h$ V
- void W25QXX_Write_Page(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)# a f; S Y; G0 C; m3 Y
- {' y7 g# l# W; N. ]& |; j: I
- uint16_t i;) \8 B2 e" T# l
- W25QXX_Write_Enable(); //SET WEL+ {4 u2 G$ _3 J( O! l: c
- W25QXX_CS_L(); //使能器件
6 f& f- a0 {/ J5 o4 y. q1 g - W25QXX_SPI_ReadWriteByte(W25X_PageProgram); //发送写页命令% W {$ l3 {5 _3 J2 K- s6 \
- W25QXX_SPI_ReadWriteByte((uint8_t)((WriteAddr)>>16)); //发送24bit地址$ I2 S3 r9 N8 V1 x
- W25QXX_SPI_ReadWriteByte((uint8_t)((WriteAddr)>>8));1 B* ~4 g* \/ Z( n& D( E
- W25QXX_SPI_ReadWriteByte((uint8_t)WriteAddr);( N+ l; c7 n2 Z) I5 D4 X
- for(i=0; i<NumByteToWrite; i++)W25QXX_SPI_ReadWriteByte(pBuffer<i>); //循环写数- J6 E! J Z* Z2 [+ i' s
- W25QXX_CS_H(); //取消片选
! ]" p: ]. k- v5 q# J# @- z5 u - W25QXX_Wait_Busy(); //等待写入结束0 H# r! W+ k; J+ _! |( T/ g
- }. y8 i6 s0 W5 X3 q# z
- //无检验写SPI FLASH
|+ r$ v' b4 T; p G - //必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!0 Y. u& @6 o. ~1 E
- //具有自动换页功能
. R+ W( y( B* S: a) M - //在指定地址开始写入指定长度的数据,但是要确保地址不越界!: U z( B' P9 y# d8 I$ A
- //pBuffer:数据存储区
0 N0 R5 g. ^9 e7 p+ A - //WriteAddr:开始写入的地址(24bit)
8 H3 x# l2 Q, j+ a* N3 ? - //NumByteToWrite:要写入的字节数(最大65535)* r! k9 e' K- u6 S; y: J) k( q
- //CHECK OK
0 o2 C5 R2 p/ b+ y" z- v - void W25QXX_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
2 e* I+ t; u2 u% T G - {
6 j9 \' A9 |. }0 g$ E9 r( E - uint16_t pageremain;$ {/ L1 C2 k/ d3 F* A8 S0 g% v6 v
- pageremain=256-WriteAddr%256; //单页剩余的字节数
* i. N; `. h6 R: M- a3 _* c+ v! M, S - if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节( D- o3 c& s" |6 V" v
- while(1)3 m3 ^7 Z$ l& Z
- { i: n$ w& G: `6 U6 v* Z' I0 \, }7 p
- W25QXX_Write_Page(pBuffer,WriteAddr,pageremain);: T. ?$ N4 b5 N- S j
- if(NumByteToWrite==pageremain)break;//写入结束了
& W/ T- |7 y: J1 R& ?7 } - else //NumByteToWrite>pageremain
9 }5 O+ w' h" ?; R5 ]$ K. z - {
, Z! Z Q. b8 d' T3 E - pBuffer+=pageremain;
; r, o7 `, _. ?0 t - WriteAddr+=pageremain;5 t- Y- b( X! z
- * o6 H, N9 ~$ c% C9 q- j a
- NumByteToWrite-=pageremain; //减去已经写入了的字节数$ J3 ~; q+ Z) v% z; Z9 M# o% _# T
- if(NumByteToWrite>256)pageremain=256; //一次可以写入256个字节4 L! g8 b8 n" I; S. j
- else pageremain=NumByteToWrite; //不够256个字节了
3 X: Y ]8 P- w% K - }, d0 }' y$ E# u. d9 A, K2 e+ s" G
- };8 k8 u# P9 t- G) ?8 {5 o
- }( T1 f1 J$ {4 E' F q
- //写SPI FLASH
5 o/ Y4 O, d- r2 d - //在指定地址开始写入指定长度的数据
3 A5 w0 _7 |" y5 i* V( E - //该函数带擦除操作!) `& B: [4 x7 r; T& R
- //pBuffer:数据存储区
/ ?' y; a1 j# \* X" r M } - //WriteAddr:开始写入的地址(24bit)
) D6 ]2 @. n! S# I - //NumByteToWrite:要写入的字节数(最大65535)+ C( _2 O5 E/ }0 H' r
- uint8_t W25QXX_BUFFER[4096];6 Y* v; Q7 X: \: V$ `
- void W25QXX_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
& I4 |9 X" A! O0 I - { U$ W7 _1 o1 Y4 ^. a2 z- I
- uint32_t secpos;
; E. Z% d, K2 p, b6 A3 ~ - uint16_t secoff;* h: }3 | U2 o4 R) P& C: P
- uint16_t secremain;
3 u6 `( {9 |, D - uint16_t i;: p6 c5 w* y/ y- G
- uint8_t * W25QXX_BUF;
3 p! [, h( ?5 V8 @4 x - W25QXX_BUF=W25QXX_BUFFER;
# }' R- ?/ \8 p1 R- f6 V - secpos=WriteAddr/4096;//扇区地址 W8 V" t5 t" A$ I7 C
- secoff=WriteAddr%4096;//在扇区内的偏移" o( V5 K0 e# M" `, ?; x
- secremain=4096-secoff;//扇区剩余空间大小& Y1 `& W: x+ u, K: W' S7 M
- if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//不大于4096个字节+ E. e, \2 }, | _ T( q
- while(1)
* i9 b7 J! a! n( [! }- w4 | - {/ ]: {9 f3 f' [* a4 a1 Y
- W25QXX_Read(W25QXX_BUF,secpos*4096,4096);//读出整个扇区的内容" R0 J: ~5 t& Q5 I
- for(i=0; i<secremain; i++) //校验数据& i9 T$ D& C* ^% ]3 N5 J
- {
- F5 w5 ^! w ]4 W7 h3 z - if(W25QXX_BUF[secoff+i]!=0XFF)break;//需要擦除/ `9 ~- c6 H/ H+ N
- }
' F- a9 R6 p( ? - if(i<secremain)//需要擦除
! a% l1 ^: M+ s0 I% o2 m5 z: F) g1 t - {$ i% y/ b- d( z. b. U8 f
- W25QXX_Erase_Sector(secpos); //擦除这个扇区
O% e y+ _+ Q0 p5 T. X2 n0 P - for(i=0; i<secremain; i++) //复制6 A- k6 j) }$ `8 U$ A- n' B2 h( D+ U
- {$ v$ M5 h% ]. U7 M
- W25QXX_BUF[i+secoff]=pBuffer<i>;9 e5 i- w2 C% ^4 E8 r
- }6 {8 v6 O3 x4 c
- W25QXX_Write_NoCheck(W25QXX_BUF,secpos*4096,4096);//写入整个扇区
) @. T% M/ G5 \9 W6 i* Y. j
- B. {1 ^, y5 ?, K4 Q- }. x$ y8 S. \; f' H: q; P3 h
- else W25QXX_Write_NoCheck(pBuffer,WriteAddr,secremain); //写已经擦除了的,直接写入扇区剩余区间. F3 R- Y6 \, `7 G$ b5 b/ w9 E
- if(NumByteToWrite==secremain)break;//写入结束了
9 N- ^+ @4 G* |2 u - else//写入未结束
; s9 [7 A% k3 r& F8 [0 g - {
7 b- n4 Y4 h! ~2 M - secpos++;//扇区地址增1
& n0 o3 t: c- Q. I4 l - secoff=0;//偏移位置为0& d0 N' A2 h+ w7 t. Y7 |7 G
8 O5 h/ D }! c3 r! |1 L- pBuffer+=secremain; //指针偏移
; M1 g6 C3 `3 z* l0 A - WriteAddr+=secremain; //写地址偏移
) G% @' T9 S! M! u9 K, `8 E - NumByteToWrite-=secremain; //字节数递减
4 ]4 _# x, P _; P# r# y# h - if(NumByteToWrite>4096)secremain=4096;//下一个扇区还是写不完0 |# n( g2 Y) R8 B
- else secremain=NumByteToWrite; //下一个扇区可以写完了
8 p4 @/ G. S' @& H H! } N" O - }
4 V: Y2 a, O$ f' _7 \$ } - };* A D. b9 H" a# q/ L0 B
- }
! c5 i1 U7 H" O! x& \$ [0 l+ k4 V' t - //擦除整个芯片7 K0 u( y" G6 T2 g
- //等待时间超长...
5 r9 j; Q. K7 Q8 g, z F7 h - void W25QXX_Erase_Chip(void)1 R2 n& O9 ]! |$ [3 e Z
- {4 X( }: v1 r7 s3 \
- W25QXX_Write_Enable(); //SET WEL
* X8 d* z, v/ v - W25QXX_Wait_Busy();" I8 w$ b% S. H( s" _7 ]
- W25QXX_CS_L(); //使能器件; f3 W5 q3 L* C0 T2 S% S
- W25QXX_SPI_ReadWriteByte(W25X_ChipErase); //发送片擦除命令; Y2 u1 h6 n. f
- W25QXX_CS_H(); //取消片选3 x4 V2 Q0 y; a/ b, A0 e3 y5 {
- W25QXX_Wait_Busy(); //等待芯片擦除结束+ I1 X* A0 |+ b) A: j3 `
- }- z- N# M( A; d
- //擦除一个扇区
, s/ X8 {1 S' ?5 u9 q0 ?) h% B - //Dst_Addr:扇区地址 根据实际容量设置
0 I7 J% U+ i' [: J& C0 e - //擦除一个山区的最少时间:150ms
) B' U6 d" M7 M/ j& a( a* ~$ i - void W25QXX_Erase_Sector(uint32_t Dst_Addr) W/ s- F) ?- b- ?% n1 A- E. L
- {
& n1 K7 N' e% s( ] - //监视falsh擦除情况,测试用
7 I( }' M( ]9 B! C2 d0 n% r/ e - Dst_Addr*=4096;
0 i; L# O* X# l$ x) N - W25QXX_Write_Enable(); //SET WEL
$ t2 Z6 @7 V/ @ - W25QXX_Wait_Busy();& e; g" }9 y* s/ [0 J
- W25QXX_CS_L(); //使能器件$ w; e6 g1 K7 u2 t+ x9 C ^
- W25QXX_SPI_ReadWriteByte(W25X_SectorErase); //发送扇区擦除指令
, e: c( m v2 e% l; ?9 P1 W - W25QXX_SPI_ReadWriteByte((uint8_t)((Dst_Addr)>>16)); //发送24bit地址( `5 x/ `* _0 |) X: e2 t0 d) U8 A
- W25QXX_SPI_ReadWriteByte((uint8_t)((Dst_Addr)>>8));
. V: A/ I* ]. Z- ^4 j - W25QXX_SPI_ReadWriteByte((uint8_t)Dst_Addr);. x; f. O3 F3 V# F
- W25QXX_CS_H(); //取消片选
+ K k9 U7 E ~3 x9 O! @ - W25QXX_Wait_Busy(); //等待擦除完成& {( Z4 n1 q; ]! x
- }
# w& E' L, g' q3 [6 F2 \9 n - //等待空闲
' |# V4 y, `3 [7 m* J: I* m - void W25QXX_Wait_Busy(void)
5 A4 }% Z6 L7 |; n - {, x7 ?( s: z4 L) ?0 V* o
- while((W25QXX_ReadSR()&0x01)==0x01); // 等待BUSY位清空 V/ {' ?1 m( o
- }: Q8 l) U7 V5 m8 z' T# U
- //进入掉电模式$ B7 c9 A5 `' l+ L! ]) j4 @
- void W25QXX_PowerDown(void)
$ E& E% ?* f2 t, ?* ^' y - {
3 n6 D5 a0 Q( h* b+ ^ F - W25QXX_CS_L(); //使能器件" N. a4 w6 S* O5 A- ?% [) Z
- W25QXX_SPI_ReadWriteByte(W25X_PowerDown); //发送掉电命令$ I/ W t" C' X$ ?& u
- W25QXX_CS_H(); //取消片选4 H* e9 Y! E6 f3 S1 g! M4 ]
- delay_us(3); //等待TPD
$ g, C0 q7 Y Z+ S6 s; R, U - }
0 [& C+ V6 U2 z. z - //唤醒
- @( d; ~6 j/ h8 k6 L - void W25QXX_WAKEUP(void)
2 K4 x% R7 E4 I3 V: w - {
$ t. j: l& }! l: B4 z# y# G - W25QXX_CS_L(); //使能器件 ~+ `6 L* G: `6 S5 W) {
- W25QXX_SPI_ReadWriteByte(W25X_ReleasePowerDown); // send W25X_PowerDown command 0xAB
% _9 ~; _6 Q- E, C; B - W25QXX_CS_H(); //取消片选
: r: `4 m0 y" @! X& c - delay_us(3); //等待TRES1$ Y- R; v' F, X* c& g
- }
0 v% e1 F- o, c) I2 U: V! H
+ m0 q4 z0 a6 c- </i></i></i></i></i>
复制代码 0 G, k; q# f+ j$ }
|