分享一个代码模块,网上找的一个STM32的SPI2通讯的FM25CL64历程,我自己结合自己的板子改成SPI1很快成功了。1FM25CL64确实简单,通讯和使用都比W25Q64容易6 q4 u# _# ? A5 J% O0 E6 \7 x
2写之前没有必要擦除 类似EEPROM) L" W! A8 M: ?3 ]" G3 d; w
先看我板子原理图
4 r) [6 C9 c; K& D2 V
) F( Q' }6 s1 {- j( A, H两个存储设备挂在SPI1上,CS脚铁电就是PA42 Y8 e" U+ b: r! W7 Z3 \0 L. S: d
上代码:
8 K: [" ~8 S5 f, W( q9 q% g4 E- #ifndef __FM25CL64_H_1 \% \/ ^ n, z. Y& ?6 O9 e
- #define __FM25CL64_H_ ' k: \0 N& s* p" A! J
- #include "sys.h"
0 y' w+ a1 O$ [1 `# {5 Y - & J$ V: w8 a; ~7 X
- , g: l8 E5 O' \$ M$ {6 y
- #define FM25CL64_CS PAout(4) //FM25CL64片选/ t# J: l; M" d/ b
" x+ ?! T5 L0 j; q! {' X3 P. l9 ~7 F- ////FM25CL64指令定义
+ Y& V; p+ q8 ]) M$ r. G - #define FM25CL64_WREN 0x06 //使能/ y* r' R- @9 d. J6 ?4 ]
- #define FM25CL64_WRDI 0x04 //失能# [/ }& }& `9 k9 [2 t8 j
- #define FM25CL64_RDSR 0x05 //读状态4 P4 ]& N7 _' H8 C: J0 r' N r
- #define FM25CL64_WRSR 0x01 //写状态( L b% h" u% ]2 L, X
- #define FM25CL64_READ 0x03 //读数据: E6 ?* y* e" U
- #define FM25CL64_WRITE 0x02 //写数据1 q+ N$ b4 k9 _) z2 C. D
- ; o! i% ]- q( ?" o8 w
- void fm25cl64_init(void);//初始化) D1 |" l5 O& p& `) q# b* ^
- uint8_t fm25cl64_read_sr(void);//读状态8 N0 |) i1 v8 Q! a6 `5 B
- void fm25cl4_write_sr(uint8_t sr);//写状态6 r; i/ p' u& o, k" ]$ I% n
- void fm25cl64_write_enable(void);//使能 ~+ C' G. h$ _ C
- void fm25cl64_write_disable(void);//失能: {( _4 z1 m9 {. I
- void fm25cl6_read_nbyte(uint8_t *pbuff, uint16_t read_addr, uint16_t read_byte);//连续读取N个字节
+ u U5 t1 b! E2 I8 ?# \ - void fm25cl6_write_nbyte(uint8_t *pbuff, uint16_t write_addr, uint16_t write_byte);//连续写入N个字节
& |* h" F# E2 a" I! ~7 N - uint8_t fm25cl6_read_1byte(uint16_t read_addr);//读取一个字节
( t0 g! G0 [3 b2 ]* R$ |& J- y - void fm25cl6_write_1byte(uint16_t write_addr, uint8_t write_data);//写入一个字节0 M# d O7 \; j1 [3 n* S. t$ Y
- void fm25cl6_clear_data(uint16_t write_addr, uint8_t len);//清除LEN长度数据, H+ l' }1 r! J) R1 @
- #endif
! p/ Q A2 O. w) o- l2 M& Z/ G' l - & `& W* O8 M6 g7 U, ]
- ) V3 l9 T0 @( o; S0 u8 [6 G; R
- , W8 b; b j1 X' ^% C! `1 ^3 a0 N% y
- 8 T/ i& v( i. H" W$ U
- $ M B; b0 S$ }$ M4 g
' w7 ^3 D& ?+ S$ a- . d% F. X% F/ i( W
8 ^$ o; |/ s( ?* F5 k
; Z( \2 d, Y8 I) A8 L8 n
复制代码
6 s& |0 x! ^, E3 p3 N* E3 g. F' q! z) S: Q9 m( q9 q' Y4 U1 N
- #include "fm25cl64.h" 7 l; o( S O. h! N
- #include "spi.h"2 X1 m& S" d+ }' O' j4 G
" I: L# f) v; v' B0 Z+ Z; Q* n4 \
5 N% L" }+ Z) I, @3 x- g7 C' S- - h# c/ r3 G/ \/ A; C* e
+ \$ r, U1 S8 I/ n9 g9 j8 Z, s
9 p7 K7 D: R5 P" S# D- /*********************************************************************************************************& S* x% M0 b6 `3 K" K+ e: F6 f
- **函数名称: void fm25cl64_init(void)' M& c7 \3 r; X' z6 y0 m6 p
- **函数功能:fm25cl64初始化
9 K" ]- t% I" @ |% P$ W; y5 W - **入口参数:无
/ o3 s j$ H) R1 M3 X2 s4 A - **返回值:无, o7 m' y& Y8 h9 ?5 H0 z8 y! O( Z
- **注释:
1 P7 A* |+ a) n- ?+ p - **********************************************************************************************************/
2 j2 c$ C$ i/ u0 d$ F - void fm25cl64_init(void)
; j2 X2 `1 U* ^$ J8 ]9 z6 Q - {
+ G- S2 O3 v- A, w8 r) h - GPIO_InitTypeDef GPIO_InitStructure;
" r, A% ~ n/ S' [% V - $ U; `9 e% B W1 D& f
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE );5 a7 o3 r0 R! |8 c8 g' O2 y
& r% F* a. }8 c7 L. K9 j$ j- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
$ c+ E1 f, e' P - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; % a* o- V0 T4 t) Q$ \4 d
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;8 u9 L1 H* W4 F! p9 {
- GPIO_Init(GPIOA, &GPIO_InitStructure);
& \0 k6 @; C0 O! m+ o% P1 K, Z; E - GPIO_SetBits(GPIOA, GPIO_Pin_4);
4 |, s$ C2 N* m' J" a
- U. O9 Y. a2 b/ @1 c8 e- FM25CL64_CS=1; //SPI FLASH不选中: F" T6 O8 s V$ k7 W: ~" j
- SPI1_Init(); //初始化SPI
" @# M! w- |$ g& D, R - SPI1_SetSpeed(SPI_BaudRatePrescaler_2);//设置为18M时钟,高速模式5 |. }% v2 u- a v# e! D
- }4 ]7 `( O# P1 [- _
1 T4 z- E, U. q5 r7 K1 `- /*********************************************************************************************************4 q6 ?& [. q4 {$ I9 l o- ]$ l; _7 Q4 W
- **函数名称: fm25cl64_read_sr
$ o g5 G, m" Q; q2 z - **函数功能:读取fm25cl64状态5 s" q7 @8 @' k4 M( _
- **入口参数:无
6 Q. P: t; B" K/ A - **返回值:读取到的字节
, R9 G. W) e7 o! j \1 Q; x - **注释:
6 T1 C+ ?5 H- ^ - **********************************************************************************************************/2 V O% J9 N& l( K* E
- uint8_t fm25cl64_read_sr(void)
- V; U4 P) {+ C) }9 | - {
. F4 b2 o+ D- x7 |/ v5 l! o5 }+ a% H - uint8_t byte = 0;2 T! ]. L, e: _4 {
- 3 J/ c, W4 _* s1 Q
- FM25CL64_CS = 0; //片选
+ C1 @6 d) }6 U% Z - SPI1_ReadWriteByte(FM25CL64_RDSR); //写入读状态命令
3 u- K$ z) Q/ m( a3 x - byte = SPI1_ReadWriteByte(0xFF); //写一个空字节再读数据
+ f u( @2 n: J2 [. {6 V - FM25CL64_CS = 1; //取消片选
( G" M$ v' s3 m3 V( }7 o# Z -
) |( K) U/ `1 E1 m5 o3 M - return byte; //返回数据- W- }! x# Q# w& V) d7 W; \& ?4 q# d
- }
* A" |, v$ }3 x* F9 \$ i/ A
% I) \ p2 u' m: t; h$ m- ; |/ n9 i! l6 P4 N% t3 M
- /*********************************************************************************************************
, h- A% l6 L; x - **函数名称: fm25cl64_write_sr, O; w" }4 E$ U) o0 X; Y- ~+ z4 u
- **函数功能:写fm25cl64状态 o; e6 \0 d& U# N+ A# W- k
- **入口参数:状态数据
& F& V' H) h0 L" L, K/ x - **返回值:无
. G( |" T, o; `6 d7 K5 u( A# J - **注释: a1 U' P2 K; B, h- J# ~
- **********************************************************************************************************/
- e) L' [) Y1 O% d9 g; J7 g" ^" U - void fm25cl4_write_sr(uint8_t sr), `# r7 t6 d9 w* @
- {
% ], U' m( h9 {4 y5 B" S9 [ - FM25CL64_CS = 0; //片选6 p0 J, k! o* |+ Q. u1 P/ \: k6 o
- SPI1_ReadWriteByte(FM25CL64_WRSR);//写入写状态命令4 S2 o: p7 x8 h* V
- SPI1_ReadWriteByte(sr); //写入状态数据0 _; g6 ]0 h/ `% A. Z1 c/ R
- FM25CL64_CS = 1; //取消片选) { ~3 ]. ?' r4 g8 K
- }
1 q: t# h% X5 p
$ T( P7 N* m0 F$ ~7 R8 a8 F- % g+ d I O5 S& Z$ B% ~8 \1 c
- /*********************************************************************************************************% z$ S% g; ^ G: `+ X% e
- **函数名称: fm25cl64_write_enable
3 O5 s& {8 j/ B5 }0 @- u8 Q - **函数功能:使能FM25CL64
" |( m4 \% C" A4 | - **入口参数:无$ ]: H. H: B5 K: k6 ?" g
- **返回值:无: f% I' {' r) W: y0 r
- **注释:
/ J5 W7 _: g$ V( o% f1 V2 B - **********************************************************************************************************// F% L% l9 a8 [" ~7 \3 Z. s1 d
- void fm25cl64_write_enable(void)
. M" P; Q c- H) j1 J9 J5 L, A+ P+ h - {
? k9 q. Y4 Z, M - FM25CL64_CS = 0;//片选) f* j; A; g! s, v. ?$ ^
- SPI1_ReadWriteByte(FM25CL64_WREN);//写入写使能命令4 W2 ^( B* Q! B* D
- FM25CL64_CS = 1;//取消片选( z5 n H0 c9 ` B+ `$ g( [
- }
) \8 H% f% O$ V; m6 ^4 R - - g. z) Q3 n9 j0 v5 p) n( S! |
4 v$ i4 o: x* ]# O- E- /*********************************************************************************************************+ c% _- t/ g6 T9 g) {/ g1 |4 r7 h
- **函数名称: fm25cl64_write_disable
7 g- H$ w9 ~( u* @& C3 [4 o - **函数功能:失能FM25CL64! ^5 \3 u0 l% }/ }- K+ E
- **入口参数:无( E8 w: D q; r, U) o3 z! S
- **返回值:无
. E4 o. ~# y. X' ^% U6 a, s - **注释:5 t8 D8 H' {6 u8 e
- **********************************************************************************************************/0 P' K1 X+ _- a ~( ^! {
- void fm25cl64_write_disable(void)% J8 {+ F z( r( O( Y* E8 `6 I
- {
( B& ~+ n9 A5 I/ d - FM25CL64_CS = 0;//片选( Y0 N" J" A. X, p
- SPI1_ReadWriteByte(FM25CL64_WRDI);//写入写失能命令
6 S( w$ ^" m) E F - FM25CL64_CS = 1;//取消片选2 N" [% {- [: Z$ G6 K0 v
- }5 p, t6 y& f3 w4 c
& |6 K- ~. p: e `2 w. G" C' x- # U! W8 s2 P) `1 F, T
- /*********************************************************************************************************% ]1 ?% b# ?7 M" y r1 h
- **函数名称: fm25cl6_read_nbyte! F& D x" U% S9 D! i
- **函数功能:连续读取N字节数据# g0 e$ A- a. o" t. q
- **入口参数:*pbuff,读取数据到指针,,read_addr,读数据首址,,read_byte,读多少字节( V2 b% r; P4 h
- **返回值:无
, m: d( b! k9 u' I3 w7 B& P# H$ E - **注释:' h0 u- Q# U; L' [% L7 J
- **********************************************************************************************************/
% a& ?+ \# ]8 I - void fm25cl6_read_nbyte(uint8_t *pbuff, uint16_t read_addr, uint16_t read_byte)
: `" n3 A G) q, e2 Y - {
; X' d1 D3 a0 w! E1 d, X7 Z. i$ V - uint16_t i;
2 c$ V) [$ {0 E. ~& n e& w* c -
1 J) A6 f, E, p( d -
% _6 a2 D; ?8 K5 T* @ - FM25CL64_CS = 0;//片选
" I! Y2 j0 I5 S1 k Q3 z4 Q/ N - SPI1_ReadWriteByte(FM25CL64_READ);//写入读数据命令% @2 E1 x/ t' v+ ~* m0 [
- SPI1_ReadWriteByte((uint8_t)((read_addr&0xE0)>>8));//写入高8位址,最大地址13位
, |' X$ f- P x$ a D - SPI1_ReadWriteByte((uint8_t)(read_addr));//写入低8位址,
0 O6 e7 F) \, Q( L$ p. { -
: g3 M0 \, w$ H- ?- i( I - for(i=0;i<read_byte;i++)//连续读取数据 f: g0 |: |% K" i" G
- {
6 v9 B2 C: ?, z2 |, j3 @1 w - pbuff[i] = SPI1_ReadWriteByte(0xFF);/ t$ s/ b @; G
- }! H$ T$ g- P' M6 q
- FM25CL64_CS = 1;//取消片选
7 S$ _1 x( t( d9 o - 3 n7 ^& Y$ Q+ E& A
- 2 z4 X7 H W6 \, Q: ?
- }, m$ j( s7 U1 s ?, ?' k
- 5 g ?# e% q& v
5 m' \/ ]+ c* U! V- /*********************************************************************************************************
7 {! ~! g$ o8 s { - **函数名称: fm25cl6_write_nbyte" s' n* a* ?3 o6 i, R. W: z1 _: [
- **函数功能:连续写入N字节数据8 y- X J; y4 X, P: y- j
- **入口参数:*pbuff,写入的数据指针,,write_addr,写入数据首址,,write_byte写多少字节- `# x l% `1 A+ `! W2 z0 k' Y
- **返回值:无( s' @- |9 ^; p; h
- **注释:
& \$ D; t+ u: z8 ~5 g0 E - **********************************************************************************************************/8 i8 i$ g9 {6 _% Z/ q- ^
- void fm25cl6_write_nbyte(uint8_t *pbuff, uint16_t write_addr, uint16_t write_byte)* W8 e* ?' t% x& f' z
- {% I Y0 V: R4 v1 @
- uint16_t i;
! ^' W: |8 O$ c' Y- W - , ^! h2 k3 a3 _2 u) M" s( {
- # X# b' H# Z/ q
- fm25cl64_write_enable();//使能写操作,一定要先使能,取消片选后再写作下面操作4 k( `: V0 c8 o
- 0 c! s! h2 N+ L, \& ?7 y G
- FM25CL64_CS = 0;//片选- s5 ^9 I: }2 T1 C1 ]: }7 K
-
9 y% s+ D. c7 x: O - SPI1_ReadWriteByte(FM25CL64_WRITE);//写数据命令4 M7 b1 t: O. a! D! u+ W' N
- SPI1_ReadWriteByte((uint8_t)((write_addr&0xE0)>>8));//写入高8位址,最大地址13位
# \; [; e$ c: ^- J: b; t1 L - SPI1_ReadWriteByte((uint8_t)(write_addr));//写入低8位址,
9 I, j- ?- X( }/ i. z - $ C) G/ N" f* c( j3 c) M
- for(i=0;i<write_byte;i++)//连续写入数据 r+ }6 E; w2 N
- {# v& }; ^/ h/ W8 x9 o v
- SPI1_ReadWriteByte(pbuff[i]);
* q' e$ P: ?% R9 U, W - }
& P& [; h' {, o. q - FM25CL64_CS = 1;//取消片选) L' g+ o1 [" r* H$ F# n; z# q
- }
7 [8 w# A$ j4 ~1 M6 d f3 ^0 |
' B1 ` J; Z6 \0 L- A
! V. F3 G' I1 A0 D" M
4 j3 u" P9 M1 d* J x- /*********************************************************************************************************- z) E6 O4 Q: [! o3 O1 f
- **函数名称: fm25cl6_read_data_1byte
! \4 E, d# k. l) u5 @8 l6 b8 e' J - **函数功能:读1字节数据
( g. n" _( Y8 D/ V6 } - **入口参数:read_addr,读取数据地址
2 I2 ]2 v# `1 {: B" N1 z - **返回值:返回读取的数据6 z) [) S) @4 P! G0 l* U3 V
- **注释:, Z- A/ m6 W0 }* P! C0 D! J
- **********************************************************************************************************/
, {$ ^6 i, _" X$ J2 x - uint8_t fm25cl6_read_1byte(uint16_t read_addr)( U' y; X& I' \8 ^
- {3 V1 k0 x; u$ S0 ]/ [
- uint8_t dat;
) ~* _# }9 ^; v% _ - # h/ Q2 J3 Z9 v1 m$ R0 y0 C" G) n
- FM25CL64_CS = 0;//片选
- C; r' B2 n2 a4 j" }' j/ |1 g - + R! q4 t8 J. w
- SPI1_ReadWriteByte(FM25CL64_READ);//写入读数据命令
! u7 T7 V* j3 J! O" y* I) A - SPI1_ReadWriteByte((uint8_t)((read_addr)>>8));//最大地址13位+ I4 f1 @ D# ?
- SPI1_ReadWriteByte((uint8_t)(read_addr));//' b% z m- z( g% t& ~& ?
-
& z* @+ x& X8 v! E/ S9 a. Q - dat = SPI1_ReadWriteByte(0xFF);//读一字节数据
! I# m; o7 d: [0 a0 B- I1 L - $ M' |! T1 _/ `% t/ o9 y# C+ U
- FM25CL64_CS = 1;//取消片选
; Q; J6 k! H3 s: a - D6 J9 @/ Q p; g( [
- return dat;
* M3 b( e4 k) |* b - }1 o3 O4 d* ~( i6 u' ?- S
; r! @0 A, F. I
" V, ^; s# H: P* N- /*********************************************************************************************************7 }$ i! A+ O" w' {
- **函数名称: fm25cl6_read_data_1byte4 J& L. k9 ]" q4 s! b% ~$ j1 D/ v
- **函数功能:写入1字节数据
- ?. G: N1 A/ m9 p7 x8 ? - **入口参数:write_addr,写入数据地址,,write_data,写入的数据
, G$ `. e2 S. O0 G - **返回值:无% p3 C/ u9 ^" d/ Z
- **注释:
+ V5 Z2 U9 G& ~/ D - **********************************************************************************************************/
) c' |+ X: H" T, i" ~. I% E& Z3 _ - void fm25cl6_write_1byte(uint16_t write_addr, uint8_t write_data)2 ^: W' i+ ~6 x S1 i
- {
4 ]" t/ ^) ]$ C8 H - ) `3 x. n; s+ Z7 d, s& m Y
- 2 {6 J V! @+ K: A
- fm25cl64_write_enable();//使能写操作,一定要先使能,取消片选后再写作下面操作
) p: X) D. f. h3 h - 4 L) N3 H+ [ v8 D- z; @1 F
-
' c3 u1 E' K# o' Z2 j& U" y+ a - FM25CL64_CS = 0;//片选0 p- ^5 z# w+ U" m; [% A
-
# v; X5 y7 C* j# o: i% p. E! c - SPI1_ReadWriteByte(FM25CL64_WRITE);//写数据命令: f, P D3 b9 o
- SPI1_ReadWriteByte((uint8_t)((write_addr)>>8));//最大地址13位, i: v7 ]7 N# e/ b( C
- SPI1_ReadWriteByte((uint8_t)(write_addr));//! H: R& l" b `# V$ t. S
- & N' x' S9 ? H! ^6 v) v
( _7 c+ f+ }) t% a- Q! s- SPI1_ReadWriteByte(write_data);//写一字节数据
7 s5 P' g4 m* _5 s1 n* ]0 b' Z
4 S7 s2 Y' `) w+ t9 V2 O! S% G0 u- FM25CL64_CS = 1;//取消片选# V0 }4 h. k1 S l9 X" z
- }
3 X7 v, l( U; U/ ~1 M ^$ |
; R0 E8 a( y: {9 F8 h7 _! K4 R
5 b* c5 Y" B# ?: j+ r: X- /********************************************************************************************************* [+ n$ z8 h. J) Y i. o1 F# \2 r, U0 ?
- **函数名称: fm25cl6_clear_data
+ E$ r* u) x. A0 F$ Y# T - **函数功能:清除指定长度数据
- L$ C0 g* v5 Y" @% Q) D - **入口参数:write_addr,清除数据地址,,len,清除的数据长度( O+ x) c$ K: {4 P( d; I
- **返回值:无+ S1 ]) M) M E) m
- **注释:& C( y5 u" Q* x+ c
- **********************************************************************************************************/, U0 B) R. d8 r) g) R; C$ P
- void fm25cl6_clear_data(uint16_t write_addr, uint8_t len)
9 e) V' q+ r# Y- t - {
6 e9 H1 ^- K t3 z! t
* D) U' D3 J3 V- 0 ]% z F4 e$ Z6 c
- fm25cl64_write_enable();//使能写操作,一定要先使能,取消片选后再写作下面操作* {; d/ t# |" p4 p& ]
- " q4 Z C8 h! A" R0 X2 X$ y9 l
- # K1 \. g5 F& b4 H; j$ @7 M& J5 Z
- FM25CL64_CS = 0;//片选6 y# Z9 J8 I; D4 L5 u
- h+ Q0 J& ^( |. M
- SPI1_ReadWriteByte(FM25CL64_WRITE);//写数据命令0 @ l; B" i% d7 m6 N- t9 E g( u# C
- SPI1_ReadWriteByte((uint8_t)((write_addr)>>8));//最大地址13位
0 j/ m4 h5 h( c9 U) A5 a+ N - SPI1_ReadWriteByte((uint8_t)(write_addr));//
g6 a( U& p% D2 o: t - 1 F. L. O6 V, u
- while(len--)
; W9 b( M: J. j4 h8 \2 Q - {
* H2 @) p& H1 i' w$ g - SPI1_ReadWriteByte(0x00);// h% u( |1 Y4 M G8 K- L2 X
- }" i: I1 X- E5 `6 _7 |' O) e1 r% R
- * z; Q: l) p/ F$ D& ~. }6 f: F
- FM25CL64_CS = 1;//取消片选8 S# k; D" l& ^2 N! l
- }( \; o0 Z% ?/ Z% |8 i
- 1 @- O% L. o1 }( o
- . z! q6 G- U& D& V7 M; C
8 \1 p" S! D& A, q3 y- $ z0 B& s' x% q6 @$ b* t
" L6 X/ Q5 ?# W4 Y! |- ( L/ b, M: _8 E2 q
7 `% _: H5 e& k {% r
- U5 B9 p/ @' x% @1 q2 t- 5 f" [. ^7 r w+ s0 ?4 a
- ( [; p7 @3 U) B3 v
7 t" V( y5 \+ S0 @6 Q
复制代码 其实如果面向接口编程,模块调用SPI的函数SPI1_ReadWriteByte还可以抽象,以备可以切换为SPIX_ReadWriteByte。
' m9 H) z9 j! C: R! X3 P3 Q# r# Q4 F; Y5 {! U( ?& [& t9 |) W+ e
测试代码
; z1 Z! M z) g5 H% X& K, _- fm25cl64_init();* }, p1 l7 m! k8 @
- fm25cl6_write_1byte(0,0xAB);$ s6 K' V5 a+ \7 c# V. y% \8 }6 Z
- GG=fm25cl6_read_1byte(0);, D. d: K n# l* W7 ]
- // fm25cl6_clear_data(0,1);: O. a% ?) d* ?5 q0 S
- fm25cl6_write_1byte(0,0xCD);
% x5 T+ W! U5 E# }3 A+ _' F - GG=fm25cl6_read_1byte(0);
复制代码
* h9 @2 B9 k! |# h) a! i
* C* i k9 J N' y W& S |
十多年来一ˊ直在用 24C64 的 FRAM 路过...1 ]1 t8 e3 i" h# {4 h" P4 j/ p3 a S