1、SDIO简介
! j) E( l A* R+ k9 h# }+ ~( ^# WSDIO,全称:Secure Digital Input and Output,即安全数字输入输出接口。它是在SD卡接口的基础上发展而来,它可以兼容之前的SD卡,并可以连接SDIO接口设备,比如:蓝牙、WIFI、照相机等。
" O2 N) F5 ^# O
" B& J; Z1 B+ j% L _4 T# z' XSDIO和SD卡规范间的一个重要区别是增加了低速标准。低速卡的目标应用是以最小的硬件开支支持低速I/O能力。低速卡支持类似调制解调器、条码扫描仪和GPS接收器等应用。
: \3 e2 X& B! W3 s) P. K
5 @' c6 C2 Q0 I5 jSTM32的SDIO控制器支持多媒体卡(MMC卡)、SD存储卡、SDI/O卡和CE-ATA设备。
& @/ X" Q+ A) I1 H. A
- u/ }& s" A% y6 Z( c: ASDIO框图* ?' m1 o& C H3 R
9 K0 I2 E/ q9 G- h% a1 O5 H1 R% Y
7 U, U" ^" x5 T2 Y6 l
r& p0 @0 Z9 Y# I3 v! l1 D8 \: Y( X% \
复位后SDIO_D0用于数据传输。初始化后主机可以改变数据总线的宽度(通过ACMD6命令设置)
6 v' _, f/ d( c& X' N
: Y$ b( x2 x1 Y* Z- ~! _) T如果一个多媒体卡接到了总线上,则SDIO_D0、SDIO_D[3:0]或SDIO_D[7:0]可以用于数据传输。
7 n* W7 M8 r7 x; j0 x; l; o# n; Y' E( D5 S' j( W
MMC版本V3.31和之前版本的协议只支持1位数据线,所以只能用SDIO_D0(为了通用性考虑,在程序里面我们只要检测到是MMC卡就设置为1位总线数据)4 c8 @. c. o; C) \/ s2 L) s
% g% G. t3 M! E6 @" r9 f
02、SDIO特点- d2 U9 s F% L0 o2 t
①与多媒体卡系统规格书版本4.2全兼容。支持三种不同的数据总线模式:1位(默认)、4位和8位。( h1 c0 e* w/ [( p% X: I4 o
1 s% |4 P" R% Z0 I" s: f) a②与较早的多媒体卡系统规格版本全兼容(向前兼容)。
; ]" G8 s6 |& e& \( @- Q$ b) H# a9 A! ~
③与SD存储卡规格版本2.0全兼容。& v' P8 B- A7 D. X+ _' v0 V% _
/ w7 }0 r$ F5 l0 m) q1 J2 H7 N1 S④与SDI/O卡规格版本2.0全兼容:支持两种不同的数据总线模式:1位(默认)和4位。/ A( ? s5 A C: e7 R
5 r, A; i7 E9 O" V. b⑤完全支持CE-ATA功能(与CE-ATA数字协议版本1.1全兼容)。8位总线模式下数据传输速率可达48MHz。
+ C H3 P X% N# z
$ q7 R w, `: H, u⑥数据和命令输出使能信号,用于控制外部双向驱动器。2 h9 P. y: v9 h, c5 v+ @
4 [' E( K/ w& e4 E1 ^5 @
03、SDIO时钟
2 \! i# {. w1 W5 v- {1.卡时钟(SDIO_CK):每个时钟周期在命令和数据线上传输1位命令或数据。对于SD或SD I/O卡,时钟频率可以在0MHz至25MHz间变化。
6 r# j7 v; G" x" K1 x2 x
0 p. G" n5 r" m H: }2.SDIO适配器时钟(SDIOCLK):该时钟用于驱动SDIO适配器,可用于产生SDIO_CK时钟。SDIOCLK来自PLL48CK(48Mhz)。
) U3 e3 w. e; n- P/ a( M/ C8 \9 a! P5 L9 g+ N0 E! H" M
APB2总线接口时钟(PCLK2):该时钟用于驱动SDIO的APB2总线接口,其频率为PCLK2=84Mhz。& ?! c J7 C7 `: |* g9 [
0 N+ d/ X: g) f" `SDIO_CK计算公式:SDIO_CK=SDIOCLK/(2+CLKDIV)
2 x; W2 ~& h8 l
4 @4 s3 T; U' s' V- n9 ]7 w4 c注意:在SD卡初始化时,SDIO_CK不可以超过400Khz,初始化完成后,可以设置为最大频率(但不可以超过SD卡最大操作频率)
! |- f' R3 J+ R3 X* ]' \
, k9 J1 m& Y) ?& n; F' _& p* o/ y04、SDIO的命令与响应6 n5 B0 W8 _* C4 J' c$ [+ l% V! N
命令
. @1 B4 L! _% e6 E9 H$ B" [
0 w8 c+ f2 z5 h1.SDIO的命令分为:应用相关命令(ACMD)和通用命令(CMD)两部分。发送ACMD时,需先发送CMD55。
1 m& W' D0 I/ ^3 ?7 W. o/ ~7 H7 W- a. z" `# ^" J
2.SDIO所有的命令和响应都是在SDIO_CMD引脚上面传输的,命令长度固定为48位,SDIO命令格式如下表所示:
" l, I8 B; g0 f, }) d; \1 z- a
8 \! \3 n* Y/ \" k0 S
7 y/ w. x8 C5 W/ z3 P5 \/ K9 k% c
* E& O. t* h( j( O4 T2 ~其中:除了命令索引和参数需要我们设置,其他都是由SDIO硬件自动控制。命令索引(如CMD0,CMD1之类)由SDIO_CMD寄存器设置,命令参数则由SDIO_ARG寄存器设置
- _8 O/ ]4 }' s4 P& G1 V3 d2 i" v$ r: Q- a$ }. j+ _5 F# g8 l) U7 U
响应1 m9 z& G1 T1 }# b4 k6 G3 O' D2 D
6 z# a! G! c0 w/ N6 O4 q
1.一般SD卡在接收到命令行,都会有一个应答(CMD0例外),这个应答我们也称之为响应。STM32的SDIO接口,支持2种响应类型:短响应(48位)和长响应(136位) Q. `0 ?8 f% H0 Z4 M4 A3 I4 {+ f/ l
. r5 e+ J/ H0 G- X
2.STM32 SDIO短响应(48位)格式如下表所示:+ g$ V, p% \% E+ \9 m; f
9 Y. }2 z( d+ e. e n. d& y
! G ]& _6 m& v1 u2 Q
$ F6 d6 _4 p; }4 [
STM32 SDIO长响应(136位)格式如下表所示
4 ^* s1 n& Q8 R1 z. F
. v* ~: t8 N" P. L: f n
8 j' Z p4 u5 J4 G( c& T$ q! O! B( e. F
不论是短响应还是长响应,硬件都会自动滤除了起始位、传输位、CRC7以及结束位等信息,对于短响应,命令索引存放在SDIO_RESPCMD寄存器,参数则存放在SDIO_RESP1寄存器里面。对于长响应,则仅留CID/CSD位域,存放在SDIO_RESP1~SDIO_RESP4等4个寄存器。
! |; L" ~8 ^ w p# E
q% c; h' G& W( ~# ?SD卡的响应
1 O O7 g" T; O& D2 a) N4 f V) s/ u# {3 @
SD卡总共有6类响应(R1、R1b、R2、R3、R6、R7),我们这里以R1为例简单介绍一下。R1(普通响应命令)响应属于短响应,其长度为48位,如下表所示:
5 D: j- v, u! v O+ p
. |& D: b$ s6 P7 k: b3 @
8 C; f6 s# t. S5 M
7 J/ y% B$ Q- L4 Q* y
在收到R1响应后,我们可以从SDIO_RESPCMD寄存器和SDIO_RESP1寄存器分别读出命令索引和卡状态信息。关于其他响应的介绍,请大家参考光盘:《SD卡2.0协议.pdf》
: z. _& z( v6 X
: l2 Z; p. H; ~" Y" _3 O Q05、SDIO块数据传输( n1 t/ N) g3 }/ I% P! d, d8 T
多数据块读操作" X7 E) J2 O, S& [
) S: f4 `: A5 CSDIO与SD卡通信一般以数据块的形式进行传输,SDIO(多)数据块读操作,如下图所示& _$ B; ]% `- ?
$ i4 G1 C) ^9 L( m8 U8 @6 G' |
+ m; n# J+ S1 G" E7 I
/ d% \; B9 R5 ~) Z- p" x G
从机在收到主机相关命令后,开始发送数据块给主机,所有数据块都带CRC校验(由硬件自动处理),单个数据块读的时候,在收到1个数据块以后即可以停止了,不需要发送停止命令(CMD12).但是多块数据读的时候,SD卡将一直发送数据给主机,直到接到主机发送的STOP命令(CMD12) E; }/ d T$ [* A! W, r; g
; l' q0 [. Q: |
多数据块写操作
2 f% P* J( [% m5 p* i2 m7 D. {, r7 z) j6 g' M( ?
SDIO(多)数据块写操作,如下图所示
* T; l# ?* c2 z ~
0 f* R1 u m4 h7 o
) a' r0 Q7 l) K
' p( m9 f$ K9 ?- j& I
数据块写操作同数据块读操作基本类似,只是数据块写的时候,多了一个繁忙判断,新的数据块必须在SD卡非繁忙的时候发送。这里的繁忙信号由SD卡拉低SDIO_D0,以表示繁忙,SDIO硬件自动控制,不需要我们软件处理。1 B7 |$ r8 l0 m- L; H7 ]7 N0 o
$ u: Z5 U1 B5 W6 r `+ C注意:当SDIO_CK频率过快时,可能导致SD卡通信失败,此时,建议降低SDIO_CK试试。3 ]. \& I' J% Q% D' i, |+ c
4 z$ @+ K2 F) y9 @( h8 i
06、代码& s" D6 l C2 `9 h( C
STM32的SDIO控制器驱动还是很复杂的,ST提供了stm32f2x_sdio_sd.c驱动文件,我们组要修改对应的GPIO驱动即可。
4 p% l1 F/ O' f" \, h. H$ U4 Z
! p! ^4 y1 r" N+ v% g) k- /**
2 C5 m0 p* u* L3 d- h' a* X - * @brief Initializes the SD Card and put it into StandBy State (Ready for
3 F5 f4 _ d' i' b" G# ~% c' n" u - * data transfer).
, w( ^: }, _. R6 E" F& M3 T3 { - * @param None' x) X' s* R* H' y6 U$ i% b# [ R7 q
- * @retval None) r" p6 y7 b7 Y6 S2 @& D' v
- */
c% w4 J7 l1 \! a& x - void SD_LowLevel_Init(void)
/ u0 G0 l. e/ H - {6 U, [4 \" a& v! _, U. |2 x* G" I+ s
- GPIO_InitTypeDef GPIO_InitStructure;6 ]9 N# s7 e! e6 ?9 p' b, z
- ! h1 r2 i' e. z# n
- /* GPIOC and GPIOD Periph clock enable */! R" Z: z4 q$ J. d, w" v% F$ `
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | SD_DETECT_GPIO_CLK, ENABLE);4 [1 @ _# Z4 j; O) y+ F. D
; d# G) C9 r8 U2 E$ r# P3 x% o- GPIO_PinAFConfig(GPIOC, GPIO_PinSource8, GPIO_AF_SDIO);9 J2 l" _. O c! R9 i& E( @, K
- GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_SDIO);
, L# w6 B/ j* v: R( B - GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_SDIO);. O4 X9 K( P% ^. B* X
- GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_SDIO);
7 x$ @5 P A: L8 g - GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_SDIO);; y2 l/ a& j9 R" u' J
- GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_SDIO);
1 G* n8 ]$ Y; ^! k& U' s8 J6 k4 u
( _' I& W4 t+ f- /* Configure PC.08, PC.09, PC.10, PC.11 pins: D0, D1, D2, D3 pins */
- ~( q9 E7 t5 n$ E& ] - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11;
* i/ C& l" |! \5 p; Z: a3 z, f: T - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;6 H. |" N0 ^, Q/ j+ X- i
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
4 e% O; |, d$ V" k( @8 Z - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
/ _4 k4 y! J* N$ g( U - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;# Q7 {" O" J/ w" r
- GPIO_Init(GPIOC, &GPIO_InitStructure);
$ {+ Z9 d! N/ i: U0 _3 i
H) n; c3 \- W+ x* R9 j- /* Configure PD.02 CMD line */
; D8 g) d0 m! h O) a - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;. G! A0 U' v0 N8 H0 \
- GPIO_Init(GPIOD, &GPIO_InitStructure);9 v* l* z7 _& z. ^9 U) _
+ W0 ]5 V1 K; ~: R- /* Configure PC.12 pin: CLK pin */
& H8 M% T" b/ } - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
7 d# k" r$ I E" e9 q9 X! w! M, } - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
* i! U) p" J* _# O - GPIO_Init(GPIOC, &GPIO_InitStructure); {. Q f1 R3 M4 g9 v% X: z$ s
- 0 O' Z2 J' N8 t
- /*!< Configure SD_SPI_DETECT_PIN pin: SD Card detect pin */
& Q' y, O5 \% O# y$ G E4 q. C1 C; T - /*GPIO_InitStructure.GPIO_Pin = SD_DETECT_PIN;5 A9 ]" |, _: t H0 x/ c8 b
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;. \# e6 H, D1 F$ X( e% b3 o. O
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;, g3 N, J, d# |5 Z8 b S7 l
- GPIO_Init(SD_DETECT_GPIO_PORT, &GPIO_InitStructure);*/
9 x4 K2 A( A1 b$ E' h* E% Z" J
2 b+ k1 D( L9 K- /* Enable the SDIO APB2 Clock */7 w3 T% d+ V' L1 K, h' ?; v- d! B/ |9 A
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_SDIO, ENABLE);
4 `1 O3 w, n+ \+ x A8 F" w9 N - - A; w, S$ S) f$ P" A
- /* Enable the DMA2 Clock */4 R8 A; K Z) e- b% I
- RCC_AHB1PeriphClockCmd(SD_SDIO_DMA_CLK, ENABLE);/ Y% p; \7 ^8 A) d7 ~* T
- }5 ^8 O4 r; G1 ~
复制代码
# w7 j7 J5 d( I6 S# SDMA等配置使用默认的即可。
' T( S1 K& R: G! h2 m6 N( {% @6 D$ y( Y9 o7 Q& S+ e# Y* R: W
我们需要使用的函数接口有
" a5 Z4 R7 a& Y" y" A. s0 ?# Z5 H+ u
- SD_Error SD_Init(void);
7 p3 f. k4 ~; z$ s - SD_Error SD_Erase(uint32_t startaddr, uint32_t endaddr);1 O2 p! x5 ? @+ E
- SD_Error SD_WriteBlock(uint8_t *writebuff, uint32_t WriteAddr, uint16_t BlockSize);& F( K0 }- h6 t' u# R
- SD_Error SD_ReadBlock(uint8_t *readbuff, uint32_t ReadAddr, uint16_t BlockSize);
复制代码
: j4 ?/ Z8 n% {9 O7 h p- m下载验证, z: |2 R% ]/ |
) r3 _9 A' o- J
! |& V/ N5 B! w7 ~/ ` V( Z% u' W5 T: O* z
0 j3 x+ i5 a: _% U7 J7 l8 _0 B! G& |5 H, |
|