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