本文移植於tutortecho 2019年5月15日文章
因為網路上都沒有一個真正可以動的 ps2 uart 接收鍵盤按鍵的 verilog 程式
找到後來我乾脆自己寫了一個
ps2的接頭有自己的clock rate
所以不用管 uart 通訊的 baud rate 是多少
由於 ps2_clk 的速度非常慢
所以接收 uart 的 code 不應該用高速的 system clock 來做
應該使用 ps2_clk來接收資料即可
至於接收到的資料要讓高速 clock 使用就必須使用 clock domain crossing
CDC的方式就不在這篇提了 我以前好像有寫過
module ps2_keyboard_listener (
input rst_n,
input ps2_clk,
input ps2_data,
output reg [2:0] kb_enter,
output reg[7:0] ps2_byte_r,
output reg ps2_vld
);
reg[7:0] byte_tmp;
wire [7:0] rx_data;
wire data_vld;
rx urx (
.clk(ps2_clk),
.reset_n(rst_n),
.din(ps2_data),
.data(rx_data),
.data_vld(data_vld),
.parity_error(),
.protocal_error()
);
always @(posedge ps2_clk or negedge rst_n) begin
if(~rst_n) begin
byte_tmp <= 0;
end else if (data_vld) begin
byte_tmp <= rx_data;
end
end
wire kb_vld = (rx_data == 8'hf0) & data_vld;
always @(posedge ps2_clk or negedge rst_n) begin
if(~rst_n) begin
ps2_byte_r <= 0;
end else if (kb_vld) begin
ps2_byte_r <= byte_tmp;
end
end
always @(posedge ps2_clk or negedge rst_n) begin
if(~rst_n) begin
ps2_vld <= 0;
end else if (ps2_vld) begin
ps2_vld <= 0;
end else if (kb_vld) begin
ps2_vld <= 1'b1;
end
end
parameter A = 3'b001;
parameter B = 3'b010;
parameter C = 3'b011;
parameter D = 3'b100;
parameter E = 3'b101;
parameter F = 3'b110;
always@(ps2_byte_r)
begin
case( ps2_byte_r)
8'h1c://a
kb_enter = A;
8'h32://b
kb_enter = B;
8'h21://c
kb_enter = C;
8'h23://d
kb_enter = D;
8'h24://e
kb_enter = E;
8'h2b://f
kb_enter = F;
default:
kb_enter = 3'b000;
endcase
end
endmodule
module rx(
input clk,
input reset_n,
input din,
output reg [7:0]data,
output data_vld,
output reg parity_error,
output reg protocal_error
);
reg [3:0]count;
wire [3:0] count_nx;
wire start;
wire parity;
wire stop;
wire [7:0]data_nx;
wire parity_error_nx;
wire protocal_error_nx;
assign start = (count == 4'd0) & (~din);
assign tras = (count > 4'd0) & (count < 4'd9);
assign parity = count == 4'd9;
assign stop = count == 4'd10;
assign count_nx = (start) ? 4'd1 :
(tras | parity) ? (count + 4'd1) :
(stop) ? 4'd0 : count;
assign data_nx = (tras) ? {din, data[7:1]}: data;
assign parity_error_nx = (parity) ? ^data: 1'd0;
assign protocal_error_nx = (stop & (~din));
always @(posedge clk or negedge reset_n) begin
if(~reset_n) begin
data <= 8'd0;
count <= 4'd0;
end else begin
data <= data_nx;
count <= count_nx;
end
end
always @(posedge clk or negedge reset_n) begin
if(~reset_n) begin
parity_error <= 1'd0;
end else if(~parity_error) begin
parity_error <= parity_error_nx;
end
end
always @(posedge clk or negedge reset_n) begin
if(~reset_n) begin
protocal_error <= 1'd0;
end else if(~protocal_error) begin
protocal_error <= protocal_error_nx;
end
end
assign data_vld = count == 4'd9;
endmodule : rx
發表留言