一、实验前期准备8 `6 }* [, A4 e9 q
本次实验的 MCU 是 STM32F103C8T6 芯片,通过 SPI 通信实现 W25Q128 的读写操作。
1 D+ e' O* p- K, P. n9 j
3 }. `" Q; b4 P5 @$ _+ \6 R7 y1. 原理图: L6 q# j5 L+ m8 K' Q
" Q r+ c! }1 h
) {* b% n' S ]8 c2 U, D4 Q2 H6 H# Z1 b. e" z, E2 m
2. 引脚连接
; e$ S: e9 B3 g
& ?0 }: S- m' p1 p2 u
: ?! P- m7 e* J- n( K8 c7 Z3 `% t3 \( E% T
二、SPI 底层驱动. j/ Y4 G$ U% A% J/ S, o# v& L8 u
SPI.c+ B9 ~# H# w3 |8 g( e
- #include "SPI.h"
# L7 m d" R" I% i& A7 q
$ G3 O; q* |. s; j9 v- /*
# K% O3 q$ P+ \ - SPI引脚初始化配置
( p' \+ H0 f& E' _# }6 l - **PA4------CS& |6 D2 J0 m; B+ ]8 R
- **PA5------SCLK
) Q+ H2 G' o0 Q& K* V - **PA6------MISO
/ n) C, R+ i2 L& P( B0 i9 R3 y6 p- y; r - **PA7------MOSI2 n; `$ S; Q; C; A6 \
- */
) l" Y: _4 s M1 A# ?* Q
) T. U4 g Y) c' A. i$ M- static void SPI1_GPIO_Config(void) * n# h5 M m& M; m1 u/ ^
- {
, W- @ R7 ]$ z2 l0 Q- V - GPIO_InitTypeDef GPIO_InitStructure;
& `8 H* y3 C+ o. T -
4 H% S" D. T! g0 _5 E8 U0 L$ Y8 f, b - RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE );//PORTA时钟使能
. ^1 `6 f* P2 s
( G7 q& x7 a! d! n' L, n2 v- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5| GPIO_Pin_6|GPIO_Pin_7;. {' c- |, L% i" h. `* e
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //PA5/6/7复用推挽输出 2 y* P! R7 x1 T7 L9 Q
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
, G6 r- F; I- R- `6 i - GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOA J2 b9 L. s. i+ Z7 }
- % T. I3 i& e" }/ _
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
0 c; w; E" n( X% x - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //PA4推挽输出9 p& R- D4 W& w+ U+ d* v- o" a
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
) r7 h2 q' t' d# J0 {4 _ - GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOA
$ q5 W7 r) g1 _$ B% B& [1 i - ! s4 e9 F( Z& t7 f, Q! N
- GPIO_SetBits(GPIOA,GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7); //初始上拉输出! t, l `! p# F" s
- - w( B3 Q: Y( Q6 ?! z
- }
- }! \1 S+ w7 O% ~; x) \ - 7 ]# B8 O6 T+ A5 ?4 F! x
- //SPI1初始化函数) t2 @: d$ c; F) G
- void SPI1_Init(void)
4 q" b$ f9 G: C( ^/ y! R - {6 r7 m8 v( r! _5 H9 t# j- Y
- SPI1_GPIO_Config();//SPI引脚初始化配置
, c3 e0 I J: E9 t1 C$ I/ {
6 _) u6 p% E8 x- SPI_InitTypeDef SPI_InitStructure;" ?( |$ ~* g# [/ W$ x. Z4 B
-
& Q0 x# o Z: n - RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI1, ENABLE );//SPI1时钟使能
; d1 {; Z7 I8 e* r& N+ K -
0 `3 _* [ Z" g. N( s& Y8 ?& t' ^ - SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工+ q: u# e4 s3 J+ a: U0 ~$ @* k }
- SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置SPI工作模式:设置为主SPI/ C, h. j) V. y* Z+ c* Q
- SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //设置SPI的数据大小:SPI发送接收8位帧结构0 O! M, n# E9 c+ @: g0 r
- SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //串行同步时钟的空闲状态为高电平
( ?# v) g7 u) f4 u - SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //串行同步时钟的第二个跳变沿(上升或下降)数据被采样
. ~" c2 F6 Q) ]" l4 Q" _ - SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
/ ~5 g3 p5 u) i1 X2 D: b - SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //定义波特率预分频的值:波特率预分频值为256
. v. I1 H$ F2 \ p; k. ~ - SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
0 K6 W" ` t+ t; Z3 p3 Y; ], @ - SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式- R& }3 }. d8 i) K3 ^+ o4 o
- SPI_Init(SPI1, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器) J; B" n: ?+ A) K( z% u% J5 ]
-
* b$ E+ U& h4 N7 O& i - SPI_Cmd(SPI1, ENABLE); //使能SPI外设9 O% P0 x2 l) n( C4 Z# N' a' P
- SPI1_ReadWriteByte(0xFF);//启动传输
, ^! _$ M. q5 m* @8 S0 K- s" y - } / ]' n6 {4 t& a) D
- 2 m% j1 `7 @$ N+ C5 d7 p# I' n, e
- /*
" A" W" A% @" w& P/ t& R - SPI的读写操作
) k& P3 |1 M: Y2 H - **TxData:要写入的字节
7 ^% @6 c8 s2 M# w$ F/ x, ^ - **返回值:读取到的字节
7 Z" ^7 i+ E9 q' T. r3 P& ?. U- Z - */
' s6 u! A1 a* M$ c2 {: c - uint8_t SPI1_ReadWriteByte(uint8_t TxData)
1 n) Y) U* [, y1 k& Z- Z7 u: _; G - { # W. Q' w( F0 X: h4 j
- while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位! I# [& e5 s9 R) G5 B
- {( e- k- r) n8 P2 \
- //等待发送完成% \) }) `2 c( x, W
- }
: E& r/ @1 |+ x( b, Q - SPI_I2S_SendData(SPI1, TxData); //通过外设SPIx发送一个数据
4 ]6 }. g7 Z) L" W- n9 K - while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET) //检查指定的SPI标志位设置与否:接受缓存非空标志位' z6 [8 ?* e' {2 f- k3 I q
- {
3 J' r. t3 H3 k9 W h' f' N- u& a - //等待接收完成: N0 O! G. D4 |/ C% j$ P4 C
- } 1 ~/ [( B/ |' W" i
- return SPI_I2S_ReceiveData(SPI1); //返回通过SPIx最近接收的数据
, z* {2 ]) ^, ]$ G8 P6 V _- e - }
复制代码 8 i( x' K: j* B" H* [
SPI.h- w: B9 o- Y/ L9 a3 \
- #ifndef __SPI_H) P! N' G+ P/ ?5 S U/ ^
- #define __SPI_H; S. ]+ n, B1 h2 f- |9 k3 Q
- ! G' }2 l" R) B/ N1 \; P' `5 E
- #include "stm32f10x.h"
: t1 f9 L3 R# b* \1 O' h - % F1 L6 S$ ?3 }$ ]
- #define SPI_CS(a) if (a) \
( @, X. {. ]$ y( `3 s3 s4 x - GPIO_SetBits(GPIOA,GPIO_Pin_4);\
+ e$ h4 [! L! _2 e - else \
3 e& W z2 z/ o/ Z9 R - GPIO_ResetBits(GPIOA,GPIO_Pin_4)
7 ~" Z% C. V# U& v3 k$ F - ' t. [% ?+ w0 N4 v( D* O3 x! r
- void SPI1_Init(void);//SPI1初始化函数0 K3 f) Z/ S, X
- uint8_t SPI1_ReadWriteByte(uint8_t TxData);//SPI1读写函数! u E% F. A( ?2 b# |0 w
! V/ A2 m$ O+ D; Y4 |! O& e5 _- #endif
复制代码
; ~* P( x f E/ ?, H三、读取 W25Q128 设备 ID B3 E' n4 l# ^9 t% }0 l! T2 }
本次实验是:读取 W25Q128 设备 ID,然后通过串口1打印出来。5 Z8 O) @9 q; g' F" E
通过简单的实验来调试,有利于发现问题。! F6 g9 p/ u5 e
通过W25Q128的数据手册可知其设备ID如下图所示:
8 E( L; l3 ~+ I3 m3 B' m5 n3 Z" o1 Q
S$ H0 c/ L5 B1 O* _
( w+ r0 x4 c- oW25Q128.c
3 W1 ^3 Q$ W. o9 f- #include "W25Q128.h"
( S/ j l5 F% z7 }) o* C - #include "SPI.h"# j2 R+ B1 F: ]' ]+ N" j" l/ B' G
- & T3 w# Z+ z/ F/ ]1 j( v& |
6 _" Q8 d4 w6 m) `# E. L- uint8_t W25Q128_ReadWriteByte(uint8_t TxData)//函数包装一下, L5 m' D+ U* w% @% ?* B' e4 D0 g# T
- { 8 H2 P8 m! [ q) w! W9 Y& i
- return SPI1_ReadWriteByte(TxData); : s1 i* a5 y' m: u; `
- }2 |2 K) z4 C B! a6 F
- ( G* Y# V% P& e! R5 ]8 T1 ^
- uint16_t W25Q128_ReadID(void)//读取芯片ID3 `( G; P% V+ s5 k. M, N7 |
- {4 S* l3 U) R2 r" D* Y& W7 Q& K% v
- uint16_t Temp = 0; ( c9 G; `- w! M& l. r4 \
- W25Q128_CS(0);
" m: a! T. r3 ^1 R0 l8 @$ a* d9 c - W25Q128_ReadWriteByte(W25X_ManufactDeviceID);//发送读取ID命令 3 c" J# X1 F Q3 V9 m: t" ~
- W25Q128_ReadWriteByte(0x00);
- [% m, j3 u, d" r" _; }0 l - W25Q128_ReadWriteByte(0x00);
, ~& l! {9 [; P2 _* I! R, |4 f - W25Q128_ReadWriteByte(0x00); , W1 G7 t! X5 z' z+ K
- Temp|=W25Q128_ReadWriteByte(0xFF)<<8;
9 o2 X: R; S0 o+ L% i - Temp|=W25Q128_ReadWriteByte(0xFF); ) O( i; \- c% M0 v
- W25Q128_CS(1); ( ~7 d9 z" ^" f
- return Temp;
* `3 [: t& O% s+ m# u4 D* y9 q - }
复制代码
$ a# A, I) m3 d' i. lW25Q128.h
2 D# o1 V5 @! L+ |0 y* C9 }- #ifndef __W25Q128_H
2 z2 u. s% \& R P$ U - #define __W25Q128_H
9 ?2 H! V* d' P5 N
+ Y2 b1 R9 \: W; ?$ ?9 N- #include "stm32f10x.h"* I5 }3 v v. c* d3 n) \4 M. |2 l
- G& k6 h/ o1 C4 Y% |3 p+ O- //操作指令表
9 e& a& u" T; O* Q. T - #define W25X_ManufactDeviceID 0x90 //制造商+设备ID; x% r! a% u1 R
! J4 |8 m8 E5 L- #define W25Q128_CS(a) SPI_CS(a) 8 r$ K- w. ^. ?) Q7 f
& V; W& R) _) ?! e* y- uint8_t W25Q128_ReadWriteByte(uint8_t TxData);//函数包装一下
' _- O p. Q! g) g* O$ L - uint16_t W25Q128_ReadID(void);//读取芯片ID
! [" ~( m! J9 Q2 O( j
7 Q* E. Q) C1 X2 b' @9 n- #endif
复制代码
; k2 {5 E# k5 D% D/ } ?/ i4 e3 smain.c
) v% L. c8 e: |* ]/ r! N, Z8 `4 S) Z- #include <stdio.h>
2 f* U* N% P s: T, b - #include "Uart1.h"$ _2 ^% Q" {( P# C, `5 K7 z% E
- #include "delay.h"* q: S' O1 P5 O
- #include "SPI.h"* I; C) f- o& P) B+ @
- #include "W25Q128.h"
0 \4 ^2 f5 [$ }5 r- j6 C! a z1 j
$ V- l" [ i1 r5 p4 r( f+ F- uint16_t W25Q128_ID=0;
: Q" J2 V% k% L7 x5 [4 N7 V
7 g& z' d8 P$ j. }! ?& m- int main (void)
% p" R! L; X6 g. D) S0 G9 [ - {
. \! m3 d+ G9 R+ b. S& u - Uart1_init();
- O: D& j5 }% B, q - SPI1_Init();9 i3 S- ^4 ?2 Y+ N% K6 S
-
/ d0 B a W9 s7 c; ^, u E2 k - W25Q128_ID = W25Q128_ReadID();6 h' M- }. m, q- M4 ~
- while(1)4 a4 t% a" Y6 t. d7 c6 c4 \
- {
1 J' Y" }& t7 H1 C: _7 O - printf("\nW25Q128_ID=0x%X\n",W25Q128_ID);+ [* v/ |7 @! S; B1 H/ D# \
- delay_ms(500);
. u1 \# E- _$ f8 Q6 \ - }( @% k) c) g, ~; l
- }
复制代码 4 p* f+ {; K( n
实验结果3 |0 p' d4 x6 N7 C4 b
3 N6 H# Z' j( ?4 W2 h6 V! b+ Y
! i3 m& h4 ?+ L# p) M接收到 W25Q128 设备ID 为0xEF17
3 e4 m: x+ h4 P) V; z
" y; b* k) W/ y+ r四、读写 W25Q128 外部 Flash
7 r3 z# S" }) P1 p6 V2 KW25Q128.c
$ Y) w. d# U" u2 ]9 v; r5 m- #include "W25Q128.h"$ q; j) I2 B5 E) Y! S* b, S
- #include "SPI.h"% M e" I8 ?4 v7 u' k+ `; T6 n
% |9 M3 R: e) e% A. {- |
6 q& ^4 o. f% ?- M+ I- uint8_t W25Q128_ReadWriteByte(uint8_t TxData)//函数包装一下
; B% w( C, R% @4 S) e - {
; Y( u5 }1 Q9 y3 Q5 K8 ? ^! G - return SPI1_ReadWriteByte(TxData); . P6 q5 g0 E7 T- q1 D) N+ b
- }
% } d9 w& {6 f - 1 h- U5 y9 N& z* { h
- 4 U$ p8 D8 c& E# [, |+ ]. n
- uint16_t W25Q128_ReadID(void)//读取芯片ID# a/ Q+ a+ \7 [. q+ T; T1 p9 y
- {
5 Q# F& {" w1 p' h. Z - uint16_t Temp = 0;
& J& J- p* D1 j4 l! z/ F - W25Q128_CS(0);
; X. z. `2 W0 a! ~7 w; G! _ - W25Q128_ReadWriteByte(W25X_ManufactDeviceID);//发送读取ID命令
4 U. N' [, X" O' J5 a - W25Q128_ReadWriteByte(0x00); 8 D' ^/ G! n* J+ t! Y6 |% ~! p# a
- W25Q128_ReadWriteByte(0x00); # N6 Q( c6 \* w3 e
- W25Q128_ReadWriteByte(0x00); ' o3 W t4 s! o% \3 k6 j5 l9 p+ z
- Temp|=W25Q128_ReadWriteByte(0xFF)<<8;
9 t# k, o L, H: j- e - Temp|=W25Q128_ReadWriteByte(0xFF);
1 B( f z+ T3 k8 O - W25Q128_CS(1);
* w. g- q+ T' R# D6 [5 @0 S - return Temp;
. |* _% }- |3 }1 S0 d - }& N! y: `/ o! f% b' J2 W* o0 \
- & W. T b5 S/ u6 a" P* Q8 @7 q O
- //读取W25Q128的状态寄存器3 U6 `$ q! \7 B( Q
- //BIT7 6 5 4 3 2 1 0
+ k7 |3 s4 U2 h( u I9 X6 [2 p2 Y, ? - //SPR RV TB BP2 BP1 BP0 WEL BUSY
4 H% h7 z+ w3 h0 o3 X, G. Y- w0 R - //SPR:默认0,状态寄存器保护位,配合WP使用3 P! L, b9 V% x+ }/ n9 c% A& J. d
- //TB,BP2,BP1,BP0:FLASH区域写保护设置
" D/ C( Y) z. h! R) `$ {' I" M* h ` - //WEL:写使能锁定
# N: D$ O6 i3 x* v8 A& F5 ] - //BUSY:忙标记位(1,忙;0,空闲)+ K/ ]" ~& l0 a. R* h( B- w
- //默认:0x005 o4 Z- s1 F0 T1 @& C7 t/ x
- uint8_t W25Q128_ReadSR(void)//读取状态寄存器
% t/ A# C7 s) q: x* C$ T( } - {
4 h/ J2 B+ `0 {7 I - uint8_t byte=0;
! B, s- u9 O4 [5 u# W- _ - W25Q128_CS(0); //使能器件
+ k# |' F- _4 ~8 E2 D% H7 |5 U - W25Q128_ReadWriteByte(W25X_ReadStatusReg1); //发送读取状态寄存器命令
. H! Y' @+ ~* F0 r7 Z - byte=W25Q128_ReadWriteByte(0Xff); //读取一个字节
3 x# y6 k, Y5 D1 t) X - W25Q128_CS(1); //取消片选% ?, [9 F- o" [8 K2 M0 W
- return byte;7 U9 l+ V$ E9 X4 r: U4 G4 a: Y
- } c @2 ~$ S4 F. T
# c' T: ^" H0 ]4 H- //写W25Q128状态寄存器3 L6 W" p/ o0 |) k8 L6 `; M
- //只有SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)可以写!!!. B, v9 H6 Z* ?5 {: H" _! i
- void W25Q128_WriteSR(uint8_t sr)//写状态寄存器. F% Q% J" @0 u) _! h9 \
- {
4 T. j5 J$ a/ K1 A5 ]& z* V - W25Q128_CS(0); //使能器件2 M2 V* ?8 N( G! @( | R7 H
- W25Q128_ReadWriteByte(W25X_WriteStatusReg1); //发送写取状态寄存器命令
3 `; o' ? u: J: F7 b9 V - W25Q128_ReadWriteByte(sr); //写入一个字节
( O; J$ M1 w. r, G6 M. a) i - W25Q128_CS(1); //取消片选
9 Z; I) c. y( u0 I - }4 e, e4 f! P7 \
7 @+ S0 P& a, P- void W25Q128_Write_Enable(void) //写使能
4 e% g, J5 k* f; M% p - {
v, M) Y, t5 B" C& G- ^: R - W25Q128_CS(0); & h7 ^# M) U. M* D4 u/ b$ N3 o! r
- W25Q128_ReadWriteByte(W25X_WriteEnable);
$ ?5 k" e9 c" M - W25Q128_CS(1);
0 p% c! I g; E; U7 Y - }* i( F) a: O: H0 A3 U' s
- + \8 T, e1 ?5 `9 h* B5 ~
- void W25Q128_Write_Disable(void) //禁止写入
; Y1 |- `$ y2 D: e' X. i9 K% m - {
% \& _2 U" A4 _( J6 l8 a' i a - W25Q128_CS(0); ; r2 Y d: q& }5 L9 N. _- M9 c( _
- W25Q128_ReadWriteByte(W25X_WriteDisable);
# }1 `. A* E( v* X8 t6 v, Q6 w - W25Q128_CS(1);
4 W# D5 m/ R6 Y2 a( J - }1 k% J7 @' h; e1 s% ]
/ Y+ F/ D7 e- E& ?/ o5 `/ D- void W25Q128_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead) * I( r* o# q6 Z& [
- {
[7 B5 u: l. c5 I - W25Q128_CS(0); //使能器件 ! u& K, }- C" ]* `' H& @5 K# C9 l
- W25Q128_ReadWriteByte(W25X_ReadData); //发送读取命令
% b; _+ v# T; {1 A, F' u0 [4 K' w - W25Q128_ReadWriteByte((uint8_t)((ReadAddr)>>16)); //发送24bit地址
8 C6 l/ y! m$ `" a - W25Q128_ReadWriteByte((uint8_t)((ReadAddr)>>8));
: ~- h9 e+ D9 _/ L6 E - W25Q128_ReadWriteByte((uint8_t)ReadAddr);
& \; I y: e0 m, t' @6 [ - for(uint16_t i=0;i<NumByteToRead;i++)! |# V/ P3 J6 a# J0 A& F2 D
- {
: |' l, e) B! y: G% R5 O' ]' E- p# } - pBuffer<i>=W25Q128_ReadWriteByte(0XFF); //循环读数
6 s9 i8 L+ d5 i - }: L' q9 R6 W% z( X6 j( [( a9 C
- W25Q128_CS(1);
* w8 i; n6 b5 o. Z - } 0 B. l. ]2 x: X( f
- . N+ v3 e+ T+ u+ E% E' a& ~+ k
7 L2 H5 B& Q" {) x5 e: j. c% _- void W25Q128_Write_Page(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
9 B" c$ W. M, ~# N$ M; E - {
: x: W7 X. w0 ?! z1 N - ! b- A# |- q' h
- W25Q128_Write_Enable(); //SET WEL / \) m5 m$ Q( I7 g ]# F* L
- W25Q128_CS(0); //使能器件
2 E) _1 @ N7 v2 b; p - W25Q128_ReadWriteByte(W25X_PageProgram); //发送写页命令 ; [; J2 W% _* f; c: k
4 y; n$ x/ L3 @- W25Q128_ReadWriteByte((uint8_t)((WriteAddr)>>16)); //发送24bit地址
! l" j- X7 W' n: j# A" G C - W25Q128_ReadWriteByte((uint8_t)((WriteAddr)>>8)); : G1 ]7 a% V& ?# } \) U7 H7 o
- W25Q128_ReadWriteByte((uint8_t)WriteAddr);
6 p' [, ~( Q5 z0 B. b1 B - for(uint16_t i=0;i<NumByteToWrite;i++)" E1 w$ n& a7 h. q8 k
- {; i" Q2 l8 F( d1 f C
- W25Q128_ReadWriteByte(pBuffer<i>);//循环写数
# J7 R$ }) o& C- i% _4 Y - }
+ P, y x, v$ ^+ F' ] - W25Q128_CS(1); //取消片选
: `; L% r: ]- S - W25Q128_Wait_Busy(); //等待写入结束( R: j+ X. i M& X+ J* |- c
- } # L( x% \0 G" y u T0 A
; c: L( I% I t* |- //无检验写SPI FLASH & U% U' N; x& S: b. \& G
- //必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
; w" \1 O5 t2 X1 y - //具有自动换页功能
- i+ \ w. @. A# e: @ - void W25Q128_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite) % L! U: j& b9 }$ N
- {
} s7 j" [6 A; c8 _ - uint16_t pageremain=256-WriteAddr%256; //单页剩余的字节数
9 N; w4 O3 y& Y) T - if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节2 m: ^; f# J, C! ~
- while(1)4 O# @1 L' l8 ]- U ~5 K7 `- i( X
- {
9 [0 Z/ U! x+ J. ]- \- x4 { - W25Q128_Write_Page(pBuffer,WriteAddr,pageremain);
- Q1 N% f" z" X. f+ j' [ - if(NumByteToWrite==pageremain) break;//写入结束了2 A Z0 }* C" b" I3 z) Q+ _2 n
- else . }) |5 _1 G0 U$ t) ]1 r: l
- {0 | {; ?0 H5 Z& l; }+ D
- pBuffer+=pageremain;
5 X Y* T7 n% j, `: ]7 p4 r8 P! E - WriteAddr+=pageremain; 4 v5 f) V7 |2 ]) l+ u. I" s. V$ r
- NumByteToWrite-=pageremain; //减去已经写入了的字节数7 l- K( f5 S/ R% c3 b% e
- if(NumByteToWrite>256)pageremain=256; //一次可以写入256个字节' a- f7 h% L) K& [9 t
- else pageremain=NumByteToWrite; //不够256个字节了; K+ R! E) R5 N7 I" z* T0 k
- }$ v# Y, R2 H5 L/ B1 k- i
- } $ f$ @' U" j0 R2 _. y1 c# A
- } " `0 N' w; u( J- m% y: d
- # c4 M1 r/ @/ k
- //写SPI FLASH
5 W6 b# s0 n9 s7 _4 U* c! T( K - //在指定地址开始写入指定长度的数据5 ^/ s6 }8 j- S, G( U' Y+ y* ~5 z2 f
- //该函数带擦除操作!7 z6 [. K& K, [5 i* y: L
- //pBuffer:数据存储区1 c7 V5 U4 Z' j0 ~8 O8 ~3 h( C
- //WriteAddr:开始写入的地址(24bit) 6 }/ ~8 c& r+ c" t$ [7 c4 m) ~
- //NumByteToWrite:要写入的字节数(最大65535) & q" D; G7 @3 v
- uint8_t W25Q128_BUFFER[4096]; : Q* y- g" e' c& V* [
- void W25Q128_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite) 6 Z, U# @' w" n+ D7 X8 h5 S0 i( B
- { / D8 ?9 O2 ~5 r3 Y1 v' S. S
- uint16_t i; 5 r# Y( [( F q3 |) e! }
- uint8_t * W25Q128_BUF;
! M- c! X9 b5 y9 g8 F - W25Q128_BUF=W25Q128_BUFFER; # c7 p- d3 D4 s: O0 M" ~
- uint32_t secpos = WriteAddr/4096;//扇区地址 $ F6 j7 w% |, g9 s6 T
- uint16_t secoff = WriteAddr%4096;//在扇区内的偏移6 u" W4 C" x* {8 e- Q- m
- uint16_t secremain = 4096-secoff;//扇区剩余空间大小 * l z Z9 R E5 ~3 a2 N" o
+ l, p: t9 b" V3 ?* e- if(NumByteToWrite<=secremain) secremain=NumByteToWrite;//不大于4096个字节" e7 G$ W! R! g" B
- while(1) 6 V8 ~" i3 O2 V' r
- { C: M0 j$ c+ A- J% N
- W25Q128_Read(W25Q128_BUF,secpos*4096,4096);//读出整个扇区的内容( X# [$ x' s' ^" d
- for(i=0;i<secremain;i++)//校验数据: T' n, F+ U( U3 b
- {
4 S* M: u$ Y7 {& E1 {1 l - if(W25Q128_BUF[secoff+i]!=0XFF) break;//需要擦除 2 I0 F" X9 m. B/ ~' {$ v. b- d% W+ D
- }
. m% v' ^" m: }! H% q8 V# H5 }' A. } - if(i<secremain)//需要擦除
s5 t/ \) D% j" V/ y: m - {! Q# u5 z: P/ P: u' ~
- W25Q128_Erase_Sector(secpos*4096);//擦除这个扇区
3 X, {0 X5 o ?& v6 J - for(i=0;i<secremain;i++) //复制, ]" e3 \& J5 r, M( I* g
- {
1 P" M. |! d# m! k( n" Q - W25Q128_BUF[i+secoff]=pBuffer<i>;
. K4 a; c9 s0 F, i: p - }
) w% Y# F' `5 X- b9 q - W25Q128_Write_NoCheck(W25Q128_BUF,secpos*4096,4096);//写入整个扇区
9 ?; a6 F! U2 l7 r6 p/ \ - ) I% V% x- W1 @; i) a$ {2 e; ?# F
- }else W25Q128_Write_NoCheck(pBuffer,WriteAddr,secremain);//写已经擦除了的,直接写入扇区剩余区间. ! L: O: r4 X/ Z% H6 i) S
- if(NumByteToWrite==secremain) break;//写入结束了
. `0 ?) \% y* o/ [2 X8 b - else//写入未结束
% Q8 D% f( D; h0 Q% A - {
( x$ u: W; [ k+ b( P - secpos++;//扇区地址增1% g* c7 |6 U+ y' d! ^7 `
- secoff=0;//偏移位置为0
: Z0 N! z9 F, i# i% C) |7 F) }1 c - * ^1 k5 i+ c) }" X
- pBuffer+=secremain; //指针偏移7 m7 C9 i9 Y- t# d7 v
- WriteAddr+=secremain;//写地址偏移 6 i) }* E/ V$ @) U* Z! X) N0 [
- NumByteToWrite-=secremain; //字节数递减
6 S6 I: b5 i# q' |9 D6 K - if(NumByteToWrite>4096) secremain=4096; //下一个扇区还是写不完5 ]8 ~/ { B# J$ f
- else secremain=NumByteToWrite; //下一个扇区可以写完了
! d# \% x- _' ?. m/ y - }
8 {( z9 ^. c: e5 q) N2 H - }
9 T, ~. x- n2 u2 [+ v% k - }
) b" s$ K; [) c) h; l
6 Q# T0 Z. e. B! g1 ~0 P# S8 w. {- //擦除一个扇区2 Z+ J8 x3 z6 ?/ k8 ?( m3 o" ^! r& Y
- //Dst_Addr:扇区地址 根据实际容量设置# [- \# a5 q% a7 S2 q* |# A8 `, W/ D
- //擦除一个扇区的最少时间:150ms
2 Z4 V3 a* D5 Y# S' p5 W: G - 2 M7 c. g, r( P" t0 z8 s; Z& F
- void W25Q128_Erase_Sector(uint32_t Dst_Addr) * _: |7 ~! A) I/ m
- {
: b3 \' a' R% r2 \% @/ ?! j - W25Q128_Write_Enable(); //SET WEL
( k7 _" t3 H+ C: k' r+ r- x - W25Q128_Wait_Busy(); : b6 j+ E [3 i9 w0 U* C y) @ x
- W25Q128_CS(0); //使能器件 3 f; p8 S) a1 C2 \+ a
- W25Q128_ReadWriteByte(W25X_SectorErase); //发送扇区擦除指令
7 W6 u% b5 y- s; G: N - W25Q128_ReadWriteByte((uint8_t)((Dst_Addr)>>16)); //发送24bit地址 ' j( M+ v' H' g* n( o- A
- W25Q128_ReadWriteByte((uint8_t)((Dst_Addr)>>8)); : ]$ H1 l- E% g+ {/ t9 |
- W25Q128_ReadWriteByte((uint8_t)Dst_Addr);
0 [. l; V2 z9 {" R+ G9 |: k - W25Q128_CS(1); //取消片选
0 V' ~& c) R% {' M - W25Q128_Wait_Busy(); //等待擦除完成
% X! \$ h6 V" Y - } 8 s1 ]$ }: L6 f! H; H3 k, p
* o$ ^3 Z' ]! i5 m- //擦除整个芯片
+ C& ]. Z0 v0 v- x* m - //等待时间超长...6 B& \, r: E8 b' @5 l$ P* R, G3 t! L
- void W25Q128_Erase_Chip(void)
5 q' J% t4 u' J' `: I - { / _" Z7 U$ u5 `1 G" i
- W25Q128_Write_Enable(); //SET WEL Z/ S5 d! T, ~7 X" ?* p
- W25Q128_Wait_Busy();
& y* T5 n- i9 Y& H2 _ - W25Q128_CS(0); //使能器件 5 l+ u- N, _* o' `2 u
- W25Q128_ReadWriteByte(W25X_ChipErase); //发送片擦除命令
6 R# Q. m) e# e N - W25Q128_CS(1); //取消片选 % }, Y/ O4 a% U& T" b w/ Y
- W25Q128_Wait_Busy(); //等待芯片擦除结束
- Y0 B2 K+ F- l0 o" x - }
$ O0 S5 F" X. d - " H" j) v1 k2 k, z I
. K+ H: H5 e: L- //等待空闲. V6 C5 ?/ {$ L: x' O8 u% w
- void W25Q128_Wait_Busy(void) ( Q6 _/ W) q3 C q
- { ' H- V* V2 e4 X4 J; b
- while((W25Q128_ReadSR()&0x01)==0x01); // 等待BUSY位清空
0 l" U/ Z$ _8 h# r - } # [ R* o q7 C. s& ~# t( Z6 T5 {* z% O! V
- 4 a* w: f7 Q* U4 ~% z+ q" ^
- //进入掉电模式
' s2 r/ O# E0 E& F$ R) v - void W25Q128_PowerDown(void)
+ `8 X4 ^6 e* G0 N - {
4 [9 I" K/ s5 L7 V) | - W25Q128_CS(0); //使能器件 ( }& Q* o) r9 v, E z) n
- W25Q128_ReadWriteByte(W25X_PowerDown); //发送掉电命令
/ n3 \8 x2 k( i0 j- s9 o - W25Q128_CS(1); //取消片选
e8 J; ~ d' _- P - }
* y- |. }# T& d8 q r - //掉电唤醒, |* [! z9 o0 g ]$ l) o1 ~3 k
- void W25Q128_WAKEUP(void) 3 o( T& u+ p7 A) i4 u, k: i
- {
6 ~5 p* n# g. \( M/ T9 D/ } - W25Q128_CS(0); //使能器件 $ d3 W* V* j# t1 ?6 D U1 t3 ^
- W25Q128_ReadWriteByte(W25X_ReleasePowerDown);
; ~% H( N+ U; x7 k7 R1 ~9 J - W25Q128_CS(1); //取消片选 3 W) w' U/ z* v, X! ]# a+ }
- } </i></i></i>
复制代码 1 ^- r) b% o' W0 ?) o
W25Q128.h0 L* ~3 T( O5 Q/ m1 F
#ifndef __W25Q128_H
. p0 \7 R( a$ U7 p z#define __W25Q128_H
8 G( m+ d3 p3 E/ w9 t0 q/ e
7 o/ y! {0 u* o& k#include "stm32f10x.h"( u7 A6 U2 i3 Q L5 U2 M; ~
; d; z; a$ G% \0 a# ~0 G, k//操作指令表
' |$ @* K+ d+ Z8 P) K& Y4 O/ ^5 }( p#define W25X_WriteEnable 0x06 //写使能) x0 f+ z2 b. X6 S
#define W25X_WriteDisable 0x04 //写禁止0 o6 V |* f9 w. w/ N
#define W25X_ReadStatusReg1 0x05 //读状态寄存器1
, C0 z1 j) \0 C6 t, I1 @#define W25X_ReadStatusReg2 0x35 //读状态寄存器2
# J9 n: l5 j6 Z% L3 j' J#define W25X_ReadStatusReg3 0x15 //读状态寄存器3
# f5 M5 U$ W- o6 {! }4 a! y+ [4 r0 K" f#define W25X_WriteStatusReg1 0x01 //写状态寄存器19 F6 g' e/ O6 ~8 j' `
#define W25X_WriteStatusReg2 0x31 //写状态寄存器2% d- S/ O( ?' r
#define W25X_WriteStatusReg3 0x11 //写状态寄存器3
8 a% X5 U* D# g* N( Y$ e% l#define W25X_ReadData 0x03 //读数据# l* R, |7 N# X; H: V
#define W25X_FastReadData 0x0B //快读
6 p# T" _* i* U0 d#define W25X_FastReadDual 0x3B //双输出快读
& T; I+ I: n$ B/ w8 y8 R7 f; O+ w#define W25X_PageProgram 0x02 //页编程
! | \4 |% }9 |4 s. J7 X; R#define W25X_BlockErase 0xD8 //块擦除(64K)( {: m# _8 T: n; E5 _( w0 a, K5 f5 m
#define W25X_SectorErase 0x20 //扇区擦除(4K) X. ~: f7 C2 P, l! O
#define W25X_ChipErase 0xC7 //芯片擦除
* H* o2 a8 C6 e- C#define W25X_PowerDown 0xB9 //掉电
; g4 c8 }" C# B: Q2 N#define W25X_ReleasePowerDown 0xAB //释放掉电" B+ ~ X8 }5 q. x8 X! H- U
#define W25X_DeviceID 0xAB //器件ID1 F+ N Q- D! v/ O' Q. E l
#define W25X_ManufactDeviceID 0x90 //制造商+设备ID
8 J$ E! { L: m# g$ d#define W25X_JedecDeviceID 0x9F //电子元件ID
* F& c! Z( v& c J
4 k/ t% J7 k; E5 }) z& }! J% ^2 F& s0 O! }9 }& F
#define W25Q128_CS(a) SPI_CS(a) 7 s( s. X8 E6 m2 @0 K
6 _2 c% {8 [. G% F- r, W
. }& w: Z# h: O5 vuint8_t W25Q128_ReadWriteByte(uint8_t TxData);//函数包装一下
) N0 W; a- Q; y2 ^- M4 @" s) X& P! u2 u6 E
uint16_t W25Q128_ReadID(void);//读取芯片ID0 J+ n/ O9 p3 l0 \; h5 C
) U8 H1 Y# t6 [# t" g9 auint8_t W25Q128_ReadSR(void);//读取状态寄存器
/ f& V6 ^. V7 h! d% gvoid W25Q128_WriteSR(uint8_t sr);//写状态寄存器
! F, k! U+ p1 k' e. t' J: t
& u. ^0 P! v: l' ^+ qvoid W25Q128_Write_Enable(void);//写使能, \/ z5 e: _0 M/ W% v' B9 d5 }: j6 \) e
void W25Q128_Write_Disable(void);//禁止写入 + f. Z; X( s1 F q# a( [ f
1 p Q/ Q/ p i0 G6 X
void W25Q128_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead); //读取数据* w( ~( b. o/ O0 R4 a/ ^. e
void W25Q128_Write_Page(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);//页写( O: `0 x; t7 {6 v; S
void W25Q128_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);//无检验写数据,可自动翻页2 `% @. g: o' N, P0 `2 ~
void W25Q128_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);//写入数据,带擦写功能7 b& T1 i- z! U
5 V! x4 E9 _$ Z* t. c3 Q
void W25Q128_Erase_Sector(uint32_t Dst_Addr);//擦除扇区( |5 I6 Y: T+ z/ b2 }' L, a* g
void W25Q128_Erase_Chip(void);//擦除整个芯片 6 R$ }1 A3 F) s4 d3 i
+ N B6 Q" Z- V: p, d) nvoid W25Q128_Wait_Busy(void);//等待空闲) U3 _( \% @" \( I! s
void W25Q128_PowerDown(void); //进入掉电模式9 s6 \. H0 p9 E9 Q
void W25Q128_WAKEUP(void);//掉电唤醒
; B9 Y; U2 K0 [& b5 ^0 k: s
3 r8 O( P& y1 O" b#endif
2 Q, Z; t7 X% z% J" c
; [# n& P% ~# w; x, p3 @$ N1
( v+ j6 s% Z, u+ J* @2
7 F0 o9 [( ^8 K3
' m2 F# K# E3 b8 g4
6 e3 x' N/ S/ n. y; o+ m- Z2 o; _5+ ~' ?. j* _( e5 v( U# |$ i2 q
6
6 _, r* J6 |5 L& B7
/ H1 r2 B# ]3 s: r5 G8
5 `8 b/ C. }: S B' x" o9
# z* A- n) T) w5 f `' C10
g) y. t6 V2 }+ O( e11; P% k: _- R& X! J5 z2 Y4 t
12
! f* i) X$ e1 J% d+ a- H13 e3 y2 v1 K" Z |: C& y
149 D% m3 @7 e: O6 Q* t3 V8 B
15
% e3 k9 j) C# u5 M* ?1 f16
2 f. D+ K3 Y+ ~# |4 P% H0 g( u/ g- V177 Q K2 R0 i: q
18# q0 _* Q! G$ ^$ @8 [7 P K0 X
19& C6 E( L5 }) w! m% j, b. L8 X! {
20
9 p3 Q/ n" a- H# B' i21
% S1 h" k- G9 I) Q! |# g l22
* C% e) b% X- t' ~$ k235 h" @6 p/ m, d6 Y2 k
24
0 f; h5 ~2 }$ |% R7 H7 ]* |25
$ ~' o P; ^) y( v9 c% A) A$ n26 g0 K; H& i) [
27
3 T+ H1 \ ]& N28 C2 @7 |: O6 M
29
# l! V& Y* N9 z" f30# k. X( ^3 l) b
31
- N) K. @9 ^# h4 z32. `% L8 d2 h5 M9 n+ P' i* S7 h
33
% t$ ?+ m/ c0 Z$ \& t6 q! g2 m34; l l9 g# I1 a& {' m0 [$ R% x; K
35) O2 \8 @" k$ h7 E; w) h1 n4 X
36
3 Y, g! G. f$ i, o- V8 x. x37
2 Z5 W4 E( H# |: D* F" C38
1 k7 ~ w5 ?8 h; _! o! g39
$ A2 B: u# W" X8 A2 a40
& G5 H3 w" g2 Q8 {! m41/ s0 l, k0 ^" H! a- |/ u
42
$ [3 O1 G, I% [43
0 x% O# |' w8 L$ k) `44
# |) Q$ N* ~2 [6 f! [% k5 a" ~45
1 Q+ `8 {% x& M( P7 R/ G46
3 ?& ~) A) }* o47" j* h, ]2 `! Q2 H$ \( D8 }& K: U+ U" p
48
; A( `9 A6 k4 [49 K9 F5 J- |& S$ b0 _8 g7 @ @
50
9 @& {9 B% s! \$ `" o51
: l: V" L; K7 U4 g& ~% a52 h3 m8 @ s; F$ o- H/ A
53
' \! u* l/ m5 x& l/ y548 U9 _5 y* b9 z& @5 Y/ E
main.c
) U5 g2 x- t: }- B, R#include <stdio.h>
$ H3 S1 \% ^- G& \, y#include "Uart1.h"
7 S- _. N9 i6 Y& U9 X) W% C/ X#include "delay.h"
% r" A- t" \" i; @" w0 f#include "SPI.h"
' y; D6 p# F0 D#include "W25Q128.h"
' x) ^6 T, W+ Y, X' U
m1 a# `/ O4 N$ T, N) Ruint16_t W25Q128_ID=0;
9 s$ C$ E' ?9 A, m5 kuint8_t Write_data[20]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
7 i; D6 Z" S# ?1 ^' Juint8_t Read_data[100];2 a1 ^7 N2 Y' d' |4 Z" ~
4 F' S2 g; f0 G: f+ ^. ^int main (void)
) ]% V& Q9 C6 ?5 u{
1 g* o2 s* B# ^( o& I/ a Uart1_init();
* a. b8 ~& \5 X; f: m1 v$ O' c SPI1_Init();
+ N3 Y$ B- M5 w! i2 x 4 k# [0 f# P% ^ u; g
W25Q128_ID=W25Q128_ReadID();
, u, B5 B7 n( i& a W25Q128_Write_Page(Write_data,0x01,20);! y/ V; G) c0 L
0 B( m) o" F8 x. ~$ p2 C
while(1)9 c) Y. {8 h8 W. X: O T7 \
{
4 w4 p" q3 ]. \ Q- b7 H# Z W25Q128_Read(Read_data,0x00,100);
! @ R- ]! L( E& Q$ T9 e for(int i=0;i<100;i++), |+ ?( h( E P. M# j% H
{" d2 L( t2 s% u
printf(" 0x%X ",Read_data);
- y' Y0 W3 q: _4 t4 q }
0 L: K$ b* O% ?5 O+ y l printf("\nW25Q128_ID=0x%X\n",W25Q128_ID);
3 U9 ^4 U+ \# i delay_ms(500);' y! {1 P9 U& F: b/ j6 ` P
}
4 l# s8 ?# t' }$ V}" N6 F! ^" T8 |/ v5 k' _6 R
! P9 J7 O6 T2 B) g; g' R16 A6 v4 W, ~; s& Q( N4 i
2
2 _. L u4 d6 s% o; W4 W4 Z3# ~! r4 D, A! O* d" R
4
' `, ]3 u" o. |3 @. f- Y' i, T5' t& D6 E ~+ S0 V$ Y' A
6
* I( R9 t P) o& X9 }0 s: J3 m7
2 H! R1 M J2 u3 {8
: x- _( V. {, j! g* F2 ]: \9& J2 j# `% D, p# Z
10
4 V% P6 w7 Q! Q8 s1 [4 P! h+ y11, T9 k& w4 O j7 H5 C
12
6 I* i3 f% U& w, g13
9 @' |' _: ` y$ W- C$ ~0 s" _' @* v144 ^. L, i- M; a* J0 p; N. D: W
15
( V2 o: o6 I% ^16
6 }, ]! f' A7 n% T17
* h* h G1 H7 n! T: L5 U$ @( Q18
; [0 N! c/ H6 S/ K. M19
- {! d( q% O( B" Y2 v/ P8 H! e9 E201 \7 U4 s# f5 h7 L9 D
21
+ t# [, F. B0 p# Y; Q7 ]8 D22
a* b* N, @: V) Y& r7 Y2 z( H6 }23$ C J, z9 P# P
24( n. V; z3 X9 }+ a$ k6 a* T# h
25
W. M- x" g$ Y c2 k' h, ]* H26: V2 S3 j4 Y1 i! z1 J3 s' o
27
- Y2 I$ O4 T" U# u* Z28+ m* C) {/ M% I' F+ T4 L
29
- [; U3 y6 N/ h实验结果
" g' ?) ~$ w- R) C- s t
& I$ \: c+ `) x————————————————+ K% _- B8 m: s& Z2 t! D0 p
版权声明:根号五; Z5 D2 G9 H$ V0 ~+ B; U/ q* i( C
+ [+ o, ?% P' O, c3 m! ~7 l: m: r
, \' t! B5 ?0 r9 A |