2026/4/16 4:55:46
网站建设
项目流程
网站运营的含义,wordpress搭建官网视频,网站页面图片,购物网站模板免费下载FPGA以SPI模式读写SD卡#xff0c;已经下板验证通过。
可移植到任何FPGA之中。在数字电路设计领域#xff0c;FPGA#xff08;现场可编程门阵列#xff09;凭借其灵活性和强大的并行处理能力#xff0c;成为众多项目的首选。而 SD 卡作为常用的存储介质#xff0c;实现 F…FPGA以SPI模式读写SD卡已经下板验证通过。 可移植到任何FPGA之中。在数字电路设计领域FPGA现场可编程门阵列凭借其灵活性和强大的并行处理能力成为众多项目的首选。而 SD 卡作为常用的存储介质实现 FPGA 对其以 SPI 模式的读写具有广泛的应用前景。今天就来分享一下我在这方面完成的工作并且已经成功下板验证通过而且这个方案可移植到任何 FPGA 之中。SPI 协议与 SD 卡SPISerial Peripheral Interface是一种高速、全双工、同步的通信总线常用于微控制器与各种外围设备之间的通信。SD 卡支持 SPI 模式这为 FPGA 与之交互提供了便利。在 SPI 模式下SD 卡有几个关键引脚与 FPGA 连接CSChip Select片选信号低电平有效用于选择特定的 SD 卡。SCKSerial Clock时钟信号用于同步数据传输。MOSIMaster Out Slave In主机输出从机输入FPGA 向 SD 卡发送数据。MISOMaster 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 3b000, INIT_CMD0 3b001, INIT_CMD8 3b010, INIT_ACMD41 3b011, INIT_WAIT_READY 3b100 } 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 1b1; spi_sck 1b0; spi_mosi 1b0; byte_index 3b000; init_done 1b0; end else begin current_state next_state; end end always (*) begin next_state current_state; case (current_state) INIT_IDLE: begin spi_cs 1b1; if (!rst) begin next_state INIT_CMD0; end end INIT_CMD0: begin spi_cs 1b0; // 填充CMD0命令字节 cmd_bytes[0] 8h40; cmd_bytes[1] 8h00; cmd_bytes[2] 8h00; cmd_bytes[3] 8h00; cmd_bytes[4] 8h00; cmd_bytes[5] 8h95; byte_index 3b000; 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 1b0) begin init_done 1b1; spi_cs 1b1; end end endcase end always (posedge clk or posedge rst) begin if (rst) begin spi_sck 1b0; end else begin spi_sck ~spi_sck; if (spi_sck 1b1) begin if (byte_index 6) begin spi_mosi current_byte[7]; current_byte {current_byte[6:0], 1b0}; if (current_byte 8h00) 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 3b000, RW_CMD17 3b001, RW_CMD24 3b010, RW_READ 3b011, RW_WRITE 3b100 } 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 1b1; spi_sck 1b0; spi_mosi 1b0; byte_index 3b000; read_done 1b0; end else begin current_state next_state; end end always (*) begin next_state current_state; case (current_state) RW_IDLE: begin spi_cs 1b1; if (init_done) { if (write_en) { next_state RW_CMD24; } else { next_state RW_CMD17; } } end RW_CMD17: begin spi_cs 1b0; // 填充CMD17读命令字节 cmd_bytes[0] 8h51; //...填充其他字节 byte_index 3b000; current_byte cmd_bytes[byte_index]; next_state RW_READ; end RW_CMD24: begin spi_cs 1b0; // 填充CMD24写命令字节 cmd_bytes[0] 8h58; //...填充其他字节 byte_index 3b000; current_byte cmd_bytes[byte_index]; next_state RW_WRITE; end RW_READ: begin // 处理读操作等待数据令牌接收数据等 //... if (/* 数据接收完成条件 */) { read_done 1b1; spi_cs 1b1; } end RW_WRITE: begin // 处理写操作发送数据令牌发送数据等 //... if (/* 数据发送完成条件 */) { spi_cs 1b1; } end endcase end always (posedge clk or posedge rst) begin if (rst) { spi_sck 1b0; } else { spi_sck ~spi_sck; if (spi_sck 1b1) { if (byte_index 6) { spi_mosi current_byte[7]; current_byte {current_byte[6:0], 1b0}; if (current_byte 8h00) { 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 卡并且具备良好的移植性希望能给大家在相关项目开发中带来一些启发。以上就是本次分享的全部内容啦欢迎各位在评论区交流讨论。