基于FPGA的SD卡写数据Verilog程序开发
Posted fpga&matlab
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于FPGA的SD卡写数据Verilog程序开发相关的知识,希望对你有一定的参考价值。
1.仿真预览
操作步骤,先格式化。设置如下:
注意,格式化之后,使用容量如下:
假如我在文档中保存一个数据
里面数据为1
此时容量使用变为:
根据这个信息,我们最后来验证写入的数据量是否正确。
然后使用我新的下载程序,运行后,再次打开,可以看到如下:
按原来的程序,下载后, 其容量为
并提示格式化。
然后按我的新程序,得到结果如下:
数据已经被写入了,由于我们写入的是bit数据,不是实际的声音或者视频,所以没法看到文件形式,这个需要借助软件查看,具体操作如下:
使用我提供给你的这个软件。
File>打开路径。定位到你的SD卡物理路径,然后点击
,然后点击。定位到偏移地址位置。
具体看录像中显示效果。
然后这个软件也显示了
使用空间大小。
假如我对SD卡格式化,重复上面的操作,结果如下所示:
具体看录像中显示效果。
这样的话,就读写成功了。
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
以上是关于基于FPGA的SD卡写数据Verilog程序开发的主要内容,如果未能解决你的问题,请参考以下文章
Arduino ESP8266 Micro SD卡写操作实例
FPGA教程案例98数据处理1——基于FPGA的数据线性插值verilog实现,MATAB辅助验证