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

【经验分享】STM32 SDIO详解

[复制链接]
STMCU小助手 发布时间:2022-4-17 21:15
1、SDIO简介
% O) F  s- @$ n$ u- NSDIO,全称:Secure Digital Input and Output,即安全数字输入输出接口。它是在SD卡接口的基础上发展而来,它可以兼容之前的SD卡,并可以连接SDIO接口设备,比如:蓝牙、WIFI、照相机等。
& w+ s& b/ g# F) y2 x9 `4 m5 ?! R+ Y7 D& r
SDIO和SD卡规范间的一个重要区别是增加了低速标准。低速卡的目标应用是以最小的硬件开支支持低速I/O能力。低速卡支持类似调制解调器、条码扫描仪和GPS接收器等应用。$ S+ J/ d: ]# Y6 ?# q9 v& |8 ?
/ \- G9 `3 S3 G3 \
STM32的SDIO控制器支持多媒体卡(MMC卡)、SD存储卡、SDI/O卡和CE-ATA设备。
- h% q- t% D# Q0 W
- l9 P7 V- e2 X3 S, mSDIO框图: ?5 J4 S: _% D# t4 Z

# @  B# g7 J3 a fce26341379d9bf350b4ff04ee7e2d8c.png
! c: J% x3 n3 i* ?
: F  T! P& x9 `% m+ j复位后SDIO_D0用于数据传输。初始化后主机可以改变数据总线的宽度(通过ACMD6命令设置)
: K3 A0 ~# A/ i4 {1 E* W; D$ @( K2 B/ w( S7 \9 E1 ?. [& v
如果一个多媒体卡接到了总线上,则SDIO_D0、SDIO_D[3:0]或SDIO_D[7:0]可以用于数据传输。      8 A, f6 e. Y" o% m% z6 ^
6 h$ U- k1 S: Y' a
MMC版本V3.31和之前版本的协议只支持1位数据线,所以只能用SDIO_D0(为了通用性考虑,在程序里面我们只要检测到是MMC卡就设置为1位总线数据)
% Y  `% a; B6 q! l
3 U9 q* W8 {& m' @  h7 T7 Y5 p02、SDIO特点
# J% W! n. X8 I) p1 R4 B①与多媒体卡系统规格书版本4.2全兼容。支持三种不同的数据总线模式:1位(默认)、4位和8位。
* S* B  m- {. b+ n7 M1 ^0 o1 z8 e
- z+ j" L! r+ p9 [$ `  E( ]②与较早的多媒体卡系统规格版本全兼容(向前兼容)。7 B2 D% {0 B1 w1 O; V

! a4 H! O2 ^; e$ Q3 a+ O③与SD存储卡规格版本2.0全兼容。% ~. T# }! ]2 y% e+ F6 a
% ^! ?; w* ^6 e% W  e
④与SDI/O卡规格版本2.0全兼容:支持两种不同的数据总线模式:1位(默认)和4位。5 J! g# c+ \" J  B- m' Q) E

2 F+ N5 n+ ~9 t⑤完全支持CE-ATA功能(与CE-ATA数字协议版本1.1全兼容)。8位总线模式下数据传输速率可达48MHz。
/ B5 W( {3 v! k5 t2 m  Y7 j7 n, t' O( P+ q2 w+ X; J* z; q* Y) z6 U
⑥数据和命令输出使能信号,用于控制外部双向驱动器。
$ [1 H: K2 p- G4 e+ A8 `' h
) W6 W' d# E& A4 F1 F! r( Z03、SDIO时钟
! t  w8 F. f2 q, Q6 ]2 h3 ~1.卡时钟(SDIO_CK):每个时钟周期在命令和数据线上传输1位命令或数据。对于SD或SD I/O卡,时钟频率可以在0MHz至25MHz间变化。
. {% v4 B" I8 K3 Q* \9 B* o2 i6 z. f1 t7 n! T
2.SDIO适配器时钟(SDIOCLK):该时钟用于驱动SDIO适配器,可用于产生SDIO_CK时钟。SDIOCLK来自PLL48CK(48Mhz)。7 C& ]+ C9 @# K6 @' m, G
5 o+ W! \1 ]) ~" \& X
APB2总线接口时钟(PCLK2):该时钟用于驱动SDIO的APB2总线接口,其频率为PCLK2=84Mhz。( Z  M+ s% i  u5 n- i' Q

! c: x: Z' Z* [: R5 qSDIO_CK计算公式:SDIO_CK=SDIOCLK/(2+CLKDIV)7 e, f8 k: r$ l9 ?$ _2 {
) M. Q9 ?* A# Z+ O# D9 M+ `) b
注意:在SD卡初始化时,SDIO_CK不可以超过400Khz,初始化完成后,可以设置为最大频率(但不可以超过SD卡最大操作频率)
, e- ^; U# f' x% \- {# |6 E& P: p6 N: q, h: H9 S
04、SDIO的命令与响应
, K: l# F  \& D: s  d, m) P9 m2 m命令

$ s$ V5 r+ X: f+ k: l
  N: Q; D( d: N& F1.SDIO的命令分为:应用相关命令(ACMD)和通用命令(CMD)两部分。发送ACMD时,需先发送CMD55。! {0 [. v' T" c' v% T
' `+ Z- g2 X8 H. W  P1 X
2.SDIO所有的命令和响应都是在SDIO_CMD引脚上面传输的,命令长度固定为48位,SDIO命令格式如下表所示:& L5 M  Y' C* {0 g  E6 X8 [

+ t/ x7 x& V" m% V: N/ G 2d83122ee069189e9e437916e670248a.png
% Y- a- m0 r' z& s3 Q" _2 M8 W: A% R7 k# Z# y0 ]+ _
其中:除了命令索引和参数需要我们设置,其他都是由SDIO硬件自动控制。命令索引(如CMD0,CMD1之类)由SDIO_CMD寄存器设置,命令参数则由SDIO_ARG寄存器设置
. [# Z# V  B$ Q! t' ~, ]
% h5 j- [* `& f( k5 V响应
/ S& Y* k. L* t6 O/ S
8 g! h  q& {& N4 A1.一般SD卡在接收到命令行,都会有一个应答(CMD0例外),这个应答我们也称之为响应。STM32的SDIO接口,支持2种响应类型:短响应(48位)和长响应(136位)2 i# l7 y+ ^. }  v$ d( G. `( a2 I
4 l+ W9 Q, ]" U0 H; c* h: n
2.STM32 SDIO短响应(48位)格式如下表所示:
8 |: X3 x; w  a. x8 p5 X2 Z1 Q# {- q9 ]5 O" u  W
130718cbce19662d2e848517a1a88e99.png
% j  S! x( f: x8 Z4 R/ [' @7 m$ I+ u+ u2 ^5 ~
STM32 SDIO长响应(136位)格式如下表所示  D" e) X5 z% T8 ]" @2 m1 T3 v

# E6 y$ w3 c: v+ H2 t/ D. W5 M 6de500f8462d205c9c47660cef1fac2d.png ; W: R5 C/ Y" J3 i
* B7 s& r5 K! P; B$ V8 G
不论是短响应还是长响应,硬件都会自动滤除了起始位、传输位、CRC7以及结束位等信息,对于短响应,命令索引存放在SDIO_RESPCMD寄存器,参数则存放在SDIO_RESP1寄存器里面。对于长响应,则仅留CID/CSD位域,存放在SDIO_RESP1~SDIO_RESP4等4个寄存器。
; S/ [  E. J- T$ Q6 X, j2 m& F8 c$ l% T+ \1 ^& Z8 G
SD卡的响应: X2 y# d  ]/ c, [
( i0 H; k3 m$ \  J
SD卡总共有6类响应(R1、R1b、R2、R3、R6、R7),我们这里以R1为例简单介绍一下。R1(普通响应命令)响应属于短响应,其长度为48位,如下表所示:; P0 I( C; y; L5 s3 F$ }% O& B8 F

  _1 k4 X* t0 |8 D 8b314e8d311ad91b556f02f55c421abf.png * |6 q- b1 I2 b

* m4 v1 M8 x( C. S- |: j在收到R1响应后,我们可以从SDIO_RESPCMD寄存器和SDIO_RESP1寄存器分别读出命令索引和卡状态信息。关于其他响应的介绍,请大家参考光盘:《SD卡2.0协议.pdf》
+ q$ e/ H6 F/ o6 \9 q- z5 E9 }, h( c+ ~
0 Z  p8 a" ~( A; s6 P" E- O9 {05、SDIO块数据传输
! r; Z% m- L  K0 w多数据块读操作
5 d) J% F" J0 z$ \! R* a
. q: f# t! u) e
SDIO与SD卡通信一般以数据块的形式进行传输,SDIO(多)数据块读操作,如下图所示
  r7 s! A) v9 [. j2 u! s) |5 q. r
e7bb859ba99ff447fce0f73a6e1e4d72.png
+ }9 u9 e7 ?2 e+ n( r% z& h+ ?; O" V. D( g# Z, r( U% V3 U
从机在收到主机相关命令后,开始发送数据块给主机,所有数据块都带CRC校验(由硬件自动处理),单个数据块读的时候,在收到1个数据块以后即可以停止了,不需要发送停止命令(CMD12).但是多块数据读的时候,SD卡将一直发送数据给主机,直到接到主机发送的STOP命令(CMD12)+ y+ j0 @# L- _6 f- ?2 Y! f2 f2 [0 o
; x7 X# N6 A7 i
多数据块写操作2 a) K# P2 ?! f6 k" F2 u
9 H7 E$ I4 }+ O7 S
SDIO(多)数据块写操作,如下图所示
7 Z% B+ t3 A" R- q) I
7 ~! Y: V) s) V0 A! T$ D 81e60d5e1e51cda815e041e241647551.png
! Q8 U. q" \' N- A$ K1 s7 `$ u' Y+ K2 z# c
数据块写操作同数据块读操作基本类似,只是数据块写的时候,多了一个繁忙判断,新的数据块必须在SD卡非繁忙的时候发送。这里的繁忙信号由SD卡拉低SDIO_D0,以表示繁忙,SDIO硬件自动控制,不需要我们软件处理。5 E1 O' o3 u% e5 n6 I

# H& k* s8 y6 I) w! m注意:当SDIO_CK频率过快时,可能导致SD卡通信失败,此时,建议降低SDIO_CK试试。
( r1 M' U; y5 a0 ^( R( q4 ?4 K# F6 J4 {0 B- V/ L1 |) N
06、代码' X8 R! X7 a) W) @! X4 @
STM32的SDIO控制器驱动还是很复杂的,ST提供了stm32f2x_sdio_sd.c驱动文件,我们组要修改对应的GPIO驱动即可。% L: ?  R' t$ Q

- L; \, p6 N+ W6 b1 H, D" M8 i
  1. /**1 |& \' A4 e6 a7 Z
  2.   * @brief  Initializes the SD Card and put it into StandBy State (Ready for
    8 j. v' H* k5 ^
  3.   *         data transfer).
    * U2 ~5 E" B) I0 A+ W
  4.   * @param  None
    1 j1 I- ]2 H6 F8 M7 p
  5.   * @retval None5 X4 C  n* i* ?  f2 X# ^0 n% S
  6.   */
    ( g4 J0 i% O; ?1 F2 u' O
  7. void SD_LowLevel_Init(void)/ h/ e  F6 U$ A8 F, \
  8. {
    8 @* \4 T* c  g' N6 M3 f
  9.   GPIO_InitTypeDef  GPIO_InitStructure;5 S. h. s( }4 @' c% E9 K3 ?5 T/ _
  10. / ^8 E3 {4 q* _+ L+ p5 ?7 {
  11.   /* GPIOC and GPIOD Periph clock enable */
    $ D: ?! X/ s, ?" c
  12.   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | SD_DETECT_GPIO_CLK, ENABLE);
    8 ^7 r6 s, e. u7 k  Y
  13. * p: T* q: ?9 w: r0 \
  14.   GPIO_PinAFConfig(GPIOC, GPIO_PinSource8, GPIO_AF_SDIO);, ^+ L1 S% `5 I, `
  15.   GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_SDIO);6 ?% S  t. Z! R! F# |% }: |/ C
  16.   GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_SDIO);* T8 A3 c+ y, C7 f* V2 s6 {' l0 D
  17.   GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_SDIO);' d' [; z' I% M4 O# R
  18.   GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_SDIO);7 G# ^0 a% I( j; T# S
  19.   GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_SDIO);
    ( A' `, y. A5 J0 [

  20. 5 z* F4 r8 e8 ]- ], a2 `7 p- ~
  21.   /* Configure PC.08, PC.09, PC.10, PC.11 pins: D0, D1, D2, D3 pins */
    ' Y. H1 X0 ~* y1 e3 A
  22.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11;
    5 G: `- T1 K. R( m1 c" Q9 z, T
  23.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;% K( P' m# K' L* x6 f
  24.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;4 L( u# q; N# S
  25.   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;) S6 i5 }* _5 Y* j8 B4 d8 N/ E
  26.   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;6 v1 U% ]6 I6 O1 B
  27.   GPIO_Init(GPIOC, &GPIO_InitStructure);7 z* `3 O0 }+ k0 l
  28. # W  w( `0 a) Z9 g
  29.   /* Configure PD.02 CMD line */- s8 ]( ]6 Y1 b* C0 W3 ^* |7 ^
  30.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    7 o3 y+ w* V! `" S. m: g6 F( I
  31.   GPIO_Init(GPIOD, &GPIO_InitStructure);
    5 H  J6 J! e) x  f
  32. 1 Z$ D! F, L5 H* K/ X& x' x& i6 [
  33.   /* Configure PC.12 pin: CLK pin */# C1 J- c7 y6 y6 X+ O/ T
  34.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;9 X3 x" G' |8 M' P* I
  35.   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;4 u* \1 t; o- ~9 S
  36.   GPIO_Init(GPIOC, &GPIO_InitStructure);) {! x- {( t0 B4 T$ W7 g( X/ U
  37. 8 l8 H* q' {# L+ U
  38.   /*!< Configure SD_SPI_DETECT_PIN pin: SD Card detect pin */' O* _  C, m9 K% `) F4 S9 d, c
  39.   /*GPIO_InitStructure.GPIO_Pin = SD_DETECT_PIN;
    3 I* [% g2 t5 |; T) [# K% b7 V
  40.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
    $ a5 C% h. ]4 ]- T- b
  41.   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;- }/ b& q* f* j/ Z
  42.   GPIO_Init(SD_DETECT_GPIO_PORT, &GPIO_InitStructure);*/
    : X8 ^0 @* G4 Q* ^5 P
  43. " N$ Y5 t; }- t# x+ ^" ^0 m
  44.   /* Enable the SDIO APB2 Clock */* N0 A5 B& B' @$ c# O
  45.   RCC_APB2PeriphClockCmd(RCC_APB2Periph_SDIO, ENABLE);
    5 v4 D  u9 E# X- m" y

  46. 9 t! X/ r$ _3 y2 W' }, p3 I
  47.   /* Enable the DMA2 Clock */! Q2 N& Q  o7 t5 `' f4 L
  48.   RCC_AHB1PeriphClockCmd(SD_SDIO_DMA_CLK, ENABLE);6 G, l' {  Z8 P
  49. }" Q3 }- o+ z( [) y- F5 k: s9 n
复制代码
% C0 ]: M) d8 _/ p% I1 i* |1 y2 g
DMA等配置使用默认的即可。3 W0 O6 z. I! ^" n/ k* r+ n* F
2 a$ n2 ~) u- s+ i) Y0 d
我们需要使用的函数接口有
! B# W2 A' |- u- Q1 d. ]
9 x4 s' Z' o9 \4 T4 @* I. K
  1. SD_Error SD_Init(void);
    * \2 ~) f/ T; J& @/ Y3 r" K+ Q
  2. SD_Error SD_Erase(uint32_t startaddr, uint32_t endaddr);
    ) w  d" j: u& q; s) E9 K4 L
  3. SD_Error SD_WriteBlock(uint8_t *writebuff, uint32_t WriteAddr, uint16_t BlockSize);
    % {5 q( _8 T3 |! {" j
  4. SD_Error SD_ReadBlock(uint8_t *readbuff, uint32_t ReadAddr, uint16_t BlockSize);
复制代码
; Q1 z" l, S) W+ [7 q$ `+ l/ ]( V
下载验证
2 ~  e4 k( i# L
" f' v2 H: j. G9 H! j- g b1f6570da5c37cff0345099d9051d796.png 6 N; w! n9 N- R/ p

1 i/ f8 u  J* M8 W
* E# V" q$ i5 K# W7 |; a9 b! s" H1 u
收藏 评论0 发布时间:2022-4-17 21:15

举报

0个回答

所属标签

相似技术帖

官网相关资源

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