- #include "mmc_sd.h"
0 c0 O9 y9 d- U ]0 O# h1 T - #include "delay.h"5 b* J1 C- m4 ?% Y; s! V9 q2 e' a' W
6 B! T! N8 ^4 N0 [# J: v9 U! v. `- uint8_t SD_Type = 0; //SD卡的类型
1 _: S) O6 i. h/ }: ]2 z! k
% X# S) H8 ] H; s4 s- /// 移植修改区函数 //) O) K% m3 W( x% h. j' l2 G+ _) }5 A
- $ Y" J9 |* S0 ?1 ~4 g8 U+ g
- /**
# r- e9 I" G) a$ F0 P0 w2 S - * SD卡SPI接口读写一个字节$ `$ Z# p4 }1 U
- * @param TxData 待写入的字节9 M) U. C8 m2 o$ W! ~4 y% y
- * @return 来自SPI的接收
/ Q# c: }: w* f! C2 E: U - */
, }; L# n; o, F4 N; L3 n' E( K% t - uint8_t SD_SPI_ReadWriteByte(uint8_t TxData)
% R$ T+ ^. Q" | - {3 @( k. S' J$ ]8 B5 \, v# T% @+ O7 o- z) \
- int i = 0;" \( I6 N6 G _2 k
- uint8_t RxData = 0;: J0 _3 z9 N* ^
- HAL_GPIO_WritePin(SPI_CLK_GPIO_Port, SPI_CLK_Pin, GPIO_PIN_RESET);
0 j0 W9 {) X8 C) r4 B - for(i = 7; i >= 0; i--)
( P. ^) b" o- [: S, a - {- N- l6 [2 N3 J% S1 _, u' {
- HAL_GPIO_WritePin(SPI_CLK_GPIO_Port, SPI_CLK_Pin, GPIO_PIN_RESET);
, f: G. P0 [* G: S- _ - if(TxData & (1 << i))
8 E0 |" x% T! P - {
, Y3 _# f# ?" E+ V - HAL_GPIO_WritePin(SPI_MOSI_GPIO_Port, SPI_MOSI_Pin, GPIO_PIN_SET);! r7 n6 J, ]. V% W I5 n) o
- }
1 [) `' `% T& _+ \; T4 t/ K - else
s8 ^9 ]) B# r$ T9 \, i/ } - {3 o; A; G" J3 f! v n4 D
- HAL_GPIO_WritePin(SPI_MOSI_GPIO_Port, SPI_MOSI_Pin, GPIO_PIN_RESET);
& J0 ?9 i; c! m" I9 E - }
! i& b9 C$ Y2 N - delay_us(1);
" C* E) ~# C% N6 y' c - HAL_GPIO_WritePin(SPI_CLK_GPIO_Port, SPI_CLK_Pin, GPIO_PIN_SET);. I/ F6 N, m1 G4 A" e
- RxData <<= 1;/ f6 F/ N: a5 }3 {6 F
- RxData |= HAL_GPIO_ReadPin(SPI_MISO_GPIO_Port, SPI_MISO_Pin);+ H# V7 l* I- ?3 m& W% [
- delay_us(1);& D: G* J* n) ]- I/ B) @6 C7 [7 ]
- }
6 j& l4 |' a5 C W b - HAL_GPIO_WritePin(SPI_CLK_GPIO_Port, SPI_CLK_Pin, GPIO_PIN_RESET);
" u& ~- k6 z$ o, X: j V - return RxData;" F( j4 a4 m; }1 O$ d
- }- H1 Z+ F! R: k9 f/ e& l5 W: n" p
2 E3 U- m* e8 W$ B+ U! J/ j, b0 G- /// SPI硬件层初始化
* u) Q f4 k$ c1 J4 N+ ? - void SD_SPI_Init(void)
7 x. s/ \3 s' s9 r% K - {. k0 p" E( i9 p7 |
- HAL_GPIO_WritePin(SPI_CLK_GPIO_Port, SPI_CLK_Pin, GPIO_PIN_RESET); /* 时钟空闲为低电平 */
+ }& H( ?! \0 g - SD_SPI_ReadWriteByte(0xFF);
) s: u# g3 \" Q8 F - SD_CS_H();
, N4 u% z# o+ e2 V1 ? - }
( I0 D6 n+ q" _6 M. u% n - $ H: Z( c' `. P, E2 Y
- SD SPI 驱动代码 /
/ I2 A' d1 _; r- |, x3 _
6 Z9 F, q9 ?& `* R S0 G" ]- //取消选择,释放SPI总线
4 M( ]' B% ~ f/ x: P/ ?+ m. |. h' ? - void SD_DisSelect(void)
" d# b; V) ?* Y6 s+ R- ` - {' e9 M3 ^: S! ~+ z! L3 K2 ^
- SD_CS_H();
" ~1 E! i% A2 m, b - SD_SPI_ReadWriteByte(0xff);//提供额外的8个时钟
( K- E4 x' a: ?: D, @7 V" T' B. b - }
( A+ S# F& D, }
S W X/ A$ f- /**: i% S8 ]' }$ ~8 C
- * 选中SD卡并等待卡准备好+ d) x$ X; N2 E
- * @return 0:成功 1:失败# G d! {, h# c6 l% F
- */
+ E2 j: Z: F+ f8 o% x9 b* L - uint8_t SD_Select(void)
0 u5 e- z, D2 s% j - {
+ c/ D- Q; q, `6 c - SD_CS_L();
7 {5 C; ~: l/ z( L: R8 b7 G& y) K - if (SD_WaitReady() == 0)return 0; //等待成功' z( ~ m0 o& ^3 Y' Z
- SD_DisSelect();# C5 e" v7 y( X7 L. P5 T" b
- return 1;//等待失败* E- T+ L( i0 }- D1 Q) |* f
- }# \0 A$ g+ V0 i$ t% H
- $ B. y& ], z8 [
- /**3 h2 N" q' P( u% M' D
- * 等待SD卡准备好% o" O; H* ~) d- ]' [1 r( U
- * @return 0:成功 other:失败
1 L/ b% q4 y. { - */0 T8 M( @( K6 a$ i9 X2 R) g6 I
- uint8_t SD_WaitReady(void)7 Y* j4 j8 `1 F* u
- {
) Q# P8 K2 ]$ T8 ^# f+ j' X - uint32_t t = 0;$ ~' v b+ o# H" m! z
- do
" w0 Y8 B' u" ?3 p3 D* S0 W5 Q - {" W0 Z* }) G/ \$ }6 @/ h
- if (SD_SPI_ReadWriteByte(0XFF) == 0XFF)return 0; //OK' A# V- J5 f3 v" U7 D2 G
- t++;
% y2 G! @+ M8 n$ T - }
5 G( b. c9 `# H: v - while (t < 0XFFFFFF); //等待
# I9 z- x! g8 E - return 1;1 O: g4 e. q# x% r
- }0 L$ q" T% ]0 T$ L' H
6 U l2 C! O) f0 u6 f8 z- /**
- j# u5 I: K; [. a1 i - * 等待SD卡回应
# \6 a* @" ~& D& G$ U% O - * @param Response 要得到的回应值# }# N3 w0 [4 A5 q6 e( i6 Q5 S
- * @return 0:成功 other:失败' j* A7 x# g- V4 v2 H
- */
, H S# N `# b - uint8_t SD_GetResponse(uint8_t Response)! z( g% a5 x/ r6 J
- {
, B! m) F( a. Q) Q7 w - uint16_t Count = 0xFFF; //等待次数
* e* ] z( e$ _. ~4 J. i0 g - while ((SD_SPI_ReadWriteByte(0XFF) != Response) && Count)Count--; //等待得到准确的回应
2 X6 p' ]4 @# @6 k - if (Count == 0)return MSD_RESPONSE_FAILURE; //得到回应失败+ x0 h4 e/ u+ S5 s& z& D4 m
- else return MSD_RESPONSE_NO_ERROR;//正确回应% ?8 V, Y" _1 N2 P
- }7 M. n, G& s% r0 n5 Y& \3 f% X# A
- 5 J- ^, w- F: ^) c
- /**
+ H! a, ?( e; s$ K - * 接收来自SD卡的一包数据% E6 C' w* a. d4 B# a' y7 T. M
- * @param buf 存放接收的数据
& s; ^: t5 x4 K: G - * @param len 接收的数据长度 i* z. m2 s- H" `
- * @return 0:成功 other:失败
% Q8 r2 ^3 y& S3 [) c9 P6 ?; ? - */0 r* U+ P: c: X; V; a* B; l5 N
- uint8_t SD_RecvData(uint8_t*buf, uint16_t len)
# ^. e& Z1 M3 a( i4 p - {0 I0 z( F4 p8 T
- if (SD_GetResponse(0xFE))return 1; //等待SD卡发回数据起始令牌0xFE3 T/ w' ]7 A1 g Z3 `9 B) b
- while (len--) //开始接收数据
& g* G ?9 y) E0 }, i - {
% {, J# L( C- Q" n - *buf = SD_SPI_ReadWriteByte(0xFF);+ r2 l. ~. Z: A( @; b7 N' |6 k
- buf++;
( N& S( l% l" H( j - }
% \& T8 o+ A7 c" g6 |! _- A - //下面是2个伪CRC(dummy CRC)
5 M+ U) Q& r* @; ? - SD_SPI_ReadWriteByte(0xFF);
2 v5 ]# G, N+ ] - SD_SPI_ReadWriteByte(0xFF);
- K# v/ Q: A( @+ t$ j) O - return 0;//读取成功4 `% b6 _5 q5 ]
- }" f( }' [$ V3 p, G; A& ]
- //向sd卡写入一个数据包的内容 512字节7 s9 S7 n k( G; F( r
- //buf:数据缓存区. [! h6 E2 q& c( l5 X, a
- //cmd:指令
+ F! D9 A7 b, e+ @ - //返回值:0,成功;其他,失败;
$ q! c$ Y. D8 k, ~( u
0 M9 |' Y# N- ]! u+ M: l# b- /**/ D( N+ Z' Z& J9 v4 _3 Y! K; ]
- * 向SD卡写入一扇区数据: r& N1 v+ x& W b0 B) e7 m
- * @param buf 待写入的数据,size=512
( O" L" [. l" h1 Q9 [/ `3 `6 X - * @param cmd 指令/ R) s. L& f; \+ n! C' h3 Y
- * @return 0:成功 other:失败& Q- z) ~- m" V9 ^9 n5 M
- */
\9 R! Q6 E2 P: u - uint8_t SD_SendBlock(uint8_t*buf, uint8_t cmd)
& h$ f+ l X% q5 t - {
+ S F4 c( m4 P2 z3 { - uint16_t t;
; ?( z2 S U T4 `& @ - if (SD_WaitReady())return 1; //等待准备失效- a- \7 D5 Z* k+ y9 m5 z
- SD_SPI_ReadWriteByte(cmd);1 E- b: R) l5 d, Q- C+ y
- if (cmd != 0XFD) //不是结束指令 Q+ {7 \' b8 a0 w
- {
3 [% F+ i/ W% O - for (t = 0; t < 512; t++)SD_SPI_ReadWriteByte(buf[t]); //提高速度,减少函数传参时间$ [. ?3 H" D) R0 }, t
- SD_SPI_ReadWriteByte(0xFF);//忽略crc
/ F5 p/ B. w" {0 [. ~ - SD_SPI_ReadWriteByte(0xFF);
, V1 V8 [ X8 ~+ D" U3 { - t = SD_SPI_ReadWriteByte(0xFF); //接收响应
) ?+ Q/ W4 r- Y, ~ - if ((t & 0x1F) != 0x05)return 2; //响应错误
4 |& |# \* d8 j3 g/ w6 W - }
$ P5 p5 M, ~( [* c$ P, @ - return 0;//写入成功0 @1 k* M+ r" @8 V. q, b) N
- }2 Y Q$ y/ Q' B+ ?$ k
- * D8 C; O/ s7 C6 G+ L+ t
- /**
( S( U' x- q3 }6 v - * 向SD卡发送命令
l; x" ~' h0 ^ - * @param cmd 待发送的命令
6 k! I Z1 l: k( @0 I4 Y, k - * @param arg 参数
+ X( v% l2 i% P, k - * @param crc crc校验值+ O% A+ N/ F+ n; P
- * @return SD卡返回的响应值& ~3 P+ Z$ ^$ D& F3 j: a+ H
- */
* x/ x. w- o# y1 f/ U - uint8_t SD_SendCmd(uint8_t cmd, uint32_t arg, uint8_t crc)
# j, U! q4 z9 Q; @: S; ~ - {
$ S7 T* j9 i' M; A$ _0 U* q4 Y5 b - uint8_t r1;
8 }6 Y4 d/ H5 f3 b( j, [$ O! H - uint8_t Retry = 0;
. ^, B8 D: z! a2 S3 N - SD_DisSelect();//取消上次片选% l4 V$ N6 Z: ?) R0 j! l, ]
- if (SD_Select())return 0XFF; //片选失效# z8 @! V/ C/ O7 m/ q# U
- //发送
# O8 ~7 z) W/ V6 _% I; |; V - SD_SPI_ReadWriteByte(cmd | 0x40);//分别写入命令; t7 u) ] Y" u: J: ^2 x9 b
- SD_SPI_ReadWriteByte(arg >> 24);
0 }; `+ \7 f! R% d+ T$ Y) Z, S, o& p - SD_SPI_ReadWriteByte(arg >> 16);7 t; J: W4 \ _
- SD_SPI_ReadWriteByte(arg >> 8);. p* }0 o0 c' v' B
- SD_SPI_ReadWriteByte(arg);. r; W8 L( k0 T" C
- SD_SPI_ReadWriteByte(crc);& j3 \2 p9 V: w3 D3 N
- if (cmd == CMD12)SD_SPI_ReadWriteByte(0xff); //Skip a stuff byte when stop reading
4 \: ]& M3 ^' V5 `7 K - //等待响应,或超时退出
1 l" W2 e4 H/ a9 x& ]6 }) B- e - Retry = 0X1F;
7 u! N+ |* y- n: Q/ y1 e - do
n3 v) B7 s0 q( {- i - {. b, I, U- I; G+ n& @
- r1 = SD_SPI_ReadWriteByte(0xFF);
: V8 h2 w+ @0 F1 | - }; J7 e# p' ^6 ]) T( f* a, ]
- while ((r1 & 0X80) && Retry--);
, G6 D9 G7 R. u/ Z, U - //返回状态值
# Q. B1 ]3 j" @* U/ o - return r1;
% a! ]( x7 N& Z - }
0 ]9 j( l+ c& F1 ^/ { - % r( q, D+ L8 s5 O7 Z2 m2 q R
- /**
: w% X3 M3 z" X4 j- `8 v - * 查询SD卡的CID信息,包括制造商信息2 L0 d) R" T" `" \
- * @param cid_data 存放CID数据,至少16字节, ]7 ^3 {7 }8 B6 ~5 |# C0 D0 M
- * @return 0:成功 1:失败 g3 b9 K, `. q4 p
- */, X! C4 @' w! o. Q! \
- uint8_t SD_GetCID(uint8_t *cid_data)
5 P: A1 N! d! S' E* T" ]! E. j - {+ @ j4 J" O0 R1 p, U: H3 E
- uint8_t r1;
4 o1 W4 r8 I: g1 F - //发CMD10命令,读CID
9 l$ E6 a- R# `: k1 Z - r1 = SD_SendCmd(CMD10, 0, 0x01);, [: \/ n: G' Y8 n* ]! f
- if (r1 == 0x00)' w1 s* D$ D& l* q+ Q+ T
- {* z( I( Q8 l5 Y" S
- r1 = SD_RecvData(cid_data, 16); //接收16个字节的数据, L" _& A) E4 A- \+ B; G
- }
6 h0 G9 w7 e5 ~ - SD_DisSelect();//取消片选
; E+ b. v' B9 l: e$ \# b$ G4 b - if (r1)return 1;
" o& S& V" [7 d6 n - else return 0;
- a, B' T6 J9 s/ H- i: d+ n - }* l' l' P8 X6 H
- 6 z# d- |# [5 E, w
- /**
2 }) b) e/ b' c; K" ?7 {$ U7 T5 a - * 查询SD卡CID信息,包括制造商信息8 {% @) ^- p! l0 F. }8 M/ o" I
- * @param csd_data 存放CID信息,至少16字节
$ H& D8 h$ r) c! R, c1 h* D& } - * @return 0:成功 1:失败) {2 B( p: }# L$ x1 b
- */" H2 }% f: d1 L0 _: F2 ]
- uint8_t SD_GetCSD(uint8_t *csd_data)3 {5 f$ a2 y2 k- }+ @) T, C9 s4 j
- {
3 p/ z3 n9 F! L2 Q$ q& a( X - uint8_t r1;
( K: g% Y! E5 K3 \ - r1 = SD_SendCmd(CMD9, 0, 0x01); //发CMD9命令,读CSD1 X. P$ Y# v) Y! U0 p- ]4 c: @
- if (r1 == 0)/ t! g1 O2 C' i$ y
- {9 ~4 R9 F1 Z' M! I% k/ D
- r1 = SD_RecvData(csd_data, 16); //接收16个字节的数据
- K; I" g- ~* W- Y0 v8 m9 e - }
\$ [! D. b8 x - SD_DisSelect();//取消片选! U q, z# w) I7 R7 `( k
- if (r1)return 1;" }4 R- }" c" J- |3 W8 |- _8 M
- else return 0;
% W0 M- A3 C* ^- _" K - }( ^3 D$ _+ T6 d
- /**
9 @0 M- I5 }4 b& k; ^- `% ^4 J - * 获取SD卡扇区数+ F* o9 | X- ]% j
- * @return 0:获取出错 other:SD卡扇区数9 p* D. ^5 a( {+ P% T
- */9 S/ B! ]8 E7 W
- uint32_t SD_GetSectorCount(void)
! R3 z# i7 G' N9 g) n, W0 u - {6 M* N+ Y0 ~, m4 O8 G) v+ C& A ]
- uint8_t csd[16];9 L# q- {6 Q0 E: q8 e6 l1 L. t
- uint32_t Capacity;6 `) J4 E! \/ _1 d$ D8 M; a
- uint8_t n;
" j4 g- D) `5 I Z2 w - uint16_t csize; w* I7 ]8 R# A% Q- @9 Q" S2 y
- //取CSD信息,如果期间出错,返回0
- l) S, i# V5 l* u/ i - if (SD_GetCSD(csd) != 0) return 0;4 x ]8 G5 z; K% J4 \
- //如果为SDHC卡,按照下面方式计算# X6 B1 t( N( Z! y n
- if ((csd[0] & 0xC0) == 0x40) //V2.00的卡7 A' K8 D* k" v, ^. a+ b9 z1 W) } d: q
- { O. f( [5 e( D! D! g2 W1 l
- csize = csd[9] + ((uint16_t)csd[8] << 8) + 1;
/ C2 d( K6 d: `# `$ u" X! d - Capacity = (uint32_t)csize << 10;//得到扇区数
2 K! G0 @; y) G/ |1 T1 o0 b. w - }
3 F4 d: n- C+ } P3 M9 Q& ] - else //V1.XX的卡2 F" H4 Y+ k4 T; j2 F
- {4 |" ?& w! m: y, ?7 T* H' L0 m
- n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
" T& Q7 J9 @) p - csize = (csd[8] >> 6) + ((uint16_t)csd[7] << 2) + ((uint16_t)(csd[6] & 3) << 10) + 1;
/ T( h* o2 C, S7 B% S - Capacity = (uint32_t)csize << (n - 9); //得到扇区数% M5 @) ^- d q, P% Q3 t9 ]/ M, _
- }
8 h! \6 z# x" Q$ v: R( k - return Capacity;3 k* x7 B3 G% \
- }0 A% Z- K4 p' [$ d0 ?
- * s- ~! g8 r3 i
- /// SD卡进入闲置状态
$ n4 M0 F) P5 _* r, p- q& c - uint8_t SD_Idle_Sta(void)3 g) X/ g/ O+ I Z, C
- {
1 u$ V. g/ {( t: X: U5 r# a - uint16_t i;
( W q4 x$ B9 O) t* j: Q# L - uint8_t retry;
. r1 ~6 v" H; D0 j# c - for (i = 0; i < 0xf00; i++); //纯延时,等待SD卡上电完成3 s+ H" Y) V7 U0 J
- //先产生>74个脉冲,让SD卡自己初始化完成' }3 V2 \! A- ?- l9 ]3 D) S
- for (i = 0; i < 10; i++)SD_SPI_ReadWriteByte(0xFF);
( a; c, Z8 E# v7 \) |9 a - //-----------------SD卡复位到idle开始-----------------" L2 E( m# b0 ?: X1 Y. ?8 U* z% F
- //循环连续发送CMD0,直到SD卡返回0x01,进入IDLE状态
, @8 b8 _+ ^4 {4 V3 ^- _) Q) ^ - //超时则直接退出 }: U7 a* {, p" ~- v2 q6 V
- retry = 0;& b0 Q0 Y1 ?" R: J/ e* Q5 r2 z
- do5 _* \+ J3 n1 u! J% `5 F* f8 F
- {
9 r3 E0 |7 p# X8 s - //发送CMD0,让SD卡进入IDLE状态
- U7 d: u- Y& L2 q - i = SD_SendCmd(CMD0, 0, 0x95);
$ Z) c1 I: t6 S" ? - retry++;1 F* w- y, N/ H+ k l6 h
- }
6 H2 J9 o7 G, v0 \ - while ((i != 0x01) && (retry < 200));; ^ s+ W7 d q% z' T3 B: Q9 l
- //跳出循环后,检查原因:初始化成功?or 重试超时?
5 f& g9 Z5 {2 V4 X' [8 W - if (retry == 200)return 1; //失败
" r, D6 P7 G; @ - return 0;//成功8 D3 m5 ?! z& g3 j
- }. c1 u. W! H: U( ~8 d. k
- /// 初始化SD卡
" M! ~( l3 Y. u6 ]0 p) F" N' g3 ^ - uint8_t SD_Initialize(void)
* P" G) p# z7 b: c9 ~4 l - {
+ k5 \& E1 u& v5 F0 q - uint8_t r1; // 存放SD卡的返回值
; ^2 n+ s C& Q - uint16_t retry; // 用来进行超时计数/ ?! m( h- E( j8 q Q8 M
- uint8_t buf[4];4 X+ X, N. M6 V U
- uint16_t i;9 q8 E+ d8 y% \4 a. g2 ?3 S
- 3 f% V7 I" C" j( b
- SD_SPI_Init(); //初始化IO7 T% t7 Z2 h8 P
- for (i = 0; i < 10; i++)SD_SPI_ReadWriteByte(0XFF); //发送最少74个脉冲
% [+ m/ }0 R2 H' {3 ^ - retry = 20;, U" R# y; n0 V, N1 A" s
- do
" M, q6 `, X n# X7 l - {3 `" C! G* {2 N1 N5 y. T" a
- r1 = SD_SendCmd(CMD0, 0, 0x95); //进入IDLE状态
) k2 |2 }, }2 g7 D' ~ - }
F3 ]. Z) [) x1 B+ n - while ((r1 != 0X01) && retry--);
# F0 ?! Z( b5 a - SD_Type = 0; //默认无卡" D @6 i+ [+ ]& f! M: h
- if (r1 == 0X01)
7 k* J3 p/ L/ v0 F: Z - {+ `& }* a! Y" y4 I1 T# Z
- if (SD_SendCmd(CMD8, 0x1AA, 0x87) == 1) //SD V2.0
6 n8 c8 {% k& @/ ^ - {
( G/ W9 Z! y* m' |% B U - for (i = 0; i < 4; i++)buf = SD_SPI_ReadWriteByte(0XFF); //Get trailing return value of R7 resp
! v V' j0 P( Y3 p9 c - if (buf[2] == 0X01 && buf[3] == 0XAA) //卡是否支持2.7~3.6V! O4 q+ e- ~ }) Y4 g; _4 x# p
- {
: b! J4 @) D3 ]% \7 a% E; i% { - retry = 0XFFFE;
% v" i" n0 Q; ?& Y4 H - do
0 q3 w* T0 L7 [ - {
9 l7 @6 k# J# L3 G, p - SD_SendCmd(CMD55, 0, 0X01); //发送CMD554 z1 a" o' y# l0 z7 O7 K( J- o+ t% b
- r1 = SD_SendCmd(CMD41, 0x40000000, 0X01); //发送CMD41
5 e# Y5 \' `+ V$ l+ ~ J - }$ d. {8 E# {! h! u: @
- while (r1 && retry--);1 z8 N+ n! C( t; d2 m
- if (retry && SD_SendCmd(CMD58, 0, 0X01) == 0) //鉴别SD2.0卡版本开始+ h5 X' @( M# T0 m
- {
& X. }5 W9 p4 f: e, J1 D, N7 n5 u - for (i = 0; i < 4; i++)buf = SD_SPI_ReadWriteByte(0XFF); //得到OCR值
* \( Y0 `" U6 H - if (buf[0] & 0x40)SD_Type = SD_TYPE_V2HC; //检查CCS" Z! q5 [4 f3 {8 [' C
- else SD_Type = SD_TYPE_V2;
$ e4 q$ o, T2 b: U# K3 R - }
3 R+ g: q. m+ b' Z4 d+ U1 O! N1 n - }
T- p) N* ]0 `6 i# Y# F - }
; @6 }4 r# ]7 F, {) g - else //SD V1.x/ MMC V3' x. L8 `2 G5 w) ~8 J- j4 @' g
- {
7 Y( `7 L9 y& j6 q& _9 R: X, d# \ - SD_SendCmd(CMD55, 0, 0X01); //发送CMD55& ~/ j- p- Q4 K
- r1 = SD_SendCmd(CMD41, 0, 0X01); //发送CMD41 u: h+ B X1 r, l, _
- if (r1 <= 1)
# \9 |! S- N7 \* J! E2 ]5 N - {
9 r/ x/ o3 \& D. E- |7 C - SD_Type = SD_TYPE_V1;- T! N& D+ e u, R4 l* e
- retry = 0XFFFE;" @' k) _4 h: e
- do //等待退出IDLE模式" C! k3 N; t, ^3 Z+ I
- {
& B" Z7 \ x* ?7 X - SD_SendCmd(CMD55, 0, 0X01); //发送CMD55
1 R6 G- A" [/ _! p! N5 m/ f5 \ - r1 = SD_SendCmd(CMD41, 0, 0X01); //发送CMD41
8 x. B J) G) D0 t - }, }5 d+ ^! Q& d- o r
- while (r1 && retry--);
7 T; Q( o, a% d/ z# r* I - }: E* o6 x! S, t: t$ R1 J
- else
2 |1 s- Z& v0 D8 @' h1 z) O h0 q6 q - {
) |" H0 f! M; a- i2 Z$ O2 D& d - SD_Type = SD_TYPE_MMC; //MMC V3
( S9 I: n' g& `9 H2 _2 C3 i - retry = 0XFFFE;
! l* s" Z# v) I" Q6 \0 K% q' m - do //等待退出IDLE模式
$ J! a2 f6 C/ P: j) S3 ? - {/ q8 Z* C: P1 _2 I6 F
- r1 = SD_SendCmd(CMD1, 0, 0X01); //发送CMD1
/ ]% m( @: A D# Y+ @8 s - }# h; F. F9 O; _
- while (r1 && retry--);
5 }9 k- J8 _7 M. z5 d - }
1 B( \' T0 x) A3 l - if (retry == 0 || SD_SendCmd(CMD16, 512, 0X01) != 0)SD_Type = SD_TYPE_ERR; //错误的卡" E8 O: d5 q! _9 j/ U- [$ B
- }
8 A- ?4 z; d: |0 A8 r% [ - }- U1 C. x5 r6 x- [
- SD_DisSelect();//取消片选
i& J0 H- w: F+ Z& S - if (SD_Type)return 0;2 e. K" K1 |, F# q, [
- else if (r1)return r1;
7 q; t- O+ R0 b* z! O$ G - return 0xaa;//其他错误
* B1 ?+ Y* M1 X) S - }9 K0 n1 a( m9 Y: ^* N
$ H) a2 A) ]: P8 Z# W8 U- /**
/ O5 S* s; R! {! l3 J - * 读取SD卡一个扇区7 x5 t( N8 S2 H/ ~- u. L: x% A
- * @param buf 存放读取的数据
]4 |# E+ z0 G u) C0 m( m - * @param sector 扇区编号
! D5 J1 R8 o( h- D1 S) a; T: @ - * @param cnt 要读取的扇区个数
: T1 n7 B* Z; p& m3 D - * @return 0:成功 other:失败
; O8 o: f: M2 }2 v - */" I6 W4 i, p. {
- uint8_t SD_ReadDisk(uint8_t*buf, uint32_t sector, uint8_t cnt): o1 q' V5 r4 g" m# v
- {
" ]* s( T3 e0 J) [ - uint8_t r1;% `5 t0 U/ j' ?' }4 P, P2 | ?
- if (SD_Type != SD_TYPE_V2HC)sector <<= 9; //转换为字节地址7 { U8 F) t7 w% i( y h* x
- if (cnt == 1); K V. z# J& q, N$ I" o
- {5 f# y0 ?/ M6 \: c* Q# m
- r1 = SD_SendCmd(CMD17, sector, 0X01); //读命令
. T) R" I* f: t/ Y9 G# w" U6 Q - if (r1 == 0) //指令发送成功
: _% O0 Q: p/ m$ ]: e" ` - {2 g7 L. F' \' b! {
- r1 = SD_RecvData(buf, 512); //接收512个字节
, _ K5 }8 {4 s+ o) [, w* \' o - }/ b% e8 O, F5 q; @
- }0 Q0 p! d5 o' Z1 {! n
- else- V3 y2 m$ Y4 T% B- n K
- {( R, V0 V, A& S& \
- r1 = SD_SendCmd(CMD18, sector, 0X01); //连续读命令; |# X4 e; Y c6 m0 j
- do
8 I- o$ L7 E; G: a, v7 p8 ^5 I - {# T( C4 F' N) A* J- O
- r1 = SD_RecvData(buf, 512); //接收512个字节
9 z5 u( P( {: p! t3 z4 F: @7 E8 q - buf += 512;+ ]1 y: m* y' A) T$ v! j5 _8 O
- }
" H2 T: Q# m+ z - while (--cnt && r1 == 0);5 `' |0 W! }; H- K
- SD_SendCmd(CMD12, 0, 0X01); //发送停止命令8 S- m/ ^0 I [+ |/ b: r
- }
2 c; b" l c! i% u5 W5 x - SD_DisSelect();//取消片选* Q. i/ j# i J
- return r1;//
e! X7 R0 U/ t$ T( y; D' X - }. N) m7 h8 m( d2 p/ L% @
) A0 F# `8 d- m U" L- /**
% j1 w, q; g* k! I& _ - * SD卡写一个扇区的数据' N. H, V: k+ I1 H! ]
- * @param buf 存放待写入的数据
( h) a0 b$ R! J/ V% y. o& L1 ` u - * @param sector 扇区编号
1 i# M8 N0 e1 m1 ] - * @param cnt 要写入的扇区个数4 h8 ~! O( z( x, b4 l9 m
- * @return 0:成功 other:失败
/ O& T' n0 B8 S8 ]6 u - */5 B/ q, p* \$ E3 r' G2 K
- uint8_t SD_WriteDisk(uint8_t*buf, uint32_t sector, uint8_t cnt)
% u5 X' C% y5 Y - {
" a( E1 C( R2 s# }# A - uint8_t r1;6 P/ @# Z) _3 g$ e
- if (SD_Type != SD_TYPE_V2HC)sector *= 512; //转换为字节地址
$ k/ D- u$ w0 j5 ?+ }5 Q* D6 A$ O - if (cnt == 1)
+ y+ F' Y% N* U, ? - {
: J1 }! @8 L6 D9 P: Y - r1 = SD_SendCmd(CMD24, sector, 0X01); //读命令
, O2 t# v2 R( g5 e% ]! o# ` - if (r1 == 0) //指令发送成功
6 W0 b4 r, @/ R5 Y) A; j. e0 M - {
5 t; E% @( Z6 Z# Y# ^% R; {( A - r1 = SD_SendBlock(buf, 0xFE); //写512个字节
3 L; c) r5 E- J0 J8 B$ s( ^ - }
& a9 F5 q! q$ A1 {0 j) s9 l3 l/ V - }
: v6 @5 {% a) T. D$ [% ] - else
' K2 K( B" V% ~. i/ M7 i) b - {
+ `3 C( ^& x3 z0 v2 J y$ }: A1 K - if (SD_Type != SD_TYPE_MMC)
& l0 i3 o- t9 K: c" a - {
( H7 @( D0 [* G* q% }8 g - SD_SendCmd(CMD55, 0, 0X01);
9 }, X3 r& f& Y9 j ^& X - SD_SendCmd(CMD23, cnt, 0X01); //发送指令6 Q e& H% h: \$ Y* \; q3 [3 h+ L
- } G+ Q5 F. O2 F( E6 ^) l
- r1 = SD_SendCmd(CMD25, sector, 0X01); //连续读命令
1 N4 ?* ~# V4 _/ v% ?; ^8 r- M - if (r1 == 0)
+ P1 v9 c' K( A" j) W - {* q' D9 L1 `& t. j* ^
- do
$ X2 a$ v" a+ S - {
2 v1 _0 ^; Q& t# o/ N! ~* v, V - r1 = SD_SendBlock(buf, 0xFC); //接收512个字节
% M! n5 I" V4 D- t6 {0 D - buf += 512;
- n. A; N1 c: _/ y3 | o - }
& N7 d7 ?1 ^+ j" p" L3 T - while (--cnt && r1 == 0);$ {$ u; |% Z. k' J& @0 u
- r1 = SD_SendBlock(0, 0xFD); //接收512个字节
* E. o3 S" ?: W' d- P - }
2 O6 W' q' h8 z0 ` - }. m: [6 j- e2 D! a
- SD_DisSelect();//取消片选
& \9 B$ \% {* i1 f - return r1;//
1 w2 }4 j. r) x, o - }
复制代码- #ifndef _MMC_SD_H_
) \, ~: z3 d6 Z0 U9 M - #define _MMC_SD_H_ u2 g* w0 `1 Q+ u) v( F# L
9 V- ^3 w4 I y' }# t% A g- #include "main.h"
% K& T. ?4 o) u$ L" ~ - j. H+ ?8 A, X) D3 ?& B3 {
- // SD卡扇区大小
) l7 D& Z& s7 j3 ?6 h1 H - #define SD_SECTOR_SIZE 512U0 Q- E: G3 v6 S! T5 r% F
5 J0 v2 T# D4 c6 a0 G2 ^* b& ]- // SD卡类型定义
0 R( @+ W" d- f+ Q, z( j" Z, _ - #define SD_TYPE_ERR 0X00$ Q$ u" [ g% E9 p
- #define SD_TYPE_MMC 0X01
7 R( o; s" ?0 u9 Z" | - #define SD_TYPE_V1 0X02* P& G1 e* I* f1 `' a: p
- #define SD_TYPE_V2 0X04
9 ?* h! _3 P: }& ]* V - #define SD_TYPE_V2HC 0X065 q' x- S9 O* f" K( h! h$ W
- . ?4 D! p. }# W& f
- // SD卡指令表
% m0 g8 O! Z! w4 q' v% [ {' B - #define CMD0 0 //卡复位
- k6 x" L8 D N - #define CMD1 1# d' b9 }" Y! K4 K" R2 J% t9 D
- #define CMD8 8 //命令8 ,SEND_IF_COND6 I* r1 s6 l1 N) z3 V: E
- #define CMD9 9 //命令9 ,读CSD数据
& X0 \9 m. x q- x0 v0 m - #define CMD10 10 //命令10,读CID数据; z! U8 U9 J( D# [) c1 I* b
- #define CMD12 12 //命令12,停止数据传输
$ F2 N& F; T( A0 P M - #define CMD16 16 //命令16,设置SectorSize 应返回0x001 e- p& [! V2 C+ k- e( r
- #define CMD17 17 //命令17,读sector
% v: I4 |/ r8 L3 \. C% M2 S - #define CMD18 18 //命令18,读Multi sector$ f' e! {$ {& S$ I& C" u3 W; h
- #define CMD23 23 //命令23,设置多sector写入前预先擦除N个block
+ Z* C( ? L/ }; s# L) s8 c - #define CMD24 24 //命令24,写sector
, v: E9 ~9 ~+ u+ l+ d - #define CMD25 25 //命令25,写Multi sector3 B& k$ S! s D! F z6 x6 I* U7 Z
- #define CMD41 41 //命令41,应返回0x00" h4 O* P) x3 n' l8 t; }
- #define CMD55 55 //命令55,应返回0x01' I, X( P* I' D7 k- v2 q( P
- #define CMD58 58 //命令58,读OCR信息- O8 {/ H3 f+ ?# U
- #define CMD59 59 //命令59,使能/禁止CRC,应返回0x00
, P; T+ I6 ]& Z - $ P- Q0 C& v4 A$ W4 g3 i6 _
- //数据写入回应字意义
; E$ ] f1 r( `0 }! O, _ - #define MSD_DATA_OK 0x057 z7 U/ a+ S$ O! j. T! R, S" C
- #define MSD_DATA_CRC_ERROR 0x0B5 v2 u; W, s: d M! h( Z
- #define MSD_DATA_WRITE_ERROR 0x0D
* j }+ ~5 m N: i - #define MSD_DATA_OTHER_ERROR 0xFF. C- M+ Z0 k8 L& H
: r' H1 c2 V: q1 Y! A, O- //SD卡回应标记字
1 H4 e; g; ? O" V% Y# i - #define MSD_RESPONSE_NO_ERROR 0x00
# Z) L" o I6 c$ r - #define MSD_IN_IDLE_STATE 0x01! D) w) ^& v2 ?0 ]0 Y/ k
- #define MSD_ERASE_RESET 0x02
. v( s) p6 M6 n# U- G% I6 F1 I' Q - #define MSD_ILLEGAL_COMMAND 0x042 G8 z- X0 W8 Q* s" E
- #define MSD_COM_CRC_ERROR 0x08* X b% j) G4 _$ N1 d0 J/ @9 T
- #define MSD_ERASE_SEQUENCE_ERROR 0x10% _4 p& ?8 x# c3 u. l9 i
- #define MSD_ADDRESS_ERROR 0x200 s6 Z: C" C& _" P
- #define MSD_PARAMETER_ERROR 0x40
- i$ a b& z% a" }. `! p/ ?3 ? - #define MSD_RESPONSE_FAILURE 0xFF
- Z& {3 ]" z; o
2 M& ~ Q% x @; C5 [. j- // SD卡片选引脚控制,使用STM32CUBEMX配置SD卡片选引脚为输出模式并设置为高电平
) v& ?' y o1 B5 z2 i3 M - #define SD_CS_H() HAL_GPIO_WritePin(SD_CS_GPIO_Port, SD_CS_Pin, GPIO_PIN_SET). [+ J5 b2 r) G" {
- #define SD_CS_L() HAL_GPIO_WritePin(SD_CS_GPIO_Port, SD_CS_Pin, GPIO_PIN_RESET)
- P/ U% h0 M! G) _
/ n+ A [$ `% U( L- extern uint8_t SD_Type; //SD卡的类型
% o8 e; h h* A0 c, J' O) o! E4 M/ {
, @! r2 t! ?; C* v* _2 V7 g- //函数申明区
7 [1 K4 u& ?& `% k) U - uint8_t SD_WaitReady(void); //等待SD卡准备
' I C# M5 M5 r8 d; M - uint8_t SD_GetResponse(uint8_t Response); //获得相应
% }% H2 }+ Z4 u' f1 J+ M2 O9 u - uint8_t SD_Initialize(void); //初始化
+ Y* }6 X8 b- T# q6 `4 V - uint8_t SD_ReadDisk(uint8_t*buf,uint32_t sector,uint8_t cnt); //读块
+ B; |1 z% ` k9 s - uint8_t SD_WriteDisk(uint8_t*buf,uint32_t sector,uint8_t cnt); //写块) |* f( ^3 I" F0 }. U; R3 W: A
- uint32_t SD_GetSectorCount(void); //读扇区数
5 d9 v( [+ J$ \ - uint8_t SD_GetCID(uint8_t *cid_data); //读SD卡CID
/ l( x& Q5 L; H, f - uint8_t SD_GetCSD(uint8_t *csd_data); //读SD卡CSD
& X1 K$ ?0 G) B4 X4 x5 d V
" {: Y* k0 ~- ?0 H: v& m; C' A- #endif
/ _/ D5 H& l9 ?: [1 x( o) C
8 s e7 [! s5 d8 K, z+ W' v5 H- " X& V& B8 l% ?6 K- l- \4 I
复制代码
, D, b8 E! U) [/ ~ |