news 2026/4/23 16:38:11

FPGA 通过 SPI 模式读写 SD 卡:实现与移植探索

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
FPGA 通过 SPI 模式读写 SD 卡:实现与移植探索

FPGA以SPI模式读写SD卡,已经下板验证通过。 可移植到任何FPGA之中。

在数字电路设计领域,FPGA(现场可编程门阵列)凭借其灵活性和强大的并行处理能力,成为众多项目的首选。而 SD 卡作为常用的存储介质,实现 FPGA 对其以 SPI 模式的读写,具有广泛的应用前景。今天就来分享一下我在这方面完成的工作,并且已经成功下板验证通过,而且这个方案可移植到任何 FPGA 之中。

SPI 协议与 SD 卡

SPI(Serial Peripheral Interface)是一种高速、全双工、同步的通信总线,常用于微控制器与各种外围设备之间的通信。SD 卡支持 SPI 模式,这为 FPGA 与之交互提供了便利。

在 SPI 模式下,SD 卡有几个关键引脚与 FPGA 连接:

  • CS(Chip Select):片选信号,低电平有效,用于选择特定的 SD 卡。
  • SCK(Serial Clock):时钟信号,用于同步数据传输。
  • MOSI(Master Out Slave In):主机输出从机输入,FPGA 向 SD 卡发送数据。
  • MISO(Master In Slave Out):主机输入从机输出,SD 卡向 FPGA 发送数据。

FPGA 代码实现

下面以 Verilog 语言为例,展示部分关键代码实现。

初始化模块

module sd_card_init ( input wire clk, input wire rst, output reg spi_cs, output reg spi_sck, output reg spi_mosi, input wire spi_miso, output reg init_done ); // 状态机状态定义 typedef enum reg [2:0] { INIT_IDLE = 3'b000, INIT_CMD0 = 3'b001, INIT_CMD8 = 3'b010, INIT_ACMD41 = 3'b011, INIT_WAIT_READY = 3'b100 } sd_init_state; sd_init_state current_state, next_state; // 发送命令的字节数组 reg [7:0] cmd_bytes [0:5]; reg [2:0] byte_index; reg [7:0] current_byte; always @(posedge clk or posedge rst) begin if (rst) begin current_state <= INIT_IDLE; spi_cs <= 1'b1; spi_sck <= 1'b0; spi_mosi <= 1'b0; byte_index <= 3'b000; init_done <= 1'b0; end else begin current_state <= next_state; end end always @(*) begin next_state = current_state; case (current_state) INIT_IDLE: begin spi_cs <= 1'b1; if (!rst) begin next_state = INIT_CMD0; end end INIT_CMD0: begin spi_cs <= 1'b0; // 填充CMD0命令字节 cmd_bytes[0] = 8'h40; cmd_bytes[1] = 8'h00; cmd_bytes[2] = 8'h00; cmd_bytes[3] = 8'h00; cmd_bytes[4] = 8'h00; cmd_bytes[5] = 8'h95; byte_index = 3'b000; current_byte = cmd_bytes[byte_index]; next_state = INIT_CMD8; end INIT_CMD8: begin // 发送CMD8命令及相关字节,类似CMD0处理 //... next_state = INIT_ACMD41; end INIT_ACMD41: begin // 发送ACMD41命令及相关字节,类似CMD0处理 //... next_state = INIT_WAIT_READY; end INIT_WAIT_READY: begin if (spi_miso == 1'b0) begin init_done <= 1'b1; spi_cs <= 1'b1; end end endcase end always @(posedge clk or posedge rst) begin if (rst) begin spi_sck <= 1'b0; end else begin spi_sck <= ~spi_sck; if (spi_sck == 1'b1) begin if (byte_index < 6) begin spi_mosi <= current_byte[7]; current_byte = {current_byte[6:0], 1'b0}; if (current_byte == 8'h00) begin byte_index = byte_index + 1; current_byte = cmd_bytes[byte_index]; end end end end end endmodule

这段代码是 SD 卡初始化模块,使用状态机控制初始化流程。在 INITIDLE 状态等待复位信号释放,然后进入 INITCMD0 状态发送 CMD0 命令,这是让 SD 卡进入空闲状态的关键命令。每个命令由多个字节组成,通过 byteindex 索引和 currentbyte 暂存来逐位发送。之后依次进入 CMD8 和 ACMD41 命令状态,完成一系列初始化操作,最后在 INITWAITREADY 状态等待 SD 卡准备好信号,当接收到准备好信号(spi_miso 为低)时,初始化完成。

读写模块

module sd_card_rw ( input wire clk, input wire rst, input wire init_done, input wire [7:0] write_data, input wire write_en, output reg [7:0] read_data, output reg read_done, output reg spi_cs, output reg spi_sck, output reg spi_mosi, input wire spi_miso ); // 状态机状态定义 typedef enum reg [2:0] { RW_IDLE = 3'b000, RW_CMD17 = 3'b001, RW_CMD24 = 3'b010, RW_READ = 3'b011, RW_WRITE = 3'b100 } sd_rw_state; sd_rw_state current_state, next_state; // 发送命令的字节数组 reg [7:0] cmd_bytes [0:5]; reg [2:0] byte_index; reg [7:0] current_byte; always @(posedge clk or posedge rst) begin if (rst) begin current_state <= RW_IDLE; spi_cs <= 1'b1; spi_sck <= 1'b0; spi_mosi <= 1'b0; byte_index <= 3'b000; read_done <= 1'b0; end else begin current_state <= next_state; end end always @(*) begin next_state = current_state; case (current_state) RW_IDLE: begin spi_cs <= 1'b1; if (init_done) { if (write_en) { next_state = RW_CMD24; } else { next_state = RW_CMD17; } } end RW_CMD17: begin spi_cs <= 1'b0; // 填充CMD17(读命令)字节 cmd_bytes[0] = 8'h51; //...填充其他字节 byte_index = 3'b000; current_byte = cmd_bytes[byte_index]; next_state = RW_READ; end RW_CMD24: begin spi_cs <= 1'b0; // 填充CMD24(写命令)字节 cmd_bytes[0] = 8'h58; //...填充其他字节 byte_index = 3'b000; current_byte = cmd_bytes[byte_index]; next_state = RW_WRITE; end RW_READ: begin // 处理读操作,等待数据令牌,接收数据等 //... if (/* 数据接收完成条件 */) { read_done <= 1'b1; spi_cs <= 1'b1; } end RW_WRITE: begin // 处理写操作,发送数据令牌,发送数据等 //... if (/* 数据发送完成条件 */) { spi_cs <= 1'b1; } end endcase end always @(posedge clk or posedge rst) begin if (rst) { spi_sck <= 1'b0; } else { spi_sck <= ~spi_sck; if (spi_sck == 1'b1) { if (byte_index < 6) { spi_mosi <= current_byte[7]; current_byte = {current_byte[6:0], 1'b0}; if (current_byte == 8'h00) { byte_index = byte_index + 1; current_byte = cmd_bytes[byte_index]; } } // 读数据时接收数据处理 if (current_state == RW_READ && /* 接收数据条件 */) { read_data = {read_data[6:0], spi_miso}; } } } end endmodule

读写模块也是基于状态机工作。在 RWIDLE 状态等待初始化完成,根据 writeen 信号决定进入读命令(CMD17)状态还是写命令(CMD24)状态。在读写状态中,按照 SPI 协议规定,发送命令字节、等待响应、处理数据传输。例如读操作时,等待数据令牌后逐位接收数据并存入 readdata 寄存器,当满足数据接收完成条件时,设置 readdone 信号。

移植性分析

为什么说这个方案可移植到任何 FPGA 呢?首先,Verilog 作为一种硬件描述语言,具有很好的通用性。不同的 FPGA 厂商可能提供不同的开发工具,但 Verilog 代码主体逻辑无需大的改动。其次,SPI 协议是标准的通信协议,与 FPGA 具体型号无关。只要确保 FPGA 有可用的 I/O 引脚用于连接 SD 卡的 SPI 接口,并且时钟资源能够满足 SPI 通信速率要求,就可以轻松移植。

比如,从 Xilinx 的 FPGA 移植到 Altera 的 FPGA,只需要在开发工具中重新分配一下引脚,根据新 FPGA 的特性设置一下时钟频率等参数,核心的 Verilog 代码基本不用修改。

通过上述的代码实现和分析,我们成功实现了 FPGA 以 SPI 模式读写 SD 卡,并且具备良好的移植性,希望能给大家在相关项目开发中带来一些启发。

以上就是本次分享的全部内容啦,欢迎各位在评论区交流讨论。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 12:29:30

PDF-Extract-Kit保姆级指南:布局检测参数详解

PDF-Extract-Kit保姆级指南&#xff1a;布局检测参数详解 1. 引言 在处理PDF文档时&#xff0c;尤其是学术论文、技术报告等复杂版式文件&#xff0c;如何高效准确地提取其中的文字、公式、表格和图像信息&#xff0c;一直是自动化文档解析的核心挑战。PDF-Extract-Kit 正是为…

作者头像 李华
网站建设 2026/4/23 13:55:11

ImageGlass:免费开源的轻量级图像浏览器终极指南

ImageGlass&#xff1a;免费开源的轻量级图像浏览器终极指南 【免费下载链接】ImageGlass &#x1f3de; A lightweight, versatile image viewer 项目地址: https://gitcode.com/gh_mirrors/im/ImageGlass 还在为Windows自带的图片查看器功能单一而烦恼吗&#xff1f;I…

作者头像 李华
网站建设 2026/4/22 9:43:36

西门子SMART200 PLC与托利多电子秤自由口通讯程序实战

西门子SMART200 PLC和托利多电子称自由口通讯程序。 通俗易懂&#xff0c;注释全&#xff0c;自己编写的&#xff0c;实际项目应用的。在实际工业项目中&#xff0c;经常会遇到需要将西门子SMART200 PLC与托利多电子秤进行通讯的需求&#xff0c;以获取精准的称重数据并进行后续…

作者头像 李华
网站建设 2026/4/23 9:44:22

PhotoDemon完整指南:免费便携的图片编辑神器如何提升你的工作效率

PhotoDemon完整指南&#xff1a;免费便携的图片编辑神器如何提升你的工作效率 【免费下载链接】PhotoDemon 项目地址: https://gitcode.com/gh_mirrors/ph/PhotoDemon 在数字创作日益普及的今天&#xff0c;一款轻量级但功能全面的图片编辑工具显得尤为重要。PhotoDemo…

作者头像 李华
网站建设 2026/4/22 20:47:14

在 JavaScript 中,精度丢失问题解决教程

在 JavaScript 中&#xff0c;浮点数相加时因 IEEE 754 双精度浮点数表示限制&#xff0c;常出现精度丢失问题&#xff08;如 0.1 0.2 0.30000000000000004&#xff09;。以下是 5 种核心解决方案及代码实现&#xff1a;一、整数放大法&#xff08;推荐简单场景&#xff09;将…

作者头像 李华
网站建设 2026/4/23 9:45:38

DDU官网案例:教育内容动态化的技术选型过程

DDU官网案例&#xff1a;教育内容动态化的技术选型过程 引言&#xff1a;从静态到动态——教育内容的进化需求 在数字化教育快速发展的今天&#xff0c;学习者对内容呈现形式的要求日益提升。传统的图文教材虽信息密度高&#xff0c;但缺乏沉浸感与互动性&#xff0c;尤其在讲解…

作者头像 李华