|
SPI协议:是由摩托罗拉公司提出的通讯协议(Serial Peripheral Interface),即串行外围设备接口,是一种高速全双工的通信总线。它被广泛地使用在ADC、LCD 等设备与MCU 间,要求通讯速率较高的场合。 , ?1 h/ v: T, t; t0 Z" s
物理层: S S ( Slave Select):从设备选择信号线,常称为片选信号线,也称为NSS、CS,以下用NSS 表示。当有多个SPI 从设备与SPI 主机相连时,设备的其它信号线SCK、MOSI及MISO 同时并联到相同的SPI 总线上,即无论有多少个从设备,都共同只使用这3 条总线;而每个从设备都有独立的这一条NSS 信号线,本信号线独占主机的一个引脚,即有多少个从设备,就有多少条片选信号线。I2C 协议中通过设备地址来寻址、选中总线上的某个设备并与其进行通讯;而SPI 协议中没有设备地址,它使用NSS 信号线来寻址,当主机要选择从设备时,把该从设备的NSS 信号线设置为低电平,该从设备即被选中,即片选有效,接着主机开始与被选中的从设备进行SPI通讯。所以SPI通讯以NSS 线置低电平为开始信号,以NSS 线被拉高作为结束信号。 4 }$ q) |, |) @8 g2 ~) G; |, m
SCK (Serial Clock):时钟信号线,用于通讯数据同步。它由通讯主机产生,决定了通讯的速率,不同的设备支持的最高时钟频率不一样,如STM32 的SPI 时钟频率最大为fpclk/2,两个设备之间通讯时,通讯速率受限于低速设备。 % x5 K0 P! \8 i
MOSI (Master Output,Slave Input):主设备输出/从设备输入引脚。主机的数据从这条信号线输出,从机由这条信号线读入主机发送的数据,即这条线上数据的方向为主机到从机。
. b# N% `1 O9 R% h+ w; iMISO(Master Input,,Slave Output):主设备输入/从设备输出引脚。主机从这条信号线读入数据,从机的数据由这条信号线输出到主机,即在这条线上数据的方向为从机到主机,只有这条线的信号由从机产生。 SPI设备之间的常用连线方式如下: - L% R% A! a4 i( X
+ t4 ]* _+ R9 j. g
$ l: W. o, C- _' O协议层: SPI 一共有四种通讯模式,它们的主要区别是总线空闲时SCK 的时钟状态以及数据采样时刻。为方便说明,在此引入“时钟极性CPOL”和“时钟相位CPHA”的概念。时钟极性CPOL 是指SPI 通讯设备处于空闲状态时,SCK 信号线的电平信号(即SPI 通讯开始前、NSS 线为高电平时SCK 的状态)。CPOL=0 时,SCK 在空闲状态时为低电平,CPOL=1 时,则相反。时钟相位CPHA 是指数据的采样的时刻,当CPHA=0 时,MOSI 或MISO 数据线上的信号将会在SCK 时钟线的“奇数边沿”被采样。当CPHA=1 时,数据线在SCK 的“偶数边沿”采样。 ' f! E1 a+ ^/ w+ l. {
7 _6 t% ?# ` u @+ Z2 Q/ t2 Z# a; E- V, d' }5 Y0 W0 Z( @* p% I: N
bsp_spi_flash.h文件: - #ifndef __SPI_FLASH_H9 E a, J6 w) P/ b& G
- #define __SPI_FLASH_H( a3 u7 r2 h5 E# b! x7 ~6 v; {
" ^" C# S! z- s7 f- h- #include "stm32f10x.h"
( j- p6 Y0 ?7 Q0 C - #include <stdio.h>
/ u- A; n' b/ W% A - #define sFLASH_ID 0XEF40173 g) w1 U k# _. T8 A, M; l' t/ \
- #define SPI_FLASH_PageSize 256* S7 F; @" R" Z% E
- #define SPI_FLASH_PerWritePageSize 2563 \( T1 A% ], N
- //Flash命令定义 ) C2 I, D6 R* v' @' ^ H
- #define W25X_WriteEnable 0x06 5 m7 D# ?4 G9 X' V8 l5 a% ]
- #define W25X_WriteDisable 0x04 . B. o% I% ^3 N0 L
- #define W25X_ReadStatusReg 0x05 : H" N, ?0 P6 F$ d$ l3 S
- #define W25X_WriteStatusReg 0x01
: Y: \$ f/ \) \2 w2 c- h - #define W25X_ReadData 0x03
( Q! X6 }4 z$ f$ ^ - #define W25X_FastReadData 0x0B
% `$ |9 }# Q4 {1 ~; | - #define W25X_FastReadDual 0x3B , O0 H' [3 Q6 G& [, ]
- #define W25X_PageProgram 0x02
6 J$ p, t( T D) k M5 M - #define W25X_BlockErase 0xD8
+ i6 H: v0 s. R1 T# ]2 r - #define W25X_SectorErase 0x20
* F' S; _- f; a; ]. \) X7 a - #define W25X_ChipErase 0xC7
) O8 {" I# ? U6 f& S$ E5 P - #define W25X_PowerDown 0xB9
5 B/ b/ K b8 @: S. S7 R - #define W25X_ReleasePowerDown 0xAB 3 V) }( O3 i$ U N; L
- #define W25X_DeviceID 0xAB
; `1 A* h/ T8 s# Z' D7 [" B - #define W25X_ManufactDeviceID 0x90 # P2 `2 f% m9 I, S# ?
- #define W25X_JedecDeviceID 0x9F
# o( q( _/ C# A% [- {. z$ I f - //WIP(busy) 标志,Flash内部正在写入/ _/ V* o/ J3 z+ A Z9 D0 t
- #define WIP_flag 0x016 r5 A) w1 P! U8 p, P
- #define Dummy_Byte 0xFF
/ @( ` Z4 R- O8 J y6 M* |% { - //SPI接口定义. j* D- P9 F+ q5 E
- #define FLASH_SPIx SPI14 W2 |5 V& b9 R1 S$ o
- #define FLASH_SPI_CLK RCC_APB2Periph_SPI14 D5 w& U, E; c7 ?+ S' M
- //片选引脚
" J2 {7 E% F/ e3 T+ Y - #define FLASH_SPI_CS_CLK RCC_APB2Periph_GPIOC
$ U5 @( C( U5 N# D1 t, a - #define FLASH_SPI_CS_PORT GPIOC- A$ G. w, j! ~! z Q
- #define FLASH_SPI_CS_PIN GPIO_Pin_0# S& A4 |6 `3 ]0 T
- //SCK引脚
2 J6 R0 }1 s1 l" {, Z% B/ Z - #define FLASH_SPI_SCK_CLK RCC_APB2Periph_GPIOA
# K! ]; x% A/ |4 y9 a4 M - #define FLASH_SPI_SCK_PORT GPIOA
' H3 U: Y. F; k U; @2 L - #define FLASH_SPI_SCK_PIN GPIO_Pin_5+ f+ [8 S3 c7 o4 n7 N
- //MISO引脚
, d+ m6 U6 P( L# @ - #define FLASH_SPI_MISO_CLK RCC_APB2Periph_GPIOA
# s! s7 m h- ^2 o% j8 @ - #define FLASH_SPI_MISO_PORT GPIOA
6 ]6 Y2 Z/ r$ P9 ]9 ^- P - #define FLASH_SPI_MISO_PIN GPIO_Pin_66 e; x Y) R9 f" y( t
- //MOSI引脚
. P2 |( }) ~3 ]8 B' I: [: K - #define FLASH_SPI_MOSI_CLK RCC_APB2Periph_GPIOA4 s4 d/ P2 L |) w1 ?" w! L r5 M) U
- #define FLASH_SPI_MOSI_PORT GPIOA6 e& d" U; K1 @7 c7 G
- #define FLASH_SPI_MOSI_PIN GPIO_Pin_7
u2 h1 i. |' R$ { - % T+ E6 K, p' d9 ]) ]; P2 \& D
- #define SPI_FLASH_CS_LOW() GPIO_ResetBits(FLASH_SPI_CS_PORT, FLASH_SPI_CS_PIN)6 r6 ~: z* t5 O9 a" A
- #define SPI_FLASH_CS_HIGH() GPIO_SetBits( FLASH_SPI_CS_PORT, FLASH_SPI_CS_PIN )
: ?& j4 H4 w( w - & M( [- {6 f& ?5 ` g& ]7 v& e4 m7 {
- #define SPIT_FLAG_TIMEOUT ((uint32_t)0x1000)
9 J1 A$ n* C& x; W) P6 G& R5 Y* ] - #define SPIT_LONG_TIMEOUT ((uint32_t)(10 * SPIT_FLAG_TIMEOUT))3 o" W1 z: X% K7 x- J/ v. l
- $ @: c# t( i: B* M/ E' N3 H$ ~
- #define FLASH_DEBUG_ON 1
, s. k4 a: k+ p0 M" J
; n0 r K( {9 h, m( C; ?0 F' I1 T- #define FLASH_INFO(fmt,arg...) printf("<<-FLASH-INFO->> "fmt"\n",##arg)
% `3 c9 V( Y N0 U! j5 [ - #define FLASH_ERROR(fmt,arg...) printf("<<-FLASH-ERROR->> "fmt"\n",##arg)% E4 H- ~: B7 y* \( w" o
- #define FLASH_DEBUG(fmt,arg...) do{\
; _/ ~+ S3 d. S0 h: K - if(FLASH_DEBUG_ON)\
$ k1 x. ?/ a. v - printf("<<-FLASH-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\8 m1 }, j, P" ]# ~
- }while(0)1 e& b: x6 q" Z9 s+ E# G
/ f M8 W+ e: \) N- void SPI_FLASH_Init(void);
! w/ E) ?7 [& N& {+ `4 ]2 x) s - void SPI_FLASH_SectorErase(u32 SectorAddr);
Y* ]$ W# j$ P - void SPI_FLASH_BulkErase(void);: Z4 `' x4 M$ S- w2 a+ f$ n
- void SPI_FLASH_PageWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite);
@& V' [1 X- m. m$ P: o - void SPI_FLASH_BufferWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite);3 f% x# b9 H* Q% Z: o
- void SPI_FLASH_BufferRead(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead);" _) U4 f1 Y6 U f; ^
- u32 SPI_FLASH_ReadID(void);
- G: } l% d2 J% p, Y5 p" P" p - u32 SPI_FLASH_ReadDeviceID(void);
. R+ A! L# T8 F - void SPI_FLASH_StartReadSequence(up32 ReadAddr);
: f% k! f+ O& Z - void SPI_Flash_PowerDown(void);
6 l* K! k4 \7 v1 t* V9 n+ K - void SPI_Flash_WAKEUP(void);
: }% B6 |5 O- c( e+ q9 }: C8 v: \ - ( _; o1 |3 x- \" Q, {! [' W# _
- + D6 X) n" w; U
- u8 SPI_FLASH_ReadByte(void);
6 I. G. M7 N9 N( S; d - u8 SPI_FLASH_SendByte(u8 byte);+ }/ O! Y, o% p/ ?( j
- u16 SPI_FLASH_SendHalfWord(u16 HalfWord);
* H! }' I/ O5 X1 i5 @ u) N( r - void SPI_FLASH_WriteEnable(void);
) T! n5 [, v4 ] T! a1 f+ S- O - void SPI_FLASH_WaitForWriteEnd(void);# a9 F+ ~' N4 u+ W/ {; }
- #endif
复制代码 9 Z' k6 t$ e4 X- u( U
bsp_spi_flash.c文件: - #include "bsp_spi_flash.h") m P3 K& g+ ^9 J7 Q" I" F8 t
- H {- D* d, e; {/ l( z% h t2 u! R- static __IO uint32_t SPITimeout = SPIT_LONG_TIMEOUT; ) u8 U" R/ k1 h' x8 {( K9 @
- static uint16_t SPI_TIMEOUT_UserCallback(uint8_t errorCode);
# I, B+ y: L: n$ T; J5 ^7 a+ a" R9 z9 P - ( g; o1 |( x+ P2 `* w
- void SPI_FLASH_Init(void)1 R9 n: d$ b2 _& k. T4 ~* l6 u B. R* h
- {9 l. K! U3 q) F. w* m7 V
- SPI_InitTypeDef SPI_InitStructure;
7 K6 B4 c4 D5 N - GPIO_InitTypeDef GPIO_InitStructure;$ e9 w1 Y+ R8 t5 R3 L
- RCC_APB2PeriphClockCmd(FLASH_SPI_CLK, ENABLE );* W8 P9 B1 b% \! Q# s G( J
- RCC_APB2PeriphClockCmd(FLASH_SPI_CS_CLK|FLASH_SPI_SCK_CLK|* t3 b; s5 p. V2 ~) ]9 U
- FLASH_SPI_MISO_PIN|FLASH_SPI_MOSI_PIN, ENABLE );
& L5 \9 }& e* v ~ - GPIO_InitStructure.GPIO_Pin = FLASH_SPI_CS_PIN;+ r" z: X* Y1 s3 t O
- //配置片选
5 C! J& \" o2 h( M! K3 b: A) I - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;$ y* a1 |0 ]: O' u3 l
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;* d4 X ?* {$ R8 B7 Q. d
- GPIO_Init(FLASH_SPI_CS_PORT, &GPIO_InitStructure);
" C5 f0 D+ r8 v2 r; L2 s - GPIO_InitStructure.GPIO_Pin = FLASH_SPI_SCK_PIN;
, W( ?$ ]& d5 Z6 t - //配置SCK 8 g7 @2 g0 l, q r6 L
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;4 m! \( z& m0 `7 d
- GPIO_Init(FLASH_SPI_SCK_PORT, &GPIO_InitStructure);/ L1 x' _7 u5 R/ z
- //配置MISO ; y: ~) e5 Z" C7 Z
- GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MISO_PIN;$ C3 K h# }$ N7 f6 U' V8 Z) j. {
- GPIO_Init(FLASH_SPI_MISO_PORT, &GPIO_InitStructure);, V5 r8 e2 C, }: w
- //配置MOSI
. B( K0 d6 q! z# B- @$ N# a$ C% T( Y - GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MOSI_PIN;
) P) W: S# ~; x: v2 |" T/ b+ Z - GPIO_Init(FLASH_SPI_MOSI_PORT, &GPIO_InitStructure);: e6 x/ F% Y1 D
- //cs高电平,通讯停止 6 w! d$ l# f6 i
- SPI_FLASH_CS_HIGH();
; ~$ J" x/ `' |8 a9 L/ M: A+ B - //SPI模式配置
8 }; h; }. z6 _( |5 @! w' |+ }- @5 b - SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;! I' ?8 B$ k1 A, y
- SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
0 p8 i- E- @7 }# K/ {+ ]2 W h7 D - SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
! u" O$ d$ y2 R O' ?6 W1 C - SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
% r6 z# h1 _) C. ^, n n4 d - SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
& \, H: F& t3 o4 Y) O5 Y* G- E H - SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
s& j" M& L( ]# w" n - SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
. a. n: a& b r% D5 } - SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;8 ~, N5 P5 I8 c5 @) a& b% K
- SPI_InitStructure.SPI_CRCPolynomial = 7;5 g& {8 i; Q# b0 p: n* V
- SPI_Init(FLASH_SPIx , &SPI_InitStructure);7 i2 U8 T7 H0 B
- SPI_Cmd(FLASH_SPIx , ENABLE);
& S/ ]+ R+ \% f# l -
( \) [ x- M5 { - }
6 g; g. c+ a0 f5 x7 U! V - //擦除FLASH
% k. i4 P$ G; t - void SPI_FLASH_SectorErase(u32 SectorAddr)
) O6 {8 V/ ?3 M7 {# l - {0 Q; e, t8 u7 h/ X' ^% w
- SPI_FLASH_WriteEnable();1 s N1 y- Z* _- @5 f
- SPI_FLASH_WaitForWriteEnd();5 o: S; M* v- ^% N3 C9 J& l
- SPI_FLASH_CS_LOW();
) u7 Z7 D8 y; {4 j; s, m1 ~* J - SPI_FLASH_SendByte(W25X_SectorErase);1 L3 ]: l0 Y" S7 ?1 m4 Y
- SPI_FLASH_SendByte((SectorAddr & 0xFF0000) >> 16);
. |% d7 o. r: Z6 { - SPI_FLASH_SendByte((SectorAddr & 0xFF00) >> 8);5 ?5 w. e, V5 H) N/ H
- SPI_FLASH_SendByte(SectorAddr & 0xFF);8 e5 P/ S, P3 T( O
- SPI_FLASH_CS_HIGH();! r! J( Z+ t$ N9 b* E6 W1 Z
- SPI_FLASH_WaitForWriteEnd();7 p) l" G5 Y1 R; z" a$ x
- }
5 ^& E6 _. Q# w9 p g8 P) U - //擦除FLASH扇区 ' k- D6 j; |; z9 E, F8 c
- void SPI_FLASH_BulkErase(void)/ D9 @1 u2 W7 g3 r
- {
+ g+ s( a% u! t - SPI_FLASH_WriteEnable();
; g1 Z# w) x" J5 n) n - SPI_FLASH_CS_LOW();
* _% d7 z, ?! @1 u4 F# f: A - SPI_FLASH_SendByte(W25X_ChipErase);' g; W7 A/ x" N
- SPI_FLASH_CS_HIGH();5 m" | Z2 g$ @. c0 g2 M
- SPI_FLASH_WaitForWriteEnd();
1 I6 h T j5 f( a- a( M2 b - }( X8 l6 X# C8 s, ?/ }5 M" [/ w# l+ W
; M, }8 r1 q/ f; I) ~- //按页写入数据 6 a L/ \: O. I7 s6 D" R
- void SPI_FLASH_PageWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite); Q. A% W+ H. N+ o6 N k
- {' |! u m, q2 c( X' q# c' S: t
- SPI_FLASH_WriteEnable();" i. y8 K6 \- q& T c d
- SPI_FLASH_CS_LOW();
9 F w) j6 j8 x- Z+ w' [ - SPI_FLASH_SendByte(W25X_PageProgram);
3 s% F0 C5 _; @; T6 L - SPI_FLASH_SendByte((WriteAddr & 0xFF0000) >> 16);$ Q" k# B# \5 f
- SPI_FLASH_SendByte((WriteAddr & 0xFF00) >> 8);
! d6 V, m* f7 b/ P8 ^/ D. I" c" [ - SPI_FLASH_SendByte(WriteAddr & 0xFF);
$ b) t) o. T" e - if(NumByteToWrite > SPI_FLASH_PerWritePageSize)* p9 I: }% @! c/ ]$ |
- {( y. V( v2 o3 o1 M
- NumByteToWrite = SPI_FLASH_PerWritePageSize;' h; S2 z1 A- `- Y2 D
- FLASH_ERROR("SPI_FLASH_PageWrite too large!"); ) j7 ?' ]: ^1 `9 I, _+ c
- }1 {( Z9 k1 a2 X( P/ s
- while (NumByteToWrite--)' F+ F8 j% d, N( P6 ]
- {
. A* k3 h* y: m) e( { - SPI_FLASH_SendByte(*pBuffer);
2 y5 @3 A; o3 _' D! q, W! J' R - pBuffer++;
$ i5 x$ |. {0 y ` - }
2 q! w0 [' h1 O, u8 d0 y - SPI_FLASH_CS_HIGH();0 w: y2 ]# I5 s" G, C6 m1 d
- SPI_FLASH_WaitForWriteEnd();
$ y) N- z# T2 x) d6 E; V! V - }
+ w- U% c' }0 {$ U: G) V - //写数据
" h2 {8 y/ a3 r; {! O - void SPI_FLASH_BufferWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)
7 ?7 h# O) ~3 ]/ }9 X# l - {3 m: r$ k: K8 a# [ J
- u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;
" K! m* }8 p' M6 l2 V9 r/ |/ u - Addr = WriteAddr % SPI_FLASH_PageSize;; S) k E( h- h8 G
- count = SPI_FLASH_PageSize - Addr;* y8 m6 k- _& q8 ^" B* h6 g
- NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
L) Z, j! i) @2 D - NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
& ?$ U8 G0 m- t( f - if (Addr == 0)8 @% z2 h+ d9 I) w+ Q- m
- {
, A3 Y2 u4 g& s5 B: | - if (NumOfPage == 0)
& C. m2 V3 U( i* R. ?. z6 u8 B - {2 e; j! ^5 m+ D! v: ^9 ^, A
- SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
; e' O$ X4 @; ^; m - }
! Z% B) [7 Y1 `8 M# U& X, z I - else ' j, n( B3 W5 G1 [9 _
- {
2 [& c8 S- u: y3 h2 y - while (NumOfPage--)8 ~( s" V! h" x* E9 f) o
- {
( m5 G5 y$ @9 `; M4 i( q: P; l: Y - SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
: B) D$ B/ G+ |! m8 k* A - WriteAddr += SPI_FLASH_PageSize;6 E# @, n. p0 B$ ]; r8 Z" e K- C
- pBuffer += SPI_FLASH_PageSize;, B6 ^2 e1 Y+ Z5 A6 f: B0 B9 R; W
- }
, m' r' R5 T; b _ - SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);8 h+ F5 E) S5 B; Q) d1 o3 z
- }" ]) i4 w2 d }" U6 ]5 U, g2 g+ n
- }# `! T5 f% u: N- R5 W
- else
7 J. v) X! A. w' e. e" e4 e - {, g9 _) r5 z0 r, [1 h3 K0 w. n
- if (NumOfPage == 0)" o- S9 p# p' R
- {; W& i; O8 |1 V/ q, g1 m: p0 ?3 g5 t. G! C
- if (NumOfSingle > count)
/ b6 n9 s0 J4 i5 z% C' g/ L7 F- s - {
9 D! k* W9 t, `: Q+ R - temp = NumOfSingle - count;
0 d8 f: B. X% V3 B' C p! f - SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
' j' z. t- X+ b# Y1 a -
' h" ^( O/ G- M- ~9 m# U - WriteAddr += count;
; ^1 x. ~* Z) E$ C Z3 S - pBuffer += count;& A, y- X: `( U8 |# Q7 F
- SPI_FLASH_PageWrite(pBuffer, WriteAddr, temp);
2 b: w+ g( Q, l2 S- I% ^" ? - }
7 l" R: Y ~/ \7 z3 }( B( {3 z - else ! A, z; w2 ?9 `/ a
- {
0 U) Y# D }' m9 X! n - SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
9 ?7 N6 R' W0 P( ^4 N% ` O( Y - }
, G, k1 X# X/ f- q% y" a+ P- S - }
+ N0 Z: B$ [) S: I- _ - else 4 y. {" T4 X/ ~% d) J; G
- {5 _: j+ o2 ^" \6 k7 D2 E" ~
- NumByteToWrite -= count;
$ K3 H" F2 {" q4 r - NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
; i5 t. e: K# }! B% o' \. G - NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
+ H; C$ M% b( R6 ] - SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);% ]& v% {6 f5 W0 N- B* @
- WriteAddr += count;# a* ^, |/ J' }; b7 s
- pBuffer += count;
1 `7 o6 X; D4 b2 R% Z - while (NumOfPage--)
% F, P% `/ z4 B% m# ^3 s1 D - {5 B9 G' c- M/ a( P2 G+ G9 T
- SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
9 V. O5 ]. R2 c5 Q# B - WriteAddr += SPI_FLASH_PageSize;3 x' I8 \; a# W* A) `
- pBuffer += SPI_FLASH_PageSize; B3 ?- O: C3 D- _( w% E0 t# p: d
- }2 w0 h$ W/ P6 V! i$ z* ] `
- if (NumOfSingle != 0)% C% c! c. l) e+ ` T
- {8 u/ L e. T7 w! H) |7 D9 d' N
- SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
# p( a. h. B& [" L, \4 K K - }& Z3 ]8 n! h$ v4 p9 ?
- }3 K( D* }2 e5 O" ~
- }
1 t7 m1 P0 e: ~( D2 K - }
9 N3 k4 D) G6 ~8 G, X" p* z
7 r+ j5 P9 t4 ^- //读数据 0 C+ u$ X0 S* N: |# F
- void SPI_FLASH_BufferRead(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead)
9 D }% ]( i( n& m: H3 ` - {9 L( f) }) t) F- a$ R
- SPI_FLASH_CS_LOW();3 {! b* r4 ~/ s$ k( T
- SPI_FLASH_SendByte(W25X_ReadData);6 _7 [* F, J1 m/ t: ]6 D; i, D
- SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);
% |) f- O L' F2 p: Z" l6 O! f - SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);0 H* O7 r. ^7 Z( @/ g- V8 d
- SPI_FLASH_SendByte(ReadAddr & 0xFF);
( i9 M" M0 {6 F( K: n; | - while (NumByteToRead--)
9 A* ~! y* w) f! E2 X' o9 G# J - {3 S' L3 j4 ~$ w i
- *pBuffer = SPI_FLASH_SendByte(Dummy_Byte);
" p2 j# k* u% C: Q$ x* E+ U - pBuffer++;
0 M; v, i0 w, o7 R) g9 l4 V - }
# m8 {$ p( b, _) u) C - SPI_FLASH_CS_HIGH();, e5 L( e; d! a# R
- }0 g% T2 c+ @6 \
- //读取ID
' |+ Y: A- T. i2 {4 a - u32 SPI_FLASH_ReadID(void)8 r5 ]2 x. S5 D# y
- {
6 H N7 f- l# h' n& K0 @. w - u32 Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;4 j% u; Y2 Y0 A1 }9 ?
- SPI_FLASH_CS_LOW();
" ~" C0 k+ f* V0 t - SPI_FLASH_SendByte(W25X_JedecDeviceID);# X/ y! v- J9 m' ]$ l; A
- Temp0 = SPI_FLASH_SendByte(Dummy_Byte);
7 x& @$ I* O& P - Temp1 = SPI_FLASH_SendByte(Dummy_Byte);
+ J3 w0 s6 Z8 ~ - Temp2 = SPI_FLASH_SendByte(Dummy_Byte);+ N8 @; M+ E: {( c) C
- SPI_FLASH_CS_HIGH();9 y* \8 Z$ L+ h! z
- Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2;+ D9 j' T! y: g9 `' I& e5 J8 t9 ?
& P& H( A; @- D- return Temp;# M1 B" F3 O# n; a/ g# P
- }
6 g" R2 h/ t J0 H$ F/ P - //读取DeviceID
& p9 x+ A1 |9 F; K7 @$ O - u32 SPI_FLASH_ReadDeviceID(void)1 ?: g1 y8 k' `
- {0 {, d5 @: F+ V* i3 d! R3 Z( N- ~
- u32 Temp = 0;7 g+ s; v, \1 W6 j4 s* F" w
- SPI_FLASH_CS_LOW();
5 l: W! x; E: D% ~- g" Y; E - SPI_FLASH_SendByte(W25X_DeviceID);6 X! N8 v. ?2 g( M ~7 Y
- SPI_FLASH_SendByte(Dummy_Byte);& u/ o/ s3 s& Q0 V/ ]" G
- SPI_FLASH_SendByte(Dummy_Byte);
5 i7 z& ]$ r! {5 d - SPI_FLASH_SendByte(Dummy_Byte);5 `% V4 S" g+ S7 W; z
- Temp = SPI_FLASH_SendByte(Dummy_Byte);
2 B$ P% }/ P/ H9 |2 M - SPI_FLASH_CS_HIGH();# l8 r: K0 y- D- `7 s, y
3 q; t/ S# f. g9 R0 J- return Temp;
9 m3 ^8 H$ }& {, D% _% s: P4 F+ ` - }
# s; f1 \9 v& d8 l - - C" z: C H/ a' B: L
- void SPI_FLASH_StartReadSequence(u32 ReadAddr)
; Q+ K; Q$ g3 Y3 N6 j3 S - {
: B2 J5 M5 U3 P5 {! _2 ]$ } - SPI_FLASH_CS_LOW();
7 t: f' [, K* F - SPI_FLASH_SendByte(W25X_ReadData);) P( ^. _( _4 @- _9 y
- SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);6 H- a9 O' p4 ?
- SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);
1 G3 Q, B5 ]! ]' o - SPI_FLASH_SendByte(ReadAddr & 0xFF);
+ B% m* z# t7 ]$ a I$ ?# \ - }
8 a5 u. A: Y8 u' l$ j6 R
5 T2 R/ R' Q# w) H0 S. l' j- u8 SPI_FLASH_ReadByte(void); t' p) t( y$ q z* m
- {
* v5 w8 W. b5 G @) F - return (SPI_FLASH_SendByte(Dummy_Byte));! C5 s) C, A. G! k4 W I* \ L
- }
5 y. t( z4 u5 Z
; ?! _2 @0 Q5 q- u8 SPI_FLASH_SendByte(u8 byte)
g, Q v$ x R: S/ u0 F - {% o+ P2 S |, u# H0 o4 F7 N! u
- SPITimeout = SPIT_FLAG_TIMEOUT;
- L7 n- w' p3 c( K - while (SPI_I2S_GetFlagStatus(FLASH_SPIx , SPI_I2S_FLAG_TXE) == RESET)
0 O W; o( }- _5 E/ z, M& i& X - {
/ P# e1 C9 Y g2 b8 F - if((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(0);
6 l- C; G6 ~+ T, v# g o$ [ - }
7 k U. u- j, U3 i8 A, U* f! _ i. u - SPI_I2S_SendData(FLASH_SPIx , byte);! R- c3 V; K0 Q. ^3 {
- + t: S' w" o; w7 l( k# `9 I
- SPITimeout = SPIT_FLAG_TIMEOUT;. Z- I! x9 B9 U1 T
- while (SPI_I2S_GetFlagStatus(FLASH_SPIx , SPI_I2S_FLAG_RXNE) == RESET)8 R7 i1 m8 k9 t# F& A* h$ G
- {
0 S2 z+ U; Y5 y& @ - if((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(1);
$ a6 {3 _) |# S3 W2 z4 @% W& L - } T; Z, q) a0 x5 W# U5 D
- return SPI_I2S_ReceiveData(FLASH_SPIx );
1 A9 U0 r/ c3 q8 U5 D - }7 l7 n+ H# T# i! n' m0 T$ \
- 8 |4 o% @- U' B+ J: v$ O
- u16 SPI_FLASH_SendHalfWord(u16 HalfWord)
; O3 f# p. j A - {& t6 Y9 M, y/ R* t% x |
- SPITimeout = SPIT_FLAG_TIMEOUT;8 d y! `( n$ T) J# s# |
- while (SPI_I2S_GetFlagStatus(FLASH_SPIx , SPI_I2S_FLAG_TXE) == RESET)
( M1 Y* A' Y' K, P0 k& H) i( z - {2 E- U1 {, [, J w( G
- if((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(2);
$ x9 U+ B6 c) \* ^$ @: M: b - }* m2 m3 j3 [8 r7 H Z
- SPI_I2S_SendData(FLASH_SPIx , HalfWord);- i2 N- c3 x, K
- 5 E! A/ k3 \2 S& S" E7 x9 a
- SPITimeout = SPIT_FLAG_TIMEOUT;
" d$ ~; ]" d" o9 Q7 g - while (SPI_I2S_GetFlagStatus(FLASH_SPIx , SPI_I2S_FLAG_RXNE) == RESET)! Z$ j2 U9 L; a
- {; r% { F7 w% i [5 A7 t
- if((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(3);
5 H0 K0 ~9 ^1 N - }
, L+ R5 h% }* Y$ B: V1 t - return SPI_I2S_ReceiveData(FLASH_SPIx );8 w) S9 h! `3 Y% P% a/ f/ u
- }5 A' l! H5 v6 B L$ ^# P: q
- 0 x2 x x" T' f( p- {
- void SPI_FLASH_WriteEnable(void)* D% d0 Y. v) m2 }
- {
7 i- O+ `2 h( s& ? - SPI_FLASH_CS_LOW();& d8 ]' h. s$ R7 h# J
- SPI_FLASH_SendByte(W25X_WriteEnable);# h4 }" q$ Q% M. K7 W
- SPI_FLASH_CS_HIGH();' _$ f( J( y: B/ ?& N# t
- }" @ S$ u+ Y3 r* W6 }8 _! T
- ! b7 V& ^8 V" O8 h6 g
- void SPI_FLASH_WaitForWriteEnd(void)
& l, m! i6 C5 z- B6 e; f - {
( B. Y" n6 P0 `3 _& y5 N9 ~5 | - u8 FLASH_Status = 0;' W5 y) H4 n* D6 x" A
- SPI_FLASH_CS_LOW();
- X. B+ N5 W9 { - SPI_FLASH_SendByte(W25X_ReadStatusReg);
9 D! {3 `% |0 ^( Z, r1 H - do7 H }+ g; A, X! s% w
- {
0 t( |3 C8 c8 H6 W7 s' n - FLASH_Status = SPI_FLASH_SendByte(Dummy_Byte);
0 |3 k$ w4 b, t' z0 L+ o' [ - }8 |8 }2 n7 X& V. a! M1 k
- while ((FLASH_Status & WIP_flag ) == SET);
' {, a4 z: B+ g1 Y - SPI_FLASH_CS_HIGH();
5 f) z9 Q) F$ L& T7 H0 [' V - }
8 h; [, V' \1 z% d+ x* C
# @2 u; U1 o' ?: W3 Z7 r( K3 ^- void SPI_Flash_PowerDown(void)
/ x6 {% j& K. s2 n - {
4 W+ C+ v* ]4 P7 V2 u - SPI_FLASH_CS_LOW();: U# z3 t I- l
- SPI_FLASH_SendByte(W25X_PowerDown);9 q/ W0 K! u$ O6 d$ V) K
- SPI_FLASH_CS_HIGH();
3 h( A+ Q8 e9 s& h1 Y9 b: R* ` - }
2 A: b4 ~3 }/ j/ ~+ A! g
: p1 m/ h) w! Z q( w7 N- void SPI_Flash_WAKEUP(void)
0 e# u+ q- \ ?# e0 s2 W1 A2 p) ^ - {( Z0 O9 m# B, q& m. U# Y0 m+ Z$ P
- SPI_FLASH_CS_LOW();
3 P: N& M# I4 F; K6 m" e - SPI_FLASH_SendByte(W25X_ReleasePowerDown);
5 o) ?5 B4 z Q3 S `" M" I - SPI_FLASH_CS_HIGH();; z0 i5 ~6 [, L/ L" u; @9 x$ _5 @
- }
+ y* W/ k# l# I4 D% f0 q -
8 J( l" e8 N" S# u/ A9 H# i D - static uint16_t SPI_TIMEOUT_UserCallback(uint8_t errorCode)2 N, l9 y" a" Y4 P0 ~$ Y5 ?
- {
( J7 f& ^ x1 ? |+ y - FLASH_ERROR("SPI等待超时!errorCode = %d",errorCode);
- ]3 H! M/ Q' g1 @5 a6 I( z o1 [; S - return 0;
A6 u; j( N) @/ @ f - }
复制代码
; z9 w2 }5 q( U& h/ Bmain.c文件: - #include "stm32f10x.h"* H3 J) ~ P/ V9 Q7 y
- #include "bsp_usart.h"0 h3 v9 u' f3 x2 q, Z& k. T# k
- #include "bsp_led.h"/ x; I2 _, w5 i) k; ?
- #include "bsp_spi_flash.h"
7 N9 D5 I1 r( e. J; s! E# b: t - q0 y M H x
4 @" T, a" u2 _. [ Q& W- typedef enum { FAILED = 0, PASSED = !FAILED} TestStatus;- M0 I( Y9 M" u, L8 U& S& @8 G
1 b# S6 L3 x) ]0 b* k* h- I; J- #define TxBufferSize1 (countof(TxBuffer1) - 1)
2 i( F. [/ r) S: [. r; M - #define RxBufferSize1 (countof(TxBuffer1) - 1)
2 d! Y" V: d2 F4 k- p9 @ - #define countof(a) (sizeof(a) / sizeof(*(a)))
, g- E3 T: e& I" {& m6 h - #define BufferSize (countof(Tx_Buffer)-1)* f/ F5 n# U5 X2 g
& L V6 T7 `9 |+ P+ {- #define FLASH_WriteAddress 0x00000
, r! |0 }) p& a2 A( _( D6 [ - #define FLASH_ReadAddress FLASH_WriteAddress) I# D9 a% }, g) E; o. X3 N: a
- #define FLASH_SectorToErase FLASH_WriteAddress: k% L) g; A* S: m5 X% w$ d) k$ ]
- # z' W# `2 e* I& o* ?5 {
- uint8_t Tx_Buffer[] = "hello stm32!!!\r\n";+ Z+ P& i* j3 ]
- uint8_t Rx_Buffer[BufferSize];( W0 b+ w+ H# V: H6 |: i$ x9 O2 x
2 y5 A/ F6 R3 C2 L, {+ l- __IO uint32_t DeviceID = 0;
( \' t5 f2 D) q" b% ~' J3 D0 z - __IO uint32_t FlashID = 0;% L9 p8 t0 r- [
- __IO TestStatus TransferStatus1 = FAILED;
5 U3 H( O, ^! x7 m: A' l- \
2 J8 w. ^9 F3 C/ @" A! i- void Delay(__IO uint32_t nCount);
2 V- k% e' d7 M - TestStatus Buffercmp(uint8_t* pBuffer1,uint8_t* pBuffer2, uint16_t BufferLength);
$ B9 i$ x" R2 d- ^$ E - / a6 y4 P; h; y# Q0 J0 J$ X
- int main(void)
0 L# _/ O; [0 C1 G" e) i- J/ u) F - {
" R3 e3 e; o' W, q; g) b( ]/ j - LED_GPIO_Config();1 S* l1 u' |( w+ U! a" ^5 T/ d
- USART_Config();
2 G# ~* y- ~/ i - printf("\r\n 这是一个8M的串行flash W25Q64实验!\r\n");5 c) R% ?! l+ \0 V& L
- SPI_FLASH_Init();/ _, D4 ~0 f$ U, Z2 g7 a3 a. N% R
- DeviceID = SPI_FLASH_ReadDeviceID();
( u/ C4 v V; k2 ~/ K" {) f - Delay( 200 );2 A6 Y5 ^1 h" y
- FlashID = SPI_FLASH_ReadID();
+ i) F/ r& D$ M1 T4 @ - printf("\r\n FlashID is 0x%X,\
: k0 ]' P+ k8 {/ U - Manufacturer Device ID is 0x%X\r\n", FlashID, DeviceID);8 F9 H: F) a. C9 m2 g
- if (FlashID == sFLASH_ID)/ K: H$ Y& d+ {6 O( G% q( V A- P
- { . e9 G& {. @! B: ~" L2 b+ G
- printf("\r\n检测到串行flash W25Q64\r\n");3 T2 v/ q O' u3 ]
- SPI_FLASH_SectorErase(FLASH_SectorToErase); $ S9 P1 g! N) q6 y5 O5 w/ X y
- SPI_FLASH_BufferWrite(Tx_Buffer, FLASH_WriteAddress, BufferSize); & p2 e, g* [, d% q' v
- printf("\r\n 写入的数据为:%s \r\t", Tx_Buffer);
& n( x+ A, t" B! Q - SPI_FLASH_BufferRead(Rx_Buffer, FLASH_ReadAddress, BufferSize);
- c2 r2 q+ _4 R5 [2 f9 @1 Y, |. V - printf("\r\n 读出的数据为\r\n", Rx_Buffer);3 {; q; l" v+ L. Y, ?" |
- TransferStatus1 = Buffercmp(Tx_Buffer, Rx_Buffer, BufferSize);
# G+ c5 Y" F4 o* J, q5 J; ~# t$ f - if( PASSED == TransferStatus1 )+ [: s, z" d7 x: Y+ Y
- { : d) a8 u! Y& M( _
- green(ON);
& t. ~; s1 B5 v( e0 x9 y" Y% f - printf("\r\n 测试成功!\n\r");
4 I. ]+ F$ ^+ `" k - }
- L+ M- B( z5 ~0 L6 a' ?- }" R2 Y - else
6 t5 ^8 ?8 }8 x" O; T - { ) \; R: E* e5 C4 q( e
- red(ON);
& v" C4 ` y" P0 _ - printf("\r\n 测试失败\n\r");
7 \/ L. n( U6 g7 f0 u# Y - }
1 y6 b- D4 K3 w! W' t - }// if (FlashID == sFLASH_ID)! e5 G; e) `3 G
- else// if (FlashID == sFLASH_ID)
+ T# _. S5 _! t9 ]; U9 O6 E( J - {
8 j4 }; \* J7 X4 o9 L - red(ON);
" t1 S( b0 O" ^ - printf("\r\n 获取不到W25Q64 ID!\n\r");! @- O& f5 g* i, S, [3 w
- }
5 R( ?; ~* X( J' r1 b! A -
' ~( N1 h7 [+ G1 W2 n4 U/ J - while(1); 9 u8 X7 g: v& z. V1 ?0 r
- }7 Z0 D( i+ V/ `! G: t, k
- //比较两个缓冲区的内容是否一样
g8 [* G' P# v+ v7 K0 y3 b; A - TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength)
* t. B' n. t' R$ x \ - {
7 M8 Q. Z" w f% q) J - while(BufferLength--)
! X: t1 z/ c% } i - {* }9 \7 S4 g$ G4 K$ K- |
- if(*pBuffer1 != *pBuffer2)
" l0 R0 b$ z7 s# F- @' u- ~ - {
n9 M$ u- @3 O2 q8 o" u. v' P1 w - return FAILED;
6 }; X( G: t) h, u - }
, E* g4 D0 b# V% x$ Y - pBuffer1++;7 O" k# Q% u- n* K# I9 H. L& r0 w
- pBuffer2++;
2 J& S* R$ m& q: [" }- \6 q - }
2 u2 D9 F/ r$ L! F - return PASSED;
/ ]" m/ [1 H, f1 e5 @+ m - }0 K( u# K- S, E' K
/ P( C) F' A' a" d( |- void Delay(__IO uint32_t nCount)
' b* n& k' G7 Z7 Z! k - {8 u6 t8 c9 g- l& p! ^. b
- for(; nCount != 0; nCount--);
! \1 n* p b, ~ - }
复制代码
6 y/ v* X' K ^ s5 B" N |