1. 项目概述
在嵌入式系统和FPGA开发中,SD卡因其大容量、低成本和高便携性成为常见的外部存储解决方案。传统SPI模式虽然接口简单,但传输速率有限(通常<10Mbps),难以满足高速数据采集、图像处理等应用需求。而SDIO模式通过4位并行数据总线,可将传输速率提升至50Mbps以上,同时保持较低的硬件资源占用。
这套SDIO模式读写SD卡的FPGA源码基于Wishbone总线架构设计,具有以下核心优势:
- 高可移植性:模块化设计+标准化接口,适配Xilinx、Altera、Lattice等主流FPGA平台
- 高性能:实测读写速率稳定在50Mbps以上,适合视频流、高速日志等场景
- 完整验证:提供测试平台和SD卡行为模型,包含6类功能测试用例
- 低资源占用:在Xilinx Artix-7上仅消耗约1200个LUT和8个Block RAM
2. 核心架构设计
2.1 系统组成框图
整个系统采用分层架构设计,各模块通过明确的接口规范交互:
code复制[Wishbone Host] ←总线交互→ [SDIO控制器] ←物理接口→ [SD卡]
↑ ↑ ↑
|寄存器访问 |命令/数据控制 |CLK/CMD/DAT信号
[测试平台/CPU] [FIFO缓存] [电平转换电路]
2.2 模块功能分解
2.2.1 顶层控制模块(SD_controller_top.v)
作为系统枢纽,主要实现:
-
时钟域管理:
- Wishbone总线时钟(wb_clk_i,典型25MHz)
- SD卡时钟(sd_clk_o,可配置1-25MHz)
- 异步FIFO隔离不同时钟域
-
中断控制:
verilog复制// 中断寄存器定义
parameter NORMAL_INT_REG = 8'h00; // 正常中断状态
parameter ERR_INT_REG = 8'h04; // 错误中断状态
- 工作模式配置:
verilog复制`define SD_CLK_SEP // 使能独立SD时钟域
`define IRQ_ENABLE // 使能中断功能
`define SD_BUS_WIDTH_4 // 4位数据总线模式
2.2.2 Wishbone总线接口
采用Wishbone B4规范设计,关键特性:
- 支持单次读写(SINGLE)和块传输(BLOCK)
- 32位数据总线宽度
- 可配置等待周期(典型2-5个时钟)
总线事务示例:
verilog复制// 单次写操作时序
wb_cyc_o <= 1'b1;
wb_stb_o <= 1'b1;
wb_we_o <= 1'b1;
wb_adr_o <= 32'h0000_0100; // 寄存器地址
wb_dat_o <= 32'h1234_5678; // 写入数据
wait(wb_ack_i); // 等待从机响应
3. 关键实现技术
3.1 SD卡初始化流程
完整的初始化序列包含以下关键步骤:
-
卡识别阶段:
- CMD0(软件复位,响应R1)
- CMD8(检查电压兼容性)
- ACMD41(发送OCR,获取卡容量信息)
-
数据传输配置:
- CMD16(设置块长度,通常512字节)
- CMD6(切换4位总线模式)
- ACMD51(读取SCR寄存器)
注意:ACMD类命令需要先发送CMD55前缀,这是SD协议的特殊要求
3.2 高速传输实现
3.2.1 时钟域同步方案
采用双时钟FIFO解决跨时钟域问题:
verilog复制// 接收FIFO实例化
async_fifo #(
.DATA_WIDTH(32),
.DEPTH(512)
) rx_fifo (
.wr_clk(sd_clk),
.rd_clk(wb_clk),
// 其他信号连接...
);
3.2.2 数据打包优化
通过32位总线+4位SDIO的带宽匹配:
- 每8个SD时钟周期传输4字节数据
- 计算理论带宽:
code复制25MHz SD时钟 × 4bit × (8/8) = 12.5MB/s ≈ 100Mbps (实际有效带宽约50-60Mbps)
3.3 CRC校验机制
3.3.1 命令CRC7
用于所有SD命令的校验,生成多项式:
code复制G(x) = x^7 + x^3 + 1
Verilog实现:
verilog复制always @(*) begin
crc = 7'h00;
for (i=39; i>=0; i=i-1) begin
crc = {crc[5:0], 1'b0} ^ (cmd[i] ? 7'h09 : 7'h00);
end
end
3.3.2 数据CRC16
用于数据块校验,多项式:
code复制G(x) = x^16 + x^12 + x^5 + 1
采用查表法实现,预计算256项CRC表。
4. 验证与调试
4.1 测试平台架构
测试环境包含:
- 行为级SD卡模型(sdModel.v)
- 自动测试序列生成器
- 总线监控模块(wb_bus_mon.v)
测试用例覆盖矩阵:
| 测试类别 | 子用例 | 检查点 |
|---|---|---|
| 寄存器访问 | 读写控制寄存器 | 地址映射正确性 |
| 命令传输 | CMD0/CMD2/CMD3 | 响应类型与时序 |
| 数据读写 | 单块/多块读写 | CRC校验与数据一致性 |
| 错误处理 | 错误命令注入 | 中断触发与状态寄存器更新 |
4.2 实测性能数据
在Xilinx Artix-7 XC7A35T平台测得:
| 测试项 | 读性能 | 写性能 |
|---|---|---|
| 单块(512B) | 48Mbps | 45Mbps |
| 多块(64KB) | 52Mbps | 49Mbps |
| 持续传输1分钟 | 无错误 | 无错误 |
5. 移植与应用指南
5.1 硬件适配要点
-
引脚分配建议:
- SD_CLK:选择全局时钟引脚
- SD_CMD/DAT:使用IOBUF原语
- 上拉电阻:所有数据线需接10kΩ上拉
-
时序约束示例:
tcl复制# SDIO时钟约束
create_clock -name sd_clk -period 40 [get_ports sd_clk_o]
set_input_delay -clock sd_clk 2 [get_ports sd_dat*]
5.2 软件驱动开发
典型操作流程:
- 初始化控制器
- 配置块大小(通常512字节)
- 设置中断处理程序
- 启动DMA传输(可选)
c复制// 示例:读取单个块
void sd_read_block(uint32_t addr, uint8_t *buf) {
write_reg(CMD_REG, CMD17 | (addr << 16));
write_reg(CTRL_REG, START_TRANS);
wait_int(TRANS_DONE);
read_fifo(buf, 512);
}
6. 常见问题排查
6.1 初始化失败
- 现象:卡在ACMD41无响应
- 排查步骤:
- 检查电源电压(3.3V±10%)
- 确认CMD线连接正常
- 尝试降低时钟频率(如100kHz)
6.2 数据传输错误
- 现象:CRC校验失败
- 解决方案:
- 检查PCB走线等长(SDIO线长差<5mm)
- 增加SD_CLK到输出延迟
- 启用内部DLL调整时钟相位
6.3 性能优化技巧
- 使用多块传输(CMD18/25)
- 增大FIFO深度(建议≥1KB)
- 采用DMA代替CPU搬运
这套SDIO控制器源码已在多个工业数据采集项目中成功应用,实测在-40℃~85℃温度范围内稳定工作。对于需要更高性能的场景,可考虑升级到SD 3.0的UHS-I模式(需硬件支持)。实际开发中建议先使用提供的测试平台验证基本功能,再逐步移植到目标硬件。