sdio开发指南
概述
SDIO(Secure Digital Input and Output,安全数字输入输出)是在SD标准上定义的一种外设接口,用于扩展SD卡功能或其他SDIO外设。
SDIO系统架构
功能描述
SDIO模块提供的接口:
| 接口声明 | 功能说明 |
|---|---|
| MMC_HostInitById() | 初始化 SDIO 主机 |
| sdio_get_func() | 获取 SDIO Function |
| sdio_en_func() | 使能 SDIO Function |
| sdio_set_cur_blk_size() | 设置 Block Size |
| sdio_require_irq() | 注册中断处理函数 |
| sdio_read_byte() | 读取单字节 |
| sdio_write_byte() | 写入单字节 |
| sdio_write_byte_raw() | 写入并回读(RAW 模式) |
| sdio_read_fifo_block() | FIFO 块读 |
| sdio_write_fifo_block() | FIFO 块写 |
| sdio_func0_read_byte() | Func0 读取 |
| sdio_func0_write_byte() | Func0 写入 |
| sdio_rescan() | 重新识别设备 |
| sdio_reset_comm() | 复位通信 |
联调前提与验收
SDIO 不是单端自回环接口,当前驱动流程需要一个可被枚举的 SDIO 对端,不能仅靠开发板本身完成有效收发验证。开始开发前应准备:
- 与目标电压和总线宽度匹配的 SDIO 外设或第二块可作为 SDIO Device 的设备;
- CLK、CMD、DATA0~DATA3、供电和 GND 连接,以及与板级设计一致的上拉电阻;
- 对端寄存器/Function 定义、支持的最大 Block Size 和中断触发方式;
- 若验证高速模式,还应准备可检查信号完整性的示波器或逻辑分析仪。
建议按“枚举到设备 → 获取并使能 Function → 设置 Block Size → 单字节读写并回读 → 块读写并比对 → 触发并收到中断”的顺序验收。只有主机日志显示正确的 Vendor/Device/Function 信息,读回数据与发送数据一致且中断计数正确,才算形成完整闭环。没有对端时可以编译接口调用代码,但不能把“编译通过”作为 SDIO 功能通过的结论。
开发指引
操作流程

初始化SDIO
errcode_t ret;
// 配置IO管脚(CLK、CMD、DATA0~DATA3)
// 具体管脚配置请参考硬件设计
// 初始化SDIO主机
ret = MMC_HostInitById(sdio_bus_id);
if (ret != ERRCODE_SUCC) {
PRINT("SDIO init failed, ret = 0x%x\n", ret);
return ret;
}
PRINT("SDIO init success\n");
获取并使能Function
struct sdio_func *func;
uint8_t func_num = 1; // Function号
uint16_t manf_id = 0xFFFF; // 厂商ID
uint16_t device_id = 0xFFFF;// 设备ID
// 获取sdio_func
func = sdio_get_func(func_num, manf_id, device_id);
if (func == NULL) {
PRINT("Failed to get sdio func\n");
return ERRCODE_FAIL;
}
// 使能Function
ret = sdio_en_func(func);
if (ret != ERRCODE_SUCC) {
PRINT("Failed to enable func\n");
return ret;
}
设置Block Size
uint16_t block_size = 64; // 不应大于512字节
ret = sdio_set_cur_blk_size(func, block_size);
if (ret != ERRCODE_SUCC) {
PRINT("Failed to set block size\n");
return ret;
}
中断处理
void handler_sample(struct sdio_func *func)
{
dprintf("%s,%d func:0x%x\n", __FUNCTION__, __LINE__, func);
return;
}
// 注册中断处理函数
ret = sdio_require_irq(func, handler_sample);
if (ret != ERRCODE_SUCC) {
PRINT("Failed to register IRQ\n");
return ret;
}
// 释放中断处理函数(当不再需要时)
// sdio_release_irq(func);
单字节读写
uint8_t addr = 0x00;
uint8_t data;
// 读取单字节
data = sdio_read_byte(func, addr);
PRINT("Read byte at 0x%02x: 0x%02x\n", addr, data);
// 写入单字节
data = 0xAB;
ret = sdio_write_byte(func, addr, data);
if (ret != ERRCODE_SUCC) {
PRINT("Failed to write byte\n");
}
// 写入并回读(RAW模式)
data = sdio_write_byte_raw(func, addr, data);
块读写
uint8_t addr = 0x10;
uint8_t *rx_buf;
uint8_t *tx_buf;
uint32_t size = 256;
rx_buf = (uint8_t *)malloc(size);
tx_buf = (uint8_t *)malloc(size);
if (rx_buf == NULL || tx_buf == NULL) {
return ERRCODE_FAIL;
}
// 填充发送数据
memset(tx_buf, 0xAA, size);
// 块读(使用FIFO模式,地址固定)
ret = sdio_read_fifo_block(func, addr, rx_buf, size);
if (ret != ERRCODE_SUCC) {
PRINT("Failed to read block\n");
}
// 块写(使用FIFO模式,地址固定)
ret = sdio_write_fifo_block(func, addr, tx_buf, size);
if (ret != ERRCODE_SUCC) {
PRINT("Failed to write block\n");
}
free(rx_buf);
free(tx_buf);
Func0读写
uint8_t addr= 0x04;
uint8_t data;
// Func0读取(用于访问Common CIS等)
data = sdio_func0_read_byte(func, addr);
PRINT("Func0 read byte: 0x%02x\n", data);
// Func0写入
data = 0x5A;
ret = sdio_func0_write_byte(func, addr, data);
重新识别设备
复位通信
errcode_t ret;
ret = sdio_reset_comm(func);
if (ret != ERRCODE_SUCC) {
PRINT("Failed to reset comm\n");
}
注意事项
-
Block Size限制:块大小不应大于512Byte
-
块读写模式:
sdio_read_fifo_block/sdio_write_fifo_block:FIFO模式,地址固定,适用于FIFO访问
-
CMD52和CMD53:
- 单字节读写使用CMD52命令
- 块读写使用CMD53命令
-
中断处理:中断处理函数需要用户自行实现
