МАРСОХОД

Open Source Hardware Project

Модуль приемника USB

//
//simplest low speed USB receive function
//

module ls_usb_recv(
    input wire reset,
    
    //clock should be 5Mhz
    input wire clk,

    //usb BUS signals
    input wire dp,
    input wire dm,
    input wire enable,

    output wire EOP,

    //output received bytes interface
    output reg [7:0]rdata,
    output reg rdata_ready,
    output reg [3:0]rbyte_cnt,
    output wire usb_reset
    );

//fix current USB line values
reg [1:0]dp_input;
reg [1:0]dm_input;

always @(posedge clk)
begin
    dp_input <= { dp_input[0], dp };
    dm_input <= { dm_input[0], dm };
end

//if both lines in ZERO this is low speed EOP
//EOP reinitializes receiver
assign EOP  = !(dp_input[0] | dp_input[1] | dm_input[0] | dm_input[1]);
reg [3:0]eop_cnt;
assign usb_reset = (eop_cnt==4'hF);
always @(posedge clk)
begin
    if(~EOP)
        eop_cnt <= 4'h0;
    else
    if( !usb_reset && strobe)
        eop_cnt <= eop_cnt + 1'b1;
end

//change on DP line defines strobing
wire dp_change; assign dp_change = dp_input[0] ^ dp_input[1];

//generate clocks with this counter
reg [5:0]clk_counter;
reg strobe;

//make strobe impulse
always @(posedge clk)
begin        
        //every edge on line resynchronizes receiver clock
        if(dp_change)
        begin
            clk_counter <= 0;
            strobe <= 1'b1;
        end
        else
            { strobe , clk_counter } <= clk_counter + 6'h13;
end

//next bit received is ONE if no signal change or ZERO if signal changed
wire next_bit; assign next_bit = (last_fixed_dp == dp_input[1]);

//calc number of sequental ONEs in received bit stream
reg [2:0]num_ones;
always @(posedge clk)
begin
    if(strobe & receiver_enabled)
    begin
        if(next_bit)
            num_ones <= num_ones + 1'b1;
        else
            num_ones <= 0;
    end
end

//flag which mean that zero should be removed from bit stream
wire do_remove_zero; assign do_remove_zero = (num_ones==6);

reg [2:0]receiver_cnt;
reg last_fixed_dp;
reg receiver_enabled;

//enable receiver on raising edge of DP line
always @(posedge clk or posedge EOP )
begin
    if(EOP)
        receiver_enabled <= 1'b0;
    else
    if( dp_input[0] )
        receiver_enabled <= 1'b1 & enable;
end

//receiver process
always @(posedge clk or posedge EOP )
begin
    if(EOP)
    begin
        //kind of reset
        receiver_cnt <= 0;
        rbyte_cnt <= 0;
        last_fixed_dp <= 1'b0;
        rdata <= 0;
        rdata_ready <= 1'b0;
    end
    else
    begin
        if(strobe & receiver_enabled & (!do_remove_zero))
        begin
            //decode NRZI
            //shift-in ONE  if older and new values are same
            //shift-in ZERO if older and new values are different
            //BUT (bitstuffling) do not shift-in one ZERO after 6 ONEs
            rdata  <= { next_bit, rdata[7:1] };
            receiver_cnt <= receiver_cnt + 1'b1;    
        end

        //set write-enable signal (write into receiver buffer)
        rdata_ready <= (receiver_cnt == 7) & (strobe & receiver_enabled & (!do_remove_zero));
        
        //remember last fixed DP,
        if(strobe & receiver_enabled)
            last_fixed_dp <= dp_input[1];

        //count nomber of received bytes
        if(rdata_ready)
            rbyte_cnt <= rbyte_cnt + 1'b1;
    end
end

endmodule

facebook  GitHub  YouTube  Twitter
Вы здесь: Начало Проекты Примеры программ Модуль приемника USB