01SDIO简介
' ] e' E8 e V/ m4 D# NSDIO,全称:Secure Digital Input and Output,即安全数字输入输出接口。它是在SD卡接口的基础上发展而来,它可以兼容之前的SD卡,并可以连接SDIO接口设备,比如:蓝牙、WIFI、照相机等。
. g, ^* f+ [) m2 I- s$ l- `. RSDIO和SD卡规范间的一个重要区别是增加了低速标准。低速卡的目标应用是以最小的硬件开支支持低速I/O能力。低速卡支持类似调制解调器、条码扫描仪和GPS接收器等应用。2 e+ X. m7 a! D
STM32的SDIO控制器支持多媒体卡(MMC卡)、SD存储卡、SDI/O卡和CE-ATA设备。
4 \' r5 Z) |+ b! }2 i% A2 `$ _5 `SDIO框图+ q/ E8 X& M B1 n# O8 u1 ]( ^$ m6 w
- A: S8 K8 y, Z$ o, M2 P
复位后SDIO_D0用于数据传输。初始化后主机可以改变数据总线的宽度(通过ACMD6命令设置)
7 ?$ s: S/ J; N# I: c% L( c1 K如果一个多媒体卡接到了总线上,则SDIO_D0、SDIO_D[3:0]或SDIO_D[7:0]可以用于数据传输。
1 d6 [2 g$ G; [2 aMMC版本V3.31和之前版本的协议只支持1位数据线,所以只能用SDIO_D0(为了通用性考虑,在程序里面我们只要检测到是MMC卡就设置为1位总线数据); ?& I& y+ C/ K" v
% Y1 g# i. P$ `
; m; ~. r' q0 v% o# {3 d02SDIO特点% u7 K' q2 O5 G6 j- V$ H0 `
①与多媒体卡系统规格书版本4.2全兼容。支持三种不同的数据总线模式:1位(默认)、4位和8位。& J+ Q3 m- Q* f. \0 N+ \" D
②与较早的多媒体卡系统规格版本全兼容(向前兼容)。* A B% Q# ~$ y0 I7 Y0 O* l {6 o
③与SD存储卡规格版本2.0全兼容。2 w' _2 }' g0 b) W+ U
④与SDI/O卡规格版本2.0全兼容:支持两种不同的数据总线模式:1位(默认)和4位。
/ _+ ^( E @' \" a& _( G⑤完全支持CE-ATA功能(与CE-ATA数字协议版本1.1全兼容)。8位总线模式下数据传输速率可达48MHz。% v" y, E, w9 o( b
⑥数据和命令输出使能信号,用于控制外部双向驱动器。
8 a& D* T. c& G' B. x/ H0 [) G4 d% i, K; ?4 y$ M5 I( `) v I
8 C3 y7 G6 p3 c4 l! t! _
03SDIO时钟
6 s6 }# ]5 R0 M0 Z卡时钟(SDIO_CK):每个时钟周期在命令和数据线上传输1位命令或数据。对于SD或SD I/O卡,时钟频率可以在0MHz至25MHz间变化。 F1 U1 ?! i8 p
SDIO适配器时钟(SDIOCLK):该时钟用于驱动SDIO适配器,可用于产生SDIO_CK时钟。SDIOCLK来自PLL48CK(48Mhz)。
5 _- s& N7 Q7 b. D* jAPB2总线接口时钟(PCLK2):该时钟用于驱动SDIO的APB2总线接口,其频率为PCLK2=84Mhz。
1 r6 P4 ^. w2 L( Q" _SDIO_CK计算公式:SDIO_CK=SDIOCLK/(2+CLKDIV)
9 U% r2 a. ^, G8 o5 g注意:在SD卡初始化时,SDIO_CK不可以超过400Khz,初始化完成后,可以设置为最大频率(但不可以超过SD卡最大操作频率)
! B1 V3 v5 ]4 A! x/ Y0 M$ E2 _, Y0 r9 S, g8 F4 W" Z
* u8 H' p, J( t5 E% g$ V; [04SDIO的命令与响应! Z/ G% r- _0 P% A& \1 n, x v
命令
( i+ }( q" m* T( `( K0 _; PSDIO的命令分为:应用相关命令(ACMD)和通用命令(CMD)两部分。发送ACMD时,需先发送CMD55。% p6 g7 s2 f! J* Y n
SDIO所有的命令和响应都是在SDIO_CMD引脚上面传输的,命令长度固定为48位,SDIO命令格式如下表所示:
: a% y4 x% ]2 |! Y
6 U* Y: h1 k7 A其中:除了命令索引和参数需要我们设置,其他都是由SDIO硬件自动控制。命令索引(如CMD0,CMD1之类)由SDIO_CMD寄存器设置,命令参数则由SDIO_ARG寄存器设置+ W, y/ F0 D$ Q$ ]/ Z, g( s @
响应
U! `6 M1 u6 t6 W一般SD卡在接收到命令行,都会有一个应答(CMD0例外),这个应答我们也称之为响应。STM32的SDIO接口,支持2种响应类型:短响应(48位)和长响应(136位), k6 r) @7 e6 q) k; P# q+ y0 E* b3 O
STM32 SDIO短响应(48位)格式如下表所示:
9 w( y* p9 j* M# M+ A; X6 D P, }
& e; M+ P/ R X% ^( a E
STM32 SDIO长响应(136位)格式如下表所示4 z# M [' |- a) E
& R8 p& c( |3 Q5 M4 |& C! |& u不论是短响应还是长响应,硬件都会自动滤除了起始位、传输位、CRC7以及结束位等信息,对于短响应,命令索引存放在SDIO_RESPCMD寄存器,参数则存放在SDIO_RESP1寄存器里面。对于长响应,则仅留CID/CSD位域,存放在SDIO_RESP1~SDIO_RESP4等4个寄存器。
, c5 p+ _" H: P0 r2 A- |SD卡的响应. r- @9 o* a, v# R2 g+ D
SD卡总共有6类响应(R1、R1b、R2、R3、R6、R7),我们这里以R1为例简单介绍一下。R1(普通响应命令)响应属于短响应,其长度为48位,如下表所示:2 R$ |4 s; p) k; g+ W
8 p" K0 I) E- R: [6 u
在收到R1响应后,我们可以从SDIO_RESPCMD寄存器和SDIO_RESP1寄存器分别读出命令索引和卡状态信息。关于其他响应的介绍,请大家参考光盘:《SD卡2.0协议.pdf》' T, U+ f8 v ?) a: D+ [) t. `
& v: O& _) _0 x0 ?- j" v
- D" |6 T% H% X# R# [# h0 b' J0 C
05SDIO块数据传输
1 |; m$ N+ B1 T0 V- V5 }: U, U4 b3 P多数据块读操作
) R. n: j1 Q7 X+ r! v& m5 ZSDIO与SD卡通信一般以数据块的形式进行传输,SDIO(多)数据块读操作,如下图所示" y, o! [" p5 C# y4 u- z4 J
8 o) P0 v2 V& i从机在收到主机相关命令后,开始发送数据块给主机,所有数据块都带CRC校验(由硬件自动处理),单个数据块读的时候,在收到1个数据块以后即可以停止了,不需要发送停止命令(CMD12).但是多块数据读的时候,SD卡将一直发送数据给主机,直到接到主机发送的STOP命令(CMD12)9 ?3 {6 J& ~0 F7 k& H1 f1 X
多数据块写操作
: y5 c" E- h6 r0 n$ M) X e2 v: TSDIO(多)数据块写操作,如下图所示
2 Y9 w( K& M" }3 m, j
x& D. X9 H2 F5 C
数据块写操作同数据块读操作基本类似,只是数据块写的时候,多了一个繁忙判断,新的数据块必须在SD卡非繁忙的时候发送。这里的繁忙信号由SD卡拉低SDIO_D0,以表示繁忙,SDIO硬件自动控制,不需要我们软件处理。; C8 n1 F8 D. q& ?. ~
注意:当SDIO_CK频率过快时,可能导致SD卡通信失败,此时,建议降低SDIO_CK试试。
$ O6 `7 y7 ^1 Q F$ x; n! V0 U3 ~! I4 i
( E. }0 K; }$ M. Y; O. \06代码
! m5 `- J' Z3 X: G; |STM32的SDIO控制器驱动还是很复杂的,ST提供了stm32f2x_sdio_sd.c驱动文件,我们组要修改对应的GPIO驱动即可。
! m/ j1 v6 H' W+ {' _- <font face="微软雅黑" size="3">/**( v- g, H4 M E5 Z
- * @brief Initializes the SD Card and put it into StandBy State (Ready for , g! c# Y% f4 ^+ f, {
- * data transfer).
7 }/ D" J& d, Y; d7 J. \' J, ? - * @param None
! a( |2 I m8 t - * @retval None
' B; |& w& G( O2 |6 F+ D - */2 u6 q1 H9 G8 D' O- n
- void SD_LowLevel_Init(void)( ~; ~* S$ J: d; |' k
- {* X/ V# Y4 n3 a% E1 Y
- GPIO_InitTypeDef GPIO_InitStructure;
) t, {, D0 P7 K - : t6 ~% s/ K) I$ C
- /* GPIOC and GPIOD Periph clock enable */" f& e& k6 A) A4 F6 x
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | SD_DETECT_GPIO_CLK, ENABLE);7 M. ^9 d" ]5 o0 e& {6 z
) Q! L( V; |- X8 _2 Q7 r" W4 z- GPIO_PinAFConfig(GPIOC, GPIO_PinSource8, GPIO_AF_SDIO); D& C1 D/ e' L" N# N6 ~- M
- GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_SDIO);
0 s: l( \6 T4 } - GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_SDIO);
) B i" B& u/ } - GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_SDIO);
) M$ E: G' E$ v# s/ e' |9 U9 {" P# w - GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_SDIO);
& M1 z5 y8 J# \2 e- } - GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_SDIO);
?1 o% ?+ `6 o! B) k
5 z# E9 S# t6 ^. N U4 q- /* Configure PC.08, PC.09, PC.10, PC.11 pins: D0, D1, D2, D3 pins */
+ [! l& J, H L, v" S5 Z( E - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11;8 w4 c V ~. d) c( _4 I( r: f# D
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz; n6 i4 U1 g. `, n% A
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;" y$ M. Y) ^6 f1 \* H% n
- GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
/ C8 @" F6 }# O6 l6 X - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
4 z$ ^$ r! Q9 J- T2 ~4 A5 Q- l1 G3 K5 _ - GPIO_Init(GPIOC, &GPIO_InitStructure);; j: q1 u% S9 g2 t/ F; \* |
- 8 C2 n8 R- C: Y7 F
- /* Configure PD.02 CMD line */4 _# c! ]& d4 K+ C3 C6 c
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
: J' b1 U& w( G- b, S/ ~ - GPIO_Init(GPIOD, &GPIO_InitStructure);
/ v7 Y4 E3 W4 u5 ?" ~0 M
. o0 k! [- ]& L1 `# x; I- /* Configure PC.12 pin: CLK pin */
# s; X. s+ W. l% o. p - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;0 `* F! f5 p, o1 Q6 `% y
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;+ j2 u2 F4 }$ v3 p
- GPIO_Init(GPIOC, &GPIO_InitStructure);
8 L% b! }6 j$ ]% x - $ _4 _+ y; s9 o- r
- /*!< Configure SD_SPI_DETECT_PIN pin: SD Card detect pin */
- q5 H, h }$ R$ n9 M+ {* Q- K) L1 I - /*GPIO_InitStructure.GPIO_Pin = SD_DETECT_PIN;
8 W5 Z1 y3 D! g' B4 q$ o$ M" H - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
$ l6 n1 d" p' M$ C- G - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
* _+ I% H, _( g/ L/ }1 M) p( d5 w0 n! A) j - GPIO_Init(SD_DETECT_GPIO_PORT, &GPIO_InitStructure);*/
( N% s8 _) ^: E- o0 o \ - . r A* P$ M6 B9 C+ J
- /* Enable the SDIO APB2 Clock */
" o6 {& x# }9 _. a9 {! V: Z - RCC_APB2PeriphClockCmd(RCC_APB2Periph_SDIO, ENABLE);3 _% S% Y- Z9 Z5 k2 W
4 q( X ]2 p" p, ]- /* Enable the DMA2 Clock */6 s1 c% Y" b2 t; Z) T; L7 L
- RCC_AHB1PeriphClockCmd(SD_SDIO_DMA_CLK, ENABLE);
* `/ C. j7 q; C+ l0 X5 \ - }
# h7 n8 E7 N' n - </font>
复制代码 DMA等配置使用默认的即可。1 }2 `: K; I7 b% W
我们需要使用的函数接口有' O5 i# D! q# i$ A3 K: P
- <font face="微软雅黑" size="3">SD_Error SD_Init(void);
9 w3 f( X$ x. p J+ \ - SD_Error SD_Erase(uint32_t startaddr, uint32_t endaddr);3 W" |& y# ]( B+ H$ q
- SD_Error SD_WriteBlock(uint8_t *writebuff, uint32_t WriteAddr, uint16_t BlockSize);
% N! C- _7 v1 J5 M1 n+ e2 T - SD_Error SD_ReadBlock(uint8_t *readbuff, uint32_t ReadAddr, uint16_t BlockSize);</font>
复制代码 下载验证: D* J# l0 f6 r* g6 K" M4 A
T6 J1 d0 b5 s% S; P4 v& A2 H6 J6 ?+ W: s! \0 x7 e
|