跳转至

sdio开发指南

概述

SDIO(Secure Digital Input and Output,安全数字输入输出)是在SD标准上定义的一种外设接口,用于扩展SD卡功能或其他SDIO外设。

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_rescan();
if (ret != ERRCODE_SUCC) {
    PRINT("Failed to rescan\n");
}

复位通信

errcode_t ret;

ret = sdio_reset_comm(func);
if (ret != ERRCODE_SUCC) {
    PRINT("Failed to reset comm\n");
}

注意事项

  1. Block Size限制:块大小不应大于512Byte

  2. 块读写模式

    • sdio_read_fifo_block/sdio_write_fifo_block:FIFO模式,地址固定,适用于FIFO访问
  3. CMD52和CMD53

    • 单字节读写使用CMD52命令
    • 块读写使用CMD53命令
  4. 中断处理:中断处理函数需要用户自行实现

**中断处理**:中断处理函数需要用户自行实现