📄 sd_controller.v
字号:
//Written by Vladimir Boykov//Last modification August, 2005module sd_controller (sys_clk, sd_clk, reset, cs, sd_cmd, address, sd_data, data_input, data_output, write_to_buffer, write, read, int_reg, clear);parameter CMD0 = 6'd0; //Reset all cards to Idle stateparameter CMD2 = 6'd2; //Ask CID numberparameter CMD3 = 6'd3; //Ask to publish a new relative address RCAparameter CMD17 = 6'd17; //Read single blockparameter CMD7 = 6'd7; //Select/Deselect SD Cardparameter CMD13 = 6'd13; //Send status registerparameter CMD55 = 6'd55; //Application specific commandparameter ACMD6 = 6'd6; //Set data line widthparameter ACMD41 = 6'd41; //Asks the accessed card to send its operating condition register (OCR) content in the response on the CMD line. input sys_clk;input sd_clk;input reset;input cs;inout sd_cmd;input [2:0] address;inout [3:0] sd_data;input [31:0] data_input;output [31:0] data_output;output write_to_buffer;input write;input read;output [31:0] int_reg;output clear;reg [31:0] control_reg, status_reg, serial_reg;reg [15:0] RCA; //New published RCA of the cardreg [31:0] blocknum; //Block number for readingwire status_req, control_req, serial_req;wire block_rdy;reg [4:0] cmd;reg [7:0] count;reg [3:0] command_count;reg rw;reg mode;reg write_to_fifo;reg clear_fifo;reg [7:0] count_resp;reg resp_start;reg ocr_rdy;reg [6:0] data_count;reg [4:0] bit_count;reg data_start;reg [31:0] word;reg block_rdy_reg;wire [47:0] command;wire [6:0] crc7;wire reset_cmd, stop_cmd;assign data_output = {word[7:0], word[15:8], word[23:16], word[31:24]};assign write_to_buffer = write_to_fifo;assign clear = clear_fifo;assign sd_data = 4'bzzzz;assign status_req = ((address==3'b010) && cs);assign control_req = ((address==3'b011) && cs);assign serial_req = ((address==3'b100) && cs);assign block_rdy = (data_start && (data_count < 7'd1))? 1'b1 : 1'b0;assign int_reg = (status_req && read)? status_reg : ((serial_req && read)? serial_reg : 32'd0);always @ (posedge sys_clk or posedge reset) begin if (reset) begin block_rdy_reg <= 1'b0; end else begin if (block_rdy) begin block_rdy_reg <= 1'b1; end else if (control_reg) begin block_rdy_reg <= 1'b0; end endend//CONTROL REGISTERalways @ (posedge sys_clk or posedge reset) begin if (reset) begin control_reg <= 32'd0; end else begin if (control_req && write && !data_start) control_reg <= data_input; else if (block_rdy) control_reg <= 32'd0; endendassign sd_cmd = (rw)? command[count] : 1'bz;assign command = (command_count==5'd0)? {2'b01, CMD0, 32'h0, crc7, 1'b1} : ((command_count==5'd1)? {2'b01, CMD55, RCA, 16'h0, crc7, 1'b1} : ((command_count==5'd2)? {2'b01, ACMD41, 32'h00FF8000, crc7, 1'b1} : ((command_count==5'd3)? {2'b01, CMD2, 32'h0, crc7, 1'b1} : ((command_count==5'd4)? {2'b01, CMD3, 32'h0, crc7, 1'b1} : ((command_count==5'd5)? {2'b01, CMD7, RCA, 16'h0, crc7, 1'b1} : ((command_count==5'd6)? {2'b01, CMD13, RCA, 16'h0, crc7, 1'b1} : ((command_count==5'd7)? {2'b01, CMD17, blocknum, crc7, 1'b1} : ((command_count==5'd9)? {2'b01, ACMD6, 30'h0, mode, 1'b0, crc7, 1'b1} : 48'hz)))))))); //SD FSM MODELalways @ (posedge sd_clk or posedge reset) begin if (reset) begin cmd <= 5'd0; count <= 8'd90; mode <= 1'b0; clear_fifo <= 1'b0; rw <= 1'b0; command_count <= 4'd0; blocknum <= 32'd0; end else begin case (cmd) //Waiting for 80 clocks cycle before work with SD 5'd0: begin if (count) count <= count - 8'd1; else cmd <= 5'd1; end //Prepearing to sending the command 5'd1: begin count <= 8'd47; rw <= 1'b1; cmd <= 5'd2; end //Sending the command 5'd2: begin if (count) count <= count - 8'd1; else begin rw <= 1'b0; if (command_count) begin //Waiting for response cmd <= 5'd3; end else begin //Send next command command_count <= command_count + 4'd1; count <= 8'd6; cmd <= 5'd0; end end end 5'd3: begin if (!count_resp) begin if (command_count!=4'd2) begin if (command_count!=4'd6) begin command_count <= command_count + 4'd1; count <= 8'd31; cmd <= 5'd0; end else begin cmd <= 5'd31; end end else begin if (ocr_rdy) begin command_count <= command_count + 4'd1; count <= 8'd31; cmd <= 5'd0; end else begin command_count <= 4'd1; count <= 8'd31; cmd <= 5'd0; end end end end //Reading some block 5'd4: begin count <= 8'd47; clear_fifo <= 1'b0; rw <= 1'b1; cmd <= 5'd5; end 5'd5: begin if (count) count <= count - 8'd1; else begin rw <= 1'b0; cmd <= 5'd6; end end 5'd6: begin if (block_rdy) begin cmd <= 5'd31; end end //Getting a command from CPU 5'd31: begin if ((control_reg[3:0]==4'b0001) && (status_reg==32'h900)) begin blocknum[31:9] <= control_reg[26:4]; blocknum[8:0] <= 9'd0; command_count <= 5'd7; clear_fifo <= 1'b1; cmd <= 5'd4; end else cmd <= 5'd31; end default: cmd <= 5'd0; endcase endend//Getting a response from SDalways @ (negedge sd_clk or negedge (!reset)) begin if (reset) begin count_resp <= 46; resp_start <= 1'b0; status_reg <= 0; serial_reg <= 0; RCA <= 16'd0; ocr_rdy <= 1'b0; end else begin if (!rw) begin if (!sd_cmd && !resp_start) begin resp_start <= 1'b1; end else if (resp_start) begin if (count_resp) begin count_resp <= count_resp - 8'd1; //R1 if ((command_count==4'd1) || (command_count>4'd4)) begin if ((count_resp>7) && (count_resp<40)) begin status_reg[31:1] <= status_reg[30:0]; status_reg[0] <= sd_cmd; end //R3 end else if (command_count==4'd2) begin if ((count_resp==39) && sd_cmd)begin ocr_rdy <=1'b1; end //R2 end else if (command_count==4'd3) begin if ((count_resp>23) && (count_resp<56)) begin serial_reg[31:1] <= serial_reg[30:0]; serial_reg[0] <= sd_cmd; end //R6 end else if (command_count==4'd4) begin if ((count_resp>23) && (count_resp<40)) begin RCA[15:1] <= RCA[14:0]; RCA[0] <= sd_cmd; end end end else begin resp_start <= 1'b0; end end end else begin if (command_count==4'd3) begin count_resp <= 8'd134; end else begin count_resp <= 8'd46; end end endend//Getting data blockalways @ (negedge sd_clk or negedge (!reset)) begin if (reset) begin data_count <= 7'd127; bit_count <= 5'd31; data_start <= 1'b0; write_to_fifo <= 1'b0; word <= 32'd0; end else begin if (!sd_data[0] && !data_start && (cmd!=5'd31)) begin data_start <= 1'b1; write_to_fifo <= 1'b0; end else if ((data_count || bit_count) && data_start) begin if (bit_count) begin write_to_fifo <= 1'b0; bit_count <= bit_count - 5'd1; word[31:1] <= word[30:0]; word[0] <= sd_data[0]; end else begin word[31:1] <= word[30:0]; word[0] <= sd_data[0]; write_to_fifo <= 1'b1; bit_count <= 5'd31; data_count <= data_count - 7'd1; end end else if (data_start) begin word[31:1] <= word[30:0]; word[0] <= sd_data[0]; write_to_fifo <= 1'b1; data_count <= 7'd127; bit_count <= 5'd31; data_start <= 1'b0; end else begin write_to_fifo <= 1'b0; end endendassign reset_cmd = ((cmd==5'd1) || (cmd==5'd4))? 1'b1 : 1'b0;assign stop_cmd = (count<8'd8)? 1'b1 : 1'b0;//Checksum for command tokencrc_unit_7 CRC_7 ( .sd_clk(sd_clk), .reset(reset_cmd), .data_in(command[count]), .stop(stop_cmd), .crc(crc7) );endmodule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -