分享一个代码模块,网上找的一个STM32的SPI2通讯的FM25CL64历程,我自己结合自己的板子改成SPI1很快成功了。1FM25CL64确实简单,通讯和使用都比W25Q64容易
1 T4 U8 O' K8 u, l ]* H+ H. g2写之前没有必要擦除 类似EEPROM
P9 U( n" a+ w, F" W先看我板子原理图$ [7 ^( P3 C2 o% I/ S% J
# ^7 M6 l( k, O/ |" c+ `$ b
两个存储设备挂在SPI1上,CS脚铁电就是PA49 {7 ~0 E6 [, D8 M
上代码:
& i2 p. g, t* P- #ifndef __FM25CL64_H_- X+ P% W# e* q' e( L, S$ w
- #define __FM25CL64_H_ . Y% B- y) F7 Q, U$ j$ c6 O' f
- #include "sys.h" 8 I4 c0 S- _: [3 }! f; Y! i
8 u* O5 R; }4 N; \: z' U- 3 J5 @# z7 y h+ }' E
- #define FM25CL64_CS PAout(4) //FM25CL64片选9 p/ Z; b# u6 X1 w6 t# e( O) d
- 1 t N" x) L. T
- ////FM25CL64指令定义
: h/ p8 f8 n& T( K' I) h - #define FM25CL64_WREN 0x06 //使能% R+ W' J( r( }5 v$ c# \
- #define FM25CL64_WRDI 0x04 //失能
7 ]# t5 t1 }' N( W/ m - #define FM25CL64_RDSR 0x05 //读状态
8 i' n X; _& i: [9 m; m' n$ X - #define FM25CL64_WRSR 0x01 //写状态
8 b9 r# |" s+ L6 j- |$ Y2 G, p - #define FM25CL64_READ 0x03 //读数据( \% W% b9 Y8 r m) W
- #define FM25CL64_WRITE 0x02 //写数据" F3 }& w: F5 |9 ?
- 2 A6 Y' `3 x! @9 H
- void fm25cl64_init(void);//初始化% _" C# Q& Q: a* z/ Z
- uint8_t fm25cl64_read_sr(void);//读状态
, V* \& N. w8 t( S7 s6 ] - void fm25cl4_write_sr(uint8_t sr);//写状态2 d3 C0 K9 |+ E1 |
- void fm25cl64_write_enable(void);//使能. S7 D( g" g1 d9 h
- void fm25cl64_write_disable(void);//失能! Z2 ~6 i2 O+ B) r+ J3 y' M
- void fm25cl6_read_nbyte(uint8_t *pbuff, uint16_t read_addr, uint16_t read_byte);//连续读取N个字节
& J, u( L P0 n _$ T% W/ v - void fm25cl6_write_nbyte(uint8_t *pbuff, uint16_t write_addr, uint16_t write_byte);//连续写入N个字节
- a( {$ m8 d# `4 q: g3 ` - uint8_t fm25cl6_read_1byte(uint16_t read_addr);//读取一个字节
8 [' Y! t- m3 H6 E7 Z; u - void fm25cl6_write_1byte(uint16_t write_addr, uint8_t write_data);//写入一个字节
8 R# U& [7 R- t9 a- X) f" t; x - void fm25cl6_clear_data(uint16_t write_addr, uint8_t len);//清除LEN长度数据+ P/ X' I7 A9 _3 r U* r7 z
- #endif8 v% S2 C- J& ]/ G o! ~% c
- . E u6 O; ~3 `$ Y/ g0 C l: R) e& H
; S- N3 q- I4 D7 ~, I8 `- / s, ^4 A9 e% G! ~8 n5 @
- # A' c& L/ |$ m8 m1 p
- s# P: `( q# K8 l' U; K; d* i$ Y
5 Z# X4 K% ^- H' L$ N3 i
7 L% A6 d) v, a% }& Q. M
! v1 o4 l! E6 E3 ^- # t" v2 }7 Q0 G, O: B. S& n" S
复制代码
- C J( R, w6 R, K# v
2 u( w% G2 k% U8 ^% E$ f8 |% s- #include "fm25cl64.h" 6 a. Y+ o: B- v& D/ s, C
- #include "spi.h"
}* z% u2 g/ E2 Y# ?) ]+ | - ( [2 u5 G% z* _6 A, s2 ?
- " P' U, ^5 D' a9 n4 _
- 1 Y" A+ X& o, ], i) [* O
- + Z. U) @6 P% g3 B0 I+ a4 W. {
- / c4 }9 G. g; g8 X
- /*********************************************************************************************************
+ z) z. g5 A5 `! g: s, R - **函数名称: void fm25cl64_init(void); [: p- B% M" G( ^6 Q% e
- **函数功能:fm25cl64初始化4 I7 r! Z* w# {! P+ _. k# v
- **入口参数:无
3 l) I; @0 ?( I2 [' j# a - **返回值:无) t1 {( [7 |8 d: `! D$ B @
- **注释:: Z! N% w5 b( q9 L8 ~
- **********************************************************************************************************/
0 x" i& |7 a- ^) v9 T - void fm25cl64_init(void) ?# X! \; ]5 x7 v
- {
% z) d5 O/ {9 k# G5 a( U - GPIO_InitTypeDef GPIO_InitStructure; N ~/ @. \. Y! C6 {8 m6 J
) z+ U/ [1 E. y" c2 U8 [8 E- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE );
9 G7 v3 ^6 @$ q5 n) J$ P) B3 y- z/ f! I - ! o$ z# P% t; O' X4 o" k& ?! F
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; * `7 B# ^$ R3 |. d
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
6 b1 X" h; s, l8 P - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;3 x: `/ `4 a0 J* P# @# \$ W5 q
- GPIO_Init(GPIOA, &GPIO_InitStructure);" \: [0 s' O3 k
- GPIO_SetBits(GPIOA, GPIO_Pin_4);
- J! l1 w7 i* {! k w - 7 X* Q+ d- P2 N
- FM25CL64_CS=1; //SPI FLASH不选中+ q& x, O9 c) [& O6 ]
- SPI1_Init(); //初始化SPI
# a7 w/ I8 O7 O! b, X* G - SPI1_SetSpeed(SPI_BaudRatePrescaler_2);//设置为18M时钟,高速模式
+ v9 k. @" o+ b( l/ R8 v: t. [ O - }/ _: w* Z4 B. U0 t* ]
- $ [7 y1 \: r6 K: G) H
- /*********************************************************************************************************
0 Y' F7 J! W( x5 Z. S( D - **函数名称: fm25cl64_read_sr
- ?9 k/ ~8 a+ g" w - **函数功能:读取fm25cl64状态
9 H1 g4 T0 g5 X i8 d - **入口参数:无
2 H4 b$ S" V; V6 Z c% ]1 T% J: R - **返回值:读取到的字节
7 ~9 ?4 R. G$ O - **注释:
6 `4 l) C& _/ H0 }: s. { - **********************************************************************************************************/
& G6 J) T) ~6 R$ A' L& ~ - uint8_t fm25cl64_read_sr(void)0 e2 ]1 d0 {; g+ Y/ H) S
- {
( M/ v, H9 c, g9 i6 k - uint8_t byte = 0;
4 j7 l* K% [" E -
n1 a' H G) T5 e, c - FM25CL64_CS = 0; //片选/ }& X7 M4 Q5 F, H& Q
- SPI1_ReadWriteByte(FM25CL64_RDSR); //写入读状态命令1 l; A5 {5 ~. `
- byte = SPI1_ReadWriteByte(0xFF); //写一个空字节再读数据0 o- b4 n0 L3 ?
- FM25CL64_CS = 1; //取消片选
d4 Y3 L9 ]& M: Q - & u% H% L% h$ G9 o* _& E) f$ y
- return byte; //返回数据
' V1 h! ~& L0 q+ u& G0 x' b& V - }' z7 W' s- i) J5 C
- 5 f& G! L& q) ?$ @+ _9 o- }
- # @/ D8 I4 W) h) Z: S" x2 L
- /*********************************************************************************************************
; s x! W5 q) d' d4 f& A - **函数名称: fm25cl64_write_sr
5 v- ^0 h8 _0 j7 {" b- `7 { - **函数功能:写fm25cl64状态
# k4 ]- ~( k9 H+ n: p- c. b - **入口参数:状态数据6 G" e8 _0 [, _* }1 ]' i
- **返回值:无
( n7 M; t" S6 C) q) c( m, X - **注释:6 D$ X: ]4 F' o% v. n) ~( S
- **********************************************************************************************************/. X, K) r% I. o" o
- void fm25cl4_write_sr(uint8_t sr)
2 T H1 g9 A0 l& T& P - {
" N3 s8 ~. p# R( W8 g. r7 n' N5 x; K - FM25CL64_CS = 0; //片选
" R5 \* \. e, c/ n. p$ w; A - SPI1_ReadWriteByte(FM25CL64_WRSR);//写入写状态命令
+ `* S- f3 s l$ E - SPI1_ReadWriteByte(sr); //写入状态数据/ j( |0 s. ?3 \& D( q# V0 e9 d
- FM25CL64_CS = 1; //取消片选7 \2 |" J+ I( \/ `, |& i) x
- }6 V( r' t5 B- ^8 [
* r j9 v6 m, v( q% G
/ G- C5 }3 |+ L6 \$ s5 J5 ?: b6 E- /*********************************************************************************************************
* z9 G5 W8 F( S( P" G1 I2 [# P( I - **函数名称: fm25cl64_write_enable
+ I A$ u$ W8 s4 G, z - **函数功能:使能FM25CL64( t# R |" p$ C, H3 M2 P7 S& A: M+ s
- **入口参数:无! j: z4 q) c; ?
- **返回值:无
* n" Y1 K i5 w6 i# w% s - **注释:
- p5 q9 |# ?/ J( A/ O - **********************************************************************************************************/- L9 w2 { n8 i9 r& H
- void fm25cl64_write_enable(void)7 C/ @0 n* E9 H
- {
5 l8 I. X: H2 a5 z - FM25CL64_CS = 0;//片选3 d8 A* t# M6 A
- SPI1_ReadWriteByte(FM25CL64_WREN);//写入写使能命令9 G. k5 R: G+ Y$ O: ?
- FM25CL64_CS = 1;//取消片选, w y" z2 d/ K0 x: X g# k) L
- } g9 W$ P6 G( Y9 V5 l5 I8 C
- : B6 i0 e9 h& h: M) Q4 z! [
- % H+ Y% k: R; k
- /*********************************************************************************************************9 k1 `; U7 ^" t1 w( P
- **函数名称: fm25cl64_write_disable
9 V! k1 H z% q* o, U3 U - **函数功能:失能FM25CL64# E, Y( [$ h4 C. k0 d
- **入口参数:无
2 C0 |$ w% d0 m8 C - **返回值:无+ J5 l) v# Y* e( ?& ]: d
- **注释:
1 t: t: s3 `0 n+ I( Y3 S - **********************************************************************************************************/$ G2 D- Y4 k1 H
- void fm25cl64_write_disable(void)
3 K* u# c7 i# i1 l6 G, N - {9 {5 }1 V% {$ {) m
- FM25CL64_CS = 0;//片选
. C6 x0 Z0 n) Y+ \! Q) \ - SPI1_ReadWriteByte(FM25CL64_WRDI);//写入写失能命令
1 C0 o' h. y+ S8 s8 f8 q - FM25CL64_CS = 1;//取消片选
% v8 X: M3 k+ o - }
% C' S; q7 j1 S0 ]' ], B
! m- r {7 x1 M9 r6 N- % ]: j4 c% z* J% G% u
- /*********************************************************************************************************; _- s' h0 D: m: C% E
- **函数名称: fm25cl6_read_nbyte2 w$ p) Q- m5 r( e Q
- **函数功能:连续读取N字节数据+ B3 A5 j/ V; {/ K( d# |: Y
- **入口参数:*pbuff,读取数据到指针,,read_addr,读数据首址,,read_byte,读多少字节% {- r5 e4 @$ t6 ] C7 p
- **返回值:无0 q$ F% n( }/ P3 z$ x
- **注释:# X" B; k, Q* e$ E! S
- **********************************************************************************************************/6 w0 [3 [* l( w6 l
- void fm25cl6_read_nbyte(uint8_t *pbuff, uint16_t read_addr, uint16_t read_byte)
* p0 }9 c- _+ A1 L; E - {( D6 i& |% H3 E; K: O! m
- uint16_t i;* M3 Q' a* R+ U- ]) ?' c# k
- % f5 a) W, X0 g3 c* x, ^
- / Q. B1 h3 r8 z+ x2 F" _
- FM25CL64_CS = 0;//片选
8 Q, ~" p w8 i- _: V1 n - SPI1_ReadWriteByte(FM25CL64_READ);//写入读数据命令
, R4 j, \! \# ] D( R - SPI1_ReadWriteByte((uint8_t)((read_addr&0xE0)>>8));//写入高8位址,最大地址13位3 l8 b+ U: v4 d3 I% a3 L
- SPI1_ReadWriteByte((uint8_t)(read_addr));//写入低8位址,: ]: N9 u: U9 R i
-
" P8 `: r1 i1 t$ C+ U - for(i=0;i<read_byte;i++)//连续读取数据
1 |& }: X |, F, x - {
3 A$ U, F# @5 z3 E+ n - pbuff[i] = SPI1_ReadWriteByte(0xFF);9 @. I5 {+ {, n) x& }
- }; i& A. o' V5 e2 Z1 }
- FM25CL64_CS = 1;//取消片选. H0 `' U v* y" f4 \
3 T( P4 o% Y8 h3 O( K5 w-
; F: A* r0 j: U - }& ]1 n, B4 q) x# r* r
- 1 f2 Q; B7 t. h$ \: g0 \
, |! T1 _( o* U' x1 G. S% ]- /*********************************************************************************************************- A3 E& W0 o Q u# v
- **函数名称: fm25cl6_write_nbyte
+ U% P2 C) u% y1 \$ o+ q9 M3 @ - **函数功能:连续写入N字节数据. z; `& H \& Q p" A
- **入口参数:*pbuff,写入的数据指针,,write_addr,写入数据首址,,write_byte写多少字节
6 a# K) C7 m- T* A+ u* d( o - **返回值:无
" T& R9 k1 _ A3 |8 v, p, U - **注释:
/ P! C: W9 [ N( Z: e) o - **********************************************************************************************************/% r" ^/ M' ]! {$ ^" B- m' q, \
- void fm25cl6_write_nbyte(uint8_t *pbuff, uint16_t write_addr, uint16_t write_byte) K3 {' O" T3 S9 \* Z
- {
# l; R6 L$ {8 r1 @# j6 h& d8 u - uint16_t i;6 N3 F1 u; Z# V2 e; R$ |
- 6 l" |7 L9 {3 Z, ^- G1 X- s
-
: ]7 Y3 z# J! c+ }5 |5 G. d# Y% N% W: i - fm25cl64_write_enable();//使能写操作,一定要先使能,取消片选后再写作下面操作; T3 { D2 u# c$ ~
-
8 s' d% q, ^* l6 e) w1 t* Q - FM25CL64_CS = 0;//片选% a* L/ p3 r- t- U/ g1 W' @
- " X( u9 i E ?2 }& p% v
- SPI1_ReadWriteByte(FM25CL64_WRITE);//写数据命令
! Q+ N& g7 H2 q - SPI1_ReadWriteByte((uint8_t)((write_addr&0xE0)>>8));//写入高8位址,最大地址13位/ x) m5 g! K1 M+ Q7 H
- SPI1_ReadWriteByte((uint8_t)(write_addr));//写入低8位址,) T; Y1 x' }( W- O5 r6 y, `0 M
-
* [: X' k4 ?1 O O) q0 @ - for(i=0;i<write_byte;i++)//连续写入数据1 ?' i' {) W; d1 q1 T' {8 K" r& Z
- {
% d& j" H" V" T Z( t2 c - SPI1_ReadWriteByte(pbuff[i]);
( \; m% M. q0 j! p/ v% j4 c9 a; K - }
) {( u3 j7 @& g4 ^' N# k - FM25CL64_CS = 1;//取消片选
: }$ Y- N0 S( ]9 c6 Z' d6 d. C# B/ a4 q - }
" Z+ ]4 E2 \9 v$ ]# E - 9 g% q$ f! M1 Z1 _
3 B, U! D: _) H& U+ j3 ?- X
8 O% Q5 N; D4 u$ N! [4 L+ u- /*********************************************************************************************************) r( I/ @/ d8 p- w
- **函数名称: fm25cl6_read_data_1byte" j% N/ p) y/ y
- **函数功能:读1字节数据+ k2 H% B, w3 j2 B2 J( T
- **入口参数:read_addr,读取数据地址. K5 m: u6 W- H* @ m
- **返回值:返回读取的数据
@0 ^8 F! T# R) R: p - **注释:
$ u# m y0 t o - **********************************************************************************************************/4 g! K: l& s5 Z& ~0 j
- uint8_t fm25cl6_read_1byte(uint16_t read_addr)+ I/ P2 t- k F/ G6 e, `
- {
2 u! x1 Y/ g/ v; x2 H - uint8_t dat;
2 Y& v" u; q' `3 z; x; s8 g& E -
- N+ u& l1 w8 C/ q* J - FM25CL64_CS = 0;//片选
& ?2 B1 W; V( S3 }- a: e' u3 W -
$ n6 i8 L3 k$ i# k - SPI1_ReadWriteByte(FM25CL64_READ);//写入读数据命令
) l, o; D7 X) ?. S+ ~# X$ W) f - SPI1_ReadWriteByte((uint8_t)((read_addr)>>8));//最大地址13位
& L, d/ H4 p1 T; T( ~ - SPI1_ReadWriteByte((uint8_t)(read_addr));//
4 k# k1 k2 f" C# Y6 H - 7 S$ ]7 i6 O) y2 v* z
- dat = SPI1_ReadWriteByte(0xFF);//读一字节数据4 V( d, B+ ^1 L; f% U; S; f& b
- & W) v @: k- j# W- S C5 P1 [! b# h
- FM25CL64_CS = 1;//取消片选
) O' O4 B) q7 R0 p: q% f - ) e% a5 s- E/ K8 y
- return dat;, t/ l$ R1 P% T- }9 c) B
- }
! j# l0 }6 R& A! o# U3 K2 s: c - / W0 y* m; a; v, k0 C$ y2 i
# [7 X9 q# _0 I: w2 ?- /*********************************************************************************************************/ Q# F" |+ @5 ~0 g8 x
- **函数名称: fm25cl6_read_data_1byte
4 U& P0 e1 Q+ L* N. \' _2 I - **函数功能:写入1字节数据' L! m* `2 z! J6 z& w
- **入口参数:write_addr,写入数据地址,,write_data,写入的数据! }9 o. j/ F3 s9 \
- **返回值:无( W. M0 q! C- r2 r; @8 E, F4 H
- **注释:
' U4 X/ G: @/ p; Q+ {8 w" @ - **********************************************************************************************************/
( f& ]" X( U3 e2 e - void fm25cl6_write_1byte(uint16_t write_addr, uint8_t write_data)
5 H2 a& }" `5 R2 ` - {' l: z( J0 `# {4 T
- 8 C3 p- M2 T8 L+ D
- " [& Y' F! i" A7 n: O
- fm25cl64_write_enable();//使能写操作,一定要先使能,取消片选后再写作下面操作- z- F9 S: v5 [/ ?$ ?, A
- , ~% z' |5 F+ ~& K, K4 u3 O
-
& Z$ T8 ?* Z4 r - FM25CL64_CS = 0;//片选! V( M/ A; D \' K5 m/ g
- 9 H- [ g8 s, `% G' t
- SPI1_ReadWriteByte(FM25CL64_WRITE);//写数据命令
, A) G) i3 `0 Q - SPI1_ReadWriteByte((uint8_t)((write_addr)>>8));//最大地址13位/ ~$ J5 V5 I. [
- SPI1_ReadWriteByte((uint8_t)(write_addr));//8 S9 d+ u* Y6 C
-
, [5 w& I. H- r) _: ?6 [9 ]$ f
) A9 i p$ e/ [0 d8 R- SPI1_ReadWriteByte(write_data);//写一字节数据8 V( v; q8 T) j
2 p, }& z6 S' Z( |- FM25CL64_CS = 1;//取消片选
- K" b, [# ~! |3 e7 l: X7 [7 E - }
/ E, L: r. V; b( H$ ?5 R" a7 M - & F; L( o6 h( [$ ]/ E
- d9 T3 ^9 D: a) ~/ S
- /*********************************************************************************************************0 f# b2 i* {% V% z& h
- **函数名称: fm25cl6_clear_data
9 |6 v: G2 d% w4 L+ p& l9 O - **函数功能:清除指定长度数据
8 X8 q( |1 q, g - **入口参数:write_addr,清除数据地址,,len,清除的数据长度
& c* j. ^9 Z5 t9 A - **返回值:无
; @4 P% ^, t8 ~5 ] - **注释:
) `8 N, S1 C" Z: W - **********************************************************************************************************/7 d, u- O% V: C! p1 w, k
- void fm25cl6_clear_data(uint16_t write_addr, uint8_t len)
1 \/ X/ P- L3 [+ n2 y - {
& T5 E' E% w. t+ j% i X - 1 L& O' `+ o8 ]0 N
- $ u m9 H0 G* H4 ?; i
- fm25cl64_write_enable();//使能写操作,一定要先使能,取消片选后再写作下面操作' ~+ V& R/ H a
-
! ^/ A* u; N4 X7 ]' z& y -
- T( x' `1 T: p$ ^ - FM25CL64_CS = 0;//片选
# d% B$ H! x- Q1 t! c/ G - & [4 F" t$ C. k/ p0 V( d; \
- SPI1_ReadWriteByte(FM25CL64_WRITE);//写数据命令9 L" Y; p* M+ ?6 u: g
- SPI1_ReadWriteByte((uint8_t)((write_addr)>>8));//最大地址13位' U5 r, {0 s- h
- SPI1_ReadWriteByte((uint8_t)(write_addr));//- `8 u! z0 i" ?
-
9 o3 V5 z1 T5 b2 q+ ] - while(len--)
+ F4 ^- V% q) Z! X+ e* X - {7 Q8 f4 g g8 T! a3 @0 I8 u
- SPI1_ReadWriteByte(0x00);//5 b7 C x" m. X2 a, r" P* V
- }
7 d* g2 H. f4 p1 }! ~ - : Y" H# F. n/ u
- FM25CL64_CS = 1;//取消片选
& P Q9 E0 G6 S# k* r - }) X8 N, h" z" ~5 N+ Z' U0 @1 |
- ( s/ Z2 C1 ~8 ~6 q7 @" s3 G6 U
, `1 O% s/ X" f9 a: E; D# c" B- ( N' F/ q( w5 G( C# q" ~% `
- , x* r& j. H5 B8 n
' w! s6 A9 E: `# o* o: P4 R- P2 C- r- U0 L1 F, `4 \* d8 K
3 S2 K" e4 b9 `% t: y; C: A% _- % l; Y7 C& d5 \4 Z& b
- . @' J0 k, h' g
$ ?& a: b9 X5 @8 M3 Q. b+ h
+ r, \$ e& X+ c# R$ d s" l
复制代码 其实如果面向接口编程,模块调用SPI的函数SPI1_ReadWriteByte还可以抽象,以备可以切换为SPIX_ReadWriteByte。
# t3 m; g6 V& `2 N
1 ]0 `" W1 z9 |) x- | ?测试代码
6 R, X* R4 q% i. q/ }+ r% b- fm25cl64_init();/ ]" M" S' [: o
- fm25cl6_write_1byte(0,0xAB);4 A1 T, K* R' H# [3 t( y
- GG=fm25cl6_read_1byte(0);5 f5 Q9 i7 T& M3 l+ ?/ L
- // fm25cl6_clear_data(0,1);
+ c$ }9 S: U2 r9 ^1 \ - fm25cl6_write_1byte(0,0xCD);
8 [/ J: z" e, V8 N' l3 _' j+ ` - GG=fm25cl6_read_1byte(0);
复制代码 ; P) Z3 ]; {6 C0 O
8 S2 k" ?5 s* A3 G0 s, {' I
|
十多年来一ˊ直在用 24C64 的 FRAM 路过...