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