分享一个代码模块,网上找的一个STM32的SPI2通讯的FM25CL64历程,我自己结合自己的板子改成SPI1很快成功了。1FM25CL64确实简单,通讯和使用都比W25Q64容易 c9 R2 I j, j$ E9 w6 o
2写之前没有必要擦除 类似EEPROM4 j+ I- O: M9 o9 M
先看我板子原理图( E# _, e. B* B! _
% G- ^, v2 W0 P5 }% V9 e! I两个存储设备挂在SPI1上,CS脚铁电就是PA49 ?3 R8 V, G0 x4 ?; I
上代码:
" k S* S+ R% v; Z- #ifndef __FM25CL64_H_+ ]5 u D- ~( _" ^' ?8 Y: S
- #define __FM25CL64_H_
" W u0 ^7 ?! j& c- i* {# `% j - #include "sys.h" + Z8 _2 g; x4 _; K7 r' ^# ^
- 5 e8 E, M9 D! C2 X2 r6 o9 p* l
( N/ `* k, B \6 k! s+ M$ `3 E) o: z z- #define FM25CL64_CS PAout(4) //FM25CL64片选+ m- K" e" U7 v; ?% m
- 0 |8 B3 s$ _! n9 [+ n9 A1 @9 \$ [) W6 B5 M
- ////FM25CL64指令定义- T6 ]5 P7 s7 {
- #define FM25CL64_WREN 0x06 //使能3 j K# }- G8 a' ^* b& _) a# @
- #define FM25CL64_WRDI 0x04 //失能) A& o( c" e8 r8 Q
- #define FM25CL64_RDSR 0x05 //读状态
! T9 B, t+ x6 X2 a9 j, e+ S - #define FM25CL64_WRSR 0x01 //写状态
8 |* l2 |1 S2 k* ]+ q- M( J r - #define FM25CL64_READ 0x03 //读数据
% S( m) }7 S& l( X! U) Y2 q - #define FM25CL64_WRITE 0x02 //写数据
4 | t) Q) w4 c+ A: o& p' U3 b4 S
, }' d6 E4 D/ d: F: e8 `0 o- void fm25cl64_init(void);//初始化
; m T* n# v5 L1 \ - uint8_t fm25cl64_read_sr(void);//读状态
: S( a" V+ _. E! J) Z6 ]# s$ q - void fm25cl4_write_sr(uint8_t sr);//写状态1 T* q& ], L: R v
- void fm25cl64_write_enable(void);//使能
/ u/ H/ ?. n* }& P+ k - void fm25cl64_write_disable(void);//失能# j; w! Y3 {$ n$ B
- void fm25cl6_read_nbyte(uint8_t *pbuff, uint16_t read_addr, uint16_t read_byte);//连续读取N个字节# H0 w3 s$ K# ]. \8 x4 Y! v d, P
- void fm25cl6_write_nbyte(uint8_t *pbuff, uint16_t write_addr, uint16_t write_byte);//连续写入N个字节
. O, i2 u8 N6 M7 K: L$ F0 Y1 f: F - uint8_t fm25cl6_read_1byte(uint16_t read_addr);//读取一个字节
* j3 f1 ^- T/ ^3 W - void fm25cl6_write_1byte(uint16_t write_addr, uint8_t write_data);//写入一个字节
" N& j$ g' }9 h" F - void fm25cl6_clear_data(uint16_t write_addr, uint8_t len);//清除LEN长度数据
: x' S f$ M* U2 ] Z) j - #endif, \/ A. N. m: v$ `5 l+ T7 ^
: G, [" H% B$ a" a- ! H* W# R9 ?' A4 l/ E4 B# Y
- ! j' O% r+ K j ~& S
- + _1 G: w5 y- {) A
- ; c0 X3 w5 U6 j+ y
- [" L: U( H* k( F
5 k0 y; [' L4 i. ]
L5 z8 k, c* |, I
6 [, f+ K$ ?+ D: G2 W
复制代码
2 k8 k' z' n; x+ k' t$ u
, i! F. b3 ~& M& G- #include "fm25cl64.h"
. ^* o/ R& k; e F$ G6 P - #include "spi.h"
" E5 C. s0 M- z! i/ q; t( f
2 `; f) {. I- Q: |3 \' z1 H" i- # A9 R1 r0 R/ H
, A7 [6 T4 I' S- 2 d/ [2 c& ^" f
- 8 {1 E- k. W/ O1 R7 d% R
- /*********************************************************************************************************6 u5 q# z7 f1 J& L
- **函数名称: void fm25cl64_init(void)
2 T( k+ h2 s) f) j1 C8 a2 Q - **函数功能:fm25cl64初始化3 `9 e( n; X. C; s) P
- **入口参数:无
$ R2 L ^9 x4 e$ k - **返回值:无
4 c4 J! l* U* E# i& H - **注释:0 ~# L; S, G3 s
- **********************************************************************************************************/# q1 A" z- G* H
- void fm25cl64_init(void)
, Y! R$ A" H; F - {
, Z3 M, D6 T' K# V - GPIO_InitTypeDef GPIO_InitStructure;0 }" d% \: m3 M9 \( v
- ) O+ [, {, Z) u% e% m
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE );2 H% }: X7 e8 i
" I0 n9 Q6 U5 ]0 ^- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
5 n4 ~) N6 m* y - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
/ g& W" T k( R1 J$ z8 u* u - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;# _. ^% G4 h3 Q- U
- GPIO_Init(GPIOA, &GPIO_InitStructure);8 ?0 ~" Y+ @- u4 T- k1 p8 G/ {+ F
- GPIO_SetBits(GPIOA, GPIO_Pin_4);
' A7 Z+ D6 m& @5 | - 1 I+ P0 U/ w: F) j; O" _
- FM25CL64_CS=1; //SPI FLASH不选中
3 O$ d2 g- X( B: | - SPI1_Init(); //初始化SPI. R1 P5 I' l- t% D# `! e! |
- SPI1_SetSpeed(SPI_BaudRatePrescaler_2);//设置为18M时钟,高速模式; {2 J3 m9 \ u
- }
" i' Z4 L% {2 J$ ^
; H% n* U* Q4 x& Q- /*********************************************************************************************************
, J M3 ? l3 r( B2 F; f - **函数名称: fm25cl64_read_sr
* `% k* [( B( |+ g) q, Q+ z* t - **函数功能:读取fm25cl64状态% }9 T U, Z9 y) |! ] z6 K" W
- **入口参数:无# V( {1 Z& ?, }- A' b) l: T
- **返回值:读取到的字节
7 g) m+ \8 A/ x: z - **注释:2 _3 h. Z5 D }' l, P# Y `1 G+ G
- **********************************************************************************************************/
2 u! A3 t# s4 g7 `% ? - uint8_t fm25cl64_read_sr(void)
: |: l3 l4 U1 T - {
! m7 V5 W- C/ D7 S3 s* v' Y - uint8_t byte = 0;
7 @7 N0 u' s( P$ A( M5 o - 3 j9 f$ Y7 r9 d0 y
- FM25CL64_CS = 0; //片选0 `- Z" U5 {% w" j
- SPI1_ReadWriteByte(FM25CL64_RDSR); //写入读状态命令
. S& G F! I; Y$ A; D - byte = SPI1_ReadWriteByte(0xFF); //写一个空字节再读数据- W- U& w1 d }, Z8 D, A
- FM25CL64_CS = 1; //取消片选/ f; J' l6 F& r4 I0 j
- / v' y& _' c" x$ n
- return byte; //返回数据+ x2 x6 a7 _5 X( q4 f
- }5 X+ g* T3 ?; V0 K* _; C% \
- 4 L" b- @& m5 H3 U) Q1 ^
" N: X2 p' D9 K- /*********************************************************************************************************
7 u7 U# S* p4 r3 O. n& y - **函数名称: fm25cl64_write_sr
! y" T4 n# ~% Y# H; e& y# | - **函数功能:写fm25cl64状态
x5 L; v/ A6 W; h! |, m8 P/ G3 z/ z1 m - **入口参数:状态数据
0 Z, s/ Z' n4 ]1 }) y) U - **返回值:无! V+ ?, D( y& t# n: k* F6 @
- **注释:
- F* \, B7 T& b0 F7 E9 m4 N - **********************************************************************************************************/
( w$ M# }1 v% G4 B% j - void fm25cl4_write_sr(uint8_t sr)) ^( d8 ?0 B4 L, o& d$ Q( ?8 F
- {# b; x H: O" ?# G8 ~! s
- FM25CL64_CS = 0; //片选( S5 `9 ^0 c' o) N
- SPI1_ReadWriteByte(FM25CL64_WRSR);//写入写状态命令
7 V' _7 O/ p2 t" ?9 u! d6 i# V - SPI1_ReadWriteByte(sr); //写入状态数据: [3 E9 N' h; f* f
- FM25CL64_CS = 1; //取消片选
1 P, Y+ h2 x. V - }1 ^/ n6 @5 x: b9 t$ x4 g8 B9 z
! X0 f- t+ |# y8 }" P- 8 N9 t8 y- v" H+ l/ x, j
- /*********************************************************************************************************
# M. c* N) ?! i3 X2 g3 a* O2 m - **函数名称: fm25cl64_write_enable6 M5 a" M$ f$ @6 D# Y, r. R& z a
- **函数功能:使能FM25CL64( D2 H0 ?2 P+ o" @
- **入口参数:无5 v) I# X; [& Y" Q
- **返回值:无
, o( P* c8 j# q) N+ H) a1 u3 N4 _ - **注释:8 O3 Q3 Y& g0 y3 W6 Y+ R
- **********************************************************************************************************/
/ E O# E! X) S2 { - void fm25cl64_write_enable(void)* ^0 N. h. m- S
- {
/ x$ k- t2 O+ S) q7 b9 o/ ?3 l - FM25CL64_CS = 0;//片选" f. }5 u( w9 l9 Z% ]
- SPI1_ReadWriteByte(FM25CL64_WREN);//写入写使能命令
5 y/ ?! t2 l. z- T - FM25CL64_CS = 1;//取消片选- d ~1 Y' z' A/ u/ `- _
- }9 S5 h$ q O, h1 R4 k1 f
- % |2 ]! }8 a8 q2 P0 l5 d- r+ Q% t
6 Z# U# E% w' X! ]% ^- /*********************************************************************************************************, w8 G* B# u/ S- D, ]* I6 d
- **函数名称: fm25cl64_write_disable/ U" g. M7 [ h+ j
- **函数功能:失能FM25CL64
) j! r5 w% s0 u. k0 F - **入口参数:无
4 I0 _0 B7 m6 u# z - **返回值:无1 M" C, h# I2 P% A" a; J
- **注释:
2 z( X" p7 ]: ?6 U6 X# y/ `& j - **********************************************************************************************************/
, H5 e6 N; F9 f4 a7 k" Z - void fm25cl64_write_disable(void)/ P# N \/ N7 L5 G# o7 a/ }5 L
- {
/ i$ G3 ]5 d9 R - FM25CL64_CS = 0;//片选" F/ w2 [) A7 x% P9 }2 X6 ^
- SPI1_ReadWriteByte(FM25CL64_WRDI);//写入写失能命令1 d: O6 F% j0 e) A* f# ?; k, Y
- FM25CL64_CS = 1;//取消片选- M5 |& F$ ^* h$ |' I( ~
- }& u; Y* S; ]* ` [! A# F
8 _7 R; o9 @& D1 H |- 1 h1 a) { q# W/ i1 o
- /*********************************************************************************************************
; f# \, ]: _+ g r3 r - **函数名称: fm25cl6_read_nbyte
" D! z B6 \! n9 \0 w6 R5 f - **函数功能:连续读取N字节数据
+ M1 j! [1 C6 G( w7 B" s - **入口参数:*pbuff,读取数据到指针,,read_addr,读数据首址,,read_byte,读多少字节
4 X3 i; p0 J6 k - **返回值:无5 v8 s! N; G3 L
- **注释:) R; \1 ^0 ~# _" V5 L: W
- **********************************************************************************************************/$ ~$ L) ^4 \0 O" E
- void fm25cl6_read_nbyte(uint8_t *pbuff, uint16_t read_addr, uint16_t read_byte)
/ \- g8 b, r( K N2 E4 F, \ - {& B$ Z9 d6 J( S2 ^% {5 i
- uint16_t i;& l: o" \# k" J3 ?; M( |
-
5 J/ _1 x0 d. F - , d) W/ N1 l1 @( ^/ n
- FM25CL64_CS = 0;//片选4 R7 S% @# C2 D
- SPI1_ReadWriteByte(FM25CL64_READ);//写入读数据命令( A- K% i+ C j6 H8 B: Y( W
- SPI1_ReadWriteByte((uint8_t)((read_addr&0xE0)>>8));//写入高8位址,最大地址13位
# |: O3 W# M1 B! I; M+ v) V V - SPI1_ReadWriteByte((uint8_t)(read_addr));//写入低8位址,
8 Z/ Q1 s" |+ H/ k8 h: x& z3 [ - $ K. a7 @. |7 \) b; W" H1 v4 S- W' C
- for(i=0;i<read_byte;i++)//连续读取数据6 O, i0 B% ^2 m1 s1 N, m
- {
9 \1 l x4 k& k - pbuff[i] = SPI1_ReadWriteByte(0xFF);' N8 C3 i$ ?% J. ^1 L/ _
- }; m/ T- t# v9 R4 X& E. z8 i t
- FM25CL64_CS = 1;//取消片选
. c2 G! p5 e0 p( H* [ - 4 i' c# c! \2 j9 r( A4 y/ O
- ) S$ k. w3 @9 J$ X* u
- }, X5 ^4 m V/ A
- 7 x2 r2 D. H, ~7 b
1 P( m2 u+ u& ]+ ~. A! T, w" b- /*********************************************************************************************************- j" h0 w7 h" S
- **函数名称: fm25cl6_write_nbyte
; t* y# y& \. S3 w, ?% Y, a' j - **函数功能:连续写入N字节数据9 Q5 I. A3 {* v( [' ?) r- b \
- **入口参数:*pbuff,写入的数据指针,,write_addr,写入数据首址,,write_byte写多少字节
9 y; a. X6 {5 F' p4 ^& B6 W - **返回值:无
0 T# o R3 {; g9 Y5 Y7 ]* Z - **注释:* p z" F* `: O
- **********************************************************************************************************/
# f& C, n. F/ i2 Y! G( t" |" L - void fm25cl6_write_nbyte(uint8_t *pbuff, uint16_t write_addr, uint16_t write_byte)
$ m2 i* K/ u- c6 v9 J: N - {! M. g# M( h# Q$ J, [
- uint16_t i;4 u, p' b0 r0 f0 I$ o) o7 X: N
# x" Z5 \0 A }- K- ' {) R9 M! E4 Y' [2 k
- fm25cl64_write_enable();//使能写操作,一定要先使能,取消片选后再写作下面操作
1 V* S V/ U. H: e3 m0 p6 U - - M( `4 G/ j- j' Y5 ?9 G. s6 l
- FM25CL64_CS = 0;//片选
3 N& H' h% o# L G3 c3 d& v5 M5 P -
+ ~6 f9 Z7 A6 |. C! U0 A6 t0 F0 T - SPI1_ReadWriteByte(FM25CL64_WRITE);//写数据命令8 Q( y( M6 o! T7 A2 U
- SPI1_ReadWriteByte((uint8_t)((write_addr&0xE0)>>8));//写入高8位址,最大地址13位
: N/ w4 s3 e' N. `, ]; A3 ^ - SPI1_ReadWriteByte((uint8_t)(write_addr));//写入低8位址,
( i2 ~+ m' F; ^" b - 4 t( O8 o5 i2 h5 f2 w, y3 C
- for(i=0;i<write_byte;i++)//连续写入数据1 C. X* F9 U. y
- {
" P- _0 y: H4 H- j) C - SPI1_ReadWriteByte(pbuff[i]);
6 E- N$ D- b: t8 n/ h% A( P) Q) { - }# n6 E0 o4 y# L- |; C+ Y+ g
- FM25CL64_CS = 1;//取消片选+ {% T4 g# }0 y
- }
( {4 ^( Y. H( C- _
5 P$ O: |' k! w# K, H- ! L# o9 [* m0 B* z
- ' W1 \5 r' f3 F% B% m( \! G, g
- /*********************************************************************************************************& E% x5 O/ I* f2 L! H
- **函数名称: fm25cl6_read_data_1byte I$ v5 y5 p5 G$ [* ?
- **函数功能:读1字节数据
' z+ d3 j5 U" a: e - **入口参数:read_addr,读取数据地址" x* g9 M4 g# O. X# G% R
- **返回值:返回读取的数据 g8 y) ~7 E5 e) H1 d
- **注释: w6 h. A; |$ ?1 m4 R6 ~0 Y, ]% z
- **********************************************************************************************************/ F1 U, Q) ^; G# \0 K) [" Z0 Y! v
- uint8_t fm25cl6_read_1byte(uint16_t read_addr)
: B6 f/ d6 |7 |( w - {$ {- C5 m. g9 e ?
- uint8_t dat;
E, H5 v) j% h- i/ B/ G -
) `! F2 o5 K/ j) \6 [ - FM25CL64_CS = 0;//片选 v1 V* M& N, p; c( q' q; C
-
% F8 o! u" a6 y# F& c& T1 Z - SPI1_ReadWriteByte(FM25CL64_READ);//写入读数据命令
2 H$ L5 ]6 l$ I9 H0 | M& d, ~5 ?5 H - SPI1_ReadWriteByte((uint8_t)((read_addr)>>8));//最大地址13位7 E# R: H3 c+ G( v* ?* C. z* @' o( d
- SPI1_ReadWriteByte((uint8_t)(read_addr));//
8 L$ E& e# ~' a: `- Y+ y -
$ l6 E5 t& B/ Q8 q7 Q$ t - dat = SPI1_ReadWriteByte(0xFF);//读一字节数据. }4 a$ G/ p( Z. V2 p0 a3 C) B" y
- 8 n% d1 p6 F9 w7 S; A
- FM25CL64_CS = 1;//取消片选
U9 {6 a( |/ O6 w% Z - % l0 ~1 w9 p' H4 c2 ]
- return dat;
6 }8 b( X1 ]- M6 j! ]( N - }
5 A0 }( W3 d( c6 h8 q; U1 z% t0 G
0 K D* Y$ i2 \8 C- % d3 R2 g! U7 x4 ?) } s/ M. P Z
- /*********************************************************************************************************. {+ ?- V9 U; L8 m4 B2 C
- **函数名称: fm25cl6_read_data_1byte j. J* x% w9 \
- **函数功能:写入1字节数据! K. ~7 x" z" i
- **入口参数:write_addr,写入数据地址,,write_data,写入的数据- _/ t" W T L {2 y
- **返回值:无$ \* Z+ c( O/ b1 T7 h+ V
- **注释:
7 `3 |' V3 @+ }, p8 e - **********************************************************************************************************/# i; e& d6 h; n) Y( p
- void fm25cl6_write_1byte(uint16_t write_addr, uint8_t write_data)( ^* @* h- C, B: y5 G
- {' H0 A3 P1 w. s" X$ u8 d
- ' b, ^/ ~3 e8 |1 R+ i
- 7 w& b7 v D2 @$ `
- fm25cl64_write_enable();//使能写操作,一定要先使能,取消片选后再写作下面操作
0 u' r6 |4 d7 ]2 }$ R1 H3 [5 O5 ~ -
8 e- C7 t% W7 ]% E6 r c -
4 N9 r6 m% y% B% ]5 e( V - FM25CL64_CS = 0;//片选
0 Y+ W& @0 p& Z; U4 o4 } -
- }/ K5 o+ A" v) B - SPI1_ReadWriteByte(FM25CL64_WRITE);//写数据命令: F# Z+ |9 c" [( \1 T. p& O
- SPI1_ReadWriteByte((uint8_t)((write_addr)>>8));//最大地址13位
& q# E6 l0 J. B- _4 }' X - SPI1_ReadWriteByte((uint8_t)(write_addr));//& d6 T' n: j9 x/ ?8 u( C
-
0 o! @' Z y9 W, L B2 f# { - ; r# N( _$ t+ ~) n; j
- SPI1_ReadWriteByte(write_data);//写一字节数据
( l8 m+ C# p; ~5 e0 K" N
1 A% F, s: B' g; O) E- FM25CL64_CS = 1;//取消片选
* [* V% G* o5 Z; \0 O8 b - }
" Y a, G" Z* d- R' V1 j1 R
7 f( x2 h8 G/ y2 I0 b P/ H- % g, d8 z9 w M2 ]8 N# g
- /*********************************************************************************************************
; ^" Z/ S9 U+ ^9 J - **函数名称: fm25cl6_clear_data9 H* G3 n. s. M! n2 c; {* V# z
- **函数功能:清除指定长度数据6 {+ I! V% c# a4 N! J# t% t
- **入口参数:write_addr,清除数据地址,,len,清除的数据长度9 A' l4 Q2 x: L/ N+ k- J
- **返回值:无9 d l% j5 I, F" T# C. C
- **注释:5 m4 V3 T" y1 H& d" h: O3 s& y- A
- **********************************************************************************************************/7 K; t7 z3 a: B3 Q# l1 l2 E+ f6 Z2 E
- void fm25cl6_clear_data(uint16_t write_addr, uint8_t len)
& l7 c% O: Y$ O4 M$ i - {
4 P- f2 |. ^4 K+ q1 t
! K% V; A2 M% H- 3 O+ i N0 U! K2 {
- fm25cl64_write_enable();//使能写操作,一定要先使能,取消片选后再写作下面操作% Y: R- L6 N( s% Z
- ( `8 u* C6 s$ R/ [4 L7 H" l7 y# {) ^
- 1 G* O' `$ p' m/ A1 ^2 K0 {2 l
- FM25CL64_CS = 0;//片选
; H& b: h8 v$ e# h# ~ - " V5 S1 |7 u9 \5 t
- SPI1_ReadWriteByte(FM25CL64_WRITE);//写数据命令3 c w% ?& E, e ~3 K
- SPI1_ReadWriteByte((uint8_t)((write_addr)>>8));//最大地址13位* e9 i! o* p4 t
- SPI1_ReadWriteByte((uint8_t)(write_addr));//
0 B9 W# |# `3 j4 i6 ` - ! O- P8 y! h0 s, U
- while(len--): `8 i0 ?$ g- r# [1 g; D! e3 K' x1 J
- {
# ~+ a4 ?: X4 b3 X8 ]9 {- C - SPI1_ReadWriteByte(0x00);//0 b' R4 o$ M2 L9 W7 }: D* O6 q
- }% r4 L, P f$ [8 v, c+ }$ {8 _
-
m* J) x' F7 D/ g - FM25CL64_CS = 1;//取消片选* c+ i4 V" t- K7 F# K
- }$ @0 l' `' h/ T! V7 K4 Q4 k9 }
4 m2 ~% X# h5 a- ' f1 e- j1 f4 \) z3 }$ a2 @7 m" }
0 ~ v9 Q4 E5 S+ p; g- ; C! z3 u( G% g$ h
- 8 F$ v7 I3 |0 Y9 [( Q& T( o
- 8 R3 M; W( }" H S+ [0 w
- $ ^; \) f1 }5 H g. \5 M8 v9 O
- p( H2 e8 @; g3 F. S n. v# s \
- ; P" }+ T9 E4 h5 @
6 `. t* x9 |: p+ R
+ D" Y0 U( b4 l. B4 g- R( L! @
复制代码 其实如果面向接口编程,模块调用SPI的函数SPI1_ReadWriteByte还可以抽象,以备可以切换为SPIX_ReadWriteByte。4 t+ [2 f% B# j$ W
! `& B" a/ }9 `6 _. Y; O测试代码( ]% Q, d+ n3 q
- fm25cl64_init();5 w' t# T, \' u
- fm25cl6_write_1byte(0,0xAB);
! f; H: N+ o) W - GG=fm25cl6_read_1byte(0);1 G' ]# S8 W* S( B
- // fm25cl6_clear_data(0,1);, |: ]+ M5 \! R4 r
- fm25cl6_write_1byte(0,0xCD);' K$ r9 Y4 g6 x+ h' T6 |6 }1 c
- GG=fm25cl6_read_1byte(0);
复制代码 5 t9 K# f7 c$ T9 u7 f: C
7 [/ h& x7 [/ v* O% [+ \4 z% f
|
十多年来一ˊ直在用 24C64 的 FRAM 路过...