协议内容
CMD
命令 | 名称 | 作用 | 响应类型 | 说明 | 命令类型 |
---|---|---|---|---|---|
CMD0 | GO_IDLE_STATE | 复位卡到闲置状态 | 无 | 基本命令 | |
CMD2 | ALL_SEND_CID | 请求所有卡发送其CID寄存器内容 | R2 | 包含CID寄存器内容(136位) | 基本命令 |
CMD3 | SEND_RELATIVE_ADDR | 请求新卡发送其相对地址(RCA) | R6 | 包含16位的RCA和卡状态 | 基本命令 |
CMD7 | SELECT/DESELECT_CARD | 选择卡进行通信或取消选择 | R1 | 包含卡状态(48位) | 基本命令 |
CMD8 | SEND_IF_COND | 检查卡是否支持电压范围和接口条件 | R7 | 包含接口条件回读(48位) | 数据传输命令 |
CMD9 | SEND_CSD | 请求卡发送CSD寄存器内容 | R2 | 包含CSD寄存器内容(136位) | 数据传输命令 |
CMD10 | SEND_CID | 请求卡发送CID寄存器内容 | R2 | 包含CID寄存器内容(136位) | 数据传输命令 |
CMD12 | STOP_TRANSMISSION | 停止数据传输 | R1b | 包含卡状态,忙标志位(48位) | 数据传输命令 |
CMD13 | SEND_STATUS | 请求卡发送其状态寄存器内容 | R1 | 包含卡状态(48位) | 数据传输命令 |
CMD16 | SET_BLOCKLEN | 设置单个数据块的长度(字节) | R1 | 包含卡状态(48位) | 数据传输命令 |
CMD17 | READ_SINGLE_BLOCK | 读取一个数据块 | R1 | 包含卡状态(48位)后跟数据块 | 数据传输命令 |
CMD18 | READ_MULTIPLE_BLOCK | 读取多个数据块 | R1 | 包含卡状态(48位)后跟多个数据块 | 数据传输命令 |
CMD24 | WRITE_BLOCK | 写入一个数据块 | R1 | 包含卡状态(48位)后跟数据块 | 数据传输命令 |
CMD25 | WRITE_MULTIPLE_BLOCK | 写入多个数据块 | R1 | 包含卡状态(48位)后跟多个数据块 | 数据传输命令 |
CMD27 | PROGRAM_CSD | 编程CSD寄存器 | R1 | 包含卡状态(48位) | 数据传输命令 |
CMD32 | ERASE_WR_BLK_START | 设置要擦除的第一个块的地址 | R1 | 包含卡状态(48位) | 错误处理命令 |
CMD33 | ERASE_WR_BLK_END | 设置要擦除的最后一个块的地址 | R1 | 包含卡状态(48位) | 错误处理命令 |
CMD38 | ERASE | 执行从CMD32和CMD33指定的地址范围内的块擦除 | R1b | 包含卡状态,忙标志位(48位) | 错误处理命令 |
CMD55 | APP_CMD | 通知卡下一条命令是应用特定命令(ACMD) | R1 | 包含卡状态(48位) | 特殊应用命令 |
CMD23 | SET_BLOCK_COUNT | 置SD卡的数据块数量 | R1 | 包含卡状态(48位) | 特殊应用命令 |
CMD58 | READ_OCR | 读取操作条件寄存器(OCR) | R3 | 包含OCR寄存器内容(48位) | 特殊应用命令 |
ACMD6 | SET_BUS_WIDTH | 设置数据总线宽度 | R1 | 包含卡状态(48位) | 应用特定命令 |
ACMD13 | SD_STATUS | 请求卡发送SD状态 | R1 | 包含卡状态(48位)后跟64字节的SD状态数据 | 应用特定命令 |
ACMD22 | SEND_NUM_WR_BLOCKS | 请求卡发送已写入的数据块数 | R1 | 包含卡状态(48位)后跟4字节的块数 | 应用特定命令 |
ACMD23 | SET_WR_BLK_ERASE_COUNT | 设置或清除多个数据块的写保护状态 | R1 | 包含卡状态(48位) | 应用特定命令 |
ACMD41 | SD_SEND_OP_COND | 初始化卡并确定工作电压 | R3 | 包含OCR寄存器内容(48位) | 应用特定命令 |
ACMD51 | SEND_SCR | 请求卡发送SCR寄存器 | R1 | 包含卡状态(48位)后跟8字节的SCR寄存器内容 | 应用特定命令 |
CMD6 | SWITCH_FUNC | 切换卡的功能 | R1 | 包含卡状态(48位) | 高级命令 |
CMD11 | VOLTAGE_SWITCH | 切换电压 | R1 | 包含卡状态(48位) | 高级命令 |
CMD52 | IO_RW_DIRECT | 直接读写I/O寄存器 | R5 | 包含I/O操作结果(48位) | SDIO相关命令 |
CMD53 | IO_RW_EXTENDED | 扩展读写I/O寄存器 | R5 | 包含I/O操作结果(48位) | SDIO相关命令 |
响应类型说明
R1: 标准响应,包含卡状态(48位)
R1b: R1响应,后跟忙信号
R2: CID和CSD寄存器响应(136位)
R3: OCR寄存器响应(48位)
R5: SDIO操作响应(48位)
R6: RCA和卡状态响应(48位)
R7: 接口条件响应(48位)
Q&A
fwrite写数据失败?
使用CMD25发送多block之后,需要紧接着发送一个CMD12,表示停止传输。
对于MMC控制器可能有AUTO_CMD12功能,也就是当发送完数据之后自动发送CMD12,不需要手动发送CMD12。因此在实际过程中,如果遇到相关问题可以尝试这两种方式切换。如果自动发送CMD12不正常,则尝试自动CMD12。
CMD12已用于停止多块读/写操作。然而,CMD12是依赖于时间的,并且很难控制在精确的时间上发出CMD12的时间。由于UHS104卡在时钟和数据之间有很大的延迟变化,CMD23有利于主机停止多次读/写操作,而不是CMD12。主机不需要控制CMD12的时间。此命令适用于总是512字节块长度的读/写操作,然后SDSC(Secure Digital Standard Capacity 低速小容量)卡不支持此命令。UHS104( Ultra High Speed 104 MB/s)卡必须支持CMD23
fwrite向SD卡写数据只能以block size的整数倍写,否则CMD25超时?
调试思路
- 定位到是哪一个层次出现的问题(fwrite -> glibc -> filesystem -> dfs_write -> mmc_write -> 驱动程序 -> mmc接口)
- 根据现有的情况进行分析。当整数倍写的时候正常,非整数倍错误,说明整个流程是没问题的,驱动程序也支持多块读写。
- 对两种情况有差异的地方进行分析,并尝试修改代码,不生效
- 进一步简化代码,将DMA模式换成Polling模式,发现与DMA在同一个地方出错,是非法地址访问
- 进一步查找问题,定位在数据buffer的地址没有4字节对齐,但是dma和polling都进行4字节访问,进而出错
解决方案
在Filesystem关于mmc_write文件中对数据进行处理。当判断地址不是4字节对齐的时候进行一次memcpy,在进行写入
Fatfs文件系统不能正常显示中文?
将ffconf.h文件中的:FF_CODE_PAGE 宏值改成936(简体中文)默认437(US);FF_LEN_UNICODE改成2(UTF-8)默认0(ANSI)。同时在使用串口工具的时候,需要指定UTF-8格式