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
! 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
% 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
% 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
; 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
* |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
+ }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
! 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 |& \' A4 e6 a7 Z
- * @brief Initializes the SD Card and put it into StandBy State (Ready for
8 j. v' H* k5 ^ - * data transfer).
* U2 ~5 E" B) I0 A+ W - * @param None
1 j1 I- ]2 H6 F8 M7 p - * @retval None5 X4 C n* i* ? f2 X# ^0 n% S
- */
( g4 J0 i% O; ?1 F2 u' O - void SD_LowLevel_Init(void)/ h/ e F6 U$ A8 F, \
- {
8 @* \4 T* c g' N6 M3 f - GPIO_InitTypeDef GPIO_InitStructure;5 S. h. s( }4 @' c% E9 K3 ?5 T/ _
- / ^8 E3 {4 q* _+ L+ p5 ?7 {
- /* GPIOC and GPIOD Periph clock enable */
$ D: ?! X/ s, ?" c - RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | SD_DETECT_GPIO_CLK, ENABLE);
8 ^7 r6 s, e. u7 k Y - * p: T* q: ?9 w: r0 \
- GPIO_PinAFConfig(GPIOC, GPIO_PinSource8, GPIO_AF_SDIO);, ^+ L1 S% `5 I, `
- GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_SDIO);6 ?% S t. Z! R! F# |% }: |/ C
- GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_SDIO);* T8 A3 c+ y, C7 f* V2 s6 {' l0 D
- GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_SDIO);' d' [; z' I% M4 O# R
- GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_SDIO);7 G# ^0 a% I( j; T# S
- GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_SDIO);
( A' `, y. A5 J0 [
5 z* F4 r8 e8 ]- ], a2 `7 p- ~- /* Configure PC.08, PC.09, PC.10, PC.11 pins: D0, D1, D2, D3 pins */
' Y. H1 X0 ~* y1 e3 A - 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 - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;% K( P' m# K' L* x6 f
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;4 L( u# q; N# S
- GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;) S6 i5 }* _5 Y* j8 B4 d8 N/ E
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;6 v1 U% ]6 I6 O1 B
- GPIO_Init(GPIOC, &GPIO_InitStructure);7 z* `3 O0 }+ k0 l
- # W w( `0 a) Z9 g
- /* Configure PD.02 CMD line */- s8 ]( ]6 Y1 b* C0 W3 ^* |7 ^
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
7 o3 y+ w* V! `" S. m: g6 F( I - GPIO_Init(GPIOD, &GPIO_InitStructure);
5 H J6 J! e) x f - 1 Z$ D! F, L5 H* K/ X& x' x& i6 [
- /* Configure PC.12 pin: CLK pin */# C1 J- c7 y6 y6 X+ O/ T
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;9 X3 x" G' |8 M' P* I
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;4 u* \1 t; o- ~9 S
- GPIO_Init(GPIOC, &GPIO_InitStructure);) {! x- {( t0 B4 T$ W7 g( X/ U
- 8 l8 H* q' {# L+ U
- /*!< Configure SD_SPI_DETECT_PIN pin: SD Card detect pin */' O* _ C, m9 K% `) F4 S9 d, c
- /*GPIO_InitStructure.GPIO_Pin = SD_DETECT_PIN;
3 I* [% g2 t5 |; T) [# K% b7 V - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
$ a5 C% h. ]4 ]- T- b - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;- }/ b& q* f* j/ Z
- GPIO_Init(SD_DETECT_GPIO_PORT, &GPIO_InitStructure);*/
: X8 ^0 @* G4 Q* ^5 P - " N$ Y5 t; }- t# x+ ^" ^0 m
- /* Enable the SDIO APB2 Clock */* N0 A5 B& B' @$ c# O
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_SDIO, ENABLE);
5 v4 D u9 E# X- m" y
9 t! X/ r$ _3 y2 W' }, p3 I- /* Enable the DMA2 Clock */! Q2 N& Q o7 t5 `' f4 L
- RCC_AHB1PeriphClockCmd(SD_SDIO_DMA_CLK, ENABLE);6 G, l' { Z8 P
- }" 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- SD_Error SD_Init(void);
* \2 ~) f/ T; J& @/ Y3 r" K+ Q - SD_Error SD_Erase(uint32_t startaddr, uint32_t endaddr);
) w d" j: u& q; s) E9 K4 L - SD_Error SD_WriteBlock(uint8_t *writebuff, uint32_t WriteAddr, uint16_t BlockSize);
% {5 q( _8 T3 |! {" j - 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
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
|