STM32 SDIO的使用
简介
本文进行的STM32 SDIO使用的探索基于STM寄存器。本次进行的STM32 SDIO的使用调试,目的是为了在STM32F429IGT6上移植U-BOOT.由于过程中SDIO驱动的缺失,所以需要编写驱动程序。U-BOOT中上册的应用比较完善,因此我只需要实现数据传输,指令发送的功能即可。但是本文不会涉及U-BOOT的内容,只使用STM32的同学放心食用。
一、SD通信协议概述
按照SD标准的文件中的描述,SD协议有以下特点:
- 每个符合SD协议的设备需要有一组标准的寄存器
- 任何对SD设备的访问都是进行一组命令,每个命令都有响应(CMD0除外)
大概就是这样,进行什么样的操作依赖于发送的命令。
- CMD0没有回应,那么就只需要主机发送命令即可
- 如果命令包含响应,则主机需要等待响应
- 命令和响应都在CMD线上传输
- 有些命令结束后需要传输数据(不只是读写卡中的数据,有些获取卡信息的指令也会在命令结束后进行数据传输)
- 命令是由主机发给卡
- 命令包含参数字段,某些不需要参数的命令以0填充该字段
- 命令响应有7种,分为长响应和短响应
- 大部分的指令、响应、数据传输都会包含CRC校验
【注】:具体的命令和对应的功能可以在SD协议中查找到
如果上述的不太理解可以接着看下面的STM32根据协议设计的通信接口
二、STM32SDIO概述
SDIO是一个完全数字通信接口,但是实际使用中大概率是接SD卡、TF卡、MMC卡(多媒体卡)的接口。按照SD的协议进行设计,STM32中的SDIO有以下设计:
- SDIO接口自动进行CRC校验,编程中不需要考虑校验的问题
- SDIO的寄存器大概可以分为四类:
- 时钟控制:控制CLK引脚时钟输出
- 命令传输:发送命令,接收响应
- 数据传输:发送数据,接收数据
- 接口状态:控制接口的状态标志
下面对寄存器进行简单的介绍,该介绍只介绍寄存器的主要作用,具体如何配置请查询手册。
STM32 SDIO时钟控制
- POWER:只有2Bit,控制卡时钟的开关
- CLKCR:
- 控制数据线的宽度,可以是1Bit,4Bit,8Bit。根据实际的电路连接配置
- SD卡的时钟使能
- SD卡时钟的分频设置
STM32 SDIO命令传输
- ARG:配置准备发送指令的参数,需要在发送前设置
- CMD:配置命令号,命令的响应类型,开始命令发送
- RESPCMD:大部分的响应中包含命令号,在收到响应是可从该寄存器中读出
- RESPx:一组寄存器,一共四个,用于接收指令响应的实际内容
以上四个寄存器就可以进行基本的命令传输了。
【注】:命令有超时标志,命令超时周期为固定值 64 个 SDIO_CK 时钟周期
STM32 SDIO数据传输
- DTIMER:命令超时计数器,开始传输时计数器开始递减,递减为0时停止接收,超时标志置1
- DLEN:需要传输的数据长度(单位Byte)
- DCTRL:DMA使能、数据传输方向、传输模式等传输控制的配置
- DCOUNT:数据计数器(只读,不需要配置)用来查看传输进度
- FIFOCNT:FIFO计数器(只读,不需要配置)用来查看传输进度(单位字)
- FIFO:32字的缓冲区,被分为两部分16字发送缓冲,16字接收缓冲。
STM32 SDIO接口状态
- STA:SDIO接口的状态,细节参考芯片手册
- ICR:清除指定状态标志,有些标志由硬件管理,不可软件清除
- MASK:控制对应的标志位是否产生中断
三、配置流程
下面的配置指令仅是可用的状态,因为有U-BOOT上层的支持,所以作者仅进行了读写测试,保证每个指令、数据的传输正常。
发送命令
- 将命令的参数写入ARG寄存器
- 将命令号写入CMD寄存器
- 配置响应类型
- 使能命令路径状态机
- 发送指令(并不能明确配置哪一位开始发送命令,一般的做法是先将配置写入临时变量,最后直接一切写入CMD寄存器,SDIO就会发送指令)
接收命令响应
接收响应的过程是自动的,数据都会存放在对应的寄存器。不需要马上进行响应,只要在下一次命令响应来之前读取寄存器即可,如果觉得该命令的响应无关紧要也可以不进行读取。当然一般都是通过中断或查询标志位的形式立即进行响应的读取。
接收/发送数据
接收数据需要在发送指令之前提前配置好上述的数据传输对应的寄存器。发送命令后,SD卡开始在数据线上传输数据。SDIO检测到总线活动后自动开始数据接收,这个需要立即将数据从FIFO中读出,否则可能导致FIFO溢出。如果等接收到响应才开始配置接收也可能导致数据丢失。
发送数据时等接收到指令的回应后开始发送数据。
初始化卡
- 打开时钟
- CMD0:复位卡状态
- CMD8:协定电压范围
- ACMD41:(CMD55-CMD41)判断卡是否是是高速卡
- CMD2:请求卡CID
- CMD3:请求卡RCA(用于寻址,接口支持同时接多个卡,用于指定卡)
经过上述的流程卡就已经初始化完成了,但是如果需要对卡进行读写或其他操作需要先使用CMD7,指定RCA选中对应的卡,对应的卡状态会转为传输状态,即可开始进行读写。
读写操作
如果熟悉了初始化流程,读写应该就不是问题了。只需要根据手册发送对应的指令等待接收数据即可。值得一提的是,如果不适用DMA和中断直接读写FIFO时官方HAL库中的做法是等待FIFO半满,然后直接读取8个字。我是使用FIFO非空标志,有数据就读。后来经过分析,官方的每次读取8个字能更快的读取数据,减少进行操作判断的次数,不容易造成FIFO溢出。但是实际上当MCU主频比较高的时候有数据就读也不会有太大问题。
四、调试错误
- 命令响应超时:
- 接口时钟未打开
- SD卡当前的状态不接收该指令(详细见SD协议)
- 缓冲区溢出/数据出错但CRC校验成功
- 接收数据不及时
- 主频太低,来不及处理
- 接收数据不及时
- 接收数据CRC校验出错/数据出错但CRC校验成功
- SDIO接口的数据线需要上拉
- 接收指令响应CRC出错
- 某些响应中不存在CRC校验位,但是SDIO依然会检测,直接忽略就好
- SDIO使用DMA传输时数据有剩余
- DMA传输时需要开启外设流控制,不能使用DMA流控制
- 识别卡过程中命令异常
- ACMD41命令不仅需要判断响应是否正常,还需要判断响应中卡的忙标志,如果卡没有就绪需要反复发送ACMD41,直到卡就绪
- 卡时钟开启后需要进行短暂的延时,否则可能会导致后续的指令出错
- CMD8与第一次ACMD41之间最好也有延时,我设置20ms的延时
- SDIO配置后不发送指令
- STA中存在错误标志时SDIO会停止数据交互,因此当检测到错误标志后需要及时清除
- 发送命令后状态寄存器没有任何响应,不报错误,不报完成,不报超时
- 先开启GPIO时钟再配置GPIO,解决错误。但未找到真正的原因。因此外设使用时先开启时钟再配置能减少错误的出现
- 其他未找到原因的错误
还有一些错误没找到错误的原因,但是经过上述错误的整改之后错误消失了,由于时间有限就没有深入探查原因。仅供参考- 发送命令后状态寄存器没有任何响应,不报错误,不报完成,不报超时
编程中参考的手册
- SD卡2.0协议.pdf
- STM32F4xx中文参考手册1.pdf
下面是本人收集的一些手册,当我还非常小白的时候找手册非常的费劲。所以分享一下,帮助一些找不到手册的兄弟。
https://www.aliyundrive.com/s/sdPfTPmeT2T
提取码: 2g0g
手册中的重要内容
SD初始化状态转移图
SD卡工作时的状态转义图
指令描述,在手册整个文档的第60页,太长了就截图个开头吧,可以自行下载查询,可以看到指令的响应类型,参数内容,功能描述。
写在最后
手册是通过【正点原子、野火、反客科技】等公开论坛、群聊,或官网获取,如有侵权请联系。
其他内容属原创内容,引用请注明出处。