《Xilinx FPGA设计与实践教程》课件-第10章_第1页
《Xilinx FPGA设计与实践教程》课件-第10章_第2页
《Xilinx FPGA设计与实践教程》课件-第10章_第3页
《Xilinx FPGA设计与实践教程》课件-第10章_第4页
《Xilinx FPGA设计与实践教程》课件-第10章_第5页
已阅读5页,还剩49页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第十章PS/2鼠标接口控制器

10.1PS/2鼠标接口电路10.2PS/2传输子系统设计10.3PS/2鼠标数据传输系统10.4PS/2鼠标数据接口电路本章小结 10.1PS/2鼠标接口电路

10.1.1关于鼠标

计算机上的鼠标是用来检测在平面二维空间中的移动状态和坐标的。其内部电路用来测量移动的相对距离以及按键状态。对于PS/2接口的鼠标,鼠标的传输信息打包成三个数据包通过PS/2口发送出去;在传输过程中,数据以串行方式发送并且按照预先设定的采样率持续传输。

PS/2端口的通信是双向的。主设备可以发送命令参数给键盘和鼠标。对于键盘来说,不需要主设备向键盘发送参数,因为这样会对键盘提出更高的要求。而鼠标不一样,上电之后不发送任何信息给主设备,反而主设备需要首先发送命令初始化鼠标,使鼠标处于连续发送信息状态。所以PS/2鼠标接口是需要支持双向通信接口的。下面介绍PS/2的鼠标接口协议,并设计一个简单的双向鼠标数据传输接口电路。10.1.2鼠标PS/2通信协议

标准的PS/2鼠标接口数据不仅反映鼠标在X轴和Y轴的移动情况,而且还包括鼠标左键、中键、右键的状态信息。鼠标电路包含一个内部计数器,其用来计算鼠标的每次移动量。当数据传输给主机时,计数器清零后重新开始计数。该计数器的值为一个9bit宽的带符号整数,其正值代表向右或向上运动,其负值代表向左或向下运动。计数器与实际物理距离之间的关系由鼠标特性参数来决定。默认为每计数4次代表1mm。当鼠标持续移动时,数据以固定速率传输,这个速率由鼠标采样率决定。默认采样率为100次每秒。如果鼠标移动速率过快,采样期间移动量计数值则有可能超过计数器的最大值。计数器在适当的方向设置有最大幅度,并用两位溢出位来指示这种情况。

反映鼠标的移动及点击活动需要三个字节,它们被封装在PS/2协议中。3个字节数据的具体格式以及含义如表10-1所示。包含有如下的信息:

(1) X8,…,X0:在2秒完全模式下的X轴移动量;

(2) Xv:X轴移动溢出;

(3) Y8,…,Y0:在2秒完全模式下的Y轴移动量;

(4) Yv;Y轴溢出;

(5) l:左键状态,当左键按下时为1;

(6) r:右键状态,当右键按下时为1;

(7) m:可选择中键,当键按下时为1。

传输过程中,字节1首先被发送,字节3最后被发送。10.1.3初始化过程

鼠标的操作相对于键盘的操作要复杂的多。它有各种不同的模式,通常用的最多的是串行流模式,即鼠标检测有移动或者有键按下时,不断将数据发送给主机,如果运动是持续的,数据按照设计的采样率发送。

操作过程中,主机可以给鼠标发送命令,修改默认值或其他参数,来设置不同的操作模式,然后鼠标发送状态信号进行响应。在设计中要求所有设置为默认值,不做变化,唯一任务是设置鼠标为持续数据流模式。这时PS/2和FPGA开发板之间的初始化步骤如下:

(1)上电时鼠标首先进行上电自检,如果鼠标发送一个字节AA,则表示自检通过;然后发送一个字节数据00,为标准鼠标的ID号。

(2) FPGA主机端发送命令F4,使能数据流模式,鼠标返回FE来响应命令。

(3)鼠标进入数据流模式,然后发送正常的数据包。

如果在FPGA板上电之前鼠标已经插在了FPGA验证板上,则当板子上电时,鼠标立即发送“AA00”,由于FPGA芯片当时还没有被配置,那么将不能接收到鼠标发送的数据。所以通常会忽略上述步骤(1),将鼠标接口时序电路做简化,仅需要发送F4命令来检测鼠标FE响应,然后直接进入正常工作状态来传输鼠标数据包。也可以通过发送复位命令来强制鼠标返回到初始状态。

(1) FPGA主机端发送命令FE复位鼠标,鼠标将返回FE来响应。

(2)鼠标执行上电自测,然后发送“AA00”,在这个过程中,数据流模式将被禁止。

新型鼠标增加了很多功能,比如鼠标带有滚轮或者另外增加新的按钮,这样就需要发送更多的信息,这些多出来的字节将和原始的三字节数据打包一起发送。

10.2PS/2传输子系统设计

10.2.1主系统对PS/2设备的通信协议

主系统对PS/2设备的通信协议包含双向数据交换。鼠标数据和时钟为开漏极电路,可以认为它们为三态门。基本时序传输协议如图10-1所示,其中,数据和时钟信号线标为ps2d和ps2c。可以清楚地发现,时序图被分成两部分,一部分反映主系统(host)的活动,而另一部分反映设备(mouse)的活动。基本操作时序如下:

(1)主设备强行置低ps2c至少100μs来禁止任何鼠标活动,可以认为是主系统请求发送数据包。

(2)主设备强行置低ps2d,禁止ps2c,可以认为是主机发送一个开始信号。

(3)此时PS/2从设备开始控制ps2c,负责PS/2时钟信号的产生;当检测到开始信号时,PS/2设备产生1到0的信号传输。

(4)一旦检测到传输开始,主系统串行移位最低位数据在ps2d线上,并一直保持原值直到PS/2设备在ps2c线上产生1到0的跳变,也称数据响应位。

(5)重复步骤(4),直到剩余的7位数据和1位奇偶校校验位发送结束。

(6)发送完奇偶校验位之后,主机禁止ps2d(设为高阻态),PS/2从设备接管ps2d数据线并通过置ps2d为0来响应传输完成。根据需要,主设备可以通过在ps2c从1到0跳变时刻检查ps2d上面的值来验证是否成功传输。图10-1PS/2接口主从设备之间的时序图10.2.2设计与编码

与前面讲述的接收子系统不同之处在于ps2c与ps2d信号为双向传输。每个信号都需要三态缓冲器,三态缓冲器的接口如图10-2所示。tri_c与tri_d信号为三态缓冲器的使能信号,当置为1时,ps2c_out与ps2d_out信号传输到输出端口,否则ps2c_out与ps2d_out信号为高阻状态。图10-2PS/2传输子系统三态缓冲器 为了更加明确设计传输子系统的流程,根据鼠标数据传输控制协议来画出ASMD状态图,如图10-3所示。状态机起始状态为空状态(idle状态)。当主机置位wr_ps2信号并将数据放在din上时,状态机启动并装载din信号和校验位par,并一同送到移位寄存器shift_reg中,然后置c_reg寄存器为全1,c_reg寄存器由一个13位计数器组成,用来产生164μs的延迟。紧接着状态机进入请求发送状态(rts状态)。在rts状态,状态机置位ps2c_out为0,并将相对应三态缓冲器的使能位tri_c置位,判断c_reg还没有清零,状态机进入开始状态(start状态)。这时,ps2时钟信号被禁止,数据线被置为0,PS/2设备接管并生成时钟信号在ps2c信号线上。当通过fall_edge信号检测到ps2c信号下降沿时,状态机进入数据传输状态(data状态),开始移位8位数据和1位检验位,而寄存器n用来保持追踪移位数目。当寄存器n为0,即数据移位传输结束时,状态机进入停止位(stopstate);此时,数据线被停止,当检测到最后一个下降沿时返回到idle状态。另外,状态机还包含tx_idle信号来指示传输是否正在进行,此信号可以被用来作为与发送和接收接口模块的状态指示信号,具体细节如程序10-1所示。fall_edge信号也是通过与前面所述的滤波电路产生的。图10-3PS/2发送子系统FSM流程图

【程序10-1】PS/2发送子系统。

moduleps2_tx

(

input

wireclk,reset,

input

wirewr_ps2,

input

wire[7:0]din,

inout

wireps2d,ps2c,

output

regtx_idle,tx_done_tick

);

//状态机状态信号定义

localparam[2:0]

idle=3'b000,

rts=3'b001,

start  =3'b010,

data=3'b011,

stop=3'b100;

//信号声明

reg[2:0]state_reg,state_next;

reg[7:0]filter_reg;

wire[7:0]filter_next;

regf_ps2c_reg;

wiref_ps2c_next;

reg[3:0]n_reg,n_next;

reg[8:0]b_reg,b_next;

reg[12:0]c_reg,c_next;

wirepar,fall_edge;

regps2c_out,ps2d_out;

regtri_c,tri_d;

//=================================================

//滤波和ps2c的下降沿检测电路

//=================================================

always@(posedgeclk,posedgereset)

if(reset)

begin

filter_reg<=0;

f_ps2c_reg<=0;

end

else

begin

filter_reg<=filter_next;

f_ps2c_reg<=f_ps2c_next;

end

assignfilter_next={ps2c,filter_reg[7:1]};

assignf_ps2c_next=(filter_reg==8'b11111111)?1'b1:

(filter_reg==8'b00000000)?1'b0:

f_ps2c_reg;

assignfall_edge=f_ps2c_reg&~f_ps2c_next;

//=============================================

//FSMD

//=============================================

//FSMD状态和数据寄存器

always@(posedgeclk,posedgereset)

if(reset)

begin

state_reg<=idle;

c_reg<=0;

n_reg<=0;

b_reg<=0;

end

else

begin

state_reg<=state_next;

c_reg<=c_next;

n_reg<=n_next;

b_reg<=b_next;

end

//偶校验位

assignpar=~(^din);

//FSMD下一状态逻辑

always@*

begin

state_next=state_reg;

c_next=c_reg;

n_next=n_reg;

b_next=b_reg;

tx_done_tick=1'b0;

ps2c_out=1'b1;

ps2d_out=1'b1;

tri_c=1'b0;

tri_d=1'b0;

tx_idle=1'b0;

case(state_reg)

idle:

begin

tx_idle=1'b1;

if(wr_ps2)

begin

b_next={par,din};

c_next=13'h1fff; //213-1

state_next=rts;

end

end

rts: //发送请求

begin

ps2c_out=1'b0;

tri_c=1'b1;

c_next=c_reg-1;

if(c_reg==0)

state_next=start;

end

start: //置位start

begin

ps2d_out=1'b0;

tri_d=1'b1;

if(fall_edge)

begin

n_next=4'h8;

state_next=data;

end

end

data: //8位数据+1位校验

begin

ps2d_out=b_reg[0];

tri_d=1'b1;

if(fall_edge)

begin

b_next={1'b0,b_reg[8:1]};

if(n_reg==0)

state_next=stop;

else

n_next=n_reg-1;

end

end

stop://ps2d置位为高

if(fall_edge)

begin

state_next=idle;

tx_done_tick=1'b1;

end

endcase

end

//三态缓冲器

assignps2c=(tri_c)?ps2c_out:1'bz;

assignps2d=(tri_d)?ps2d_out:1'bz;

endmodule

本代码中没有错误检查电路。更健壮的设计要求检查校验位的正确性,并且包含一个看门狗计数器来防止鼠标在错误的状态下抖动。

10.3PS/2鼠标数据传输系统

10.3.1双向传输PS/2接口电路设计

综合接收和发送系统来设计双向传输PS/2接口电路。图10-4为设计模块框图,用tx_idle和rx_en作为状态信号来调整传输和接收操作。传输操作优先级略高,当系统正在进行传输时,tx_idle信号无效;否则,禁止接收操作。接收系统只有在传输系统为空的情况下才允许输入,两者轮流工作,具体细节如程序10-2所示。图10-4双向PS/2接口的顶层模块图

【程序10-2】双向传播PS/2接口电路。

moduleps2_rxtx

(

input

wireclk,reset,

input

wirewr_ps2,

inout

wireps2d,ps2c,

input

wire[7:0]din,

output

wirerx_done_tick,tx_done_tick,

output

wire[7:0]dout

);

//信号声明

wiretx_idle;

//例化PS/2接收器

ps2_rxps2_rx_unit

(.clk(clk),.reset(reset),.rx_en(tx_idle),

.ps2d(ps2d),.ps2c(ps2c),

.rx_done_tick(rx_done_tick),.dout(dout));

//例化PS/2发送器

ps2_txps2_tx_unit

(.clk(clk),.reset(reset),.wr_ps2(wr_ps2),

.din(din),.ps2d(ps2d),.ps2c(ps2c),

.tx_idle(tx_idle),.tx_done_tick(tx_done_tick));

endmodule10.3.2双向传输PS/2验证电路

设计一个测试电路来验证双向传输PS/2接口电路,整体框图如10-5所示。人工发送传输命令,用8位拨码开关设置数据,然后用按键产生一个时钟脉宽的脉冲来发送数据包,接收数据包首先需要通过byte-to-ascii电路,将数据转接成ASCII码外加空格的形式,然后用UART发送到PC的超级终端上。具体细节如程序10-3所示。图10-5PS/2双向接口验证电路【程序10-3】双向传输PS/2验证电路。

moduleps2_monitor

(

input

wireclk,reset,

input

wire[7:0]sw,

input

wire[2:0]btn,

inout

wireps2d,ps2c,

output

wiretx

);

//常数定义

localparamSP=8'h20; //spaceinASCII

//状态声明

localparam[1:0]

idle=2'b00,

send1=2'b01,

send0=2'b10,

sendb=2'b11;

//信号声明

reg[1:0]state_reg,state_next;

wire[7:0]rx_data;

reg[7:0]w_data,ascii_code;

wirepsrx_done_tick,wr_ps2;

regwr_uart;

wire[3:0]hex_in;

//==============================================

//例化

//==============================================

//例化PS/2传输接收

ps2_rxtxps2_rxtx_unit

(.clk(clk),.reset(reset),.wr_ps2(wr_ps2),

.din(sw),.dout(rx_data),.ps2d(ps2d),.ps2c(ps2c),

.rx_done_tick(psrx_done_tick),.tx_done_tick());

//例化UART发送模块

uartuart_unit

(.clk(clk),.reset(reset),.rd_uart(1'b0),

.wr_uart(wr_uart),.rx(1'b1),.w_data(w_data),

.tx_full(),.rx_empty(),.r_data(),.tx(tx));

//例化按键防反弹电路

debouncebtn_db_unit

(.clk(clk),.reset(reset),.sw(btn[0]),

.db_level(),.db_tick(wr_ps2));

//============================================

//发送ASCII字符状态机模块

//============================================

//状态寄存器

always@(posedgeclk,posedgereset)

if(reset)

state_reg<=idle;

else

state_reg<=state_next;

//下一状态逻辑

always

@*

begin

wr_uart=1'b0;

w_data=SP;

state_next=state_reg;

case(state_reg)

idle:

if(psrx_done_tick) //接收扫描码

state_next=send1;

send1: //发送十六进制字符高字节

begin

w_data=ascii_code;

wr_uart=1'b1;

state_next=send0;

end

send0: //发送十六进制字符低字节

begin

w_data=ascii_code;

wr_uart=1'b1;

state_next=sendb;

end

sendb: //发送空格字符

begin

w_data=SP;

wr_uart=1'b1;

state_next=idle;

end

endcase

end

//===========================================

//显示扫描码

//===========================================

//将扫描码分离成两个4bit十六进制数

assignhex_in=(state_reg==send1)?rx_data[7:4]:

rx_data[3:0];

//十六进制数到ASCII码转换电路

always@*

case(hex_in)

4'h0:ascii_code=8'h30;

4'h1:ascii_code=8'h31;

4'h2:ascii_code=8'h32;

4'h3:ascii_code=8'h33;

4'h4:ascii_code=8'h34;

4'h5:ascii_code=8'h35;

4'h6:ascii_code=8'h36;

4'h7:ascii_code=8'h37;

4'h8:ascii_code=8'h38;

4'h9:ascii_code=8'h39;

4'ha:ascii_code=8'h41;

4'hb:ascii_code=8'h42;

4'hc:ascii_code=8'h43;

4'hd:ascii_code=8'h44;

4'he:ascii_code=8'h45;

default:ascii_code=8'h46;

endcase

endmodule 10.4PS/2鼠标数据接口电路

10.4.1传输PS/2接口电路设计

PS/2接口电路是在PS/2双向传输电路外面再包一层电路。其主要功能是使能串行流模式和处理三个传输数据字节。电路的输出包括两个9位信号:xm和ym,分别代表鼠标在X轴和Y轴的移动信号;btm为3位按键状态信号;信号m_done_tick为一位时钟脉宽长度的状态信号,当传输数据有效时置位。

具体细节如程序10-4所示。程序主体状态机由7个状态组成。int1、int2和int3三个状态为在reset有效之后执行。在这三个状态中,状态机处理F4命令,等待数据传输后数据包开始响应,这时鼠标进入串行数据流模式。之后,状态机在pack1、pack2和pack3三个状态获取和处理下一个三字节数据包,然后在done状态激活m_done_tick信号,状态机不断循环后面四个状态。

【程序10-4】基本鼠标接口电路。

modulemouse

(

input

wireclk,reset,

inout

wireps2d,ps2c,

output

wire[8:0]xm,ym,

output

wire[2:0]btnm,

output

regm_done_tick

);

//常数声明

localparamSTRM=8'hf4; //数据流发送命令F4

//状态声明

localparam[2:0]

init1=3'b000,

init2=3'b001,

init3=3'b010,

pack1=3'b011,

pack2=3'b100,

pack3=3'b101,

done=3'b110;

//信号声明

reg[2:0]state_reg,state_next;

wire[7:0]rx_data;

regwr_ps2;

wirerx_done_tick,tx_done_tick;

reg[8:0]x_reg,y_reg,x_next,y_next;

reg[2:0]btn_reg,btn_next;

//例化

ps2_rxtxps2_unit

(.clk(clk),.reset(reset),.wr_ps2(wr_ps2),

.din(STRM),.dout(rx_data),.ps2d(ps2d),.ps2c(ps2c),

.rx_done_tick(rx_done_tick),

.tx_done_tick(tx_done_tick));

//FSMD状态和数据寄存器

always@(posedgeclk,posedgereset)

if(reset)

begin

state_reg<=init1;

x_reg<=0;

y_reg<=0;

btn_reg<=0;

end

else

begin

state_reg<=state_next;

x_reg<=x_next;

y_reg<=y_next;

btn_reg<=btn_next;

end

//FSMD下一状态逻辑

always

@*

begin

state_next=state_reg;

wr_ps2=1'b0;

m_done_tick=1'b0;

x_next=x_reg;

y_next=y_reg;

btn_next=btn_reg;

case(state_reg)

init1:

begin

wr_ps2=1'b1;

state_next=init2;

end

init2: //等待发送完毕

if(tx_done_tick)

state_next=init3;

init3: //等待数据包返回标志

if(rx_done_tick)

state_next=pack1;

pack1: //等待第一个数据包

if(rx_done_tick)

begin

state_next=pack2;

y_next[8]=rx_data[5];

x_next[8]=rx_data[4];

btn_next=rx_data[2:0];

end

pack2: //等待第二个数据包

if(rx_done_tick)

begin

state_next=pack3;

x_next[7:0]=rx_data;

end

pack3: //等待第三个数据包

if(rx_done_tick)

begin

state_next=done;

y_next[7:0]=rx_data;

end

done:

begin

m_done_tick=1'b1;

state_next=pack1;

end

endcase

end

//输出逻辑

assignxm=x_reg;

assignym=y_reg;

assignbtnm=btn_reg;

endmodule

10.4.2传输PS/2接口电路测试

我们设计一个简单的测试电

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论