你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32使用HAL库IO模拟SPI驱动SD卡

[复制链接]
STMCU小助手 发布时间:2022-4-11 10:16
  1. #include "mmc_sd.h"
    0 c0 O9 y9 d- U  ]0 O# h1 T
  2. #include "delay.h"5 b* J1 C- m4 ?% Y; s! V9 q2 e' a' W

  3. 6 B! T! N8 ^4 N0 [# J: v9 U! v. `
  4. uint8_t SD_Type = 0; //SD卡的类型
    1 _: S) O6 i. h/ }: ]2 z! k

  5. % X# S) H8 ]  H; s4 s
  6. /// 移植修改区函数 //) O) K% m3 W( x% h. j' l2 G+ _) }5 A
  7. $ Y" J9 |* S0 ?1 ~4 g8 U+ g
  8. /**
    # r- e9 I" G) a$ F0 P0 w2 S
  9. * SD卡SPI接口读写一个字节$ `$ Z# p4 }1 U
  10. * @param  TxData 待写入的字节9 M) U. C8 m2 o$ W! ~4 y% y
  11. * @return        来自SPI的接收
    / Q# c: }: w* f! C2 E: U
  12. */
    , }; L# n; o, F4 N; L3 n' E( K% t
  13. uint8_t SD_SPI_ReadWriteByte(uint8_t TxData)
    % R$ T+ ^. Q" |
  14. {3 @( k. S' J$ ]8 B5 \, v# T% @+ O7 o- z) \
  15.     int i = 0;" \( I6 N6 G  _2 k
  16.     uint8_t RxData = 0;: J0 _3 z9 N* ^
  17.     HAL_GPIO_WritePin(SPI_CLK_GPIO_Port, SPI_CLK_Pin, GPIO_PIN_RESET);
    0 j0 W9 {) X8 C) r4 B
  18.     for(i = 7; i >= 0; i--)
    ( P. ^) b" o- [: S, a
  19.     {- N- l6 [2 N3 J% S1 _, u' {
  20.         HAL_GPIO_WritePin(SPI_CLK_GPIO_Port, SPI_CLK_Pin, GPIO_PIN_RESET);
    , f: G. P0 [* G: S- _
  21.         if(TxData & (1 << i))
    8 E0 |" x% T! P
  22.         {
    , Y3 _# f# ?" E+ V
  23.             HAL_GPIO_WritePin(SPI_MOSI_GPIO_Port, SPI_MOSI_Pin, GPIO_PIN_SET);! r7 n6 J, ]. V% W  I5 n) o
  24.         }
    1 [) `' `% T& _+ \; T4 t/ K
  25.         else
      s8 ^9 ]) B# r$ T9 \, i/ }
  26.         {3 o; A; G" J3 f! v  n4 D
  27.             HAL_GPIO_WritePin(SPI_MOSI_GPIO_Port, SPI_MOSI_Pin, GPIO_PIN_RESET);
    & J0 ?9 i; c! m" I9 E
  28.         }
    ! i& b9 C$ Y2 N
  29.         delay_us(1);
    " C* E) ~# C% N6 y' c
  30.         HAL_GPIO_WritePin(SPI_CLK_GPIO_Port, SPI_CLK_Pin, GPIO_PIN_SET);. I/ F6 N, m1 G4 A" e
  31.         RxData <<= 1;/ f6 F/ N: a5 }3 {6 F
  32.         RxData |= HAL_GPIO_ReadPin(SPI_MISO_GPIO_Port, SPI_MISO_Pin);+ H# V7 l* I- ?3 m& W% [
  33.         delay_us(1);& D: G* J* n) ]- I/ B) @6 C7 [7 ]
  34.     }
    6 j& l4 |' a5 C  W  b
  35.     HAL_GPIO_WritePin(SPI_CLK_GPIO_Port, SPI_CLK_Pin, GPIO_PIN_RESET);
    " u& ~- k6 z$ o, X: j  V
  36.     return RxData;" F( j4 a4 m; }1 O$ d
  37. }- H1 Z+ F! R: k9 f/ e& l5 W: n" p

  38. 2 E3 U- m* e8 W$ B+ U! J/ j, b0 G
  39. /// SPI硬件层初始化
    * u) Q  f4 k$ c1 J4 N+ ?
  40. void SD_SPI_Init(void)
    7 x. s/ \3 s' s9 r% K
  41. {. k0 p" E( i9 p7 |
  42.     HAL_GPIO_WritePin(SPI_CLK_GPIO_Port, SPI_CLK_Pin, GPIO_PIN_RESET);    /* 时钟空闲为低电平 */
    + }& H( ?! \0 g
  43.     SD_SPI_ReadWriteByte(0xFF);
    ) s: u# g3 \" Q8 F
  44.     SD_CS_H();
    , N4 u% z# o+ e2 V1 ?
  45. }
    ( I0 D6 n+ q" _6 M. u% n
  46. $ H: Z( c' `. P, E2 Y
  47.   SD SPI 驱动代码  /
    / I2 A' d1 _; r- |, x3 _

  48. 6 Z9 F, q9 ?& `* R  S0 G" ]
  49. //取消选择,释放SPI总线
    4 M( ]' B% ~  f/ x: P/ ?+ m. |. h' ?
  50. void SD_DisSelect(void)
    " d# b; V) ?* Y6 s+ R- `
  51. {' e9 M3 ^: S! ~+ z! L3 K2 ^
  52.     SD_CS_H();
    " ~1 E! i% A2 m, b
  53.     SD_SPI_ReadWriteByte(0xff);//提供额外的8个时钟
    ( K- E4 x' a: ?: D, @7 V" T' B. b
  54. }
    ( A+ S# F& D, }

  55.   S  W  X/ A$ f
  56. /**: i% S8 ]' }$ ~8 C
  57. * 选中SD卡并等待卡准备好+ d) x$ X; N2 E
  58. * @return  0:成功  1:失败# G  d! {, h# c6 l% F
  59. */
    + E2 j: Z: F+ f8 o% x9 b* L
  60. uint8_t SD_Select(void)
    0 u5 e- z, D2 s% j
  61. {
    + c/ D- Q; q, `6 c
  62.     SD_CS_L();
    7 {5 C; ~: l/ z( L: R8 b7 G& y) K
  63.     if (SD_WaitReady() == 0)return 0; //等待成功' z( ~  m0 o& ^3 Y' Z
  64.     SD_DisSelect();# C5 e" v7 y( X7 L. P5 T" b
  65.     return 1;//等待失败* E- T+ L( i0 }- D1 Q) |* f
  66. }# \0 A$ g+ V0 i$ t% H
  67. $ B. y& ], z8 [
  68. /**3 h2 N" q' P( u% M' D
  69. * 等待SD卡准备好% o" O; H* ~) d- ]' [1 r( U
  70. * @return  0:成功  other:失败
    1 L/ b% q4 y. {
  71. */0 T8 M( @( K6 a$ i9 X2 R) g6 I
  72. uint8_t SD_WaitReady(void)7 Y* j4 j8 `1 F* u
  73. {
    ) Q# P8 K2 ]$ T8 ^# f+ j' X
  74.     uint32_t t = 0;$ ~' v  b+ o# H" m! z
  75.     do
    " w0 Y8 B' u" ?3 p3 D* S0 W5 Q
  76.     {" W0 Z* }) G/ \$ }6 @/ h
  77.         if (SD_SPI_ReadWriteByte(0XFF) == 0XFF)return 0; //OK' A# V- J5 f3 v" U7 D2 G
  78.         t++;
    % y2 G! @+ M8 n$ T
  79.     }
    5 G( b. c9 `# H: v
  80.     while (t < 0XFFFFFF); //等待
    # I9 z- x! g8 E
  81.     return 1;1 O: g4 e. q# x% r
  82. }0 L$ q" T% ]0 T$ L' H

  83. 6 U  l2 C! O) f0 u6 f8 z
  84. /**
    - j# u5 I: K; [. a1 i
  85. * 等待SD卡回应
    # \6 a* @" ~& D& G$ U% O
  86. * @param  Response 要得到的回应值# }# N3 w0 [4 A5 q6 e( i6 Q5 S
  87. * @return          0:成功  other:失败' j* A7 x# g- V4 v2 H
  88. */
    , H  S# N  `# b
  89. uint8_t SD_GetResponse(uint8_t Response)! z( g% a5 x/ r6 J
  90. {
    , B! m) F( a. Q) Q7 w
  91.     uint16_t Count = 0xFFF; //等待次数
    * e* ]  z( e$ _. ~4 J. i0 g
  92.     while ((SD_SPI_ReadWriteByte(0XFF) != Response) && Count)Count--; //等待得到准确的回应
    2 X6 p' ]4 @# @6 k
  93.     if (Count == 0)return MSD_RESPONSE_FAILURE; //得到回应失败+ x0 h4 e/ u+ S5 s& z& D4 m
  94.     else return MSD_RESPONSE_NO_ERROR;//正确回应% ?8 V, Y" _1 N2 P
  95. }7 M. n, G& s% r0 n5 Y& \3 f% X# A
  96. 5 J- ^, w- F: ^) c
  97. /**
    + H! a, ?( e; s$ K
  98. * 接收来自SD卡的一包数据% E6 C' w* a. d4 B# a' y7 T. M
  99. * @param  buf 存放接收的数据
    & s; ^: t5 x4 K: G
  100. * @param  len 接收的数据长度  i* z. m2 s- H" `
  101. * @return     0:成功  other:失败
    % Q8 r2 ^3 y& S3 [) c9 P6 ?; ?
  102. */0 r* U+ P: c: X; V; a* B; l5 N
  103. uint8_t SD_RecvData(uint8_t*buf, uint16_t len)
    # ^. e& Z1 M3 a( i4 p
  104. {0 I0 z( F4 p8 T
  105.     if (SD_GetResponse(0xFE))return 1; //等待SD卡发回数据起始令牌0xFE3 T/ w' ]7 A1 g  Z3 `9 B) b
  106.     while (len--) //开始接收数据
    & g* G  ?9 y) E0 }, i
  107.     {
    % {, J# L( C- Q" n
  108.         *buf = SD_SPI_ReadWriteByte(0xFF);+ r2 l. ~. Z: A( @; b7 N' |6 k
  109.         buf++;
    ( N& S( l% l" H( j
  110.     }
    % \& T8 o+ A7 c" g6 |! _- A
  111.     //下面是2个伪CRC(dummy CRC)
    5 M+ U) Q& r* @; ?
  112.     SD_SPI_ReadWriteByte(0xFF);
    2 v5 ]# G, N+ ]
  113.     SD_SPI_ReadWriteByte(0xFF);
    - K# v/ Q: A( @+ t$ j) O
  114.     return 0;//读取成功4 `% b6 _5 q5 ]
  115. }" f( }' [$ V3 p, G; A& ]
  116. //向sd卡写入一个数据包的内容 512字节7 s9 S7 n  k( G; F( r
  117. //buf:数据缓存区. [! h6 E2 q& c( l5 X, a
  118. //cmd:指令
    + F! D9 A7 b, e+ @
  119. //返回值:0,成功;其他,失败;
    $ q! c$ Y. D8 k, ~( u

  120. 0 M9 |' Y# N- ]! u+ M: l# b
  121. /**/ D( N+ Z' Z& J9 v4 _3 Y! K; ]
  122. * 向SD卡写入一扇区数据: r& N1 v+ x& W  b0 B) e7 m
  123. * @param  buf 待写入的数据,size=512
    ( O" L" [. l" h1 Q9 [/ `3 `6 X
  124. * @param  cmd 指令/ R) s. L& f; \+ n! C' h3 Y
  125. * @return     0:成功  other:失败& Q- z) ~- m" V9 ^9 n5 M
  126. */
      \9 R! Q6 E2 P: u
  127. uint8_t SD_SendBlock(uint8_t*buf, uint8_t cmd)
    & h$ f+ l  X% q5 t
  128. {
    + S  F4 c( m4 P2 z3 {
  129.     uint16_t t;
    ; ?( z2 S  U  T4 `& @
  130.     if (SD_WaitReady())return 1; //等待准备失效- a- \7 D5 Z* k+ y9 m5 z
  131.     SD_SPI_ReadWriteByte(cmd);1 E- b: R) l5 d, Q- C+ y
  132.     if (cmd != 0XFD) //不是结束指令  Q+ {7 \' b8 a0 w
  133.     {
    3 [% F+ i/ W% O
  134.         for (t = 0; t < 512; t++)SD_SPI_ReadWriteByte(buf[t]); //提高速度,减少函数传参时间$ [. ?3 H" D) R0 }, t
  135.         SD_SPI_ReadWriteByte(0xFF);//忽略crc
    / F5 p/ B. w" {0 [. ~
  136.         SD_SPI_ReadWriteByte(0xFF);
    , V1 V8 [  X8 ~+ D" U3 {
  137.         t = SD_SPI_ReadWriteByte(0xFF); //接收响应
    ) ?+ Q/ W4 r- Y, ~
  138.         if ((t & 0x1F) != 0x05)return 2; //响应错误
    4 |& |# \* d8 j3 g/ w6 W
  139.     }
    $ P5 p5 M, ~( [* c$ P, @
  140.     return 0;//写入成功0 @1 k* M+ r" @8 V. q, b) N
  141. }2 Y  Q$ y/ Q' B+ ?$ k
  142. * D8 C; O/ s7 C6 G+ L+ t
  143. /**
    ( S( U' x- q3 }6 v
  144. * 向SD卡发送命令
      l; x" ~' h0 ^
  145. * @param  cmd 待发送的命令
    6 k! I  Z1 l: k( @0 I4 Y, k
  146. * @param  arg 参数
    + X( v% l2 i% P, k
  147. * @param  crc crc校验值+ O% A+ N/ F+ n; P
  148. * @return     SD卡返回的响应值& ~3 P+ Z$ ^$ D& F3 j: a+ H
  149. */
    * x/ x. w- o# y1 f/ U
  150. uint8_t SD_SendCmd(uint8_t cmd, uint32_t arg, uint8_t crc)
    # j, U! q4 z9 Q; @: S; ~
  151. {
    $ S7 T* j9 i' M; A$ _0 U* q4 Y5 b
  152.     uint8_t r1;
    8 }6 Y4 d/ H5 f3 b( j, [$ O! H
  153.     uint8_t Retry = 0;
    . ^, B8 D: z! a2 S3 N
  154.     SD_DisSelect();//取消上次片选% l4 V$ N6 Z: ?) R0 j! l, ]
  155.     if (SD_Select())return 0XFF; //片选失效# z8 @! V/ C/ O7 m/ q# U
  156.     //发送
    # O8 ~7 z) W/ V6 _% I; |; V
  157.     SD_SPI_ReadWriteByte(cmd | 0x40);//分别写入命令; t7 u) ]  Y" u: J: ^2 x9 b
  158.     SD_SPI_ReadWriteByte(arg >> 24);
    0 }; `+ \7 f! R% d+ T$ Y) Z, S, o& p
  159.     SD_SPI_ReadWriteByte(arg >> 16);7 t; J: W4 \  _
  160.     SD_SPI_ReadWriteByte(arg >> 8);. p* }0 o0 c' v' B
  161.     SD_SPI_ReadWriteByte(arg);. r; W8 L( k0 T" C
  162.     SD_SPI_ReadWriteByte(crc);& j3 \2 p9 V: w3 D3 N
  163.     if (cmd == CMD12)SD_SPI_ReadWriteByte(0xff); //Skip a stuff byte when stop reading
    4 \: ]& M3 ^' V5 `7 K
  164.     //等待响应,或超时退出
    1 l" W2 e4 H/ a9 x& ]6 }) B- e
  165.     Retry = 0X1F;
    7 u! N+ |* y- n: Q/ y1 e
  166.     do
      n3 v) B7 s0 q( {- i
  167.     {. b, I, U- I; G+ n& @
  168.         r1 = SD_SPI_ReadWriteByte(0xFF);
    : V8 h2 w+ @0 F1 |
  169.     }; J7 e# p' ^6 ]) T( f* a, ]
  170.     while ((r1 & 0X80) && Retry--);
    , G6 D9 G7 R. u/ Z, U
  171.     //返回状态值
    # Q. B1 ]3 j" @* U/ o
  172.     return r1;
    % a! ]( x7 N& Z
  173. }
    0 ]9 j( l+ c& F1 ^/ {
  174. % r( q, D+ L8 s5 O7 Z2 m2 q  R
  175. /**
    : w% X3 M3 z" X4 j- `8 v
  176. * 查询SD卡的CID信息,包括制造商信息2 L0 d) R" T" `" \
  177. * @param  cid_data 存放CID数据,至少16字节, ]7 ^3 {7 }8 B6 ~5 |# C0 D0 M
  178. * @return          0:成功  1:失败  g3 b9 K, `. q4 p
  179. */, X! C4 @' w! o. Q! \
  180. uint8_t SD_GetCID(uint8_t *cid_data)
    5 P: A1 N! d! S' E* T" ]! E. j
  181. {+ @  j4 J" O0 R1 p, U: H3 E
  182.     uint8_t r1;
    4 o1 W4 r8 I: g1 F
  183.     //发CMD10命令,读CID
    9 l$ E6 a- R# `: k1 Z
  184.     r1 = SD_SendCmd(CMD10, 0, 0x01);, [: \/ n: G' Y8 n* ]! f
  185.     if (r1 == 0x00)' w1 s* D$ D& l* q+ Q+ T
  186.     {* z( I( Q8 l5 Y" S
  187.         r1 = SD_RecvData(cid_data, 16); //接收16个字节的数据, L" _& A) E4 A- \+ B; G
  188.     }
    6 h0 G9 w7 e5 ~
  189.     SD_DisSelect();//取消片选
    ; E+ b. v' B9 l: e$ \# b$ G4 b
  190.     if (r1)return 1;
    " o& S& V" [7 d6 n
  191.     else return 0;
    - a, B' T6 J9 s/ H- i: d+ n
  192. }* l' l' P8 X6 H
  193. 6 z# d- |# [5 E, w
  194. /**
    2 }) b) e/ b' c; K" ?7 {$ U7 T5 a
  195. * 查询SD卡CID信息,包括制造商信息8 {% @) ^- p! l0 F. }8 M/ o" I
  196. * @param  csd_data 存放CID信息,至少16字节
    $ H& D8 h$ r) c! R, c1 h* D& }
  197. * @return          0:成功  1:失败) {2 B( p: }# L$ x1 b
  198. */" H2 }% f: d1 L0 _: F2 ]
  199. uint8_t SD_GetCSD(uint8_t *csd_data)3 {5 f$ a2 y2 k- }+ @) T, C9 s4 j
  200. {
    3 p/ z3 n9 F! L2 Q$ q& a( X
  201.     uint8_t r1;
    ( K: g% Y! E5 K3 \
  202.     r1 = SD_SendCmd(CMD9, 0, 0x01); //发CMD9命令,读CSD1 X. P$ Y# v) Y! U0 p- ]4 c: @
  203.     if (r1 == 0)/ t! g1 O2 C' i$ y
  204.     {9 ~4 R9 F1 Z' M! I% k/ D
  205.         r1 = SD_RecvData(csd_data, 16); //接收16个字节的数据
    - K; I" g- ~* W- Y0 v8 m9 e
  206.     }
      \$ [! D. b8 x
  207.     SD_DisSelect();//取消片选! U  q, z# w) I7 R7 `( k
  208.     if (r1)return 1;" }4 R- }" c" J- |3 W8 |- _8 M
  209.     else return 0;
    % W0 M- A3 C* ^- _" K
  210. }( ^3 D$ _+ T6 d
  211. /**
    9 @0 M- I5 }4 b& k; ^- `% ^4 J
  212. * 获取SD卡扇区数+ F* o9 |  X- ]% j
  213. * @return  0:获取出错  other:SD卡扇区数9 p* D. ^5 a( {+ P% T
  214. */9 S/ B! ]8 E7 W
  215. uint32_t SD_GetSectorCount(void)
    ! R3 z# i7 G' N9 g) n, W0 u
  216. {6 M* N+ Y0 ~, m4 O8 G) v+ C& A  ]
  217.     uint8_t csd[16];9 L# q- {6 Q0 E: q8 e6 l1 L. t
  218.     uint32_t Capacity;6 `) J4 E! \/ _1 d$ D8 M; a
  219.     uint8_t n;
    " j4 g- D) `5 I  Z2 w
  220.     uint16_t csize;  w* I7 ]8 R# A% Q- @9 Q" S2 y
  221.     //取CSD信息,如果期间出错,返回0
    - l) S, i# V5 l* u/ i
  222.     if (SD_GetCSD(csd) != 0) return 0;4 x  ]8 G5 z; K% J4 \
  223.     //如果为SDHC卡,按照下面方式计算# X6 B1 t( N( Z! y  n
  224.     if ((csd[0] & 0xC0) == 0x40)         //V2.00的卡7 A' K8 D* k" v, ^. a+ b9 z1 W) }  d: q
  225.     {  O. f( [5 e( D! D! g2 W1 l
  226.         csize = csd[9] + ((uint16_t)csd[8] << 8) + 1;
    / C2 d( K6 d: `# `$ u" X! d
  227.         Capacity = (uint32_t)csize << 10;//得到扇区数
    2 K! G0 @; y) G/ |1 T1 o0 b. w
  228.     }
    3 F4 d: n- C+ }  P3 M9 Q& ]
  229.     else //V1.XX的卡2 F" H4 Y+ k4 T; j2 F
  230.     {4 |" ?& w! m: y, ?7 T* H' L0 m
  231.         n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
    " T& Q7 J9 @) p
  232.         csize = (csd[8] >> 6) + ((uint16_t)csd[7] << 2) + ((uint16_t)(csd[6] & 3) << 10) + 1;
    / T( h* o2 C, S7 B% S
  233.         Capacity = (uint32_t)csize << (n - 9); //得到扇区数% M5 @) ^- d  q, P% Q3 t9 ]/ M, _
  234.     }
    8 h! \6 z# x" Q$ v: R( k
  235.     return Capacity;3 k* x7 B3 G% \
  236. }0 A% Z- K4 p' [$ d0 ?
  237. * s- ~! g8 r3 i
  238. /// SD卡进入闲置状态
    $ n4 M0 F) P5 _* r, p- q& c
  239. uint8_t SD_Idle_Sta(void)3 g) X/ g/ O+ I  Z, C
  240. {
    1 u$ V. g/ {( t: X: U5 r# a
  241.     uint16_t i;
    ( W  q4 x$ B9 O) t* j: Q# L
  242.     uint8_t retry;
    . r1 ~6 v" H; D0 j# c
  243.     for (i = 0; i < 0xf00; i++); //纯延时,等待SD卡上电完成3 s+ H" Y) V7 U0 J
  244.     //先产生>74个脉冲,让SD卡自己初始化完成' }3 V2 \! A- ?- l9 ]3 D) S
  245.     for (i = 0; i < 10; i++)SD_SPI_ReadWriteByte(0xFF);
    ( a; c, Z8 E# v7 \) |9 a
  246.     //-----------------SD卡复位到idle开始-----------------" L2 E( m# b0 ?: X1 Y. ?8 U* z% F
  247.     //循环连续发送CMD0,直到SD卡返回0x01,进入IDLE状态
    , @8 b8 _+ ^4 {4 V3 ^- _) Q) ^
  248.     //超时则直接退出  }: U7 a* {, p" ~- v2 q6 V
  249.     retry = 0;& b0 Q0 Y1 ?" R: J/ e* Q5 r2 z
  250.     do5 _* \+ J3 n1 u! J% `5 F* f8 F
  251.     {
    9 r3 E0 |7 p# X8 s
  252.         //发送CMD0,让SD卡进入IDLE状态
    - U7 d: u- Y& L2 q
  253.         i = SD_SendCmd(CMD0, 0, 0x95);
    $ Z) c1 I: t6 S" ?
  254.         retry++;1 F* w- y, N/ H+ k  l6 h
  255.     }
    6 H2 J9 o7 G, v0 \
  256.     while ((i != 0x01) && (retry < 200));; ^  s+ W7 d  q% z' T3 B: Q9 l
  257.     //跳出循环后,检查原因:初始化成功?or 重试超时?
    5 f& g9 Z5 {2 V4 X' [8 W
  258.     if (retry == 200)return 1; //失败
    " r, D6 P7 G; @
  259.     return 0;//成功8 D3 m5 ?! z& g3 j
  260. }. c1 u. W! H: U( ~8 d. k
  261. /// 初始化SD卡
    " M! ~( l3 Y. u6 ]0 p) F" N' g3 ^
  262. uint8_t SD_Initialize(void)
    * P" G) p# z7 b: c9 ~4 l
  263. {
    + k5 \& E1 u& v5 F0 q
  264.     uint8_t r1;      // 存放SD卡的返回值
    ; ^2 n+ s  C& Q
  265.     uint16_t retry;  // 用来进行超时计数/ ?! m( h- E( j8 q  Q8 M
  266.     uint8_t buf[4];4 X+ X, N. M6 V  U
  267.     uint16_t i;9 q8 E+ d8 y% \4 a. g2 ?3 S
  268. 3 f% V7 I" C" j( b
  269.     SD_SPI_Init();                //初始化IO7 T% t7 Z2 h8 P
  270.     for (i = 0; i < 10; i++)SD_SPI_ReadWriteByte(0XFF); //发送最少74个脉冲
    % [+ m/ }0 R2 H' {3 ^
  271.     retry = 20;, U" R# y; n0 V, N1 A" s
  272.     do
    " M, q6 `, X  n# X7 l
  273.     {3 `" C! G* {2 N1 N5 y. T" a
  274.         r1 = SD_SendCmd(CMD0, 0, 0x95); //进入IDLE状态
    ) k2 |2 }, }2 g7 D' ~
  275.     }
      F3 ]. Z) [) x1 B+ n
  276.     while ((r1 != 0X01) && retry--);
    # F0 ?! Z( b5 a
  277.     SD_Type = 0; //默认无卡" D  @6 i+ [+ ]& f! M: h
  278.     if (r1 == 0X01)
    7 k* J3 p/ L/ v0 F: Z
  279.     {+ `& }* a! Y" y4 I1 T# Z
  280.         if (SD_SendCmd(CMD8, 0x1AA, 0x87) == 1) //SD V2.0
    6 n8 c8 {% k& @/ ^
  281.         {
    ( G/ W9 Z! y* m' |% B  U
  282.             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
  283.             if (buf[2] == 0X01 && buf[3] == 0XAA) //卡是否支持2.7~3.6V! O4 q+ e- ~  }) Y4 g; _4 x# p
  284.             {
    : b! J4 @) D3 ]% \7 a% E; i% {
  285.                 retry = 0XFFFE;
    % v" i" n0 Q; ?& Y4 H
  286.                 do
    0 q3 w* T0 L7 [
  287.                 {
    9 l7 @6 k# J# L3 G, p
  288.                     SD_SendCmd(CMD55, 0, 0X01);        //发送CMD554 z1 a" o' y# l0 z7 O7 K( J- o+ t% b
  289.                     r1 = SD_SendCmd(CMD41, 0x40000000, 0X01); //发送CMD41
    5 e# Y5 \' `+ V$ l+ ~  J
  290.                 }$ d. {8 E# {! h! u: @
  291.                 while (r1 && retry--);1 z8 N+ n! C( t; d2 m
  292.                 if (retry && SD_SendCmd(CMD58, 0, 0X01) == 0) //鉴别SD2.0卡版本开始+ h5 X' @( M# T0 m
  293.                 {
    & X. }5 W9 p4 f: e, J1 D, N7 n5 u
  294.                     for (i = 0; i < 4; i++)buf = SD_SPI_ReadWriteByte(0XFF); //得到OCR值
    * \( Y0 `" U6 H
  295.                     if (buf[0] & 0x40)SD_Type = SD_TYPE_V2HC; //检查CCS" Z! q5 [4 f3 {8 [' C
  296.                     else SD_Type = SD_TYPE_V2;
    $ e4 q$ o, T2 b: U# K3 R
  297.                 }
    3 R+ g: q. m+ b' Z4 d+ U1 O! N1 n
  298.             }
      T- p) N* ]0 `6 i# Y# F
  299.         }
    ; @6 }4 r# ]7 F, {) g
  300.         else //SD V1.x/ MMC        V3' x. L8 `2 G5 w) ~8 J- j4 @' g
  301.         {
    7 Y( `7 L9 y& j6 q& _9 R: X, d# \
  302.             SD_SendCmd(CMD55, 0, 0X01);                //发送CMD55& ~/ j- p- Q4 K
  303.             r1 = SD_SendCmd(CMD41, 0, 0X01);        //发送CMD41  u: h+ B  X1 r, l, _
  304.             if (r1 <= 1)
    # \9 |! S- N7 \* J! E2 ]5 N
  305.             {
    9 r/ x/ o3 \& D. E- |7 C
  306.                 SD_Type = SD_TYPE_V1;- T! N& D+ e  u, R4 l* e
  307.                 retry = 0XFFFE;" @' k) _4 h: e
  308.                 do //等待退出IDLE模式" C! k3 N; t, ^3 Z+ I
  309.                 {
    & B" Z7 \  x* ?7 X
  310.                     SD_SendCmd(CMD55, 0, 0X01);        //发送CMD55
    1 R6 G- A" [/ _! p! N5 m/ f5 \
  311.                     r1 = SD_SendCmd(CMD41, 0, 0X01); //发送CMD41
    8 x. B  J) G) D0 t
  312.                 }, }5 d+ ^! Q& d- o  r
  313.                 while (r1 && retry--);
    7 T; Q( o, a% d/ z# r* I
  314.             }: E* o6 x! S, t: t$ R1 J
  315.             else
    2 |1 s- Z& v0 D8 @' h1 z) O  h0 q6 q
  316.             {
    ) |" H0 f! M; a- i2 Z$ O2 D& d
  317.                 SD_Type = SD_TYPE_MMC; //MMC V3
    ( S9 I: n' g& `9 H2 _2 C3 i
  318.                 retry = 0XFFFE;
    ! l* s" Z# v) I" Q6 \0 K% q' m
  319.                 do //等待退出IDLE模式
    $ J! a2 f6 C/ P: j) S3 ?
  320.                 {/ q8 Z* C: P1 _2 I6 F
  321.                     r1 = SD_SendCmd(CMD1, 0, 0X01); //发送CMD1
    / ]% m( @: A  D# Y+ @8 s
  322.                 }# h; F. F9 O; _
  323.                 while (r1 && retry--);
    5 }9 k- J8 _7 M. z5 d
  324.             }
    1 B( \' T0 x) A3 l
  325.             if (retry == 0 || SD_SendCmd(CMD16, 512, 0X01) != 0)SD_Type = SD_TYPE_ERR; //错误的卡" E8 O: d5 q! _9 j/ U- [$ B
  326.         }
    8 A- ?4 z; d: |0 A8 r% [
  327.     }- U1 C. x5 r6 x- [
  328.     SD_DisSelect();//取消片选
      i& J0 H- w: F+ Z& S
  329.     if (SD_Type)return 0;2 e. K" K1 |, F# q, [
  330.     else if (r1)return r1;
    7 q; t- O+ R0 b* z! O$ G
  331.     return 0xaa;//其他错误
    * B1 ?+ Y* M1 X) S
  332. }9 K0 n1 a( m9 Y: ^* N

  333. $ H) a2 A) ]: P8 Z# W8 U
  334. /**
    / O5 S* s; R! {! l3 J
  335. * 读取SD卡一个扇区7 x5 t( N8 S2 H/ ~- u. L: x% A
  336. * @param  buf    存放读取的数据
      ]4 |# E+ z0 G  u) C0 m( m
  337. * @param  sector 扇区编号
    ! D5 J1 R8 o( h- D1 S) a; T: @
  338. * @param  cnt    要读取的扇区个数
    : T1 n7 B* Z; p& m3 D
  339. * @return        0:成功  other:失败
    ; O8 o: f: M2 }2 v
  340. */" I6 W4 i, p. {
  341. uint8_t SD_ReadDisk(uint8_t*buf, uint32_t sector, uint8_t cnt): o1 q' V5 r4 g" m# v
  342. {
    " ]* s( T3 e0 J) [
  343.     uint8_t r1;% `5 t0 U/ j' ?' }4 P, P2 |  ?
  344.     if (SD_Type != SD_TYPE_V2HC)sector <<= 9; //转换为字节地址7 {  U8 F) t7 w% i( y  h* x
  345.     if (cnt == 1); K  V. z# J& q, N$ I" o
  346.     {5 f# y0 ?/ M6 \: c* Q# m
  347.         r1 = SD_SendCmd(CMD17, sector, 0X01); //读命令
    . T) R" I* f: t/ Y9 G# w" U6 Q
  348.         if (r1 == 0) //指令发送成功
    : _% O0 Q: p/ m$ ]: e" `
  349.         {2 g7 L. F' \' b! {
  350.             r1 = SD_RecvData(buf, 512); //接收512个字节
    , _  K5 }8 {4 s+ o) [, w* \' o
  351.         }/ b% e8 O, F5 q; @
  352.     }0 Q0 p! d5 o' Z1 {! n
  353.     else- V3 y2 m$ Y4 T% B- n  K
  354.     {( R, V0 V, A& S& \
  355.         r1 = SD_SendCmd(CMD18, sector, 0X01); //连续读命令; |# X4 e; Y  c6 m0 j
  356.         do
    8 I- o$ L7 E; G: a, v7 p8 ^5 I
  357.         {# T( C4 F' N) A* J- O
  358.             r1 = SD_RecvData(buf, 512); //接收512个字节
    9 z5 u( P( {: p! t3 z4 F: @7 E8 q
  359.             buf += 512;+ ]1 y: m* y' A) T$ v! j5 _8 O
  360.         }
    " H2 T: Q# m+ z
  361.         while (--cnt && r1 == 0);5 `' |0 W! }; H- K
  362.         SD_SendCmd(CMD12, 0, 0X01);        //发送停止命令8 S- m/ ^0 I  [+ |/ b: r
  363.     }
    2 c; b" l  c! i% u5 W5 x
  364.     SD_DisSelect();//取消片选* Q. i/ j# i  J
  365.     return r1;//
      e! X7 R0 U/ t$ T( y; D' X
  366. }. N) m7 h8 m( d2 p/ L% @

  367. ) A0 F# `8 d- m  U" L
  368. /**
    % j1 w, q; g* k! I& _
  369. * SD卡写一个扇区的数据' N. H, V: k+ I1 H! ]
  370. * @param  buf    存放待写入的数据
    ( h) a0 b$ R! J/ V% y. o& L1 `  u
  371. * @param  sector 扇区编号
    1 i# M8 N0 e1 m1 ]
  372. * @param  cnt    要写入的扇区个数4 h8 ~! O( z( x, b4 l9 m
  373. * @return        0:成功  other:失败
    / O& T' n0 B8 S8 ]6 u
  374. */5 B/ q, p* \$ E3 r' G2 K
  375. uint8_t SD_WriteDisk(uint8_t*buf, uint32_t sector, uint8_t cnt)
    % u5 X' C% y5 Y
  376. {
    " a( E1 C( R2 s# }# A
  377.     uint8_t r1;6 P/ @# Z) _3 g$ e
  378.     if (SD_Type != SD_TYPE_V2HC)sector *= 512; //转换为字节地址
    $ k/ D- u$ w0 j5 ?+ }5 Q* D6 A$ O
  379.     if (cnt == 1)
    + y+ F' Y% N* U, ?
  380.     {
    : J1 }! @8 L6 D9 P: Y
  381.         r1 = SD_SendCmd(CMD24, sector, 0X01); //读命令
    , O2 t# v2 R( g5 e% ]! o# `
  382.         if (r1 == 0) //指令发送成功
    6 W0 b4 r, @/ R5 Y) A; j. e0 M
  383.         {
    5 t; E% @( Z6 Z# Y# ^% R; {( A
  384.             r1 = SD_SendBlock(buf, 0xFE); //写512个字节
    3 L; c) r5 E- J0 J8 B$ s( ^
  385.         }
    & a9 F5 q! q$ A1 {0 j) s9 l3 l/ V
  386.     }
    : v6 @5 {% a) T. D$ [% ]
  387.     else
    ' K2 K( B" V% ~. i/ M7 i) b
  388.     {
    + `3 C( ^& x3 z0 v2 J  y$ }: A1 K
  389.         if (SD_Type != SD_TYPE_MMC)
    & l0 i3 o- t9 K: c" a
  390.         {
    ( H7 @( D0 [* G* q% }8 g
  391.             SD_SendCmd(CMD55, 0, 0X01);
    9 }, X3 r& f& Y9 j  ^& X
  392.             SD_SendCmd(CMD23, cnt, 0X01); //发送指令6 Q  e& H% h: \$ Y* \; q3 [3 h+ L
  393.         }  G+ Q5 F. O2 F( E6 ^) l
  394.         r1 = SD_SendCmd(CMD25, sector, 0X01); //连续读命令
    1 N4 ?* ~# V4 _/ v% ?; ^8 r- M
  395.         if (r1 == 0)
    + P1 v9 c' K( A" j) W
  396.         {* q' D9 L1 `& t. j* ^
  397.             do
    $ X2 a$ v" a+ S
  398.             {
    2 v1 _0 ^; Q& t# o/ N! ~* v, V
  399.                 r1 = SD_SendBlock(buf, 0xFC); //接收512个字节
    % M! n5 I" V4 D- t6 {0 D
  400.                 buf += 512;
    - n. A; N1 c: _/ y3 |  o
  401.             }
    & N7 d7 ?1 ^+ j" p" L3 T
  402.             while (--cnt && r1 == 0);$ {$ u; |% Z. k' J& @0 u
  403.             r1 = SD_SendBlock(0, 0xFD); //接收512个字节
    * E. o3 S" ?: W' d- P
  404.         }
    2 O6 W' q' h8 z0 `
  405.     }. m: [6 j- e2 D! a
  406.     SD_DisSelect();//取消片选
    & \9 B$ \% {* i1 f
  407.     return r1;//
    1 w2 }4 j. r) x, o
  408. }
复制代码
  1. #ifndef _MMC_SD_H_
    ) \, ~: z3 d6 Z0 U9 M
  2. #define _MMC_SD_H_  u2 g* w0 `1 Q+ u) v( F# L

  3. 9 V- ^3 w4 I  y' }# t% A  g
  4. #include "main.h"
    % K& T. ?4 o) u$ L" ~
  5.   j. H+ ?8 A, X) D3 ?& B3 {
  6. // SD卡扇区大小
    ) l7 D& Z& s7 j3 ?6 h1 H
  7. #define SD_SECTOR_SIZE  512U0 Q- E: G3 v6 S! T5 r% F

  8. 5 J0 v2 T# D4 c6 a0 G2 ^* b& ]
  9. // SD卡类型定义
    0 R( @+ W" d- f+ Q, z( j" Z, _
  10. #define SD_TYPE_ERR     0X00$ Q$ u" [  g% E9 p
  11. #define SD_TYPE_MMC     0X01
    7 R( o; s" ?0 u9 Z" |
  12. #define SD_TYPE_V1      0X02* P& G1 e* I* f1 `' a: p
  13. #define SD_TYPE_V2      0X04
    9 ?* h! _3 P: }& ]* V
  14. #define SD_TYPE_V2HC    0X065 q' x- S9 O* f" K( h! h$ W
  15. . ?4 D! p. }# W& f
  16. // SD卡指令表
    % m0 g8 O! Z! w4 q' v% [  {' B
  17. #define CMD0    0       //卡复位
    - k6 x" L8 D  N
  18. #define CMD1    1# d' b9 }" Y! K4 K" R2 J% t9 D
  19. #define CMD8    8       //命令8 ,SEND_IF_COND6 I* r1 s6 l1 N) z3 V: E
  20. #define CMD9    9       //命令9 ,读CSD数据
    & X0 \9 m. x  q- x0 v0 m
  21. #define CMD10   10      //命令10,读CID数据; z! U8 U9 J( D# [) c1 I* b
  22. #define CMD12   12      //命令12,停止数据传输
    $ F2 N& F; T( A0 P  M
  23. #define CMD16   16      //命令16,设置SectorSize 应返回0x001 e- p& [! V2 C+ k- e( r
  24. #define CMD17   17      //命令17,读sector
    % v: I4 |/ r8 L3 \. C% M2 S
  25. #define CMD18   18      //命令18,读Multi sector$ f' e! {$ {& S$ I& C" u3 W; h
  26. #define CMD23   23      //命令23,设置多sector写入前预先擦除N个block
    + Z* C( ?  L/ }; s# L) s8 c
  27. #define CMD24   24      //命令24,写sector
    , v: E9 ~9 ~+ u+ l+ d
  28. #define CMD25   25      //命令25,写Multi sector3 B& k$ S! s  D! F  z6 x6 I* U7 Z
  29. #define CMD41   41      //命令41,应返回0x00" h4 O* P) x3 n' l8 t; }
  30. #define CMD55   55      //命令55,应返回0x01' I, X( P* I' D7 k- v2 q( P
  31. #define CMD58   58      //命令58,读OCR信息- O8 {/ H3 f+ ?# U
  32. #define CMD59   59      //命令59,使能/禁止CRC,应返回0x00
    , P; T+ I6 ]& Z
  33. $ P- Q0 C& v4 A$ W4 g3 i6 _
  34. //数据写入回应字意义
    ; E$ ]  f1 r( `0 }! O, _
  35. #define MSD_DATA_OK                0x057 z7 U/ a+ S$ O! j. T! R, S" C
  36. #define MSD_DATA_CRC_ERROR         0x0B5 v2 u; W, s: d  M! h( Z
  37. #define MSD_DATA_WRITE_ERROR       0x0D
    * j  }+ ~5 m  N: i
  38. #define MSD_DATA_OTHER_ERROR       0xFF. C- M+ Z0 k8 L& H

  39. : r' H1 c2 V: q1 Y! A, O
  40. //SD卡回应标记字
    1 H4 e; g; ?  O" V% Y# i
  41. #define MSD_RESPONSE_NO_ERROR      0x00
    # Z) L" o  I6 c$ r
  42. #define MSD_IN_IDLE_STATE          0x01! D) w) ^& v2 ?0 ]0 Y/ k
  43. #define MSD_ERASE_RESET            0x02
    . v( s) p6 M6 n# U- G% I6 F1 I' Q
  44. #define MSD_ILLEGAL_COMMAND        0x042 G8 z- X0 W8 Q* s" E
  45. #define MSD_COM_CRC_ERROR          0x08* X  b% j) G4 _$ N1 d0 J/ @9 T
  46. #define MSD_ERASE_SEQUENCE_ERROR   0x10% _4 p& ?8 x# c3 u. l9 i
  47. #define MSD_ADDRESS_ERROR          0x200 s6 Z: C" C& _" P
  48. #define MSD_PARAMETER_ERROR        0x40
    - i$ a  b& z% a" }. `! p/ ?3 ?
  49. #define MSD_RESPONSE_FAILURE       0xFF
    - Z& {3 ]" z; o

  50. 2 M& ~  Q% x  @; C5 [. j
  51. // SD卡片选引脚控制,使用STM32CUBEMX配置SD卡片选引脚为输出模式并设置为高电平
    ) v& ?' y  o1 B5 z2 i3 M
  52. #define SD_CS_H()                HAL_GPIO_WritePin(SD_CS_GPIO_Port, SD_CS_Pin, GPIO_PIN_SET). [+ J5 b2 r) G" {
  53. #define SD_CS_L()                HAL_GPIO_WritePin(SD_CS_GPIO_Port, SD_CS_Pin, GPIO_PIN_RESET)
    - P/ U% h0 M! G) _

  54. / n+ A  [$ `% U( L
  55. extern uint8_t  SD_Type;                        //SD卡的类型
    % o8 e; h  h* A0 c, J' O) o! E4 M/ {

  56. , @! r2 t! ?; C* v* _2 V7 g
  57. //函数申明区
    7 [1 K4 u& ?& `% k) U
  58. uint8_t SD_WaitReady(void);                                                        //等待SD卡准备
    ' I  C# M5 M5 r8 d; M
  59. uint8_t SD_GetResponse(uint8_t Response);                                        //获得相应
    % }% H2 }+ Z4 u' f1 J+ M2 O9 u
  60. uint8_t SD_Initialize(void);                                                        //初始化
    + Y* }6 X8 b- T# q6 `4 V
  61. uint8_t SD_ReadDisk(uint8_t*buf,uint32_t sector,uint8_t cnt);                //读块
    + B; |1 z% `  k9 s
  62. uint8_t SD_WriteDisk(uint8_t*buf,uint32_t sector,uint8_t cnt);                //写块) |* f( ^3 I" F0 }. U; R3 W: A
  63. uint32_t SD_GetSectorCount(void);                                           //读扇区数
    5 d9 v( [+ J$ \
  64. uint8_t SD_GetCID(uint8_t *cid_data);                     //读SD卡CID
    / l( x& Q5 L; H, f
  65. uint8_t SD_GetCSD(uint8_t *csd_data);                     //读SD卡CSD
    & X1 K$ ?0 G) B4 X4 x5 d  V

  66. " {: Y* k0 ~- ?0 H: v& m; C' A
  67. #endif
    / _/ D5 H& l9 ?: [1 x( o) C

  68. 8 s  e7 [! s5 d8 K, z+ W' v5 H
  69. " X& V& B8 l% ?6 K- l- \4 I
复制代码

, D, b8 E! U) [/ ~
赞 收藏 评论0 发布时间:2022-4-11 10:16

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版