|
module xpt2046(
Clk50m,
Rst_n,
EN,
X_Value,
Y_Value,
Get_Flag,
PenIrq_n,
DCLK,
DIN,
DOUT,
CS_N,
BUSY
);
input Clk50m;
input Rst_n;
input EN;
output reg [11:0]X_Value;
output reg [11:0]Y_Value;
output reg Get_Flag;
input PenIrq_n;
input BUSY;
output reg DCLK;
output reg DIN;
output reg CS_N;
input DOUT;
wire pen_flag;
wire pen_state;
reg [4:0]DIV_CNT;//得到DCLK时钟两倍的采样时钟以产生DCLK
reg [5:0]CLK_GEN_CNT;//产生DCLK时钟计数器
reg [5:0]CONV_CNT;//记录完成了多少次转换
reg [19:0]PEN_CNT;
reg DCLK2X;
reg CONV_DONE;
reg [11:0]Dtmp;
reg EN_CONV;
reg [16:0]tmp_X_Value,tmp_Y_Value;
reg [11:0]X_MAX,X_MIN,Y_MAX,Y_MIN;
reg r_Get_Flag;
localparam S = 1'b1; //起始位
localparam MODE = 1'b0; //采样精度
localparam SER_DFR = 1'b0; //单端/差分采样模式
localparam PD = 2'b00; //功耗控制
parameter CONV_TIMES = 36; //每多少次转换计算一次均值
parameter FILTER_PARAM = 4; //除以16 == 右移4位
parameter CNT_TOP = 20'd499999; //对PEN引脚信号滤波延时
wire [2:0]ADDR; //采样通道控制
assign ADDR = (CONV_CNT[0])?3'b101:3'b001;//CONV_CNT值为偶数,选择测量X通道
wire cnt_full;//PEN引脚信号滤波计数器计数满标志
//PEN引脚延时滤波计数器
always@(posedge Clk50m or negedge Rst_n)
if(!Rst_n)
PEN_CNT <= 20'd0;
else if(!PenIrq_n)begin //笔触为低电平
if(cnt_full) //计满归零
PEN_CNT <= 20'd0;
else //未计满累加
PEN_CNT <= PEN_CNT + 1'b1;
end else //笔触为高电平,禁止计数
PEN_CNT <= 20'd0;
assign cnt_full = (PEN_CNT == CNT_TOP);
assign pen_state = cnt_full;//在PenIrq_n引脚为低电平的时候,每计数满产生一次pen_state信号,触发一36次采样
//2倍DCLK采样时钟分频计数器
always@(posedge Clk50m or negedge Rst_n)
if(!Rst_n)
DIV_CNT <= 5'd0;
else if(EN_CONV)begin
if(DIV_CNT == 5'd24)
DIV_CNT <= 5'd0;
else
DIV_CNT <= DIV_CNT + 1'b1;
end
else
DIV_CNT <= 5'd0;
//产生2倍DCLK使能时钟
always@(posedge Clk50m or negedge Rst_n)
if(!Rst_n)
DCLK2X <= 1'b0;
else if(DIV_CNT == 5'd24)
DCLK2X <= 1'b1;
else
DCLK2X <= 1'b0;
//对2倍DCLK采样时钟进行技术,以产生序列机基本序列
always@(posedge Clk50m or negedge Rst_n)
if(!Rst_n)
CLK_GEN_CNT <= 6'b0;
else if(EN_CONV)begin
if(DCLK2X)begin
if(CLK_GEN_CNT == 6'd45)//计数到46以后,回到16开始重新计数
CLK_GEN_CNT <= 6'd16;
else
CLK_GEN_CNT <= CLK_GEN_CNT + 1'b1;
end
end
else
CLK_GEN_CNT <= 6'b0;
//根据CLK_GEN_CNT值控制序列,发送控制字并读取采样结果
always@(posedge Clk50m or negedge Rst_n)
if(!Rst_n)begin
DIN <= 1'b1;
Dtmp <= 12'd0;
DCLK <= 1'd0;
CONV_CNT <= 6'd0;
end
else if(EN_CONV)begin
if(DCLK2X)begin
case(CLK_GEN_CNT)
0:begin DIN <= S; DCLK <= 1'b0; end //发送首次转换起始位
1:begin DCLK <= 1'b1; end
2:begin DIN <= ADDR[2]; DCLK <= 1'b0; end //发送A2
3:begin DCLK <= 1'b1; end
4:begin DIN <= ADDR[1]; DCLK <= 1'b0; end//发送A1
5:begin DCLK <= 1'b1; end
6:begin DIN <= ADDR[0]; DCLK <= 1'b0; end//发送A0
7:begin DCLK <= 1'b1; end
8:begin DIN <= MODE; DCLK <= 1'b0; end//发送采样精度设置位
9:begin DCLK <= 1'b1; end
10:begin DIN <= SER_DFR; DCLK <= 1'b0; end//发送ADC输入模式位
11:begin DCLK <= 1'b1;end
12:begin DIN <= PD[1]; DCLK <= 1'b0; end//发送功耗控制位PD1
13:begin DCLK <= 1'b1; end
14:begin DIN <= PD[0]; DCLK <= 1'b0; end//发送功耗控制位PD0
15:begin DCLK <= 1'b1; end
16:begin DIN <= 0; DCLK <= 1'b0; end//等待采样保持电路工作
17:begin DCLK <= 1'b1; end
18:begin DIN <= 0; DCLK <= 1'b0; end
19:begin Dtmp[11] <= DOUT; DCLK <= 1'b1; end//读取第11位转换结果
20:begin DIN <= 0; DCLK <= 1'b0; end
21:begin Dtmp[10] <= DOUT; DCLK <= 1'b1; end//读取第10位转换结果
22:begin DIN <= 0; DCLK <= 1'b0; end
23:begin Dtmp[9] <= DOUT; DCLK <= 1'b1; end//读取第9位转换结果
24:begin DIN <= 0; DCLK <= 1'b0; end
25:begin Dtmp[8] <= DOUT;DCLK <= 1'b1; end//读取第8位转换结果
26:begin DIN <= 0; DCLK <= 1'b0; end
27:begin Dtmp[7] <= DOUT; DCLK <= 1'b1; end//读取第7位转换结果
28:begin DIN <= 0; DCLK <= 1'b0; end
29:begin Dtmp[6] <= DOUT; DCLK <= 1'b1; end//读取第6位转换结果
30:begin DIN <= S; DCLK <= 1'b0; end //发送下次转换的控制字起始位
31:begin Dtmp[5] <= DOUT; DCLK <= 1'b1; end//读取第5位转换结果
32:begin DIN <= ADDR[2]; DCLK <= 1'b0; end//发送下次转换的A2
33:begin Dtmp[4] <= DOUT; DCLK <= 1'b1; end
34:begin DIN <= ADDR[1]; DCLK <= 1'b0; end//发送下次转换的A1
35:begin Dtmp[3] <= DOUT; DCLK <= 1'b1; end
36:begin DIN <= ADDR[0]; DCLK <= 1'b0; end//发送下次转换的A0
37:begin Dtmp[2] <= DOUT; DCLK <= 1'b1; end
38:begin DIN <= MODE; DCLK <= 1'b0; end//发送下次转换的采样精度设置位
39:begin Dtmp[1] <= DOUT; DCLK <= 1'b1; end
40:begin DIN <= SER_DFR; DCLK <= 1'b0; end//发送下次采样ADC输入模式位
41:begin Dtmp[0] <= DOUT; DCLK <= 1'b1; CONV_CNT <= CONV_CNT + 1'b1; end
42:begin DIN <= PD[1]; DCLK <= 1'b0; end//发送功耗控制位PD1
43:begin DCLK <= 1'b1; end
44:begin DIN <= PD[0]; DCLK <= 1'b0; end//发送功耗控制位PD0
45:begin DCLK <= 1'b1; CONV_DONE <= 1'b1; end
endcase
end else
CONV_DONE <= 1'b0;
end else if(!EN_CONV)begin
CONV_CNT <= 0;
CONV_DONE <= 1'b0;
end
//将36次采样中18次的X通道的采样结果累加
always@(posedge Clk50m or negedge Rst_n)
if(!Rst_n)
tmp_X_Value <= 17'd0;
else if(EN_CONV == 1'b0)
tmp_X_Value <= 17'd0;
else if(CONV_DONE && CONV_CNT[0])//转换完成,转换计数为奇数,将转换结果累加到X临时寄存器
tmp_X_Value <= tmp_X_Value + Dtmp;
//记录18次X通道采样的最大值
always@(posedge Clk50m or negedge Rst_n)
if(!Rst_n)
X_MAX <= 12'd0;
else if(EN_CONV == 1'b0)
X_MAX <= 12'd0;
else if(CONV_DONE && CONV_CNT[0])begin//转换完成,转换计数为奇数,判断当前值是否大于已存最大值
if(Dtmp > X_MAX)
X_MAX <= Dtmp;
else
X_MAX <= X_MAX;
end
//记录18次X通道采样的最小值
always@(posedge Clk50m or negedge Rst_n)
if(!Rst_n)
X_MIN <= 12'd0;
else if(EN_CONV == 1'b0)
X_MIN <= 12'd4095;
else if(CONV_DONE && CONV_CNT[0])begin//转换完成,转换计数为奇数,判断当前值是否小于已存最小值
if(Dtmp < X_MIN)
X_MIN <= Dtmp;
else
X_MIN <= X_MIN;
end
//将36次采样中18次的Y通道的采样结果累加
always@(posedge Clk50m or negedge Rst_n)
if(!Rst_n)
tmp_Y_Value <= 17'd0;
else if(EN_CONV == 1'b0)
tmp_Y_Value <= 17'd0;
else if(CONV_DONE && (!CONV_CNT[0]))//转换完成,转换计数为偶数,将转换结果累加到Y临时寄存器
tmp_Y_Value <= tmp_Y_Value + Dtmp;
//记录18次Y通道采样的最大值
always@(posedge Clk50m or negedge Rst_n)
if(!Rst_n)
Y_MAX <= 12'd0;
else if(EN_CONV == 1'b0)
Y_MAX <= 12'd0;
else if(CONV_DONE && (~CONV_CNT[0]))begin//转换完成,转换计数为奇数,判断当前值是否大于已存最大值
if(Dtmp > Y_MAX)
Y_MAX <= Dtmp;
else
Y_MAX <= Y_MAX;
end
//记录18次Y通道采样的最小值
always@(posedge Clk50m or negedge Rst_n)
if(!Rst_n)
Y_MIN <= 12'd0;
else if(EN_CONV == 1'b0)
Y_MIN <= 12'd4095;
else if(CONV_DONE && (~CONV_CNT[0]))begin//转换完成,转换计数为奇数,判断当前值是否小于已存最小值
if(Dtmp < Y_MIN)
Y_MIN <= Dtmp;
else
Y_MIN <= Y_MIN;
end
//使能一个36次转换
always@(posedge Clk50m or negedge Rst_n)
if(!Rst_n)
EN_CONV <= 1'b0;
else if(EN)begin
if(pen_state)
EN_CONV <= 1'b1;
else if((CONV_CNT == CONV_TIMES) && CLK_GEN_CNT == 29)//转换完成,对齐15周期时序
EN_CONV <= 1'b0;
else
EN_CONV <= EN_CONV;
end
else
EN_CONV <= 1'b0;
//
always@(posedge Clk50m or negedge Rst_n)
if(!Rst_n)
r_Get_Flag <= 1'b0;
else if((CONV_CNT == CONV_TIMES) && CONV_DONE)
r_Get_Flag <= 1'b1;
else
r_Get_Flag <= 1'b0;
always@(posedge Clk50m)
Get_Flag <= r_Get_Flag;
always@(posedge Clk50m)
CS_N <= ~EN_CONV;
reg [11:0]r_X_Value,r_Y_Value;
//计算当前X均值,X均值 = (18次累加值 - 最大值 - 最小值)/ 16
always@(posedge Clk50m or negedge Rst_n)
if(!Rst_n)
r_X_Value <= 12'd0;
else if(r_Get_Flag)
r_X_Value <= (tmp_X_Value - X_MAX - X_MIN) >> FILTER_PARAM;
else
r_X_Value <= r_X_Value;
//计算当前Y均值,Y均值 = (18次累加值 - 最大值 - 最小值)/ 16
always@(posedge Clk50m or negedge Rst_n)
if(!Rst_n)
r_Y_Value <= 12'd0;
else if(r_Get_Flag)
r_Y_Value <= (tmp_Y_Value - Y_MAX - Y_MIN) >> FILTER_PARAM;
else
r_Y_Value <= r_Y_Value;
//存储上一次X结果作为输出,为了滤除最后一次转换结果,因为最后一次转换结果存在按压释放时刻,结果不太稳定
always@(posedge Clk50m or negedge Rst_n)
if(!Rst_n)
X_Value <= 12'd0;
else if(r_Get_Flag)
X_Value <= r_X_Value;
//存储上一次Y结果作为输出,为了滤除最后一次转换结果,因为最后一次转换结果存在按压释放时刻,结果不太稳定
always@(posedge Clk50m or negedge Rst_n)
if(!Rst_n)
Y_Value <= 12'd0;
else if(r_Get_Flag)
Y_Value <= r_Y_Value;
endmodule
`timescale 1ns/1ns
module xpt2046_tb;
reg Clk50m;
reg Rst_n;
reg EN;
wire [11:0]X_Value;
wire [11:0]Y_Value;
wire Get_Flag;
reg PenIrq_n;
reg BUSY;
wire DCLK;
wire DIN;
wire CS_N;
reg DOUT;
initial Clk50m = 1;
always #10 Clk50m = ~Clk50m;
initial begin
Rst_n = 0;
PenIrq_n = 1;
EN = 0;
#201;
Rst_n = 1;
EN = 1;
#300;
PenIrq_n = 0;
#5000000;
PenIrq_n = 1;
#5000000;
$stop;
end
// initial begin
// DOUT = 1'b0;
// forever begin
// DOUT = ~DOUT;
// #30154;
// end
// end
initial DOUT = 1;
xpt2046 xpt2046(
.Clk50m(Clk50m),
.Rst_n(Rst_n),
.EN(EN),
.X_Value(X_Value),
.Y_Value(Y_Value),
.Get_Flag(Get_Flag),
.PenIrq_n(PenIrq_n),
.DCLK(DCLK),
.DIN(DIN),
.DOUT(DOUT),
.CS_N(CS_N),
.BUSY(BUSY)
);
endmodule