分享一个代码模块,网上找的一个STM32的SPI2通讯的FM25CL64历程,我自己结合自己的板子改成SPI1很快成功了。1FM25CL64确实简单,通讯和使用都比W25Q64容易
! @" D, _: N6 ?7 e% q2写之前没有必要擦除 类似EEPROM
9 X% O0 f$ p% W) C: M7 p+ U7 n+ V: h先看我板子原理图5 ~% W* j! B! k2 s7 Z
) w5 `- @# T+ ^
两个存储设备挂在SPI1上,CS脚铁电就是PA4; ~3 y) g- P. Q1 S7 `
上代码:7 c4 u) s% \- A' j; f I6 l
- #ifndef __FM25CL64_H_6 p5 L3 Z F6 n7 W: \$ f. m
- #define __FM25CL64_H_
6 X& h$ c2 c3 \" p1 z! i) `8 f - #include "sys.h" % a: Q# X8 Y- W# E9 t4 I0 E4 @
# t2 F3 h8 M( b1 m+ A8 L* y
, b! S) G0 s4 ^' @! I2 U \; G0 ?- #define FM25CL64_CS PAout(4) //FM25CL64片选3 I8 F' C. V( c
9 G8 g: B8 V1 N2 j- ////FM25CL64指令定义
: u) d) U, Z$ C: j6 E7 k% b - #define FM25CL64_WREN 0x06 //使能8 ?0 q! P3 I% Q' t
- #define FM25CL64_WRDI 0x04 //失能6 S: o2 M% t6 H. v7 _/ U& }
- #define FM25CL64_RDSR 0x05 //读状态) Q1 r1 L' P* e# B, E; x {0 e/ I
- #define FM25CL64_WRSR 0x01 //写状态% t; w# z1 d$ u! t* c
- #define FM25CL64_READ 0x03 //读数据
3 i. o! S: T4 H; \# b: d( V; k+ Z - #define FM25CL64_WRITE 0x02 //写数据
; _, f# H, ~( ~" o' ?3 N2 [
' ?) q0 c8 [/ ^" S0 v6 n5 [0 y' }( G% I- void fm25cl64_init(void);//初始化
9 M- M& v/ w5 i9 ^ - uint8_t fm25cl64_read_sr(void);//读状态
0 V+ Y+ v: X7 h8 H - void fm25cl4_write_sr(uint8_t sr);//写状态+ ~' o( r: C8 k$ X5 O* d
- void fm25cl64_write_enable(void);//使能
+ v* l& d! S9 d& X- f - void fm25cl64_write_disable(void);//失能/ c/ M0 R) r0 W( C0 H+ c4 s
- void fm25cl6_read_nbyte(uint8_t *pbuff, uint16_t read_addr, uint16_t read_byte);//连续读取N个字节
7 h1 k# r( V: P8 z2 \, @+ g - void fm25cl6_write_nbyte(uint8_t *pbuff, uint16_t write_addr, uint16_t write_byte);//连续写入N个字节; j5 _% S' n6 `0 {
- uint8_t fm25cl6_read_1byte(uint16_t read_addr);//读取一个字节
4 G+ x! v( ^0 T0 g' k - void fm25cl6_write_1byte(uint16_t write_addr, uint8_t write_data);//写入一个字节
! ~" j" d4 q! H* u - void fm25cl6_clear_data(uint16_t write_addr, uint8_t len);//清除LEN长度数据
9 B+ M; r Y/ O7 Y7 ? - #endif( _# B; k* J. ?' z* P0 n
- 2 R; i* a& \4 W' z
- : Z9 [- j9 x2 C9 W' B
- - o4 b/ x0 I- N! I8 k4 Z- k
9 u0 A( L; e& E3 p- 2 u& S/ e; z- G
- 8 I0 t- @6 X% I; B/ e; i! h
! }- f! X: i# E' u, e. ~& s- k6 w: U1 h" L! K4 T
- $ L: g4 [5 F+ _6 H8 ~0 ?
复制代码
6 p; w& _0 `; y0 C: v) z! {) l- X; R7 `# H) `3 A
- #include "fm25cl64.h"
, |! Y1 T% ~; \9 @, [ - #include "spi.h"
- V* R% b' S) r0 k( G+ N4 ], ^
) I; U0 f1 L# Y- p
0 O2 M$ g4 Q" w+ s2 a# s+ Y$ F& I- 0 N# `* U' L: X+ t6 I6 [% G: t; w& V
- & Z" P8 I- S; D9 i; [( [/ q% k
- ; M z9 Z* v9 a4 `- s
- /*********************************************************************************************************
5 R4 t* H: |, g7 @/ E* y - **函数名称: void fm25cl64_init(void)& ~: ?$ f5 Q+ m( M' L
- **函数功能:fm25cl64初始化$ X) p: T4 n: s* O: g8 r& D' l
- **入口参数:无" D, z I; S/ S5 T6 e# M3 {
- **返回值:无
b- ~: k# x' X/ y/ a - **注释:4 S4 t" Q G! {
- **********************************************************************************************************/
- n5 ]/ M( W2 T1 l: j - void fm25cl64_init(void)) y7 ~5 o @+ s, A
- {
) r6 i: l1 b6 R; C - GPIO_InitTypeDef GPIO_InitStructure;4 i1 e* g8 _+ \6 l5 b
- ! F/ F: P+ D7 I0 a
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE );
, @0 ?5 n7 `3 [( b* r - # K( t9 W$ b! b0 q; S
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; # y8 w6 Y6 m: ]; p, ^
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
/ n3 S7 g8 }; {* F9 Y2 O8 X& @( F) q - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;; s5 a6 p) q! }( {$ m
- GPIO_Init(GPIOA, &GPIO_InitStructure);
6 `2 I q+ }- c3 _ - GPIO_SetBits(GPIOA, GPIO_Pin_4); 6 ]9 _9 y* |" n4 @ V
H+ ~ j& A& \- `' z- FM25CL64_CS=1; //SPI FLASH不选中
' ]/ D" W L4 g" U- [ - SPI1_Init(); //初始化SPI8 q0 P+ M9 b4 v4 ~' f
- SPI1_SetSpeed(SPI_BaudRatePrescaler_2);//设置为18M时钟,高速模式5 x/ h/ R# m$ N+ a( }) q' a8 p
- }
2 B- v3 f/ `5 I% s7 n _ - # I: ]/ M" g! `' c; R
- /*********************************************************************************************************8 V2 ^' p* y" t: O: p- S5 G$ J' h u
- **函数名称: fm25cl64_read_sr
9 B" w; P8 w; M8 Z& f9 M# E - **函数功能:读取fm25cl64状态
4 N( K- M. z9 K2 y* f$ m* D - **入口参数:无
* d! i7 @( A( P, P$ `# _ - **返回值:读取到的字节
' v+ T6 t. L/ z3 N/ S - **注释:9 Y V' ]6 K; }/ f
- **********************************************************************************************************/" [1 U7 r1 h% C0 y* e
- uint8_t fm25cl64_read_sr(void)& @7 f7 V, N, B# c; ~
- {8 T4 w! y& z2 M+ z4 `) E7 _3 E# z
- uint8_t byte = 0;
" [4 s. b9 C. v# R9 l( d& R - ! R: r. s% a( q
- FM25CL64_CS = 0; //片选
1 f9 w# F7 [' v: o2 `! Z - SPI1_ReadWriteByte(FM25CL64_RDSR); //写入读状态命令
( [! L6 Q- b! T9 @6 ?: E* c+ p% G - byte = SPI1_ReadWriteByte(0xFF); //写一个空字节再读数据" @2 I( v8 R! f- H' p* F
- FM25CL64_CS = 1; //取消片选
+ p/ U) x' M: Y; W -
- j9 }, s- o' X- h - return byte; //返回数据
9 ?# _$ L, ~6 v- I. }1 q - }- z! _* A; L" x y# P% H2 c: e
- 1 p* `: n0 y9 c
4 O* p+ |. J) }: Z2 \4 H- /*********************************************************************************************************
( o; d Y6 |2 `6 x/ ] - **函数名称: fm25cl64_write_sr
7 e- Z z5 j* c! N' h/ {/ U+ Q - **函数功能:写fm25cl64状态
# A. c; W& B( v% p8 @ - **入口参数:状态数据
$ {' H+ A5 [+ r2 C5 w \0 d9 R - **返回值:无- L# F8 S! |3 N2 N2 R
- **注释:% `: k- C5 Z' k# K4 D- R5 H0 t
- **********************************************************************************************************/* q7 b& O2 X8 Q9 p% {
- void fm25cl4_write_sr(uint8_t sr)0 r- c+ ?5 F5 x( }7 V: n+ Y
- {
7 r5 ~$ Q1 C2 I9 V - FM25CL64_CS = 0; //片选
2 ~: c* `+ F0 A2 j* k - SPI1_ReadWriteByte(FM25CL64_WRSR);//写入写状态命令
, I& X% ^7 t# w$ v! V3 X* J8 Z9 ` - SPI1_ReadWriteByte(sr); //写入状态数据
8 U; D* R/ F; U - FM25CL64_CS = 1; //取消片选
* p( \3 [+ j; m! p- K4 f - }
$ I5 j9 J% s2 h0 U5 ^ - " _: p+ v$ Z2 w/ e
2 r+ C: j/ j& d/ f- /*********************************************************************************************************
; J7 P0 P9 Y# j - **函数名称: fm25cl64_write_enable
5 d: }9 c8 D( m$ N* D' I1 @ - **函数功能:使能FM25CL64
4 K! a7 k% _8 U8 k6 D - **入口参数:无
. n2 h* R9 n! m. x - **返回值:无. |- c3 |5 a H/ \
- **注释:
6 V1 l7 U# [- d' Z4 P - **********************************************************************************************************/' [& n* g# M- Q2 a* R3 r! e" o( ^
- void fm25cl64_write_enable(void)$ }0 u9 `/ Z5 x0 {
- {
* @0 l! H, y$ w( O& ^ - FM25CL64_CS = 0;//片选/ B8 K2 e+ q8 ~+ W" E3 n! s
- SPI1_ReadWriteByte(FM25CL64_WREN);//写入写使能命令( a3 r$ R3 ]4 W' Z- |
- FM25CL64_CS = 1;//取消片选
7 `; W0 O. A- s n8 x* u6 ^9 @ - }
; ?- b5 H0 A. ?) B
0 @$ ]: f, X# Q) o3 T- $ B! Y% L) u+ J2 j, h) ]
- /*********************************************************************************************************
% I) v+ [. ^- N" r9 g8 s; V - **函数名称: fm25cl64_write_disable f. Y: l7 r. A: x. \$ v
- **函数功能:失能FM25CL641 u- z; D; i5 |2 X1 W
- **入口参数:无
2 G( x) V. d5 e7 Y( m7 u8 {7 P; U$ e - **返回值:无4 n) n; Q5 x0 V0 Q" ^( y' g
- **注释:8 V0 X+ S) r3 s9 z, \* p6 s; k/ E
- **********************************************************************************************************/6 f3 [6 O% q4 O' N; A' y
- void fm25cl64_write_disable(void)
9 Q2 R1 ~9 e5 p; Z4 O - {
' f+ C6 I0 |! [0 p( t x. B& t5 c - FM25CL64_CS = 0;//片选
9 o. V, e$ D; u2 |, z, X3 [ - SPI1_ReadWriteByte(FM25CL64_WRDI);//写入写失能命令
& S7 x+ p: O% T3 j - FM25CL64_CS = 1;//取消片选% N. r; H) S* }2 J B6 \9 V
- }: l; }; V" w5 s# w7 Z
- # [7 R6 a# @! t& v5 {4 U9 R7 [
J2 H: t/ r# F& D" j- /*********************************************************************************************************3 h* R1 S/ d( X" M
- **函数名称: fm25cl6_read_nbyte `2 n$ o: H% c4 u1 B( m1 \
- **函数功能:连续读取N字节数据. l+ U& F9 v. i+ I0 l+ R
- **入口参数:*pbuff,读取数据到指针,,read_addr,读数据首址,,read_byte,读多少字节4 F4 n% n5 {/ l: I& k( @6 g Z
- **返回值:无8 ?0 w0 f1 d+ Q
- **注释:
5 v! P/ t: ]/ X$ \- P - **********************************************************************************************************/; k! @+ B* J, L: ~
- void fm25cl6_read_nbyte(uint8_t *pbuff, uint16_t read_addr, uint16_t read_byte)
( u1 p/ ?$ R9 J3 o) Z - {% q2 t! e. V0 r
- uint16_t i;& C; x; r3 ^4 k) l# Q! A* |
-
3 u) Z6 j7 }5 p! Z6 r -
* Y* p( Q0 [4 _' h2 M% v - FM25CL64_CS = 0;//片选: }# G9 `: @6 \; _
- SPI1_ReadWriteByte(FM25CL64_READ);//写入读数据命令
/ i! U0 ]. r, l1 j/ E) A - SPI1_ReadWriteByte((uint8_t)((read_addr&0xE0)>>8));//写入高8位址,最大地址13位" P4 m: K1 x" R; b
- SPI1_ReadWriteByte((uint8_t)(read_addr));//写入低8位址,
6 Z5 F! O d4 Z2 V% H" k& w2 c# b -
) U+ O8 T7 [ z5 v+ t- D, {! { - for(i=0;i<read_byte;i++)//连续读取数据
0 ?) X2 u3 I3 l- a- e2 E) U - {: }1 m6 @( H$ @# k8 }7 C
- pbuff[i] = SPI1_ReadWriteByte(0xFF);
6 J: t$ J# C- T& U$ \* D8 X2 ?1 ?$ u - }: R. c, m9 L9 `6 k/ R$ H
- FM25CL64_CS = 1;//取消片选
" s- H( v8 V; `
0 k+ ?/ b# D0 C" g# N3 \-
+ `4 E3 X, N2 `9 L1 t" D: v: F7 ~$ L - }
* Q) ^ E$ j3 _0 {) z! m) e
3 V+ \( G( s$ U- & l, w- _9 H3 P
- /*********************************************************************************************************# V+ B. A7 s# q' U/ C
- **函数名称: fm25cl6_write_nbyte7 ^: z. v5 n& X, J$ |8 K
- **函数功能:连续写入N字节数据, `5 s% P( V5 N% C+ y4 z$ q
- **入口参数:*pbuff,写入的数据指针,,write_addr,写入数据首址,,write_byte写多少字节" m; K a1 H: r' w3 K& m+ @, |
- **返回值:无. l2 B ]* r5 N- u
- **注释:3 c! c: T/ T5 Q7 m) D
- **********************************************************************************************************/
b4 x) c6 ~4 S2 @5 Z - void fm25cl6_write_nbyte(uint8_t *pbuff, uint16_t write_addr, uint16_t write_byte)
0 I7 T4 ?9 D8 ~ y7 { - {
, ~4 ?& S+ |3 C) r6 @ - uint16_t i;
2 c$ |' E' c# m& K/ B$ W - % Y: o, T* U6 y2 `
-
" b/ g8 V) U6 ]1 x2 G& c f - fm25cl64_write_enable();//使能写操作,一定要先使能,取消片选后再写作下面操作
" Q/ w9 t0 F& P, J -
6 |* Q# k5 e( f$ m; _" M% G- ^ - FM25CL64_CS = 0;//片选 K1 r+ w' _; O' ^8 a1 L3 N
-
: r; E) j) @ U, q5 C - SPI1_ReadWriteByte(FM25CL64_WRITE);//写数据命令
9 W i& G# g; K+ h* Y7 K$ o - SPI1_ReadWriteByte((uint8_t)((write_addr&0xE0)>>8));//写入高8位址,最大地址13位, u, t4 J" a" S$ D* M" Y* ?
- SPI1_ReadWriteByte((uint8_t)(write_addr));//写入低8位址,9 T( t3 p$ v8 v' j% A* n6 l
- 3 P. v: [# p( _2 @1 X# {
- for(i=0;i<write_byte;i++)//连续写入数据
, \0 K6 j3 L! W/ d! x; c6 C* { - {0 a0 o; j, L. M6 u2 I+ ?
- SPI1_ReadWriteByte(pbuff[i]);# R8 [. q* e/ S" m# z3 h" B1 P9 Q
- }
% ]' X5 W) W- s3 Z - FM25CL64_CS = 1;//取消片选
2 C8 L% P3 d5 [4 E9 i - }. n" A1 r$ b9 h$ |
- 9 C: z( W5 d8 M) N& ]0 [
- " i! Q% h0 F% ?0 }8 P+ Y* v
- ) G/ ?1 R1 b1 l
- /*********************************************************************************************************
! ` N d, _* z9 J - **函数名称: fm25cl6_read_data_1byte, u) k; v9 J. ?: r
- **函数功能:读1字节数据$ D. W& B& _+ }% \
- **入口参数:read_addr,读取数据地址* [' c, F9 X. x: }: \5 t+ Q5 D
- **返回值:返回读取的数据' q8 ]* X9 w( [+ ~" G
- **注释:
0 P. l7 H; \4 R! z4 _% F - **********************************************************************************************************/# b! ?$ t+ B7 X+ h0 V
- uint8_t fm25cl6_read_1byte(uint16_t read_addr)
# ^0 Z+ `1 K3 e! X& W. w - {
' {3 d) Q( j, L/ z& E9 a - uint8_t dat;6 q) Q a0 j# g* D, ?
-
( T c/ h/ _! Z - FM25CL64_CS = 0;//片选
" }, t5 F5 Y- f8 p& G -
( r7 D, H6 g+ } - SPI1_ReadWriteByte(FM25CL64_READ);//写入读数据命令
/ {1 G* h; Y: A+ p - SPI1_ReadWriteByte((uint8_t)((read_addr)>>8));//最大地址13位
3 Y) w2 o4 H9 S h( U& E( S& j - SPI1_ReadWriteByte((uint8_t)(read_addr));//
1 ^* R6 Z' @: H% Q6 s -
u( a6 f. i: I; ], J9 n$ i+ z - dat = SPI1_ReadWriteByte(0xFF);//读一字节数据! P- w+ v# M: L/ z
8 w' C1 [3 i3 y: ]- FM25CL64_CS = 1;//取消片选
- l- v' u) h. N, ^$ J
! c/ o4 U5 K+ n$ K+ j+ o5 \- return dat;! v& K B5 G) ^3 X% O+ T0 k
- }" Q! B1 H( v, n, B
- . N1 [: m! Q" k r$ q5 i+ g2 ^& b
7 ~% |% ]4 s! m. I( b0 @- /*********************************************************************************************************: K* O p" g5 l% ] W' h2 I
- **函数名称: fm25cl6_read_data_1byte
, h' P8 o0 n2 Q( o: t3 f T - **函数功能:写入1字节数据# D1 [4 M6 P, x$ N: Q! X
- **入口参数:write_addr,写入数据地址,,write_data,写入的数据
+ y0 p7 W. g3 Z- I1 D - **返回值:无2 ?! s! w5 {9 }" y* h
- **注释:
1 k8 m4 E& U/ z6 Q* @) c5 w - **********************************************************************************************************/: Z# r8 g% ]' J$ K
- void fm25cl6_write_1byte(uint16_t write_addr, uint8_t write_data)
9 f( i% c* e, m( q: z# x2 [2 ^ - {
4 r) m8 e- x; ]" C& z9 m
* j. H0 c/ ~, d' `-
# e7 U/ m; l1 g! O( H! N- E3 K, C - fm25cl64_write_enable();//使能写操作,一定要先使能,取消片选后再写作下面操作2 d! m3 ] m' d8 g2 H! D- E6 a+ y
- 2 K" x( i9 h. Z' K; ^7 C+ k, ^9 P
- ! O! q; O& J8 z4 q8 Z( z4 d; \! r
- FM25CL64_CS = 0;//片选# O) m$ I- R% K) S
-
) {, L* D5 R. I4 j# w+ Y - SPI1_ReadWriteByte(FM25CL64_WRITE);//写数据命令2 w) u9 F& ?5 s( d0 x0 {% e* g& Z
- SPI1_ReadWriteByte((uint8_t)((write_addr)>>8));//最大地址13位& A3 l! k: X# s; g' @& H/ S
- SPI1_ReadWriteByte((uint8_t)(write_addr));//
/ Z2 K" E M8 u' a( n! D( b -
; e% V* v4 ]7 _/ U" Z. Q: s - 9 ?( H+ e8 A: j! t* q2 _. W
- SPI1_ReadWriteByte(write_data);//写一字节数据
! C4 s* _8 s6 c8 }/ L
$ U Y) H4 l2 P% x; ]% O- FM25CL64_CS = 1;//取消片选1 W, {" K9 l) V' ^# E
- }
u: E' M% e: |* s) I! t - $ C0 y* n# ~! t" j7 F- @
( V) y+ {- b: A: L o$ }- /*********************************************************************************************************
; q2 g8 u6 X. m' I1 X$ q - **函数名称: fm25cl6_clear_data, x6 M( U6 O2 T3 v; ?
- **函数功能:清除指定长度数据* n6 t7 T+ V y
- **入口参数:write_addr,清除数据地址,,len,清除的数据长度; `5 c1 d7 L6 K3 V
- **返回值:无
! b6 Z. @& f( j( O9 k. s - **注释:7 T' e8 s2 g/ A
- **********************************************************************************************************/+ Y( Y3 E6 U# F
- void fm25cl6_clear_data(uint16_t write_addr, uint8_t len)6 O, A. e0 g9 s) J u/ |& z
- {
9 W5 ^- z% N1 I1 Y9 ]5 M. j* }- e
6 ^2 H: {+ O/ k+ l-
0 y/ r$ B3 ^) C' Z. I - fm25cl64_write_enable();//使能写操作,一定要先使能,取消片选后再写作下面操作
2 z7 m. f% }* a: ` -
. Y- Q, j" ^* _' |2 }. h - ! E" n& x8 ]7 R6 k0 O+ ?
- FM25CL64_CS = 0;//片选7 Q: M% K0 u0 T
- 9 P: S0 i3 z/ y" ~
- SPI1_ReadWriteByte(FM25CL64_WRITE);//写数据命令) D: X. r0 o% w* t
- SPI1_ReadWriteByte((uint8_t)((write_addr)>>8));//最大地址13位6 o. U2 o4 }$ V" _/ ^5 J4 V7 p
- SPI1_ReadWriteByte((uint8_t)(write_addr));//
0 |) a, g% p6 n3 k -
$ k/ [* d% y* E - while(len--); c6 J- m8 i; Y' B
- {
; ^6 ?9 R+ y4 H/ b - SPI1_ReadWriteByte(0x00);//% F* E; h6 s: O* M
- } `* t e& |' `* N3 q; s& S7 d: E
- 2 t$ z0 ?* D2 c7 O8 B% L3 J7 n8 L
- FM25CL64_CS = 1;//取消片选
5 V0 B! {1 ?' A* a4 }* V; Q - }+ O J4 o9 |; \4 _2 |7 q
/ {# [ r2 s w4 U+ P
5 g4 L" c1 U8 |% |3 t' E: a
, Q A7 G. C+ T% |
4 f# q' ]6 Q0 s- x; ] c
$ n. g: r; |4 R' u- 1 _2 [* B/ [8 q2 o
+ k: }3 y5 L: t/ U; r: A/ |/ t- 0 h1 w A+ G: x
- ' A! ]6 H5 s' _# c0 G6 \, ]
- 0 l. P) U, F$ v$ f
# }. @+ P' p6 F0 T# U
复制代码 其实如果面向接口编程,模块调用SPI的函数SPI1_ReadWriteByte还可以抽象,以备可以切换为SPIX_ReadWriteByte。* X; c! l; D! B) ^. [
" o' u, O7 c6 M% D- ^! Y测试代码' ~: m8 f+ x2 [8 t
- fm25cl64_init();8 }1 G0 M; o6 r8 U& w; ^, W
- fm25cl6_write_1byte(0,0xAB);
) T% R9 Q8 z* O. ` - GG=fm25cl6_read_1byte(0);
& L& ]9 y2 n" f. X - // fm25cl6_clear_data(0,1);9 P6 Z0 T! `5 a. ]: m1 o& E& X2 {
- fm25cl6_write_1byte(0,0xCD);
8 ` }$ l- M: Q( M! K* { - GG=fm25cl6_read_1byte(0);
复制代码 p5 P2 ~' `8 B$ p
. Q1 p2 x$ _( \" j4 d* }$ J |
十多年来一ˊ直在用 24C64 的 FRAM 路过...+ k$ N! }' U3 g+ v' w2 B$ z( Q9 g