基于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的数字基线恢复算法verilog开发实现

基于FPGA的BP神经网络的verilog实现

FPGA教程案例98数据处理1——基于FPGA的数据线性插值verilog实现,MATAB辅助验证

FPGA教程案例29基于FPGA的DDS直接数字频率合成器之二——Verilog开发

IDCT-FPGA基于FPGA的IDCT变换的verilog实现