[讨论] FPGA初步之PS2接口(发送和接收,附图)

DSP16   2009-12-23 10:44 楼主
关于PS2接口,前面已经给出接收模块,对于发送模块,小鱼整了好长时间,前前后后大概有两个多星期了,期间小鱼犯过一个很严重的问题,PS2是半双工通信,小鱼硬是把它拆成了发送和接收两个模块,结果在调试的时候造成了总线冲突,得不到正确的结果,这一点需要注意,其实发送和接收是不能拆分的。同时小鱼也意识到另一个问题,以前小鱼只是机械的把代码贴上去,加了一点简单的注释,这对于看的人造成了极大的困难,从这一节开始,小鱼也会把编写的思路一并写上。
关于PS2接口模块,主要还要通过状态机来实现的。
首先对ps2_clk,ps2_data信号进行滤波。
状态转移图如下,由两张图拼接而成,上面那幅图是接收,下面那幅图是发送,最后回到初态的线没显示出来,不过这不妨碍大家看,
这个状态转移图也代表了小鱼的思路:

回复评论 (1)

1[1][1].JPG.thumb.jpg
CODE:
`timescale 1ns / 1ps

module ps2_interface(rst_n,clk50M,m1_ps2_clk,m1_ps2_data,m2_ps2_clk,m2_ps2_data,
                     ps2_tx_start,ps2_tx_data,ps2_rx_ready,ps2_rx_data,
                                                        ps2_busy,ps2_error);
input rst_n,clk50M;
input m1_ps2_clk,m1_ps2_data; //input of ps2_clk and ps2_data
output reg m2_ps2_clk,m2_ps2_data; //control the output of ps2_clk and ps2_data

input ps2_tx_start;
input[7:0] ps2_tx_data;

output reg ps2_rx_ready;
output[7:0] ps2_rx_data;
reg[7:0] ps2_rx_data;

output ps2_busy,ps2_error;
reg ps2_error;

//parameter define
parameter[3:0] DEBOUNCE_DELAY=4'hf; //delay for debouncing
parameter[3:0] TOTAL_BIT=4'd11; //total bits in a frame
//values are valid for a 50MHz clk,please adjust for other frequence if necessary
//20ns*5000=100us
parameter[15:0] DELAY_100US=16'd5000;
//20ns*1000=20us
parameter[15:0] DELAY_20US=16'd1000;
//delay 63clk
parameter[5:0] DELAY_63CLK=6'd63;

//state machine
parameter[4:0] idle=5'h0;
parameter[4:0] rx_clk_h=5'h1;
parameter[4:0] rx_falling_edge=5'h2; //ps2_clk falling edge
parameter[4:0] rx_clk_l=5'h3;
parameter[4:0] rx_error_parity=5'h4;
parameter[4:0] rx_ready=5'h5;
parameter[4:0] tx_force_clk_l=5'h6;
parameter[4:0] tx_bring_data_down=5'h7;
parameter[4:0] tx_release_clk=5'h8;
parameter[4:0] tx_first_wait_falling_edge=5'h9;
parameter[4:0] tx_falling_edge=5'ha;
parameter[4:0] tx_clk_l=5'hb;
parameter[4:0] tx_clk_h=5'hc;
parameter[4:0] tx_rising_edge_before_ack=5'hd;
parameter[4:0] tx_wait_ack=5'he;
parameter[4:0] tx_receive_ack=5'hf;
parameter[4:0] tx_error_no_ack=5'h10;

//intermediary signal, will be used in debouncing
reg[3:0] ps2_clk_cnt,ps2_data_cnt;
reg ps2_clk_inter,ps2_data_inter;
reg ps2_clk_syn,ps2_data_syn;

always@(negedge rst_n,posedge clk50M)
begin
        if(!rst_n)
        begin
                ps2_clk_cnt<=4'h0;
                ps2_clk_inter<=1'b0;
        end
        else
        begin
                if(ps2_clk_inter!=m1_ps2_clk)
                begin
                        ps2_clk_cnt<=4'h0;
                        ps2_clk_inter<=m1_ps2_clk;
                end
                else
                begin
                        if(ps2_clk_cnt==DEBOUNCE_DELAY)
                        begin
                                ps2_clk_syn<=ps2_clk_inter;
                        end
                        else
                        begin
                                ps2_clk_cnt<=ps2_clk_cnt+1'b1;
                        end
                end
        end
end

always@(negedge rst_n,posedge clk50M)
begin
        if(!rst_n)
        begin
                ps2_data_cnt<=4'h0;
                ps2_data_inter<=1'b0;
        end
        else
        begin
                if(ps2_data_inter!=m1_ps2_data)
                begin
                        ps2_data_cnt<=4'h0;
                        ps2_data_inter<=m1_ps2_data;
                end
                else
                begin
                        if(ps2_data_cnt==DEBOUNCE_DELAY)
                        begin
                                ps2_data_syn<=ps2_data_inter;
                        end
                        else
                        begin
                                ps2_data_cnt<=ps2_data_cnt+1'b1;
                        end
                end
        end
end

//state define
reg[4:0] cur_state,next_state;

//16 bits counter,used to wait 100us
reg[15:0] delay_100us_cnt;
//done signal for the counter
reg delay_100us_done;
wire delay_100us_enable;

assign delay_100us_enable=(next_state==tx_force_clk_l) ? 1'b1 : 1'b0;

always@(negedge rst_n,posedge clk50M)
begin
        if(!rst_n)
        begin
                delay_100us_cnt<=16'h0;
                delay_100us_done<=1'b0;
        end
        else
        begin
                if(delay_100us_enable==1'b1)
                begin
                        if(delay_100us_cnt==DELAY_100US)
                        begin
                                delay_100us_cnt<=delay_100us_cnt;
                                delay_100us_done<=1'b1;
                        end
                        else
                        begin
                                delay_100us_cnt<=delay_100us_cnt+1'b1;
                                delay_100us_done<=1'b0;
                        end
                end
                else
                begin
                        delay_100us_cnt<=16'h0;
                        delay_100us_done<=1'b0;
                end
        end
end

//16 bits counter,used to wait 20us
reg[15:0] delay_20us_cnt;
//done signal for the counter
reg delay_20us_done;
wire delay_20us_enable;

assign delay_20us_enable=(next_state==tx_bring_data_down) ? 1'b1 : 1'b0;

always@(negedge rst_n,posedge clk50M)
begin
        if(!rst_n)
        begin
                delay_20us_cnt<=16'h0;
                delay_20us_done<=1'b0;
        end
        else
        begin
                if(delay_20us_enable==1'b1)
                begin
                        if(delay_20us_cnt==DELAY_20US)
                        begin
                                delay_20us_cnt<=delay_20us_cnt;
                                delay_20us_done<=1'b1;
                        end
                        else
                        begin
                                delay_20us_cnt<=delay_20us_cnt+1'b1;
                                delay_20us_done<=1'b0;
                        end
                end
                else
                begin
                        delay_20us_cnt<=16'h0;
                        delay_20us_done<=1'b0;
                end
        end
end

//6 bits couner,useed to wait 63 clk periods
reg[5:0] delay_63clk_cnt;
//done signal for the counter
reg delay_63clk_done;
wire delay_63clk_enable;

assign delay_63clk_enable=(next_state==tx_first_wait_falling_edge) ? 1'b1 : 1'b0;

always@(negedge rst_n,posedge clk50M)
begin
        if(!rst_n)
        begin
                delay_63clk_cnt<=6'h0;
                delay_63clk_done<=1'b0;
        end
        else
        begin
                if(delay_63clk_enable==1'b1)
                begin
                        if(delay_63clk_cnt==DELAY_63CLK)
                        begin
                                delay_63clk_cnt<=delay_63clk_cnt;
                                delay_63clk_done<=1'b1;
                        end
                        else
                        begin
                                delay_63clk_cnt<=delay_63clk_cnt+1'b1;
                                delay_63clk_done<=1'b0;
                        end
                end
                else
                begin
                        delay_63clk_cnt<=6'h0;
                        delay_63clk_done<=1'b0;
                end
        end
end

//state transition,three paragraph
reg rst_bit_cnt;
reg[10:0] data_frame;
reg[3:0] bit_cnt; //how many bits have been received or transmitted
reg bit_parity; //parity bit
reg load_rx_data; //load data what have been received
reg load_tx_data; //if this signal is 1'b1,load data which will be transmitted
reg load_error_flag;
reg shift_rx_frame;
reg shift_tx_frame;

assign ps2_busy=(next_state==idle) ? 1'b0 : 1'b1;

always@(negedge rst_n,posedge clk50M)
begin
        if(!rst_n)
        begin
                cur_state<=idle;
        end
        else
        begin
                cur_state<=next_state;
        end
end

always@(cur_state,ps2_clk_syn,ps2_data_syn,bit_cnt,bit_parity,
        delay_100us_done,delay_20us_done,delay_63clk_done,ps2_tx_start)
begin
        rst_bit_cnt<=1'b0;
        load_rx_data<=1'b0;
        load_tx_data<=1'b0;
        load_error_flag<=1'b0;
        shift_rx_frame<=1'b0;
        shift_tx_frame<=1'b0;
        next_state<=idle;
        
        case(cur_state)
                idle:
                begin
                        if(!ps2_clk_syn)
                        begin
                                shift_rx_frame<=1'b1;
                                next_state<=rx_falling_edge;
                        end
                        else if(ps2_tx_start==1'b1)
                        begin
                                next_state<=tx_force_clk_l;
                                load_tx_data<=1'b1;
                        end
                        else
                        begin
                                rst_bit_cnt<=1'b1;
                                next_state<=idle;
                        end
                end
               
                rx_clk_h:
                begin
                        if(!ps2_clk_syn)
                        begin
                                shift_rx_frame<=1'b1;
                                next_state<=rx_falling_edge;
                        end
                        else
                                next_state<=rx_clk_h;
                end
               
                rx_falling_edge:
                begin
                        next_state<=rx_clk_l;
                end
               
                rx_clk_l:
                begin
                        if(bit_cnt==TOTAL_BIT)
                        begin
                                if(bit_parity)
                                begin
                                        next_state<=rx_ready;
                                        load_rx_data<=1'b1;
                                end
                                else
                                begin
                                        load_error_flag<=1'b1;
                                        next_state<=rx_error_parity;
                                end
                        end
                        else if(ps2_clk_syn)
                        begin
                                next_state<=rx_clk_h;
                        end
                        else
                                next_state<=rx_clk_l;
                end
               
                rx_ready:
                begin
                        if((ps2_clk_syn==1'b1) && (ps2_data_syn==1'b1))
                        begin
                                rst_bit_cnt<=1'b1;
                                next_state<=idle;
                        end
                        else
                        begin
                                next_state<=rx_ready;
                        end
                end
               
                rx_error_parity:
                begin
                        if((ps2_clk_syn==1'b1) && (ps2_data_syn==1'b1))
                        begin
                                rst_bit_cnt<=1'b1;
                                next_state<=idle;
                        end
                        else
                        begin
                                next_state<=rx_error_parity;
                        end
                end
               
                tx_force_clk_l:
                begin
                        if(delay_100us_done==1'b1)
                        begin
                                next_state<=tx_bring_data_down;
                        end
                        else
                        begin
                                next_state<=tx_force_clk_l;
                        end
                end
               
                tx_bring_data_down:
                begin
                        if(delay_20us_done==1'b1)
                        begin
                                next_state<=tx_release_clk;
                        end
                        else
                        begin
                                next_state<=tx_bring_data_down;
                        end
                end
               
                tx_release_clk:
                begin
                        next_state<=tx_first_wait_falling_edge;
                end
               
                tx_first_wait_falling_edge:
                begin
                        if(delay_63clk_done==1'b1)
                        begin
                                if(ps2_clk_syn==1'b0)
                                begin
                                        shift_tx_frame<=1'b1;
                                        next_state<=tx_falling_edge;
                                end
                                else
                                begin
                                        next_state<=tx_first_wait_falling_edge;
                                end
                        end
                        else
                        begin
                                next_state<=tx_first_wait_falling_edge;
                        end
                end
               
                tx_falling_edge:
                begin
                        next_state<=tx_clk_l;
                end
               
                tx_clk_l:
                begin
                        if(bit_cnt==(TOTAL_BIT-1))
                        begin
                                next_state<=tx_rising_edge_before_ack;
                        end
                        else if(ps2_clk_syn==1'b1)
                        begin
                                next_state<=tx_clk_h;
                        end
                        else
                        begin
                                next_state<=tx_clk_l;
                        end
                end
               
                tx_clk_h:
                begin
                        if(ps2_clk_syn==1'b0)
                        begin
                                shift_tx_frame<=1'b1;
                                next_state<=tx_falling_edge;
                        end
                        else
                        begin
                                next_state<=tx_clk_h;
                        end
                end
               
                tx_rising_edge_before_ack:
                begin
                        if(ps2_clk_syn==1'b1)
                        begin
                                next_state<=tx_wait_ack;
                        end
                        else
                        begin
                                next_state<=tx_rising_edge_before_ack;
                        end
                end
               
                tx_wait_ack:
                begin
                        if(ps2_clk_syn==1'b0)
                        begin
                                if(ps2_data_syn==1'b0)
                                begin
                                        next_state<=tx_receive_ack;
                                end
                                else
                                begin
                                        load_error_flag<=1'b1;
                                        next_state<=tx_error_no_ack;
                                end
                        end
                        else
                        begin
                                next_state<=tx_wait_ack;
                        end
                end
               
                tx_receive_ack:
                begin
                        if((ps2_clk_syn==1'b1) && (ps2_data_syn==1'b1))
                        begin
                                rst_bit_cnt<=1'b1;
                                next_state<=idle;
                        end
                        else
                        begin
                                next_state<=tx_receive_ack;
                        end
                end
               
                tx_error_no_ack:
                begin
                        if((ps2_clk_syn==1'b1) && (ps2_data_syn==1'b1))
                        begin
                                rst_bit_cnt<=1'b1;
                                next_state<=idle;
                        end
                        else
                        begin
                                next_state<=tx_error_no_ack;
                        end
                end
               
                default:
                begin
                        if((ps2_clk_syn==1'b1) && (ps2_data_syn==1'b1))
                        begin
                                rst_bit_cnt<=1'b1;
                                next_state<=idle;
                        end
                        else
                        begin
                                next_state<=next_state;
                        end
                end
        endcase
end

always@(negedge rst_n,posedge clk50M)
begin
        if(!rst_n)
        begin
                m2_ps2_clk<=1'b1;
                m2_ps2_data<=1'b1;
        end
        else
        begin
                case(next_state)
                        tx_force_clk_l:
                        begin
                                m2_ps2_clk<=1'b0;
                                m2_ps2_data<=1'b1;
                        end
                        
                        tx_bring_data_down:
                        begin
                                m2_ps2_clk<=1'b0;
                                m2_ps2_data<=1'b0;
                        end
                        
                        tx_release_clk:
                        begin
                                m2_ps2_clk<=1'b1;
                                m2_ps2_data<=1'b0;
                        end
                        
                        tx_first_wait_falling_edge:
                        begin
                                m2_ps2_clk<=1'b1;
                                m2_ps2_data<=1'b0;
                        end
                        
                        tx_falling_edge:
                        begin
                                m2_ps2_clk<=1'b1;
                                m2_ps2_data<=1'b1;
                        end
                        
                        tx_clk_l:
                        begin
                                m2_ps2_clk<=1'b1;
                                m2_ps2_data<=data_frame[0];
                        end
                        
                        tx_clk_h:
                        begin
                                m2_ps2_clk<=1'b1;
                                m2_ps2_data<=data_frame[0];
                        end
                        
                        tx_rising_edge_before_ack:
                        begin
                                m2_ps2_clk<=1'b1;
                                m2_ps2_data<=data_frame[0];
                        end
                        
                        default:
                        begin
                                m2_ps2_clk<=1'b1;
                                m2_ps2_data<=1'b1;
                        end
                endcase
        end
end

always@(negedge rst_n,posedge clk50M)
begin
        if(!rst_n)
        begin
                bit_cnt<=4'h0;
                data_frame<=11'h0;
                bit_parity<=1'b0;
        end
        else
        begin
                if(rst_bit_cnt==1'b1)
                begin
                        bit_cnt<=4'h0;
                        data_frame<=11'h0;
                        bit_parity<=1'b0;
                end
               
                if(shift_rx_frame==1'b1)
                begin
                        data_frame<={ps2_data_syn,data_frame[10:1]};
                        bit_cnt<=bit_cnt+1'b1;
                        
                        if(bit_cnt>4'd0 && bit_cnt<4'd10)
                                bit_parity<=bit_parity ^ ps2_data_syn;
                end
               
                if(load_tx_data==1'b1)
                begin
                        data_frame[0]<=1'b0;
                        data_frame[8:1]<=ps2_tx_data;
                        data_frame[9]<=~^ps2_tx_data;
                        data_frame[10]<=1'b1;
                end
               
                if(shift_tx_frame==1'b1)
                begin
                        data_frame[9:0]<=data_frame[10:1];
                        bit_cnt<=bit_cnt+1'b1;
                end
        end
end

always@(negedge rst_n,posedge clk50M)
begin
        if(!rst_n)
        begin
                ps2_rx_data<=8'd0;
                ps2_rx_ready<=1'b0;
        end
        else
        begin
                if(load_rx_data)
                begin
                        ps2_rx_data<=data_frame[8:1];
                        ps2_rx_ready<=1'b1;
                end
                else
                begin
                        ps2_rx_ready<=1'b0;
                end
        end
end

always@(negedge rst_n,posedge clk50M)
begin
        if(!rst_n)
        begin
                ps2_error<=1'b0;
        end
        else
        begin
                if(load_error_flag==1'b1)
                        ps2_error<=1'b1;
                else
                        ps2_error<=1'b0;
        end
end

endmodule
点赞  2009-12-23 10:46
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复