SD-Host 数据控制模块

SD_DATA_FSM

数据发送/接收控制模块,根据输入的控制信号,进行状态机的跳转判定,以控制sd_data_send_shift_register和sd_data_receive_shift_register模块进行符合SD协议的数据处理过程。

状态转换图

在这里插入图片描述
PS:右边SEND_END_BIT状态后应该加入一个CRC_STATUS_WAIT (等对方发Start bit,然后再接收crc 状态)

STATE_STOP :停止状态,in_data_ready高有效时(写:sd_fifo_full, 读:命令发送完),状态机进入STATE_IDLE状态;
STATE_IDLE: 读写判断状态,in_data_direction高有效时,表示host准备开始发送数据,进入STATE_END_WAIT状态,反之,则表示host准备开始接收数据,进入RECEIVE_WAIT状态
STATE_WAIT_RECEIVE : 读操作准备状态,首先判断已接收的数据块是否满足要求,若满足,则跳入STATE_STOP,状态机停止工作,并给出状态信号read_to_error.最后,检测数据线data[0]是否低有效,有效则跳入STATE_RECEIVE状态,否则保持;
STATE_RECEIVE :数据读操作处理过程,并需要判断每块byte数据是否读完(has_receive_bit == need_to_receive_bit-1),满足则跳入STATE_RECEIVE_CRC状态,否则保持;
STATE_RECEIVE_CRC :判断每块crc数据是否读完(receive_crc_counter ==15,数据的时候对应CRC16,命令CRC7),满足则跳入STATE_RECEIVE_END_BIT状态,否则保持;
STATE_RECEIVE_END_BIT :首先判断已接收的数据块是否满足要求,若满足,则跳入STATE_STOP,状态机停止工作。不满足,则跳入STATE_WAIT_RECEIVE状态;

PS:STATE_RECEIVE 和 STATE_RECEIVE_END_BIT状态都进行已读取数据块的判断,但其作用不同:(下面DATA_STATE_WAIT_SEND和STATE_SEND_BUSY类似)STATE_RECEIVE 状态的判断,是允许提前结束读操作的。此状态内,软件修改参数need_to_receive_block(大小为has_receive_blcok+1),使得硬件状态机结束;STATE_RECEIVE_END_BIT状态的判断是正常情况下的操作,即软件配置操作值need_to_receive_block之后,host硬件必须从device读取相等大小数据块;

DATA_STATE_WAIT_SEND :数据输出等待状态,在条件fifo已被写满情况下,判断所有数据块是否发送完成,满足则跳入STATE_STOP状态,状态机停止工作。否则进行data[0]数据判断,高有效,跳入DATA_STATE_SNED_Z状态,否则保持;
DATA_STATE_SNED_Z:不做任何数据处理,进入DATA_STATE_SNED_P状态;
DATA_STATE_SNED_P:总线方向改变方向;
DATA_STATE_SNED_BIT:开始数据发送状态,跳入STATE_SEND状态;
DATA_SEND:数据发送状态,单块数据所有bit发送完成后(has_send_bit==need_to_send_bit-1),进入STATE_SEND_CRC状态,否则保持;
STATE_SEND_CRC:CRC数据发送状态,完成后,跳入STATE_SEND_END_BIT;
STATE_SEND_END_BIT:结束位发送状态,并用于数据线的方向切换(状态中间点),进入STATE_RECEIVE_CRC_STATUS状态;
STATE_SEND_BUSY:数据块传输结束判断状态,所有block发送结束,跳入STATE_STOP状态,停止操作。否则,进入DATA_STATE_WAIT_SEND状态,等待下一次块数据传输的开始。

信号描述

signalsI/OWidthfromtodeclaration
in_sd_clkinput1sd_clk
hrst_ninput1AHB bus异步复位
in_soft_resetinput1软件复位
in_data_readyinput1sd_if状态机启动信号
in_sd_datainput[3:0]sd_card数据读入端口
in_data_directioninput1sd_ifhost读写控制信号:1/write 0/read
need_to_receive_byteinput[10:0]sd_if控制器每块接收的数据量
need_to_send_byteinput[10:0]sd_if控制器每块发送的数据量
need_to_receive_blockinput[31:0]sd_if控制器
need_to_send_blockinput[31:0]sd_if控制器需发送的块数据大小
in_data_widthinput1sd_ifhost使用数据线判定信号:1/4 data line
in_read_toinput[31:0]sd_ifhost读操作time out时间,超出则状态机返回STOP状态
current_stateoutput[3:0]sd_if sd_data_send sd_data_receive当前状态标志位
next_stateoutput[3:0]sd_data_send次状态标志位
has_send_bit_counter_enoutput1发送bit数计数器使能
send_crc_counteroutput[3:0]sd_data_send已发送crc数据的bit大小,作为sd_data_send_shift_register模块的CRC输出控制信号
has_send_bitoutput[13:0]sd_data_sendHost已发送的数据bit大小
receive_crc_status_counteroutput[1:0]计数接收crc status的周期(时序)
has_receive_bitoutput[13:0]sd_data_receiveHost已接收的数据bit大小
out_transfer_completeoutput1sd_if数据传输结束状态标志位
interval_counteroutput[1:0]sd_data_send单块block写结束位时钟计数器,用于数据端口方向位的控制
out_read_to_erroroutput1sd_if读操作timeout标志位,ISR位
one_bk_re_endoutput1sd_if一个block数据读操作结束状态位,用于硬件停时钟

verilog实现

module (
    in_sd_clk,              //clock for sd card
    hrst_n,                 //ahb reset signal
    in_soft_reset,          //software reset
    in_data_ready,          //data fsm ready signal
    sd_fifo_full,
    in_sd_data,             //data input from sd card
    in_data_direction,      //data direction 1:write 0:read
    need_to_receive_byte,   //block length
    need_to_receive_block, //block number
    need_to_send_byte,      //block length
    need_to_send_block,     //block number
    in_data_width,          //data width 1:4bit  0:1bit
    in_read_to,             //time of read data fsm
    current_state,          //current state of data fsm
    next_state,             //next state of data fsm
    has_send_bit_counter_en,//has send bit counter enable
    send_crc_counter,       //has sent crc bits counter
    has_send_bit,           //has send data bits counter
    receive_crc_status_counter, //has receive crc status bits counter
    has_receive_bit,        //has receive data bits counter
    out_transfer_complete,  //indicate data transfer has completed 
    interval_counter,       //time interval between data end bit and crc status
    out_read_to_error,      //read timeout error flag
    one_bk_re_end
);                      
input           in_sd_clk;              //clock for sd card
input           hrst_n;                 //ahb reset signal
input           in_soft_reset;          //software reset
input           in_data_ready;
input           sd_fifo_full;
input [3:0]     in_sd_data;             //data input from sd card
input           in_data_direction;      //data direction 1:write 0:read
input [10:0]    need_to_receive_byte;   //block length
input [10:0]    need_to_receive_block; //block number
input [31:0]    need_to_send_byte;      //block length
input [31:0]    need_to_send_block;     //block number
input           in_data_width;          //data width 1:4bit  0:1bit
input [31:0]    in_read_to;             //time of read data fsm

output [3:0]    current_state;          //current state of data fsm
output [3:0]    next_state;             //next state of data fsm
output          has_send_bit_counter_en;//has send bit counter enable
output [3:0]    send_crc_counter;       //has sent crc bits counter
output [13:0]   has_send_bit;           //has send data bits counter
output [1:0]    receive_crc_status_counter; //has receive crc status bits counter
output [13:0]   has_receive_bit;        //has receive data bits counter
output          out_transfer_complete;  //indicate data transfer has completed 
output [1:0]    interval_counter;       //time interval between data end bit and crc status
output          out_read_to_error;      //read timeout error flag
output          one_bk_re_end;

out_transfer_complete;
reg     [3:0]       eurrent_state;
reg     [3:0]       next_state;
reg                 has_receive_bit_counter_en;
reg                 has_send_bit_counter_en;
reg                 has_receive_block_counter_en;
reg                 has_send_block_counter_en;
reg                 receive_crc_counter_en;
reg                 read_resp_time_counter_en;
reg                 send_crc_counter_en;
reg                 interval_counter_en;
reg                 receive_crc_status_counter_en;
reg     [13:0]      has_receive_bit;
reg     [13:0]      has_send_bit;
reg     [31:0]      has_receive_block;
reg     [31:0]      has_send_block;
reg     [3:0]       receive_crc_counter;
reg     [31:0]      read_resp_time_counter;
reg     [31:0]      send_crc_counter;
reg     [1:0]       interval_counter;
reg     [1:0]       receive_crc_status_counter;
reg                 out_read_to_error;

wire                one_bk_re_end_tp;
reg                 one_bk_re_end;

wire    [13:0]      need_to_send_bit;
wire    [13:0]      need_to_receive_bit;
wire    [13:0]      need_to_send_bit_4;
wire    [13:0]      need_to_receive_bit_4;

//--------------------------------------------------------
// Beginning of main code 
//--------------------------------------------------------
//将要接收/发送的字节数转化为bit数,用于计数比较
assign      need_to_send_bit = {need_to_send_byte,3'b0};
assign      need_to_receive_bit = {need_to_receive_byte,3'b0};
assign      need_to_send_bit_4 = {2'b0,need_to_send_byte,1'b0};
assign      need_to_receive_bit_4 = {2'b0,need_to_receive_byte,1'b0};

//----------------------------------------------------------------------
// Data fsm
//----------------------------------------------------------------------
// State description:
//
// DATA_STATE_STOP is the reset state of data fsm
// DATA_STATE_IDLE determines the data direction
// DATA_STATE_WAIT_RECEIVE waits for the start bit of data from sd card
// DATA_STATE_RECEIVE receives payload data from sd card
// DATA_STATE_RECEIVE_CRC receives crc of data from sd card
// DATA_STATE_RECEIVE_END_BIT receives the end bit of data from sd card and
// determines if all blocks have sent
// DATA_STATE_WAIT_SEND waits to send data to sd card until sd is not busy
// DATA_STATE_SEND sends payload data to sd card
// DATA_STATE_SEND_CRC send crc of data to sd card
// DATA_STATE_SEND_END_BIT send the end bit of the data to sd card
// DATA_STATE_RECEIVE_CRC_STATUS receives the crc status of data sent from sd
// card
// DATA_STATE_SEND_BUSY determines if all blcks have been sent
// DATA_STATE_START_BIT sends the start bit of data to sd card
// DATA_STATE_SEND_Z sends a Z bit to sd card
// DATA_STATE_SEND_P sends a P bit to sd card

//fsm1
always @ (posedge in_sd_clk or negedge hrst_n) begin
    if(!hrst_n)
        current_state <= `CMD_STATE_STOP;
    else if(!in_soft_reset)
        current_state <= `CMD_STATE_STOP;
    else 
        current_state <= next_state;
end

//fsm2
always @(*) begin
    out_read_to_error = 1'b0;
    case (current_state)
        `DATA_STATE_STOP: //0
        begin
            has_receive_bit_counter_en      = 1'b0;
            has_send_bit_counter_en         = 1'b0;
            has_receive_block_counter_en    = 1'b0;
            has_send_block_counter_en       = 1'b0;
            receive_crc_counter_en          = 1'b0;
            read_resp_time_counter_en       = 1'b0; 
            send_crc_counter_en             = 1'b0;
            interval_counter_en             = 1'b0;
            receive_crc_status_counter_en   = 1'b0;
            out_transfer_complete           = 1'b0;
            
            if(in_data_ready)
                next_state = `DATA_STATE_IDLE;
            else
                next_state = `DATA_STATE_STOP;
        end

        `DATA_STATE_IDLE: //1
		//IDLE状态判断读/写sd,进入读写等待状态
        begin
            has_receive_bit_counter_en      = 1'b0;
            has_send_bit_counter_en         = 1'b0;
            has_receive_block_counter_en    = 1'b0;
            has_send_block_counter_en       = 1'b0;
            receive_crc_counter_en          = 1'b0;
            read_resp_time_counter_en       = 1'b0; 
            send_crc_counter_en             = 1'b0;
            interval_counter_en             = 1'b0;
            receive_crc_status_counter_en   = 1'b0;
            out_transfer_complete           = 1'b0;
            if(!in_data_direction)
                next_state = `DATA_STATE_WAIT_RECEIVE;
            else
                next_state = `DATA_STATE_WAIT_SEND;
        end

        `DATA_STATE_WAIT_RECEIVE: //2
		//数据等待接收状态:所有blcok收完STOP;读超时STOP;
		//接收到数据的开始位data[0]==0,进入数据接收模式
        begin
            has_receive_bit_counter_en      = 1'b0;
            has_send_bit_counter_en         = 1'b0;
            has_receive_block_counter_en    = 1'b0;
            has_send_block_counter_en       = 1'b0;
            receive_crc_counter_en          = 1'b0;
            read_resp_time_counter_en       = 1'b0; 
            send_crc_counter_en             = 1'b0;
            interval_counter_en             = 1'b0;
            receive_crc_status_counter_en   = 1'b0;

            if (has_receive_block == need_to_receive_block)
            begin
                next_state = `DATA_STATE_STOP;
                out_transfer_complete = 1'b1;
            end
            else if (read_resp_time_counter == in_read_to)
            begin
                next_state = `DATA_STATE_STOP;
                out_read_to_error = 1'b1;
            end
            else begin
                if(!in_sd_data[0])
                    next_state = `DATA_STATE_RECEIVE;
                else begin
                    next_state = `DATA_STATE_WAIT_RECEIVE;
                    read_resp_time_counter_en = 1'b1;
                end
            end
        end
        
        `DATA_STATE_RECEIVE: //3
		//数据接收状态,启用接收bit计数器,需要接收的bit全接收了
		//进入接收crc的状态,
        begin
            //has_receive_bit_counter_en      = 1'b0;
            has_send_bit_counter_en         = 1'b0;
            has_receive_block_counter_en    = 1'b0;
            has_send_block_counter_en       = 1'b0;
            receive_crc_counter_en          = 1'b0;
            read_resp_time_counter_en       = 1'b0; 
            send_crc_counter_en             = 1'b0;
            interval_counter_en             = 1'b0;
            receive_crc_status_counter_en   = 1'b0;
            out_transfer_complete           = 1'b0;

            if(!in_data_width) begin
                if (has_receive_bit == need_to_receive_bit - 1)
                begin
                    next_state = `DATA_STATE_RECEIVE_CRC;
                    has_receive_bit_counter_en = 1'b0;
                end
                else begin
                    next_state = `DATA_STATE_RECEIVE;
                    has_receive_bit_counter_en = 1'b1;
                end
            end
            else begin
                if (has_receive_bit_4 == (need_to_receive_bit_4 - 1))
                begin
                    next_state = `DATA_STATE_RECEIVE_CRC;
                    has_receive_bit_counter_en = 1'b0;
                end
                else begin
                    next_state = `DATA_STATE_RECEIVE;
                    has_receive_bit_counter_en = 1'b1;
                end
            end
        end

        `DATA_STATE_RECEIVE_CRC: //4
		//接收crc状态,启用接收crc计数器,接收完成进入,接收end_bit状态
        begin
            has_receive_bit_counter_en      = 1'b0;
            has_send_bit_counter_en         = 1'b0;
            has_receive_block_counter_en    = 1'b0;
            has_send_block_counter_en       = 1'b0;
            //receive_crc_counter_en          = 1'b0;
            read_resp_time_counter_en       = 1'b0; 
            send_crc_counter_en             = 1'b0;
            interval_counter_en             = 1'b0;
            receive_crc_status_counter_en   = 1'b0;
            out_transfer_complete           = 1'b0;
            if(receive_crc_counter == 15) begin
                next_state =`DATA_STATE_RECEIVE_END_BIT;
                receive_crc_counter_en = 1'b0;
            end
            else begin
                next_state = `DATA_STATE_REVEIVE_CRC;
                receive_crc_counter_en = 1'b1;
            end
        end
        
        `DATA_STATE_RECEIVE_END_BIT: //5
		//接收end_bit,全部block接收完则回到STOP
		//否则blcok计数器启用,调到等待接收,启用被释放,相当于block计数只加了1
        begin
            has_receive_bit_counter_en      = 1'b0;
            has_send_bit_counter_en         = 1'b0;
            //has_receive_block_counter_en    = 1'b0;
            has_send_block_counter_en       = 1'b0;
            receive_crc_counter_en          = 1'b0;
            read_resp_time_counter_en       = 1'b0; 
            send_crc_counter_en             = 1'b0;
            interval_counter_en             = 1'b0;
            receive_crc_status_counter_en   = 1'b0;
            out_transfer_complete           = 1'b0;
            if(has_receive_block == (need_to_receive_block - 1)) begin
                next_state = `DATA_STATE_STOP;
                has_receive_block_counter_en = 1'b0;
                out_transfer_complete = 1'b1;
            end
            else begin
                next_state = `DATA_STATE_WAIT_RECEIVE;
                has_receive_block_counter_en = 1'b1;
            end
        end

        `DATA_STATE_WAIT_SEND: //6
        begin
            has_receive_bit_counter_en      = 1'b0;
            has_send_bit_counter_en         = 1'b0;
            has_receive_block_counter_en    = 1'b0;
            has_send_block_counter_en       = 1'b0;
            receive_crc_counter_en          = 1'b0;
            read_resp_time_counter_en       = 1'b0; 
            send_crc_counter_en             = 1'b0;
            interval_counter_en             = 1'b0;
            receive_crc_status_counter_en   = 1'b0;
            out_transfer_complete           = 1'b0;
            if(sd_fifo_full) begin
                if(has_send_block == need_to_send_block)
                begin
                    next_state = `DATA_STATE_STOP;
                    out_transfer_complete = 1'b1;
                end
                else begin
                   // if (!in_sd_data[0])
				    if (in_sd_data[0])
                        next_state = `DATA_STATE_WAIT_SEND;
                    else
                        next_state = `DATA_STAET_SEND_Z;
                end
            end
            else
                next_state = `DATA_STATE_WAIT_SEND;
        end
        
        `DATA_STATE_SEND: //7
		//启用发送bit计数,发送完数据准备发crc,
        begin
            has_receive_bit_counter_en      = 1'b0;
            //has_send_bit_counter_en         = 1'b0;
            has_receive_block_counter_en    = 1'b0;
            has_send_block_counter_en       = 1'b0;
            receive_crc_counter_en          = 1'b0;
            read_resp_time_counter_en       = 1'b0; 
            send_crc_counter_en             = 1'b0;
            interval_counter_en             = 1'b0;
            receive_crc_status_counter_en   = 1'b0;
            out_transfer_complete           = 1'b0;
            if (!in_data_width)
            begin
                if (has_send_bit == (need_send_bit - 1))
                begin
                    next_state = `DAYA_STATE_SEND_CRC;
                    has_send_bit_counter_en = 1'b0;
                end
                else begin
                    next_state = `DATA_STATE_SEND;
                    has_send_bit_counter_en = 1'b1;
                end
            end
            else begin
                if (has_send_bit == (need_to_seed_bit_4 - 1))
                begin
                    next_state = `DAYA_STATE_SEND_CRC;
                    has_send_bit_counter_en = 1'b0;
                end
                else begin
                    next_state = `DATA_STATE_SEND;
                    has_send_bit_counter_en = 1'b1;
                end
            end
        end
        
        `DATA_STATE_SEND_CRC: //8
		//启用发送crc bit计数,发送完crc准备发end bit
        begin
            has_receive_bit_counter_en      = 1'b0;
            has_send_bit_counter_en         = 1'b0;
            has_receive_block_counter_en    = 1'b0;
            has_send_block_counter_en       = 1'b0;
            receive_crc_counter_en          = 1'b0;
            read_resp_time_counter_en       = 1'b0; 
            //send_crc_counter_en             = 1'b0;
            interval_counter_en             = 1'b0;
            receive_crc_status_counter_en   = 1'b0;
            out_transfer_complete           = 1'b0;
            if (send_crc_counter == 15)
            begin
                next_state = `DATA_STATE_SEND_END_BIT;
                send_crc_counter_en = 1'b0;
            end
            else begin
                next_state = `DATA_STATE_SEND_CRC;
                send_crc_counter_en = 1'b1;
            end
        end

        `DATA_STATE_SEND_END_BIT: //9
		//发送完endbit ,准备接收数据是否正确的信号,
		//这里应该增加一个状态更好,而不是用计数的方式
        begin
            has_receive_bit_counter_en      = 1'b0;
            has_send_bit_counter_en         = 1'b0;
            has_receive_block_counter_en    = 1'b0;
            has_send_block_counter_en       = 1'b0;
            receive_crc_counter_en          = 1'b0;
            read_resp_time_counter_en       = 1'b0; 
            send_crc_counter_en             = 1'b0;
            interval_counter_en             = 1'b0;
            receive_crc_status_counter_en   = 1'b0;
            out_transfer_complete           = 1'b0;
			//这里4个周期接收EZZS
            if (interval_counter == 3)
            begin
                next_state = `DATA_STATE_RECEIVE_CRC_STATUS;
                interval_counter_en = 1'b0;
            end
            else begin
                next_state = `DATA_STATE_SNED_END_BIT;
                interval_counter_en = 1'b1;
            end
        end

        `DATA_STATE_RECEIVE_CRC_STATUS ://10
		
        begin
            has_receive_bit_counter_en      = 1'b0;
            has_send_bit_counter_en         = 1'b0;
            has_receive_block_counter_en    = 1'b0;
            has_send_block_counter_en       = 1'b0;
            receive_crc_counter_en          = 1'b0;
            read_resp_time_counter_en       = 1'b0; 
            send_crc_counter_en             = 1'b0;
            interval_counter_en             = 1'b0;
            receive_crc_status_counter_en   = 1'b0;
            out_transfer_complete           = 1'b0;
			//这里4个周期接收status(3bit)+E
            if (receive_crc_status_counter == 3)
            begin
                next_state = `DATA_STATE_SEND_BUSY;
                receive_crc_status_counter_en = 1'b0;
            end
            else begin
                next_state = `DATA_STATE_RECEIVE_CRC_STATUS;
                receive_crc_status_counter_en = 1'b1;
            end
        end

        `DATA_STATE_SEND_BUSY: //11
		//数据块传输结束判断状态,所有block发送结束,
		//跳入STATE_STOP状态,停止操作。
		//否则,进入DATA_STATE_WAIT_SEND状态,等待下一次块数据传输的开始。
        begin
            has_receive_bit_counter_en      = 1'b0;
            has_send_bit_counter_en         = 1'b0;
            has_receive_block_counter_en    = 1'b0;
            //has_send_block_counter_en       = 1'b0;
            receive_crc_counter_en          = 1'b0;
            read_resp_time_counter_en       = 1'b0; 
            send_crc_counter_en             = 1'b0;
            interval_counter_en             = 1'b0;
            receive_crc_status_counter_en   = 1'b0;
            out_transfer_complete           = 1'b0;
            if (has_send_block == (need_to_send_block - 1))
            begin
                next_state = `DATA_STATE_STOP;
                has_send_block_counter_en = 1'b0;
                out_transfer_complete = 1'b1;
            end
            else begin
                next_state = `DATA_STATE_WAIT_SEND;
                has_send_block_counter_en = 1'b1;
            end
        end

        `DATA_STATE_SEND_START_BIT: //12
        begin
            has_receive_bit_counter_en      = 1'b0;
            has_send_bit_counter_en         = 1'b0;
            has_receive_block_counter_en    = 1'b0;
            has_send_block_counter_en       = 1'b0;
            receive_crc_counter_en          = 1'b0;
            read_resp_time_counter_en       = 1'b0; 
            send_crc_counter_en             = 1'b0;
            interval_counter_en             = 1'b0;
            receive_crc_status_counter_en   = 1'b0;
            out_transfer_complete           = 1'b0;
            next_state = `DATA_STATE_SEND;
        end

        `DATA_STATE_SEND_Z:
        begin
            has_receive_bit_counter_en      = 1'b0;
            has_send_bit_counter_en         = 1'b0;
            has_receive_block_counter_en    = 1'b0;
            has_send_block_counter_en       = 1'b0;
            receive_crc_counter_en          = 1'b0;
            read_resp_time_counter_en       = 1'b0; 
            send_crc_counter_en             = 1'b0;
            interval_counter_en             = 1'b0;
            receive_crc_status_counter_en   = 1'b0;
            out_transfer_complete           = 1'b0;
            next_state = `DATA_STATE_SEND_P;
        end

        `DATA_STATE_SEND_P:
        begin
            has_receive_bit_counter_en      = 1'b0;
            has_send_bit_counter_en         = 1'b0;
            has_receive_block_counter_en    = 1'b0;
            has_send_block_counter_en       = 1'b0;
            receive_crc_counter_en          = 1'b0;
            read_resp_time_counter_en       = 1'b0; 
            send_crc_counter_en             = 1'b0;
            interval_counter_en             = 1'b0;
            receive_crc_status_counter_en   = 1'b0;
            out_transfer_complete           = 1'b0;
            next_state = `DATA_STATE_SEND_START_BIT;
        end

        default:
        begin
            has_receive_bit_counter_en      = 1'b0;
            has_send_bit_counter_en         = 1'b0;
            has_receive_block_counter_en    = 1'b0;
            has_send_block_counter_en       = 1'b0;
            receive_crc_counter_en          = 1'b0;
            read_resp_time_counter_en       = 1'b0; 
            send_crc_counter_en             = 1'b0;
            interval_counter_en             = 1'b0;
            receive_crc_status_counter_en   = 1'b0;
            out_transfer_complete = 1'b0;
            next_state = `DATA_STATE_STOP;
        end
    endcase
end

assign  one_bk_re_end_tp = (current_state == `DATA_STATE_RECEIVE_END_BIT);

always @(posedge in_sd_clk or negedge hrst_n) begin
    if (!hrst_n)
		one_bk_re_end <= 1'b0;
	else 
		one_bk_re_end <= one_bk_re_end_tp;

//---------------------------------------------------------------------
// Has received data bits from sd card counter
//---------------------------------------------------------------------
always @(posedge in_sd_clk or negedge hrst_n) begin
    if (!hrst_n)
        has_receive_bit <= 14'b0;
    else if (!in_soft_reset)
        has_receive_bit <= 14'b0;
    else if (current_state == `DATA_STATE_RECEIVE_CRC)
        has_receive_bit <= 14'b0;
    else if (has_receive_bit == (need_to_send_block - 1))
        has_receive_bit <= 14'b0;
    else if (has_receive_bit_counter_en)
        has_receive_bit <= has_receive_bit + 1;
end

//---------------------------------------------------------------------
// Read data from sd card response time counter
//---------------------------------------------------------------------
always @(posedge in_sd_clk or negedge hrst_n) begin
    if (!hrst_n)
        read_resp_time_counter <= 32'b0;
    else if (!in_soft_reset)
        read_resp_time_counter <= 32'b0;
    else if (current_state == `DATA_STATE_STOP)
        read_resp_time_counter <= 32'b0;
    else if (read_resp_time_counter == in_read_to)
        read_resp_time_counter <= 32'b0;
    else if (read_resp_time_counter_en)
        read_resp_time_counter <= read_resp_time_counter + 1;
end       

//---------------------------------------------------------------------
// Has sent data bits counter
//---------------------------------------------------------------------
always @(posedge in_sd_clk or negedge hrst_n) begin
    if (!hrst_n)
        has_send_bit <= 14'b0;
    else if (!in_soft_reset)
        has_send_bit <= 14'b0;
    else if (current_state == `DATA_STATE_SEND_CRC)
        has_send_bit <= 14'b0;
    else if (has_send_bit_counter_en)
        has_send_bit <= has_send_bit + 1;
end

//---------------------------------------------------------------------
// Has received crc number counter
//---------------------------------------------------------------------
always @(posedge in_sd_clk or negedge hrst_n) begin
    if (!hrst_n)
        receive_crc_counter <= 14'b0;
    else if (!in_soft_reset)
        receive_crc_counter <= 14'b0;
    else if (receive_crc_counter == 15)
        receive_crc_counter <= 14'b0;
    else if (receive_crc_counter_en)
        receive_crc_counter <= receive_crc_counter + 1;
end

//---------------------------------------------------------------------
// Has received block number counter
//---------------------------------------------------------------------
always @(posedge in_sd_clk or negedge hrst_n) begin
    if (!hrst_n)
        has_receive_block <= 32'b0;
    else if (!in_soft_reset)
        has_receive_block <= 32'b0;
    else if (current_state == `DATA_STATE_STOP)
        has_receive_block <= 32'b0;
    else if (has_receive_block_counter_en)
        has_receive_block <= has_receive_block + 1;
end


//---------------------------------------------------------------------
// Has sent block number counter
//---------------------------------------------------------------------
always @(posedge in_sd_clk or negedge hrst_n) begin
    if (!hrst_n)
        has_send_block <= 32'b0;
    else if (!in_soft_reset)
        has_send_block <= 32'b0;
    else if (current_state == `DATA_STATE_STOP)
        has_send_block <= 32'b0;
    else if (has_send_block_counter_en)
        has_send_block <= has_send_block + 1;
end

//---------------------------------------------------------------------
// Time interval between the end bit of sent data and crc status counter
//---------------------------------------------------------------------
always @(posedge in_sd_clk or negedge hrst_n) begin
    if (!hrst_n)
        interval_counter <= 2'b0;
    else if (!in_soft_reset)
        interval_counter <= 2'b0;
    else if (interval_counter == 3)
        interval_counter <= 2'b0;
    else if (interval_counter_en)
        interval_counter <= interval_counter + 1;
end

//---------------------------------------------------------------------
// Has receive crc status bits counter
//---------------------------------------------------------------------
always @(posedge in_sd_clk or negedge hrst_n) begin
    if (!hrst_n)
        receive_crc_status_counter <= 2'b0;
    else if (!in_soft_reset)
        receive_crc_status_counter <= 2'b0;
    else if (receive_crc_status_counter == 3)
        receive_crc_status_counter <= 14'b0;
    else if (receive_crc_status_counter_en)
        receive_crc_status_counter <= receive_crc_status_counter + 1;
end

//---------------------------------------------------------------------
// Has sent crc bits counter
//---------------------------------------------------------------------
always @(posedge in_sd_clk or negedge hrst_n) begin
    if (!hrst_n)
        send_crc_counter <= 14'b0;
    else if (!in_soft_reset)
        send_crc_counter <= 14'b0;
    else if (send_crc_counter == 15)
        send_crc_counter <= 14'b0;
    else if (send_crc_counter_en)
        send_crc_counter <= send_crc_counter + 1;
end

endmodule

sd_data_send_shift_register

data数据的发送模块,根据sd_data_fsm模块状态机的状态,读取内部fifo数据和CRC数据,拆分成bit数据,送入data line。并根据接收的状态数据,判定一块数据发送是否正确
功能描述:
1、数据线方向控制,根据状态信息,判定数据IO线是输入还是输出;
下图所示的是在低速时钟下,host数据发送和方向控制时序。在下降沿对输出的方向控制寄存器,得到下降沿输出数据。根据信号in_high_speed_clk (host是否工作在高速时钟情况),判定是下降沿输出还是上升沿输出。
在这里插入图片描述
2、数据的输出
a. fifo数据的swap,fifo数据是地址顺序存储的(the first byte is the least significant byte ),但host数据的输出就是FIFO数据左移数来的最高位,不符合sd协议,输出前需要4个byte的swap调整;
b. 读入FIFO数据和模块生成的CRC数据左移输出。
3、CRC数据的生成;
4、数据输出错误判定;

信号描述

signalsI/OWidthfromtodeclaration
in_sd_clkinput1sd_clk时钟信号
hrst_ninput1异步复位
in_soft_resetinput1软件复位
in_sd_datainput[3:0]数据读入端口(接收crc)
sd_fifo_rdatainput[31:0]fifo数据读出数据端口
in_current_stateinput[3:0]sd_data_fsm数据当前状态标志位
in_next_stateinput[3:0]sd_data_fsm数据次状态标志位
in_data_widthinput1sd_ifhost使用数据线判定信号:1/4 data line
in_send_crc_counterinput[3:0]sd_data_fsmhost已发送crc数据的bit大小
in_has_send_bitinput[13:0]sd_data_fsmHost已发送的数据bit大小
in_interval_counterinput[1:0]sd_data_fsm单块block写结束位时钟计数器,用于数据端口方向位的控制
in_high_speed_clkinput1sd_if数据输出方式,1:高速 0:低速
out_serial_dataoutput[3:0]sd_card向sd card 输入数据
sd_fifo_reoutput1fifofifo读请求信号
out_crc_status_wrongoutput1sd_if数据发送crc检验错误
out_data_diroutput[3:0]数据方向控制端口 1 发送到sd card
out_data_half_delayoutput[3:0]数据输出端口(高速:上升沿 低速:下降沿)
in_TestModeoutput1测试模式

verilog 实现

module sd_data_send_shift_register (
        in_sd_clk,
        hrst_n,
        in_soft_reset,
        in_sd_data,
        sd_fifo_rdata,
        in_current_state,
        in_next_state,
        in_data_width,
        in_send_crc_counter,
        in_has_send_bit,
        in_interval_counter,
        in_high_speed_clk,
        out_serial_data,
        sd_fifo_re,
        out_crc_status_wrong,
        out_data_dir,
        out_data_half_delay
);

input               in_sd_clk;              //clock for sd card
input               hrst_n;                 //ahb signal
input               in_soft_reset;          //software reset
input   [3:0]       in_sd_data;             //data input drom sd card
input   [31:0]      sd_fifo_rdata;          //parallel data from tx fifo
input   [3:0]       in_current_state;       //current state of data fsm
input   [3:0]       in_next_state;          //next state of data fsm
input               in_data_width;          //data width 1:4bit 0:1bit
input   [3:0]       in_send_crc_counter;    //has sent crc bits
input   [13:0]      in_has_send_bit;        //has sent data bits
input   [1:0]       in_interval_counter;    //time interval
input               in_high_speed_clk;      

output  [3:0]       out_serial_data;        //original serial output data
output              sd_fifo_re;             //tx fifo read enable
output              out_crc_status_wrong;   //crc status wrong flag
output  [3:0]       out_data_dir;           //data direction   1:send
output  [3:0]       out_data_half_delay;    //serial output data to sd card


reg [3:0]   out_serial_data;
reg [31:0]  shift_reg0;
reg [15:0]  crc_reg0;
reg [15:0]  crc_reg1;
reg [15:0]  crc_reg2;
reg [15:0]  crc_reg3;
reg [15:0]  crc_shift_reg0;
reg [15:0]  crc_shift_reg1;
reg [15:0]  crc_shift_reg2;
reg [15:0]  crc_shift_reg3;
reg [0:31]  data_for_send;
reg [3:0]   crc_status_reg;
reg         sd_fifo_re;
reg         out_crc_status_wrong;
reg [3:0]   out_data_half_delay_tp;
reg [3:0]   data_dir_nes;

wire [31:0] sd_fifo_rdata_tp;
wire [3:0]  data_dir_pos;



//-------------------------------------------------------------------
// Beginning of main code
//---------------------------------------------------------------------
// Overview of the data send shift register operation
// The following key signals are used in the command send shift register
// out_data_dir is the data direction
// out_data_half_delay is the output data to sd card
// crc_reg3 is the denerated data crc register
// crc_reg2 is the denerated data crc register
// crc_reg1 is the denerated data crc register
// crc_reg0 is the denerated data crc register
// sd_fifo_rdata is the parallel data from tx fifo
// sd_fifo_re is the tx fifo read enable signal
// crc_status_reg is the crc status from sd card after sending data

//-----------------------------------------------------------------------
// Output data to sd card
//---------------------------------------------------------------------
//the data was sent at negedge
always @(negedge in_sd_clk or negedge hrst_n) begin
    if (!hrst_n) begin
        out_data_half_delay_tp <= 4'b1111;
    end
    else begin
        out_data_half_delay_tp <= out_serial_data;
		//用clk下降沿打拍,延迟半个周期
    end
end
//数据输出端口(高速:上升沿  低速:下降沿)  ??讲者说考虑timing 切换相位可以满足时序
assign out_data_half_delay = in_high_speed_clk ? out_serial_data : out_data_half_delay_tp;
//-----------------------------------------------------------------------------
// Data direction   0:receive  1:send
//------------------------------------------------------------------------------
//输出使能,向sd方向
assign data_dir_pos[0] = (  (in_current_state == `DATA_STATE_SEND_P)            ||
                            (in_current_state == `DATA_STATE_SEND_START_BIT)    ||
                            (in_current_state == `DATA_STATE_SEND)              ||
                            (in_current_state == `DATA_STATE_SEND_CRC)          ||
                            ((in_current_state == `DATA_STATE_SEND_END_BIT)     &&
                            ((in_interval_counter == 0) || (in_interval_counter == 1)))
                        );

assign data_dir_pos[1] = in_data_width && ((in_current_state == `DATA_STATE_SEND_P) ||
                            (in_current_state == `DATA_STATE_SEND_START_BIT)        ||
                            (in_current_state == `DATA_STATE_SEND)                  ||
                            (in_current_state == `DATA_STATE_SEND_CRC)              ||
                            ((in_current_state == `DATA_STATE_SEND_END_BIT)         &&
                            ((in_interval_counter == 0) || (in_interval_counter == 1)))
                        );

assign data_dir_pos[2] = in_data_width && ((in_current_state == `DATA_STATE_SEND_P) ||
                            (in_current_state == `DATA_STATE_SEND_START_BIT)        ||
                            (in_current_state == `DATA_STATE_SEND)                  ||
                            (in_current_state == `DATA_STATE_SEND_CRC)              ||
                            ((in_current_state == `DATA_STATE_SEND_END_BIT)         &&
                            ((in_interval_counter == 0) || (in_interval_counter == 1)))
                        );

assign data_dir_pos[3] = in_data_width && ((in_current_state == `DATA_STATE_SEND_P) ||
                            (in_current_state == `DATA_STATE_SEND_START_BIT)        ||
                            (in_current_state == `DATA_STATE_SEND)                  ||
                            (in_current_state == `DATA_STATE_SEND_CRC)              ||
                            ((in_current_state == `DATA_STATE_SEND_END_BIT)         &&
                            ((in_interval_counter == 0) || (in_interval_counter == 1)))
                        );
// assign data_dir_pos[1] = in_data_width && data_dir_pos[0];
// assign data_dir_pos[2] = data_dir_pos[1];
// assign data_dir_pos[3] = data_dir_pos[1];

always @(negedge in_sd_clk or negedge hrst_n) begin
    if (!hrst_n) begin
        data_dir_nes <= 4'b0
    end
    else begin
            data_dir_nes <= {data_dir_pos[3],data_dir_pos[2],data_dir_pos[1],data_dir_pos[0]};
    end
end
// out_data_dir 端口方向的控制??
assign out_data_dir = in_high_speed_clk ? data_dir_pos :data_dir_nes;

//---------------------------------------------------------------------------------
// Generate output data to sd card 1ibt and 4bit mode and receive crc status bits
// -------------------------------------------------------------------------------
always @(posedge in_sd_clk or negedge hrst_n) begin
    if (!hrst_n) begin
        shift_reg0 <= 32'b0;
        out_serial_data <= 4'b1111;
        crc_status_reg <= 4'b0;
        crc_shift_reg0 <= 16'b0;
        crc_shift_reg1 <= 16'b0;
        crc_shift_reg2 <= 16'b0;
        crc_shift_reg3 <= 16'b0;
    end
    else if (!in_soft_reset) 
    begin
        shift_reg0 <= 32'b0;
        out_serial_data <= 4'b1111;
        crc_status_reg <= 4'b0;
        crc_shift_reg0 <= 16'b0;
        crc_shift_reg1 <= 16'b0;
        crc_shift_reg2 <= 16'b0;
        crc_shift_reg3 <= 16'b0;
    end
    else 
    begin
        if(!in_data_width)
        begin
            if (in_current_state == `DATA_STATE_SEND_START_BIT)
			//send start bit
                out_serial_data[0] <= 1'b0;
            else if (in_current_state == `DATA_STATE_SEND)
            begin
			//每32个bit,重新赋一个值(从fifo中读出得到)
                if (in_has_send_bit[4:0] == 5'b0)
                    {out_serial_data[0],shift_reg0} <= {sd_fifo_rdata_tp,1'b0};
                else 
                    {out_serial_data[0],shift_reg0} <= {shift_reg0,1'b0};
					//向左移位输出,并行转串行
            end
            else if (in_current_state == `DATA_STATE_SEND_CRC)
            begin
                if (in_send_crc_counter == 0)
                    {out_serial_data[0],crc_shift_reg0} <= {crc_reg0,1'b0};
                else 
                    {out_serial_data[0],crc_shift_reg0} <= {crc_shift_reg0,1'b0};
            end
            else if (in_current_state == `DATA_STATE_SEND_END_BIT)
            begin
                out_serial_data[0] <= 1'b1;
            end
			//DATA_STATE_RECEIVE_CRC_STATUS 这里sd 数据线的方向变化,变为接收crc_status
            else if (in_current_state == `DATA_STATE_RECEIVE_CRC_STATUS)
            begin
                crc_status_reg <= {crc_status_reg[2:0], in_sd_data[0]};
            end
            else if (in_current_state == `DATA_STATE_WAIT_SEND)
            begin
                crc_status_reg <= 4'b0;
            end
        end
        else
        begin
            if (in_current_state == `DATA_STATE_SEND_START_BIT)
                out_serial_data <= 4'b0;
            else if (in_current_state == `DATA_STATE_SEND)
            begin
                if (in_has_send_bit[2:0] == 3'b0)
                    {out_serial_data,shift_reg0} <= {sd_fifo_rdata_tp,4'b0};
                else
                    {out_serial_data,shift_reg0} <= {shift_reg0,4'b0};
            end
            else if (in_current_state == `DATA_STATE_SEND_CRC)
            begin
                if(in_send_crc_counter == 0)
                begin
                    {out_serial_data[3],crc_shift_reg3} <= {crc_reg3,1'b0};
                    {out_serial_data[2],crc_shift_reg2} <= {crc_reg2,1'b0};
                    {out_serial_data[1],crc_shift_reg1} <= {crc_reg1,1'b0};
                    {out_serial_data[0],crc_shift_reg0} <= {crc_reg0,1'b0};
                end
                else
                begin
                    {out_serial_data[3],crc_shift_reg3} <= {crc_shift_reg3,1'b0};
                    {out_serial_data[2],crc_shift_reg2} <= {crc_shift_reg2,1'b0};
                    {out_serial_data[1],crc_shift_reg1} <= {crc_shift_reg1,1'b0};
                    {out_serial_data[0],crc_shift_reg0} <= {crc_shift_reg0,1'b0};
                end
            end
            else if (in_current_state == `DATA_STATE_RECEIVE_CRC_STATUS)
            begin
                crc_status_reg <= {crc_status_reg[2:0],in_sd_data[0]};
            end
            else if (in_current_state ==`DATA_STATE_WAIT_SEND)
                crc_status_reg <= 4'b0
        end
    end

end

//----------------------------------------------------
// Generate output data crc
//----------------------------------------------------

always @(posedge in_sd_clk or negedge hrst_n) begin
    if (!hrst_n) begin
        crc_reg3 <= 16'b0;
        crc_reg2 <= 16'b0;
        crc_reg1 <= 16'b0;
        crc_reg0 <= 16'b0;
    end
    else if (!in_soft_reset) begin
        crc_reg3 <= 16'b0;
        crc_reg2 <= 16'b0;
        crc_reg1 <= 16'b0;
        crc_reg0 <= 16'b0;
    end
    else if (in_current_state == `DATA_STATE_WAIT_SEND)
    begin
        crc_reg3 <= 16'b0;
        crc_reg2 <= 16'b0;
        crc_reg1 <= 16'b0;
        crc_reg0 <= 16'b0;
    end
    else if (in_current_state == `DATA_STATE_SEND)
    begin
        if (!in_data_width)
        begin
            crc_reg0[0] <= data_for_send[in_has_send_bit[4:0]] ^ crc_reg0[15];
            crc_reg0[1] <= crc_reg0[0];
            crc_reg0[2] <= crc_reg0[1];
            crc_reg0[3] <= crc_reg0[2];
            crc_reg0[4] <= crc_reg0[3];
            crc_reg0[5] <= crc_reg0[4] ^ data_for_send[in_has_send_bit[4:0]] ^ crc_reg0[15];
            crc_reg0[6] <= crc_reg0[5];
            crc_reg0[7] <= crc_reg0[6];
            crc_reg0[8] <= crc_reg0[7];
            crc_reg0[9] <= crc_reg0[8];
            crc_reg0[10] <= crc_reg0[9];
            crc_reg0[11] <= crc_reg0[10];
            crc_reg0[12] <= crc_reg0[11] ^ data_for_send[in_has_send_bit[4:0] ^ crc_reg0[15]];
            crc_reg0[13] <= crc_reg0[12];
            crc_reg0[14] <= crc_reg0[13];
            crc_reg0[15] <= crc_reg0[14];
        end
        else
        begin
            crc_reg3[0] <= data_for_send[{in_has_send_bit[2:0],2'b0}] ^ crc_reg3[15];
            crc_reg3[1] <= crc_reg3[0];
            crc_reg3[2] <= crc_reg3[1];
            crc_reg3[3] <= crc_reg3[2];
            crc_reg3[4] <= crc_reg3[3];
            crc_reg3[5] <= crc_reg3[4] ^ data_for_send[{in_has_send_bit[2:0],2'b0}] ^ crc_reg3[15];
            crc_reg3[6] <= crc_reg3[5];
            crc_reg3[7] <= crc_reg3[6];
            crc_reg3[8] <= crc_reg3[7];
            crc_reg3[9] <= crc_reg3[8];
            crc_reg3[10] <= crc_reg3[9];
            crc_reg3[11] <= crc_reg3[10];
            crc_reg3[12] <= crc_reg3[11] ^ data_for_send[{in_has_send_bit[2:0],2'b0}] ^ crc_reg3[15];
            crc_reg3[13] <= crc_reg3[12];
            crc_reg3[14] <= crc_reg3[13];
            crc_reg3[15] <= crc_reg3[14];
            
            crc_reg2[0] <= data_for_send[{in_has_send_bit[2:0],2'b0}+1] ^ crc_reg2[15];
            crc_reg2[1] <= crc_reg2[0];
            crc_reg2[2] <= crc_reg2[1];
            crc_reg2[3] <= crc_reg2[2];
            crc_reg2[4] <= crc_reg2[3];
            crc_reg2[5] <= crc_reg2[4] ^ data_for_send[{in_has_send_bit[2:0],2'b0}+1] ^ crc_reg2[15];
            crc_reg2[6] <= crc_reg2[5];
            crc_reg2[7] <= crc_reg2[6];
            crc_reg2[8] <= crc_reg2[7];
            crc_reg2[9] <= crc_reg2[8];
            crc_reg2[10] <= crc_reg2[9];
            crc_reg2[11] <= crc_reg2[10];
            crc_reg2[12] <= crc_reg2[11] ^ data_for_send[{in_has_send_bit[2:0],2'b0}+1] ^ crc_reg2[15];
            crc_reg2[13] <= crc_reg2[12];
            crc_reg2[14] <= crc_reg2[13];
            crc_reg2[15] <= crc_reg2[14];
           

            crc_reg1[0] <= data_for_send[{in_has_send_bit[2:0],2'b0}+2] ^ crc_reg1[15];
            crc_reg1[1] <= crc_reg1[0];
            crc_reg1[2] <= crc_reg1[1];
            crc_reg1[3] <= crc_reg1[2];
            crc_reg1[4] <= crc_reg1[3];
            crc_reg1[5] <= crc_reg1[4] ^ data_for_send[{in_has_send_bit[2:0],2'b0}+2] ^ crc_reg1[15];
            crc_reg1[6] <= crc_reg1[5];
            crc_reg1[7] <= crc_reg1[6];
            crc_reg1[8] <= crc_reg1[7];
            crc_reg1[9] <= crc_reg1[8];
            crc_reg1[10] <= crc_reg1[9];
            crc_reg1[11] <= crc_reg1[10];
            crc_reg1[12] <= crc_reg1[11] ^ data_for_send[{in_has_send_bit[2:0],2'b0}+2] ^ crc_reg1[15];
            crc_reg1[13] <= crc_reg1[12];
            crc_reg1[14] <= crc_reg1[13];
            crc_reg1[15] <= crc_reg1[14];

            crc_reg0[0] <= data_for_send[{in_has_send_bit[2:0],2'b0}+3] ^ crc_reg0[15];
            crc_reg0[1] <= crc_reg0[0];
            crc_reg0[2] <= crc_reg0[1];
            crc_reg0[3] <= crc_reg0[2];
            crc_reg0[4] <= crc_reg0[3];
            crc_reg0[5] <= crc_reg0[4] ^ data_for_send[{in_has_send_bit[2:0],2'b0}+3] ^ crc_reg0[15];
            crc_reg0[6] <= crc_reg0[5];
            crc_reg0[7] <= crc_reg0[6];
            crc_reg0[8] <= crc_reg0[7];
            crc_reg0[9] <= crc_reg0[8];
            crc_reg0[10] <= crc_reg0[9];
            crc_reg0[11] <= crc_reg0[10];
            crc_reg0[12] <= crc_reg0[11] ^ data_for_send[{in_has_send_bit[2:0],2'b0}+3] ^ crc_reg0[15];
            crc_reg0[13] <= crc_reg0[12];
            crc_reg0[14] <= crc_reg0[13];
            crc_reg0[15] <= crc_reg0[14];
        end
    end
end

//------------------------------------------------------
// Generate data for send
//------------------------------------------------------
assign sd_fifo_rdata_tp = {sd_fifo_rdata[7:0],sd_fifo_rdata[15:8],sd_fifo_rdata[23:16],sd_fifo_rdata[31:24]};
//data_for_send是[0:31] 把sd_fifo_rdata_tp 的高位放在地位,用在crc的生成
always @(*) begin
    data_for_send = 32'b0;
    if (in_current_state == `DATA_STATE_SEND)
        data_for_send = sd_fifo_rdata_tp;
end

//-------------------------------------------------------
// GEnerate tx fifo read enable signal
//-------------------------------------------------------

always @(*) begin
    sd_fifo_re = 1'b0;
    if (!in_data_width)
    begin
        if(((in_current_state == `DATA_STATE_SEND_START_BIT) && (in_has_send_bit[4:0] == 5'b0)) ||
            ((in_current_state == `DATA_STATE_SEND) && (in_next_state == `DATA_STATE_SEND) && (in_has_send_bit[4:0] == 5'b11111)))
            sd_fifo_re = 1'b1;
    end
    else begin
        if(((in_current_state == `DATA_STATE_SEND_START_BIT) && (in_has_send_bit[2:0] == 3'b0)) ||
            ((in_current_state == `DATA_STATE_SEND) && (in_next_state == `DATA_STATE_SEND) && (in_has_send_bit[2:0] == 3'b111)))
            sd_fifo_re = 1'b1;
    end
end

//---------------------------------------------------------------
// Generate crc status wrong flag after sending data to sd card
//---------------------------------------------------------------
//crc的状态用3bit表示(010是OK),当状态为错误时产生数据错误信号
//应该是用高3位010判断(课上提出)?后面看波形确认
always @(*) begin
    out_crc_status_wrong =1'b0;
    //  there crc_status_reg maybe sould be 4'b0100  ,see the wave
    if((in_current_state == `DATA_STATE_SEND_BUSY) && !(crc_status_reg == 4'b0010))
        out_crc_status_wrong =1'b1;
end

endmodule

sd_data_receive_shift_register

功能描述:
1、数据读入并成一个word,swap,写入fifo
2、CRC数据读取,并和内部产生的CRC数据进行对比,以判定读入的数据是否出错,以out_receive_data_crc_error信号作标志位。

信号描述

signalsI/OWidthfromtodeclaration
in_sd_clkinput1sd_clk时钟信号
in_soft_resetinput1软件复位
in_current_stateinput[3:0]sd_data_fsm数据当前状态标志位
in_serial_datainput[3:0]sd_card数据输入端口
in_data_widthinput1sd_ifhost使用数据线判定信号:1/4 data line
in_has_receive_bitinput[13:0]sd_data_fsmHost已接收的数据bit大小
sd_fifo_weoutput1fifofifo写请求信号
sd_fifo_wdataoutput[31:0]fifofifo数据写入端口
out_receive_data_crc_erroutput1sd_if读入数据crc检验错误

verilog实现

module sd_data_receive_shift_register(
        in_sd_clk,                  //clock for sd card
        hrst_n,                     
        in_soft_reset,              //software reset
        in_current_state,           //surrent state of data fsm
        in_serial_data,             //data input from sd card
        in_data_width,              //data width 1:4bit 0:1bit
        in_has_receive_bit,         //has received data bits
        sd_fifo_wdata,              //output parallel data to rx fifo
        sd_fifo_we,                 //host writes rx_fifo
        out_receive_data_crc_error  //receive data crc error flag
);
input               in_sd_clk;                  //clock for sd card
input               hrst_n;                     
input               in_soft_reset;              //software reset
input   [3:0]       in_current_state;           //surrent state of data fsm
input   [3:0]       in_serial_data;             //data input from sd card
input               in_data_width;              //data width 1:4bit 0:1bit
input   [13:0]      in_has_receive_bit;         //has received data bits

output  [31:0]      sd_fifo_wdata;              //output parallel data to rx fifo
output              sd_fifo_we;                 //host writes rx_fifo
output              out_receive_data_crc_error;  //receive data crc error flag

reg                 out_receive_data_crc_error;
reg                 sd_fifo_we;
reg     [15:0]      crc_reg0;
reg     [15:0]      crc_reg1;
reg     [15:0]      crc_reg2;
reg     [15:0]      crc_reg3;
reg     [15:0]      generate_crc_reg0;
reg     [15:0]      generate_crc_reg1;
reg     [15:0]      generate_crc_reg2;
reg     [15:0]      generate_crc_reg3;
reg     [31:0]      shift_reg;
reg                 out_write_receive_fifo;

//------------------------------------------------------------
// Beginning of main code
//------------------------------------------------------------
// Overview of the data receive shift register operation
// the following key signals are used in the data receive shift register
// in_serial_data is the data input from sd card
// out_write_receive_fifo is the rx fifo write enable signal
// crc_regx is the received data crc
// generate_crc_regx is the generated data crc
// out_receive_data_crc_error is the data receiveing crc error flag

//assign sd_fifo_wdata =shift_reg;
assign sd_fifo_wdata = {shift_reg[7:0],shift_reg[15:8],shift_reg[23:16],shift_reg[31:24]};

//------------------------------------------------------
// Register rx fifo write enable signal
//------------------------------------------------------

always @(posedge in sd_clk or negedhe hrst_n) begin
    if (!hrst_n)
        sd_fifo_we <= 1'b0;
    else if (!in_soft_reset)
        sd_fifo_we <= 1'b0;
    else 
        sd_fifo_we <= out_write_receive_fifo;
end

//-------------------------------------------------------------
// Serial to Parallel conversion
// ------------------------------------------------------------

always @(posedge in_sd_clk or negedge hrst_n) begin
    if(!hrst_n)
        shift_reg <= 32'b0;
    else if (!in_soft_reset)
        shift_reg <= 32'b0;
    else begin
        if (in_current_state == `DATA_STATE_RECEIVE)
        begin
            if(!in_data_width)
                shift_reg <= {shift_reg[30:0],in_serial_data[0]};
            else
                shift_reg <= {shift_reg[27:0],in_serial_data};
        end
    end
end

//-------------------------------------------------------------------
//Generate rx fifo write enable signal
//-------------------------------------------------------------------
always @(*) begin
    out_write_receive_fifo = 1'b0;
    if (!in_data_width) 
    begin
        if ((in_current_state == `DATA_STATE_RECEIVE) && (in_has_receive_bit[4:0] == 5'b11111))
            out_write_receive_fifo = 1'b1;
    end
    else begin
        if((in_current_state == `DATA_STATE_RECEIVE) && (in_has_receive_bit[2:0] == 3'b111))
            out_write_receive_fifo = 1'b1;
    end
end

//--------------------------------------------------------------------
// Receive data crc 1bit and 4bit mode
//--------------------------------------------------------------------

always @(posedge in_sd_clk or negedge hrst_n)
    if (!hrst_n)
    begin
        crc_reg0 <= 16'b0;
        crc_reg1 <= 16'b0;
        crc_reg2 <= 16'b0;
        crc_reg3 <= 16'b0;
    end
    else if (in_soft_reset)
    begin
        crc_reg0 <= 16'b0;
        crc_reg1 <= 16'b0;
        crc_reg2 <= 16'b0;
        crc_reg3 <= 16'b0;
    end
    else if ((in_current_state == `DATA_STATE_RECEIVE_END_BIT))
    begin
        crc_reg0 <= 16'b0;
        crc_reg1 <= 16'b0;
        crc_reg2 <= 16'b0;
        crc_reg3 <= 16'b0;
    end
    else if (in_current_state == `DATA_STATE_RECEIVE_CRC)
    begin
        if(in_data_width == 1'b0)
            crc_reg0 <= {crc_reg0[14:0],in_serial_data[0]};
        else begin
            crc_reg0 <= {crc_reg0[14:0],in_serial_data[0]};
            crc_reg1 <= {crc_reg1[14:0],in_serial_data[1]};
            crc_reg2 <= {crc_reg2[14:0],in_serial_data[2]};
            crc_reg3 <= {crc_reg3[14:0],in_serial_data[3]};
        end
    end
end

//-----------------------------------------------------
// Generate data crc for 1bit and 4bit mode
//-----------------------------------------------------
 always @(posedge in_sd_clk or negedge hrst_n) begin
     if (!hrst_n)
     begin
         generate_crc_reg0 <= 16'b0;
         generate_crc_reg1 <= 16'b0;
         generate_crc_reg2 <= 16'b0;
         generate_crc_reg3 <= 16'b0;
    end
    else if (!in_soft_reset)
    begin
         generate_crc_reg0 <= 16'b0;
         generate_crc_reg1 <= 16'b0;
         generate_crc_reg2 <= 16'b0;
         generate_crc_reg3 <= 16'b0;
     end
     else if ((in_current_state == `DATA_STATE_RECEIVE_END_BIT))
     begin
         generate_crc_reg0 <= 16'b0;
         generate_crc_reg1 <= 16'b0;
         generate_crc_reg2 <= 16'b0;
         generate_crc_reg3 <= 16'b0;
     end
     else if (in_current_state == `DATA_STATE_RECEIVE)
     begin
         if (in_data_width == 1'b0)
         begin
             generate_crc_reg0[0] <= in_serial_data[0] ^ generate_crc_reg0[15];
             generate_crc_reg0[1] <= generate_crc_reg0[0];
             generate_crc_reg0[2] <= generate_crc_reg0[1];
             generate_crc_reg0[3] <= generate_crc_reg0[2];
             generate_crc_reg0[4] <= generate_crc_reg0[3];
             generate_crc_reg0[5] <= generate_crc_reg0[4] ^ in_serial_data[0] ^ generate_crc_reg0[15];
             generate_crc_reg0[6] <= generate_crc_reg0[5];
             generate_crc_reg0[7] <= generate_crc_reg0[6];
             generate_crc_reg0[8] <= generate_crc_reg0[7];
             generate_crc_reg0[9] <= generate_crc_reg0[8];
             generate_crc_reg0[10] <= generate_crc_reg0[9];
             generate_crc_reg0[11] <= generate_crc_reg0[10];
             generate_crc_reg0[12] <= generate_crc_reg0[11] ^ in_serial_data[0] ^ generate_crc_reg0[15];
             generate_crc_reg0[13] <= generate_crc_reg0[12];
             generate_crc_reg0[14] <= generate_crc_reg0[13];
             generate_crc_reg0[15] <= generate_crc_reg0[14];
         end
         else begin
             generate_crc_reg0[0] <= in_serial_data[0] ^ generate_crc_reg0[15];
             generate_crc_reg0[1] <= generate_crc_reg0[0];
             generate_crc_reg0[2] <= generate_crc_reg0[1];
             generate_crc_reg0[3] <= generate_crc_reg0[2];
             generate_crc_reg0[4] <= generate_crc_reg0[3];
             generate_crc_reg0[5] <= generate_crc_reg0[4] ^ in_serial_data[0] ^ generate_crc_reg0[15];
             generate_crc_reg0[6] <= generate_crc_reg0[5];
             generate_crc_reg0[7] <= generate_crc_reg0[6];
             generate_crc_reg0[8] <= generate_crc_reg0[7];
             generate_crc_reg0[9] <= generate_crc_reg0[8];
             generate_crc_reg0[10] <= generate_crc_reg0[9];
             generate_crc_reg0[11] <= generate_crc_reg0[10];
             generate_crc_reg0[12] <= generate_crc_reg0[11] ^ in_serial_data[0] ^ generate_crc_reg0[15];
             generate_crc_reg0[13] <= generate_crc_reg0[12];
             generate_crc_reg0[14] <= generate_crc_reg0[13];
             generate_crc_reg0[15] <= generate_crc_reg0[14];

             generate_crc_reg1[0] <= in_serial_data[1] ^ generate_crc_reg1[15];
             generate_crc_reg1[1] <= generate_crc_reg1[0];
             generate_crc_reg1[2] <= generate_crc_reg1[1];
             generate_crc_reg1[3] <= generate_crc_reg1[2];
             generate_crc_reg1[4] <= generate_crc_reg1[3];
             generate_crc_reg1[5] <= generate_crc_reg1[4] ^ in_serial_data[1] ^ generate_crc_reg1[15];
             generate_crc_reg1[6] <= generate_crc_reg1[5];
             generate_crc_reg1[7] <= generate_crc_reg1[6];
             generate_crc_reg1[8] <= generate_crc_reg1[7];
             generate_crc_reg1[9] <= generate_crc_reg1[8];
             generate_crc_reg1[10] <= generate_crc_reg1[9];
             generate_crc_reg1[11] <= generate_crc_reg1[10];
             generate_crc_reg1[12] <= generate_crc_reg1[11] ^ in_serial_data[1] ^ generate_crc_reg1[15];
             generate_crc_reg1[13] <= generate_crc_reg1[12];
             generate_crc_reg1[14] <= generate_crc_reg1[13];
             generate_crc_reg1[15] <= generate_crc_reg1[14];

             generate_crc_reg2[0] <= in_serial_data[2] ^ generate_crc_reg2[15];
             generate_crc_reg2[1] <= generate_crc_reg2[0];
             generate_crc_reg2[2] <= generate_crc_reg2[1];
             generate_crc_reg2[3] <= generate_crc_reg2[2];
             generate_crc_reg2[4] <= generate_crc_reg2[3];
             generate_crc_reg2[5] <= generate_crc_reg2[4] ^ in_serial_data[2] ^ generate_crc_reg2[15];
             generate_crc_reg2[6] <= generate_crc_reg2[5];
             generate_crc_reg2[7] <= generate_crc_reg2[6];
             generate_crc_reg2[8] <= generate_crc_reg2[7];
             generate_crc_reg2[9] <= generate_crc_reg2[8];
             generate_crc_reg2[10] <= generate_crc_reg2[9];
             generate_crc_reg2[11] <= generate_crc_reg2[10];
             generate_crc_reg2[12] <= generate_crc_reg2[11] ^ in_serial_data[2] ^ generate_crc_reg2[15];
             generate_crc_reg2[13] <= generate_crc_reg2[12];
             generate_crc_reg2[14] <= generate_crc_reg2[13];
             generate_crc_reg2[15] <= generate_crc_reg2[14];

             generate_crc_reg3[0] <= in_serial_data[3] ^ generate_crc_reg3[15];
             generate_crc_reg3[1] <= generate_crc_reg3[0];
             generate_crc_reg3[2] <= generate_crc_reg3[1];
             generate_crc_reg3[3] <= generate_crc_reg3[2];
             generate_crc_reg3[4] <= generate_crc_reg3[3];
             generate_crc_reg3[5] <= generate_crc_reg3[4] ^ in_serial_data[3] ^ generate_crc_reg3[15];
             generate_crc_reg3[6] <= generate_crc_reg3[5];
             generate_crc_reg3[7] <= generate_crc_reg3[6];
             generate_crc_reg3[8] <= generate_crc_reg3[7];
             generate_crc_reg3[9] <= generate_crc_reg3[8];
             generate_crc_reg3[10] <= generate_crc_reg3[9];
             generate_crc_reg3[11] <= generate_crc_reg3[10];
             generate_crc_reg3[12] <= generate_crc_reg3[11] ^ in_serial_data[3] ^ generate_crc_reg3[15];
             generate_crc_reg3[13] <= generate_crc_reg3[12];
             generate_crc_reg3[14] <= generate_crc_reg3[13];
             generate_crc_reg3[15] <= generate_crc_reg3[14];
         end
     end
 end

 //----------------------------------------------------------
 // Compare generated data crc with received data crc
 //----------------------------------------------------------
 
 always @(*) begin
     out_receive_data_crc_error = 1'b0;
     if(!in_data_width)
     begin
         if ((in_current_state == `DATA_STATE_RECEIVE_END_BIT) && !(crc_reg0 == generate_crc_reg0))
             out_receive_data_crc_error = 1'b1;
     end
     else begin
         if((in_current_state == `DATA_STATE_RECEIVE_END_BIT) && 
               (!(crc_reg0 == generate_crc_reg0) ||
                !(crc_reg1 == generate_crc_reg1) ||
                !(crc_reg2 == generate_crc_reg2) ||
                !(crc_reg3 == generate_crc_reg3) )
            out_receive_data_crc_error = 1'b1;
    end
end

  • 2
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
SD Host是一个针对SD卡的项目,需要熟悉AHB协议和SD协议。SD Host项目的代码量是SRAMC的10倍,因此自学起来可能会有一定难度。关于SD Host项目的详细内容,包括Datasheet、验证计划和SD协议等相关文件,可以通过私信获取。在SD卡的识别模式下,控制器会检验SD卡的工作电压范围,识别SD卡类型,并要求它们发送各自的地址。这些操作在SD卡的CMD线上进行,使用默认的SD卡识别时钟频率。\[1\]\[2\]关于SD Host的具体实现细节,包括SD-Host数据控制模块SD_DATA_FSM状态转换图、sd_data_send_shift_register和sd_data_receive_shift_register的信号描述,可以在相关的Verilog实现中找到。\[3\] #### 引用[.reference_title] - *1* *2* [IC验证-SDHOST项目2](https://blog.csdn.net/weixin_48014653/article/details/124760076)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [SD-Host 数据控制模块](https://blog.csdn.net/zgezi/article/details/107017640)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值