1、SDIO简介. X, F. O: a" |2 ~9 A6 |
SDIO,全称:Secure Digital Input and Output,即安全数字输入输出接口。它是在SD卡接口的基础上发展而来,它可以兼容之前的SD卡,并可以连接SDIO接口设备,比如:蓝牙、WIFI、照相机等。
; C* }0 Q2 S, I+ G9 q* w, z/ t" o& L: V- @3 ]+ e
SDIO和SD卡规范间的一个重要区别是增加了低速标准。低速卡的目标应用是以最小的硬件开支支持低速I/O能力。低速卡支持类似调制解调器、条码扫描仪和GPS接收器等应用。
1 k t, i8 c- r% q- V; u" o2 `6 G" w7 E$ T9 b9 t0 v
STM32的SDIO控制器支持多媒体卡(MMC卡)、SD存储卡、SDI/O卡和CE-ATA设备。1 q* t( H; z( V+ c' w
! U6 i3 Q& U! N+ F7 a8 e
SDIO框图# M: w [( d( P& o& Q+ }* Q2 ?
7 x* X6 ?1 s$ {6 [
& y$ b9 C, |; M. \, I5 e% S
" Q& t7 C" K! N( @0 E复位后SDIO_D0用于数据传输。初始化后主机可以改变数据总线的宽度(通过ACMD6命令设置)$ a* l$ \, C5 [& q8 `" O6 _
3 [5 J" z3 C! a* O0 Y: t如果一个多媒体卡接到了总线上,则SDIO_D0、SDIO_D[3:0]或SDIO_D[7:0]可以用于数据传输。
% }0 L) k# B, X( d7 U. V' D1 n; e# x- I
MMC版本V3.31和之前版本的协议只支持1位数据线,所以只能用SDIO_D0(为了通用性考虑,在程序里面我们只要检测到是MMC卡就设置为1位总线数据)
+ B1 `8 R; R) _$ t: T$ N
7 L9 T9 b. T% d9 ^- e' s02、SDIO特点0 i( x# @/ L7 D9 P+ N/ p$ A
①与多媒体卡系统规格书版本4.2全兼容。支持三种不同的数据总线模式:1位(默认)、4位和8位。 }% V! s! b# [7 P5 G
; [8 B2 m0 p) W) b
②与较早的多媒体卡系统规格版本全兼容(向前兼容)。) n# M g& K& n/ w: Q+ u
+ b4 A1 _7 B: |* Q' f- }4 N, v③与SD存储卡规格版本2.0全兼容。
1 _; I( D$ b$ G4 H J# Q3 u8 }2 z5 N, x- H3 i# j+ _1 [! h, ]
④与SDI/O卡规格版本2.0全兼容:支持两种不同的数据总线模式:1位(默认)和4位。
: @$ i, l3 }' @& P# e, F# E
) D5 J8 O* g+ y1 N3 y& c/ j/ [⑤完全支持CE-ATA功能(与CE-ATA数字协议版本1.1全兼容)。8位总线模式下数据传输速率可达48MHz。 c E: d" v {* G; P+ w
: E6 i7 o0 B2 b/ a$ h⑥数据和命令输出使能信号,用于控制外部双向驱动器。4 B/ l9 f& S6 X7 k# b) _) [
8 v8 X- n8 I6 E0 r" _7 ?03、SDIO时钟
; c ~( ]0 { V) M% ` C p1.卡时钟(SDIO_CK):每个时钟周期在命令和数据线上传输1位命令或数据。对于SD或SD I/O卡,时钟频率可以在0MHz至25MHz间变化。
- l5 [0 z1 R. a8 K+ U2 d1 [: P, l, }5 W+ x
2.SDIO适配器时钟(SDIOCLK):该时钟用于驱动SDIO适配器,可用于产生SDIO_CK时钟。SDIOCLK来自PLL48CK(48Mhz)。$ I7 ], o# z4 [! G% M
+ J$ X, @3 @* w" ~# k/ wAPB2总线接口时钟(PCLK2):该时钟用于驱动SDIO的APB2总线接口,其频率为PCLK2=84Mhz。
6 {; p" s( P% ?4 u9 F
" T' E. [+ c; h" ]6 F0 h& M" Z# JSDIO_CK计算公式:SDIO_CK=SDIOCLK/(2+CLKDIV)
. a7 ?( Y% Y$ ?" S; [* W* p
8 E1 s: S4 N2 w, n/ q5 A( Z7 o注意:在SD卡初始化时,SDIO_CK不可以超过400Khz,初始化完成后,可以设置为最大频率(但不可以超过SD卡最大操作频率)% p2 `+ k% X. t- o2 x
7 S2 u# g! ?9 h, {4 S8 i( |/ F }
04、SDIO的命令与响应; n. [9 c* D- a! w, [/ w) H/ t
命令, t" ]+ F0 ^! x6 A5 r- B2 F) B1 v
P T" J& K- c- Z2 j, \1.SDIO的命令分为:应用相关命令(ACMD)和通用命令(CMD)两部分。发送ACMD时,需先发送CMD55。) k9 o* S4 R' r
! L/ N! a. A) z/ k1 k2.SDIO所有的命令和响应都是在SDIO_CMD引脚上面传输的,命令长度固定为48位,SDIO命令格式如下表所示: X' o6 P/ ]/ [2 c! N, E
8 y! Z, M- p6 t; a h( W" B! e
, t" g& V" s4 N+ ? c
0 f" G* E1 h8 d2 ^/ o
其中:除了命令索引和参数需要我们设置,其他都是由SDIO硬件自动控制。命令索引(如CMD0,CMD1之类)由SDIO_CMD寄存器设置,命令参数则由SDIO_ARG寄存器设置8 n5 S3 _4 Q4 s& `
6 N, x* t2 \3 s
响应" p6 s8 V8 o {& N% j1 P
5 [5 i* {' F+ B1 l% P1.一般SD卡在接收到命令行,都会有一个应答(CMD0例外),这个应答我们也称之为响应。STM32的SDIO接口,支持2种响应类型:短响应(48位)和长响应(136位) \7 f6 B, |6 Q( h6 p$ e2 {
- U/ \! e0 o/ }' q
2.STM32 SDIO短响应(48位)格式如下表所示:
( I/ p0 l9 e, @5 Y: h
k6 e, a8 p2 P% B4 ]# M
9 x, h; m; h2 y: K$ l6 b9 u# ]1 k
6 \: q7 w0 g! M$ Q0 H
STM32 SDIO长响应(136位)格式如下表所示
& H- P' D; }/ P2 H f8 o' P4 e2 c5 y; ]8 R% t
( `. M# k. z( v' D* G& d" h8 ?
% `. J6 m6 R- p; v% K r( | Q不论是短响应还是长响应,硬件都会自动滤除了起始位、传输位、CRC7以及结束位等信息,对于短响应,命令索引存放在SDIO_RESPCMD寄存器,参数则存放在SDIO_RESP1寄存器里面。对于长响应,则仅留CID/CSD位域,存放在SDIO_RESP1~SDIO_RESP4等4个寄存器。. g- M, }* r2 A& W1 b% ~1 I
* w0 J& R' V( d0 E" p# H, hSD卡的响应- P$ I7 N! S8 Q( B$ S
' P* v; t! i2 ^$ i @* z
SD卡总共有6类响应(R1、R1b、R2、R3、R6、R7),我们这里以R1为例简单介绍一下。R1(普通响应命令)响应属于短响应,其长度为48位,如下表所示:4 U% V: S& e3 J) c; F: d/ |
( X6 b6 h3 Q# O% \4 f* f) Z$ y
8 m2 G b# h! m8 A; w8 b3 B
& _. U1 P& C& [8 e在收到R1响应后,我们可以从SDIO_RESPCMD寄存器和SDIO_RESP1寄存器分别读出命令索引和卡状态信息。关于其他响应的介绍,请大家参考光盘:《SD卡2.0协议.pdf》* K$ x7 O* B7 K" u; d
" P* m4 t; [! O! K$ J. F' B
05、SDIO块数据传输
: `2 ^( e$ t$ a1 a( m" c+ ~多数据块读操作8 i3 o9 o1 _0 C o9 V
|6 t0 `# a$ G, b
SDIO与SD卡通信一般以数据块的形式进行传输,SDIO(多)数据块读操作,如下图所示' _1 H9 k0 v, i+ B$ w
# k/ b) X& a) q m6 l& Z" w1 }
" b6 e" `: h$ S9 _4 Q6 H$ R5 I
# l- h. g% V. y9 M8 j' m5 J
从机在收到主机相关命令后,开始发送数据块给主机,所有数据块都带CRC校验(由硬件自动处理),单个数据块读的时候,在收到1个数据块以后即可以停止了,不需要发送停止命令(CMD12).但是多块数据读的时候,SD卡将一直发送数据给主机,直到接到主机发送的STOP命令(CMD12)
: T/ \) z# \4 ^! E! \% G* R; a" e0 f/ b% f) j) [8 ~6 i8 k0 F$ T
多数据块写操作
7 i: D; r, y; z+ z7 D, u6 x
. t& t h9 G% p- f: {) TSDIO(多)数据块写操作,如下图所示
2 N7 Z5 O6 ~# a7 X
3 w* i8 Y2 G' Y8 ?
& f5 b2 a- E+ J; M
+ R" h' { u/ L5 a数据块写操作同数据块读操作基本类似,只是数据块写的时候,多了一个繁忙判断,新的数据块必须在SD卡非繁忙的时候发送。这里的繁忙信号由SD卡拉低SDIO_D0,以表示繁忙,SDIO硬件自动控制,不需要我们软件处理。$ c4 K, H: ~% N+ ]
7 i7 ]2 W3 M h: K5 {5 ^
注意:当SDIO_CK频率过快时,可能导致SD卡通信失败,此时,建议降低SDIO_CK试试。
9 n; D' i% R+ u4 i8 A- q7 L' q. ^( h3 t" z; U
06、代码
/ x) }4 c* F6 PSTM32的SDIO控制器驱动还是很复杂的,ST提供了stm32f2x_sdio_sd.c驱动文件,我们组要修改对应的GPIO驱动即可。
7 s: u- G( u0 r/ n8 f8 P* p; ~: C. T9 p$ P, h# \3 k
- /**
. j9 b9 ?/ s% O5 H4 C# M9 i, B% I, Q - * @brief Initializes the SD Card and put it into StandBy State (Ready for 3 W3 v* X4 r* N0 M9 W
- * data transfer).3 Y& [) H9 Z/ P
- * @param None
8 ~& F: B1 T: S# H* c% j0 e" V/ S - * @retval None
% |7 a( X" ~& L. n4 ~ - */
7 D) C/ B; ` x& ~ - void SD_LowLevel_Init(void)
5 g; j& n% ^! H - {
8 u5 |9 N2 ^+ L1 @" u7 X - GPIO_InitTypeDef GPIO_InitStructure;7 b- s+ F% T1 m: j7 D" F& H
% r& @" u. O( ?0 }1 z6 q1 S- /* GPIOC and GPIOD Periph clock enable */
9 H& z/ x" [7 F - RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | SD_DETECT_GPIO_CLK, ENABLE);
) l: `' h7 u+ n3 Z- z i4 y - 8 u8 q) B) R; `1 e- f
- GPIO_PinAFConfig(GPIOC, GPIO_PinSource8, GPIO_AF_SDIO);
1 x* V! i3 I' y3 S# ]' D - GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_SDIO);
M, d, [- L) |! [ - GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_SDIO);
4 x" t: a) {* y6 ]1 X( u - GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_SDIO);; U4 y( m8 x" Y
- GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_SDIO);) }: Z7 y9 Z8 \% F" T
- GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_SDIO);# A3 l W- H# |- U/ u: r! E& K+ Y
F: ?1 H6 l7 ^; c0 W- /* Configure PC.08, PC.09, PC.10, PC.11 pins: D0, D1, D2, D3 pins */
7 g' s! U" P# ? - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11;
0 J2 Z& ]9 r2 H# I, Z& W- ^: n - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
7 |# k% L7 N3 j - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
) e8 G% D: o* A0 ] - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
2 n% Y$ d2 R( y: ^6 h, E - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
, c5 m( O, R! o4 N1 P: H; [* F - GPIO_Init(GPIOC, &GPIO_InitStructure);: Q1 \; H6 F! ?- i
+ _2 m' j: r/ t3 L/ L- /* Configure PD.02 CMD line */ V3 I* Y4 Y# r
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
- n; H" H7 I5 W' e8 U+ @; z- k - GPIO_Init(GPIOD, &GPIO_InitStructure);
5 X7 [, j* S j% Z5 D9 ^5 D8 z! H2 [ - 9 u4 F; K) F& L$ E: H+ O ~
- /* Configure PC.12 pin: CLK pin */& }2 g6 _* f" t4 L
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
* @9 a" p" u/ {* q. V* K - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;0 a! k5 l7 W1 T0 u/ A" j
- GPIO_Init(GPIOC, &GPIO_InitStructure);6 x% m" A. V7 M; D# j
# q# B. a! _9 ~' d5 s- /*!< Configure SD_SPI_DETECT_PIN pin: SD Card detect pin */( f7 {0 B1 O( x$ X, s" K
- /*GPIO_InitStructure.GPIO_Pin = SD_DETECT_PIN;
* K5 l/ H* ]- f4 j6 c# @ - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
6 ]1 Y/ S- r2 c& `, e# A - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
. {/ k( i( B+ X9 e' A6 q - GPIO_Init(SD_DETECT_GPIO_PORT, &GPIO_InitStructure);*/" H, h! w! w1 b) u9 ~4 ?9 ]
8 ]6 J* _( Q: J0 a! R8 b- /* Enable the SDIO APB2 Clock */2 v9 u: a* H, e3 q. [2 }
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_SDIO, ENABLE);
0 r$ }0 @$ c4 I; N5 u' x% }" R S6 z
E0 a8 m* I+ Q6 V6 z& T/ _, Z! u5 {- /* Enable the DMA2 Clock *// p* ~4 C+ ^- P
- RCC_AHB1PeriphClockCmd(SD_SDIO_DMA_CLK, ENABLE);
8 L' b6 ]" ?2 k) }5 O - }% `, l3 t' T( C5 ~$ b6 g( s' K
复制代码
: z2 k2 ~# O2 i/ D; xDMA等配置使用默认的即可。
' L1 ] q; R) A9 c, I7 _0 a4 B5 j& I: b; z1 Y! _$ n
我们需要使用的函数接口有
/ v z# n( i( F. E5 E$ M& B# ~' r
- SD_Error SD_Init(void);
0 P9 S% u5 o$ T2 T$ T E! w - SD_Error SD_Erase(uint32_t startaddr, uint32_t endaddr);
8 ?9 l* [5 z$ m9 W5 {3 P - SD_Error SD_WriteBlock(uint8_t *writebuff, uint32_t WriteAddr, uint16_t BlockSize);
6 H x) L, w' g' J7 |7 i+ B1 M9 Z - SD_Error SD_ReadBlock(uint8_t *readbuff, uint32_t ReadAddr, uint16_t BlockSize);
复制代码
4 u7 A9 p% ^) F+ C$ I' u5 Y$ l+ Z下载验证
0 r: m! {* C% m% Y( ]. [% c9 M( }8 V
: o" O1 @ t! ~' }4 @9 I5 a
+ X1 l, p$ Z; t7 [% d! j, b
/ B0 d% v; j9 f9 h* G2 n" e4 e
+ F: Q0 g8 l9 T( ~ P |