当前位置:网站首页>SD_DATA_SEND_SHIFT_REGISTER

SD_DATA_SEND_SHIFT_REGISTER

2022-07-07 15:46:00 捌肆幺幺

1.接口

  • 时钟复位软复位
  • sd卡数据线过来的数据in_sd_data
  • 数据传输宽度in_data_width
  • 从fifo中读出的数据sd_fifo_rdata、使能sd_fifo_re
  • 状态in_current_state、in_next_state
  • 发送的crc,需要in_send_crc_counter、out_crc_status_wrong
  • 发送的数据信号in_has_send_bit、in_interval_counter、out_serial_data
  • 输出数据out_data_half_delay、out_data_dir
  • 高速时钟模式in_high_speed_clk
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 数对面crc
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

2.内部信号

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;

3.高速时钟模式

  • 由in_high_speed_clk的输入决定out口用哪个数据
assign out_data_half_delay = in_high_speed_clk ? out_serial_data : out_data_half_delay_tp;

assign out_data_dir = in_high_speed_clk ? data_dir_pos :data_dir_nes;
 
 //-------------------------------------------------------
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
//-------------------------------------------------
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

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 && data_dir_pos[0];
 assign data_dir_pos[2] = data_dir_pos[1];
 assign data_dir_pos[3] = data_dir_pos[1];

4.移位进行数据的并转串

  • 需要移位的数据有out_serial_data、crc_status_reg、crc_shift_reg
  • 在每个不同状态,移位不一样的数据
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

5.data_for_send的产生,后面用于计算crc

  • 同样的对于从fifo读到的数据进行高位低位变换,记作sd_fifo_rdata_tp
  • 当状态为DATA_STATE_SEND时,将sd_fifo_rdata_tp给到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]};

always @(*) begin
    data_for_send = 32'b0;
    if (in_current_state == `DATA_STATE_SEND)
        data_for_send = sd_fifo_rdata_tp;
end

6.计算crc16

  • 在发送状态的时候,一遍发一边在算
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

7.fifo读使能

  • 分为1线和4线的情况
  • 数据发完的时候给出fifo的读使能,表明这一次发完了,需要读下一次的数据
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

8.crc16的状态

  • crc16的状态为3bit数,由crc_status_reg 决定,010表示正常
always @(*) begin
    out_crc_status_wrong =1'b0;
    if((in_current_state == `DATA_STATE_SEND_BUSY) && !(crc_status_reg == 4'b0010))
        out_crc_status_wrong =1'b1;
end

原网站

版权声明
本文为[捌肆幺幺]所创,转载请带上原文链接,感谢
https://blog.csdn.net/qq_38502780/article/details/125631063