1.仿真预览

操作步骤,先格式化。设置如下:

基于FPGA的SD卡写数据Verilog程序开发_fpga开发

注意,格式化之后,使用容量如下:

基于FPGA的SD卡写数据Verilog程序开发_SD卡写数据_02

假如我在文档中保存一个数据

基于FPGA的SD卡写数据Verilog程序开发_数据_03

里面数据为1

基于FPGA的SD卡写数据Verilog程序开发_fpga开发_04

此时容量使用变为:

基于FPGA的SD卡写数据Verilog程序开发_fpga开发_05

根据这个信息,我们最后来验证写入的数据量是否正确。

然后使用我新的下载程序,运行后,再次打开,可以看到如下:

按原来的程序,下载后, 其容量为

基于FPGA的SD卡写数据Verilog程序开发_SD卡写数据_06

并提示格式化。

然后按我的新程序,得到结果如下:

基于FPGA的SD卡写数据Verilog程序开发_sd卡_07

数据已经被写入了,由于我们写入的是bit数据,不是实际的声音或者视频,所以没法看到文件形式,这个需要借助软件查看,具体操作如下:

使用我提供给你的

基于FPGA的SD卡写数据Verilog程序开发_数据_08

这个软件。

File>打开路径。定位到你的SD卡物理路径,然后点击

基于FPGA的SD卡写数据Verilog程序开发_SD卡写数据_09

,然后点击

基于FPGA的SD卡写数据Verilog程序开发_sd卡_10

。定位到偏移地址位置。

具体看录像中显示效果。

然后这个软件也显示了

基于FPGA的SD卡写数据Verilog程序开发_数据_11

使用空间大小。

假如我对SD卡格式化,重复上面的操作,结果如下所示:

基于FPGA的SD卡写数据Verilog程序开发_数据_12

具体看录像中显示效果。

这样的话,就读写成功了。

2.部分核心代码

`timescale 1ns / 1ps
//
// Module Name: sd_write
//
module sd_write( input SD_clk,
output reg SD_cs,
output reg SD_datain,
input SD_dataout,

input init,

input [31:0] sec, //写SD的sec地址
input write_req, //写SD卡请求

output reg [3:0] mystate,

output reg rx_valid,

output reg write_o


);


parameter idle=4'd0;
parameter write_cmd=4'd1;
parameter wait_8clk=4'd2;
parameter start_taken=4'd3;
parameter writea=4'd4;
parameter write_crc=4'd5;
parameter write_wait=4'd6;
parameter write_done=4'd7;

//定义要写入的数据
wire[7:0]DATAIN;
assign DATAIN = 8'h3f;//可以随便定义

wire [3:0] mystate_o;

reg [7:0] rx;

reg en;

reg [5:0] aa;
reg [21:0] cnt;

reg [7:0] write_data;

reg [47:0] CMD24={8'h58,8'h00,8'h00,8'h00,8'h00,8'hff};//block写命令CMD24的字节序列
reg [7:0] Sblock_token=8'hfe; //令牌字

reg [7:0] CMDX;
reg [7:0] CMDY=8'hff;
reg [2:0] cnta;



always @(posedge SD_clk)
begin
rx[0]<=SD_dataout;
rx[7:1]<=rx[6:0];
end

//接收SD卡的应答数据
always @(posedge SD_clk)
begin
if(!SD_dataout&&!en)begin rx_valid<=1'b0; aa<=1;en<=1'b1;end //等待SD_dataout为低,SD_dataout为低,开始接收数据
else if(en) begin
if(aa<7) begin
aa<=aa+1'b1;
rx_valid<=1'b0;
end
else begin
aa<=0;
en<=1'b0;
rx_valid<=1'b1; //接收完第8bit后,rx_valid信号开始有效
end
end
else begin en<=1'b0;aa<=0;rx_valid<=1'b0;end
end

//SD卡写程序
always @(negedge SD_clk)
if(!init)
begin
mystate<=idle;
CMD24<={8'h58,8'h00,8'h00,8'h00,8'h00,8'hff};
write_o<=1'b0;
end
else
begin
case(mystate)
idle: begin
SD_cs<=1'b1;
SD_datain<=1'b1;
cnt<=22'd0;
if(write_req) begin //如果有写请求
mystate<=write_cmd;
CMD24<={8'h58,sec[31:24],sec[23:16],sec[15:8],sec[7:0],8'hff};
Sblock_token<=8'hfe;
write_o<=1'b0;
end
else mystate<=idle;
end
write_cmd: begin //发送CMD24命令 (single Block write)
if(CMD24!=48'd0) begin
SD_cs<=1'b0;
SD_datain<=CMD24[47];
CMD24<={CMD24[46:0],1'b0}; //移位输出,高位在先
end
else begin
if(rx_valid) begin //等待应答信号
cnta<=7;
mystate<=wait_8clk;
SD_cs<=1'b1;
SD_datain<=1'b1;
end
end
end
wait_8clk: begin //写数据之前等待8clock
if(cnta>0) begin
cnta<=cnta-1'b1;
SD_cs<=1'b1;
SD_datain<=1'b1;
end
else begin
SD_cs<=1'b1;
SD_datain<=1'b1;
mystate<=start_taken;
cnta<=7;
end
end
start_taken: begin //发送Start Block Taken
if(cnta>0) begin
cnta<=cnta-1'b1;
SD_cs<=1'b0;
SD_datain<=Sblock_token[cnta]; //高位在先发送
end
else begin
SD_cs<=1'b0;
SD_datain<=Sblock_token[0];
mystate<=writea;
cnta<=7;
cnt<=0;
end
end
writea: begin //写字节到SD卡
if(cnt<512) begin
if(cnta>0)
begin
SD_cs<=1'b0;
SD_datain<=DATAIN[cnta];
cnta<=cnta-1'b1;
end
else begin
SD_cs<=1'b0;
SD_datain<=DATAIN[0];
cnta<=7;
cnt<=cnt+1'b1;
end
end
else begin

if(cnta>0) begin
SD_datain<=DATAIN[cnta];
cnta<=cnta-1'b1;
end
else begin
SD_datain<=DATAIN[cnta];
cnta<=7;
cnt<=0;
mystate<=write_crc;
end
end
end
write_crc: begin //写crc:0xff,0xff
if(cnt<16) begin
SD_cs<=1'b0;
SD_datain<=1'b1;
cnt<=cnt+1'b1;
end
else begin
if(rx_valid) //等待Data Response Token
mystate<=write_wait;
else
mystate<=write_crc;
end
end
write_wait: begin //等待数据写入完成,
if(rx==8'hff) begin
mystate<=write_done;
end
else begin
mystate<=write_wait;
end
end
write_done:begin
if(cnt<22'd15) begin //等待15个clock
SD_cs<=1'b1;
SD_datain<=1'b1;
cnt<=cnt+1'b1;
end
else begin
mystate<=idle;
write_o<=1'b1;
cnt<=0;
end
end
default:mystate<=idle;
endcase
end


endmodule
`timescale 1ns / 1ps

module sd_test(
input clk, //50Mhz input clock
input rst_n,

output SD_clk, //25Mhz SD SPI时钟
output SD_cs, //SD SPI片选
output SD_datain, //SD SPI数据输入
input SD_dataout, //SD SPI数据输出
output led

);


reg rst_n2=1'b0;
reg[31:0]cnt=32'd0;
always @(posedge clk)
begin
cnt<=cnt+32'd1;
if(cnt==32'h00ff_ffff)
rst_n2<=1'b1;
else
rst_n2<=rst_n2;
end

assign led=~rst_n2;


wire SD_datain_i;
wire SD_datain_w;
wire SD_datain_r;
reg SD_datain_o;

wire SD_cs_i;
wire SD_cs_w;
wire SD_cs_r;
reg SD_cs_o;



//PLL产生25Mhz的SD卡SPI时钟
pll pll_inst(
.areset (~rst_n2),
.inclk0 (clk),
.c0 (SD_clk),
.locked ()
);




reg [31:0]read_sec;
reg read_req;

reg [31:0]write_sec;
reg write_req;

wire [7:0]mydata_o/* synthesis keep */;
wire myvalid_o/* synthesis keep */;

wire init_o/* synthesis keep */; //SD 初始化完成标识
wire write_o; //SD blcok写完成标识
wire read_o; //SD blcok读完成标识

reg [3:0] sd_state;

wire [3:0] initial_state;
wire [3:0] write_state;
wire [3:0] read_state;

wire rx_valid;

parameter STATUS_INITIAL=4'd0;
parameter STATUS_WRITE=4'd1;
parameter STATUS_READ=4'd2;
parameter STATUS_IDLE=4'd3;

assign SD_cs = SD_cs_o;
assign SD_datain = SD_datain_o;


always @ ( posedge SD_clk or negedge rst_n2 )
if( !rst_n2 )
begin
sd_state <= STATUS_INITIAL;
read_req <= 1'b0;
read_sec <= 32'd0;
write_req <= 1'b0;
write_sec <= 32'd0;
end
else
case( sd_state )

STATUS_INITIAL:
if( init_o )
begin
sd_state <= STATUS_WRITE;
write_sec <= 32'd0;
write_req <= 1'b1;
end
else
begin
sd_state <= STATUS_INITIAL;
end

STATUS_WRITE:
if( write_o )
begin
sd_state <= STATUS_IDLE;
end
else
begin
write_req<= 1'b0;
sd_state <= STATUS_WRITE;
end


STATUS_IDLE:
sd_state <= STATUS_IDLE;

default: sd_state <= STATUS_IDLE;
endcase



//SD卡初始化程序
sd_initial sd_initial_inst(
.rst_n(rst_n2),
.SD_clk(SD_clk),
.SD_cs(SD_cs_i),
.SD_datain(SD_datain_i),
.SD_dataout(SD_dataout),
.rx(),
.init_o(init_o),
.state(initial_state)

);


//write
sd_write sd_write_inst(
.SD_clk(SD_clk),
.SD_cs(SD_cs_w),
.SD_datain(SD_datain_w),
.SD_dataout(SD_dataout),

.init(init_o),
.sec(32'd16448),
.write_req(write_req),
.mystate(write_state),
.rx_valid(rx_valid),

.write_o(write_o)

);



always @(*)
begin
case( sd_state )
STATUS_INITIAL:
begin
SD_cs_o<=SD_cs_i;
SD_datain_o<=SD_datain_i;
end

STATUS_WRITE:
begin SD_cs_o<=SD_cs_w;
SD_datain_o<=SD_datain_w;
end

default:
begin
SD_cs_o<=1'b1;
SD_datain_o<=1'b1;
end

endcase
end




endmodule

A38-11