分享一个代码模块,网上找的一个STM32的SPI2通讯的FM25CL64历程,我自己结合自己的板子改成SPI1很快成功了。1FM25CL64确实简单,通讯和使用都比W25Q64容易
+ H1 C! {( P8 C- r) e8 P% _( \2写之前没有必要擦除 类似EEPROM
- A+ R. i; Y6 W) i: H, q7 a) M先看我板子原理图
0 F* R: q# ?7 T/ U v- Z
d" A6 n% r Q# C
两个存储设备挂在SPI1上,CS脚铁电就是PA4
# r7 n# |% i+ P$ N% E上代码:2 H9 {* A; k) W) t9 ?6 `8 ^/ u
- #ifndef __FM25CL64_H_1 j/ L0 k1 I* Y% }
- #define __FM25CL64_H_ . O0 p t' }' W/ H
- #include "sys.h"
2 t/ a. [1 w l* }3 |$ n7 H8 z
% M8 d0 z8 k$ N5 X- ) x6 s9 h: T, h
- #define FM25CL64_CS PAout(4) //FM25CL64片选' B" `2 H8 ^2 K5 g- _
- , q$ S2 p9 n+ p. e: u# R
- ////FM25CL64指令定义
7 u" J2 T, Z5 b* z3 B; X" @ - #define FM25CL64_WREN 0x06 //使能% J4 Y" w3 n) }
- #define FM25CL64_WRDI 0x04 //失能
1 J8 F2 o: r1 F, ? - #define FM25CL64_RDSR 0x05 //读状态" G1 m; X" R# e4 a# j
- #define FM25CL64_WRSR 0x01 //写状态
4 j& e; P2 a Y" e- n - #define FM25CL64_READ 0x03 //读数据: I1 [1 v" I* X9 V7 Y& t
- #define FM25CL64_WRITE 0x02 //写数据
% T. a- _; m; h6 M- r
8 S! d+ _3 w9 q8 W% D! X- void fm25cl64_init(void);//初始化
* F( H6 b7 O" `! }& e1 T - uint8_t fm25cl64_read_sr(void);//读状态9 R+ L0 r J9 b l" \
- void fm25cl4_write_sr(uint8_t sr);//写状态
8 |1 ^( r9 i; V% Z! j0 m1 P - void fm25cl64_write_enable(void);//使能
! r* i: P$ q& I3 @, X - void fm25cl64_write_disable(void);//失能8 f- w5 a1 B1 `7 h
- void fm25cl6_read_nbyte(uint8_t *pbuff, uint16_t read_addr, uint16_t read_byte);//连续读取N个字节
, k; |, h# y1 R - void fm25cl6_write_nbyte(uint8_t *pbuff, uint16_t write_addr, uint16_t write_byte);//连续写入N个字节
j1 ]3 j. r8 e6 u0 n0 h9 X - uint8_t fm25cl6_read_1byte(uint16_t read_addr);//读取一个字节+ ^% E' R; p" F" l/ Y0 P
- void fm25cl6_write_1byte(uint16_t write_addr, uint8_t write_data);//写入一个字节' _9 m, x9 U* {+ L
- void fm25cl6_clear_data(uint16_t write_addr, uint8_t len);//清除LEN长度数据, q4 ?* w6 q0 h; w' W. y2 S
- #endif" C" w. B6 `$ F& q) l% m9 n
7 h7 ^/ k3 d, c6 l+ W1 |- 8 h2 ~2 p& G$ k- N: Y" d% \
- : o* c. H, D6 q
- 8 x3 Y# ]# X0 v5 `6 d
- 2 d9 a6 @% q6 M- R( @
, b0 ]9 S! {; {9 w& Y- + O! `4 p& S( F0 t* E
) X+ ^1 _+ Z& P1 f+ i
* g4 x% [: p( `, D: Q
复制代码
5 h2 ?/ {, K% o7 C
+ _# n" s+ u" e! U/ Z& t- #include "fm25cl64.h" + k9 Y3 ?6 A3 ~% |
- #include "spi.h". h Y$ \+ _6 T1 X
- 1 F/ h, E. ?/ ]" p# v3 K* U% ^: H
" }3 H6 W& ~/ G$ ` m5 f: P
% ?, t2 Z( h. x5 B5 @) a1 H- & T' z O& b2 I
- ! v* ~5 {; J7 |; p- @6 h4 f" }
- /*********************************************************************************************************
9 X! ~! l1 E9 ]# q8 w6 y) O - **函数名称: void fm25cl64_init(void)( L5 P/ v9 B* z) r3 D; f* e
- **函数功能:fm25cl64初始化
, }- h+ I, H/ q9 Y' ^% m - **入口参数:无
: F7 |2 ]4 d% H" ^- w5 _1 { - **返回值:无2 X4 i2 k- `. C4 n
- **注释:/ S1 _/ L5 W' ?7 U+ _8 K
- **********************************************************************************************************/
" ~! h! q6 ~4 r7 N0 F - void fm25cl64_init(void)7 q: m- m' K: J2 j
- {
/ i. F' b, N9 ?" L5 G - GPIO_InitTypeDef GPIO_InitStructure;
- L7 f P& G W - " r! w7 ^' |5 `$ W) o
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE );" u. [$ y) K7 } r* s. ^- y! @( s- ?
- % D5 @- w9 x: k" w! S
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; 4 q) e1 v# r7 ^0 [
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
, u! z c8 w0 D! C - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
: M/ \$ u- Z' l2 g - GPIO_Init(GPIOA, &GPIO_InitStructure);
2 F# z% B3 A' s2 p: C* F - GPIO_SetBits(GPIOA, GPIO_Pin_4); ' g( C; Q) C1 \2 y& `% w
$ P( y/ B. t0 ~% y% o6 m- FM25CL64_CS=1; //SPI FLASH不选中, _/ i. k. ~5 h4 q, M
- SPI1_Init(); //初始化SPI+ l, b* D1 Q" k# ?- \
- SPI1_SetSpeed(SPI_BaudRatePrescaler_2);//设置为18M时钟,高速模式
; _+ y1 E4 B, x* b" j - }% x+ N7 f6 h6 @: D }# t n u
- 4 y) |' i6 U# ~1 y6 {
- /*********************************************************************************************************
% y+ q; ^* g+ }) x4 V2 ? - **函数名称: fm25cl64_read_sr
( K7 Q0 J/ ~& x" u0 W0 B - **函数功能:读取fm25cl64状态7 l$ }# q9 @1 D+ E; U
- **入口参数:无
( j" M7 q7 \% @# I2 F - **返回值:读取到的字节
$ N( @& U! l# t7 j3 V8 } - **注释:
' z6 z& e: i- @, h! q - **********************************************************************************************************/% D4 ?, R/ R& E% X$ T
- uint8_t fm25cl64_read_sr(void)4 k3 H& }& V) I/ z
- {1 c6 [$ {) T0 ~1 X
- uint8_t byte = 0;- @: W9 p8 N* p# `$ s8 R! B
-
- g! \4 M8 C1 l0 N7 T6 G; \ - FM25CL64_CS = 0; //片选' L. G8 E9 |7 C) {: ?* ~
- SPI1_ReadWriteByte(FM25CL64_RDSR); //写入读状态命令
; o$ U! r, {8 v - byte = SPI1_ReadWriteByte(0xFF); //写一个空字节再读数据" s$ x5 Z$ k. R$ V) U5 V4 S9 P! \
- FM25CL64_CS = 1; //取消片选; B! q9 ?! n2 w6 b7 j% W9 Z# ?
-
' `7 d$ C' q$ \) T( r- ]0 B7 \ - return byte; //返回数据
3 ]+ R: q# ?' p+ I# j5 c4 M3 z* i - }
# M+ Y: X, ]$ R+ R/ b
& @; F6 r5 w. J- v) Z1 Y- 8 r/ |+ I, y! h; \6 H: f
- /*********************************************************************************************************" B* p0 r E- J B/ ]% }: t
- **函数名称: fm25cl64_write_sr# P1 f+ X. Y3 W) `( s
- **函数功能:写fm25cl64状态7 O1 k9 c2 _) `' `4 k: W
- **入口参数:状态数据! `+ x6 j% ]( [/ x0 t% g/ T2 B
- **返回值:无
; G- }( F" `2 f) Y0 n7 b - **注释:
, P% ~. Y' \ W) N4 U: m - **********************************************************************************************************/9 X; W& r! E l7 U5 m9 j
- void fm25cl4_write_sr(uint8_t sr)
( t& m7 t8 J5 Z- o1 c0 W - {+ d4 g, [* s( S) t. g/ e
- FM25CL64_CS = 0; //片选
, b; N/ e8 Q5 }# R8 k ` - SPI1_ReadWriteByte(FM25CL64_WRSR);//写入写状态命令
3 A& i$ {; x) u. z1 f& |9 D _ - SPI1_ReadWriteByte(sr); //写入状态数据3 e3 B) h( ~( Q% A: {6 M
- FM25CL64_CS = 1; //取消片选
9 U* e0 U$ p* A' s6 S0 Y* w& C - }
) @ L# J6 e: ^9 M; h2 n/ [% b1 C - 4 N+ }2 H Z2 Z8 l" K
- ) ~! ]6 @5 K' H9 n) n& Y, z
- /*********************************************************************************************************0 \ D5 G) V4 |. {0 [( p7 O
- **函数名称: fm25cl64_write_enable' ~; K# W& ]( m! J5 z! o
- **函数功能:使能FM25CL64
1 |* i5 g. e% t7 d/ g; A - **入口参数:无6 I) r* m; `' o5 ]. I1 }1 M
- **返回值:无
8 `1 l( c) o% s. B& o% A3 v - **注释:
$ ^, p- a- E U) \ - **********************************************************************************************************/' V5 h4 _: ]2 L j2 T+ K/ A" _
- void fm25cl64_write_enable(void)# i2 S- G% O j/ l$ A2 c' i9 L3 h
- {4 ]7 o+ J: M$ }) Q3 ]8 E
- FM25CL64_CS = 0;//片选0 Q" d0 X* f5 A5 b, r6 L( H
- SPI1_ReadWriteByte(FM25CL64_WREN);//写入写使能命令4 u& |7 u( s7 O8 x+ f: D: o
- FM25CL64_CS = 1;//取消片选9 d* g3 j0 A# d; Z2 k
- }6 V- c+ l. {! x+ z k% l0 g2 n
- 9 \- Y' x, J& e$ f9 R- s6 l I
1 F' A8 Z, d: N' c0 c$ B- /*********************************************************************************************************
" G1 i0 d* x' [) r - **函数名称: fm25cl64_write_disable
: A o3 N$ f0 x; j) h1 \" z - **函数功能:失能FM25CL646 n5 e; X+ U0 a7 ^
- **入口参数:无1 C9 _$ c8 s; e' E; t( y
- **返回值:无; k Z4 K1 x9 G$ e: r3 W, {# I
- **注释:: j6 H+ C: r. |, J% ]
- **********************************************************************************************************/ H# p, T9 j2 C" Z! E
- void fm25cl64_write_disable(void)
7 v1 u# p# O6 g2 Q9 n$ P9 n5 i - {
7 [' j4 H' p. I; e% f - FM25CL64_CS = 0;//片选4 ~1 t6 F" [3 n
- SPI1_ReadWriteByte(FM25CL64_WRDI);//写入写失能命令
+ G" @) m7 i' Q: U& H! ] - FM25CL64_CS = 1;//取消片选
2 p3 F! b* i; a" }1 \: N; x - }
1 n8 S% Y+ N/ h0 f& k# y% q
, k' E- ?0 G8 r5 H$ r$ ?
, |4 P9 J3 ^! I; p+ [% F- /*********************************************************************************************************/ N+ n: }8 V: N; g
- **函数名称: fm25cl6_read_nbyte
4 X9 K' T1 ?& d - **函数功能:连续读取N字节数据, y! a3 L/ C+ C5 `
- **入口参数:*pbuff,读取数据到指针,,read_addr,读数据首址,,read_byte,读多少字节. Y2 q W& s0 q h
- **返回值:无) q( |: e# J* u; G
- **注释:
: @) |3 b8 m$ q! a. k - **********************************************************************************************************/( f L, a9 h/ l2 q0 M
- void fm25cl6_read_nbyte(uint8_t *pbuff, uint16_t read_addr, uint16_t read_byte)% ?5 P3 o/ f9 r$ _) R2 E3 p* W
- {
1 V- c$ }0 w$ S7 C+ D2 Y _! f - uint16_t i;
0 D) `- N/ I9 ^7 ~( S+ B& v+ u - # Z% ^9 c, J* o* e' ^. ^7 ~2 C
-
; L" r( n( L) j. ^* ^ - FM25CL64_CS = 0;//片选( K' g: L% q' ^% n/ q& K
- SPI1_ReadWriteByte(FM25CL64_READ);//写入读数据命令
3 a" P; d$ I, y - SPI1_ReadWriteByte((uint8_t)((read_addr&0xE0)>>8));//写入高8位址,最大地址13位
% U- ]- R) u- V - SPI1_ReadWriteByte((uint8_t)(read_addr));//写入低8位址,# B) ~9 i' M. z7 {" [
-
. ^' b9 \: `- E - for(i=0;i<read_byte;i++)//连续读取数据
0 _5 b; |. p9 `9 g' B - {: ] q9 W$ n7 D! b( [/ }
- pbuff[i] = SPI1_ReadWriteByte(0xFF);0 X; p9 V4 N7 G7 s+ P
- }
4 F; ~: W! S0 E" s - FM25CL64_CS = 1;//取消片选7 e* o" |, j$ ]* ?$ Y* @
- |( M2 p; A& u' a# [
- 9 o$ P: _2 x9 k: i* y- K0 Q& e
- }3 G, ]9 i1 p# y0 ?3 h" P, I- W. e
2 \9 R/ t; c! y ~3 F* z; G- 0 L( K( b5 j2 w! k0 {" M$ ]
- /*********************************************************************************************************% b* y0 `0 o U3 Z2 m
- **函数名称: fm25cl6_write_nbyte* V9 _$ `* G3 R7 a' m( _
- **函数功能:连续写入N字节数据$ B) A H5 I F+ U
- **入口参数:*pbuff,写入的数据指针,,write_addr,写入数据首址,,write_byte写多少字节$ C E5 s+ |5 y$ k
- **返回值:无
5 _' T; Z5 H# D7 P - **注释:: J( t' D; ]2 l |( E! ]
- **********************************************************************************************************/
6 n1 a( E, a; [0 Q1 p - void fm25cl6_write_nbyte(uint8_t *pbuff, uint16_t write_addr, uint16_t write_byte)$ U9 u$ x- @: r$ g) y$ d( H% X: O' g+ `! S
- {
# f O- h0 S0 E! Z. k - uint16_t i;
, G1 C( h9 M: K- b
* P3 W2 P8 m3 x- ! T8 T# c' \- I/ N- T. h
- fm25cl64_write_enable();//使能写操作,一定要先使能,取消片选后再写作下面操作
5 k$ E& b& s' Q# N p" D -
& L7 `: w \; w2 P& s8 ` - FM25CL64_CS = 0;//片选. l9 a2 L# Y9 d+ k
- 0 S' Z4 S9 Q j9 ?( Y. p+ x
- SPI1_ReadWriteByte(FM25CL64_WRITE);//写数据命令
V7 I6 C, m4 A+ T Z; a; ^; a7 V - SPI1_ReadWriteByte((uint8_t)((write_addr&0xE0)>>8));//写入高8位址,最大地址13位( E" s5 b; E* b. C3 ?8 \
- SPI1_ReadWriteByte((uint8_t)(write_addr));//写入低8位址,* b9 `/ E, L) W, s5 b6 @5 Y
-
3 W) z1 w$ K$ W, e" }/ c; } - for(i=0;i<write_byte;i++)//连续写入数据
7 O @7 c- r5 u: b d8 u - {
, f% k. z5 Y( }5 u - SPI1_ReadWriteByte(pbuff[i]);5 T! R. r* D+ G0 N/ y
- }. l2 V2 j4 b1 m4 ^% I a
- FM25CL64_CS = 1;//取消片选
) L) ^& u, p4 o( @6 g, Y - }
" p L4 y D/ R5 S - ) @. B( h/ R" \
/ x$ C5 ^9 e* `- y7 f4 D
1 M+ i( y$ B/ |! x6 _- /*********************************************************************************************************
0 }3 ]# S% W. F# G0 W, n+ U2 O - **函数名称: fm25cl6_read_data_1byte
% ^! @* a- u" F. O& m. ]2 r G* r - **函数功能:读1字节数据' l. {! H# |+ e' [
- **入口参数:read_addr,读取数据地址0 y2 K- [7 X% i8 X7 t# n' @7 Y2 _
- **返回值:返回读取的数据( g+ F: U: w# J1 b2 ?* j
- **注释:
) }: A- c6 t* G6 H$ x* y - **********************************************************************************************************/
# j3 B; G' O1 o' i" r+ x - uint8_t fm25cl6_read_1byte(uint16_t read_addr)
; `* g9 Q$ e9 V: O+ G1 U1 w - {% u V6 X+ ^2 E: R2 o9 Z& F( o0 c
- uint8_t dat;; x' M/ s7 {+ E( P6 o
-
; Z. v0 R3 ] }2 I; @ - FM25CL64_CS = 0;//片选' q# q A' a3 B- i8 I
-
( N# m; Y" E3 m, T" w - SPI1_ReadWriteByte(FM25CL64_READ);//写入读数据命令
N! B n6 f C: _' Q4 ~( W5 G - SPI1_ReadWriteByte((uint8_t)((read_addr)>>8));//最大地址13位
. v n9 |# Q1 Z0 W - SPI1_ReadWriteByte((uint8_t)(read_addr));//
4 K. E& y! V. d+ P3 K - 2 o, p: D% l0 T& ^+ Z
- dat = SPI1_ReadWriteByte(0xFF);//读一字节数据" \! O) W; E! P5 g, G# P
1 V) O. `& u; s# A# i- FM25CL64_CS = 1;//取消片选% z& L5 R# Q) D4 L |8 G( x
/ r7 q; R/ s4 ~" {2 A7 [- return dat;
8 e& {. w F: J0 n& T# o0 e - }
$ G2 w# y$ j8 A( r - 3 w8 M% Q. U* V# A- e0 q* Q; n
N0 @! [7 G$ u3 I3 ?- /*********************************************************************************************************, w2 T( {- a9 v1 M$ r. u1 B
- **函数名称: fm25cl6_read_data_1byte
. E: n5 o2 V, b- y - **函数功能:写入1字节数据2 |. p. p" s1 a) B/ x" p
- **入口参数:write_addr,写入数据地址,,write_data,写入的数据0 K0 z3 U& n& N7 k1 A, |
- **返回值:无) N5 K8 ?8 ~3 Y) s* W- n, Y! O
- **注释:
1 d4 `& J* m) w0 _$ E - **********************************************************************************************************/
5 [4 ~& H( N& D e3 p& u. B - void fm25cl6_write_1byte(uint16_t write_addr, uint8_t write_data)+ b7 }2 E' V5 `, d9 u& j
- {2 A- z6 R4 e) j$ M; M
6 i# ]# v3 A0 i7 ]- , E6 O0 L a; Q K
- fm25cl64_write_enable();//使能写操作,一定要先使能,取消片选后再写作下面操作
0 D4 _$ l$ m' h6 s -
& D& q) H% b! X - # b# V1 D1 L- S. f9 p: a3 G
- FM25CL64_CS = 0;//片选
3 Q7 [' w H' A% B2 L -
1 \- J& z1 `$ c, \* c( a - SPI1_ReadWriteByte(FM25CL64_WRITE);//写数据命令4 O. Z) T! `) s. ~" q
- SPI1_ReadWriteByte((uint8_t)((write_addr)>>8));//最大地址13位+ l+ ?; B+ F8 M( i% Q
- SPI1_ReadWriteByte((uint8_t)(write_addr));//
) \* Y3 E) w0 l( ^& u: U" b& G -
. d" u f# g8 u; h. p - % ~4 o& @6 p8 B0 {
- SPI1_ReadWriteByte(write_data);//写一字节数据: v& i, W# U) k& p0 `1 m
- i# g9 r0 ~1 M9 X6 }/ k4 t- FM25CL64_CS = 1;//取消片选
- B- |9 W. C% ] - }
+ C( W3 U0 W. K. T - / Q7 w) g: J5 x {! G4 i# g
3 ~' R8 l* \6 P- /*********************************************************************************************************
1 k- f/ S" r3 k6 @. l. [) \ - **函数名称: fm25cl6_clear_data
4 f8 A. Q$ ~) m4 ]* Z' n4 }3 o - **函数功能:清除指定长度数据/ G$ S+ f! l7 G" x( @
- **入口参数:write_addr,清除数据地址,,len,清除的数据长度: W$ U E8 v) T) v/ Z7 F$ c2 u+ r
- **返回值:无
4 K' P; g) P: \" v) M4 k - **注释:& V% x, E; a z4 R/ `4 w' @; ^
- **********************************************************************************************************/
4 o1 h* J- w4 m0 ^ - void fm25cl6_clear_data(uint16_t write_addr, uint8_t len)
9 v: k+ ~! E1 M! Z* u - {
2 y% F+ L* ^ v
, W6 Y" |6 Z, T8 V- 8 T- c" w9 ?! Z( y9 Q" D
- fm25cl64_write_enable();//使能写操作,一定要先使能,取消片选后再写作下面操作7 v: A. Y$ r$ i: L! [' [0 R3 Z
-
# c! D! j( x+ n -
$ e+ m- \; ?) Q4 } - FM25CL64_CS = 0;//片选
" M6 {, j8 N3 c0 l/ i - ! f; x; r$ C# r& C2 b$ G! W
- SPI1_ReadWriteByte(FM25CL64_WRITE);//写数据命令5 e( T* E" ]$ j# q: ], P
- SPI1_ReadWriteByte((uint8_t)((write_addr)>>8));//最大地址13位
+ G2 T& A5 V0 D& ?% S% a& y6 O - SPI1_ReadWriteByte((uint8_t)(write_addr));//
# C# Z/ `* ?0 Y1 E8 Z/ C -
) j! z9 `( m* R4 i+ D$ [# f+ Y - while(len--)( [% c3 k0 I1 ~# _1 d6 O# k) V
- {" l! X* g0 k( P: h, \
- SPI1_ReadWriteByte(0x00);//
3 J8 h# |2 b- y' V2 [ - }4 r; k% u; T1 ~0 b0 S5 e
-
) S. P Y3 H8 s5 q - FM25CL64_CS = 1;//取消片选
; i0 R9 F/ ^3 Z$ s - }
: j* J$ Z6 ^4 O - 8 `! p( T |/ E& f& Y% b
! A( s+ _8 c6 x+ N$ L. S- 9 q r0 h9 e: s1 y0 K
A5 [. J5 g3 X6 B7 `7 s
( D1 Q4 w8 B b* X* o1 a
( g) e* U+ ^, {( [) i
' |# O, ~" @7 X+ w( Y" q9 K
7 B6 o6 t. R/ M1 C5 G8 a' [$ q- / _0 O" t1 |* I) M9 y3 E
- 4 j7 L$ F( Q4 f5 k# J/ i$ [7 M
- " h. t6 y$ e! s& i. o3 U
复制代码 其实如果面向接口编程,模块调用SPI的函数SPI1_ReadWriteByte还可以抽象,以备可以切换为SPIX_ReadWriteByte。
; S& o a8 d. D
. m7 n, ?1 ^: z( q' W测试代码
& R D: x7 O8 i+ p: F9 X- fm25cl64_init();" ?9 W$ H L+ a1 B0 D# c- {
- fm25cl6_write_1byte(0,0xAB);
9 V4 r0 Q5 s2 c: M - GG=fm25cl6_read_1byte(0);
: p' w( K+ q- Q - // fm25cl6_clear_data(0,1);7 ]& V1 P6 M. o4 F [
- fm25cl6_write_1byte(0,0xCD);2 F" y$ r# e0 L! G g
- GG=fm25cl6_read_1byte(0);
复制代码
! V: H! T$ B# n# n
$ k- F# e" t" f# Y- O- W* { |
十多年来一ˊ直在用 24C64 的 FRAM 路过...