完全跟着老师的思路走的,该学的东西我都放在代码的注释里了
首先创建TLV1544_CTRL.v文件
module TLV1544_CTRL(
Clk,
Rst_n,
Do_Conv, //开始转换使能信号
AD_DONE, //转换完成信号//外部控制逻辑,也就是说外部什么时候控制adc开始转换呢,就是用这一个转换完成标志来实现
ADC_CHSEL, //通道选择
ADC_DATA, //采样结果
DATA_Valid,
TLV1544_SDO,//这个应该是数据吧 这个对于TLV1544来说是数据输出,而对于FPGA来说是数据输入
TLV1544_SDI, //这个是控制A1A2A3A0的,具体什么作用我也不懂
TLV1544_SCLK,//数据接口时钟
TLV1544_NCS, //芯片选择脚,该引脚由高变低会使器件内部的计数器和控制逻辑复位,并使能DATA IN,DATA OUT,和IO CLK,该引脚由低变高会禁止DATA IN,DATA OUT,和IO CLK的功能
TLV1544_FS,//DSP的帧同步输入,FS信号指示了串行数据帧从器件中开始输入或输出。当使用微处理器接口时,该引脚连接到VCC
TLV1544_EOC//转换忙标志位,当该引脚在IO CLK的第十个时钟的上升沿(微处理器模式)或下降沿(DSP 模式)变为低电平,并将保持低电平直到转换完成,数据已经就绪
);
input Clk;
input Rst_n;
input Do_Conv; //开始转换使能信号
input [3:0]ADC_CHSEL; //通道选择A0A1A2A3
output reg [9:0]ADC_DATA; //采样结果
output reg AD_DONE; //转换完成信号
output reg DATA_Valid;
input TLV1544_SDO;
input TLV1544_EOC;//转换完成的标志信号
output reg TLV1544_SDI;
output reg TLV1544_SCLK;
output reg TLV1544_NCS;
output wire TLV1544_FS;
assign TLV1544_FS = 1'b1;//整个过程中FS保持高电平不变
reg [7:0] LSM_CNT;//序列计数器
reg [9:0] rADC_DATA;//内部数据计数器,在整个转换的过程中,数据集都是往radc_DATA里面聚集,当转换完成之后,数据再送到我们的adc_DATA
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
LSM_CNT <= 8'd0;
else if(LSM_CNT <204 && (TLV1544_EOC == 1'b1) && (Do_Conv || LSM_CNT > 8'd0))
LSM_CNT <= LSM_CNT + 1'b1;
else if(LSM_CNT < 204 && (TLV1544_EOC == 1'b0))
LSM_CNT <= LSM_CNT;
else if(LSM_CNT == 204 && (TLV1544_EOC == 1'b1))
LSM_CNT <= 8'd0;
//&是按位与
//&&表示的是逻辑与
//比如
//a=4'b1001
//b=4'b1100
//a&b=4'b1000
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
rADC_DATA <= 10'd0;
TLV1544_SDI <= 1'b0;
TLV1544_SCLK <= 1'b0;
TLV1544_NCS <= 1'b1;
AD_DONE <= 1'b0;//转换完成信号
DATA_Valid <= 1'b0;
ADC_DATA <= 10'd0;
end
else begin
case(LSM_CNT)
0:
begin
rADC_DATA <= 10'd0;
TLV1544_SDI <= 1'b0;
TLV1544_SCLK <= 1'b0;
TLV1544_NCS <= 1'b1;
AD_DONE <= 1'b0;
end
1:
begin
TLV1544_NCS <= 1'b0;
TLV1544_SDI <= ADC_CHSEL[3];
end
9:
begin
TLV1544_SCLK <= 1'b1;
rADC_DATA[9] <= TLV1544_SDO;
end
19:
begin
TLV1544_SDI <= ADC_CHSEL[2];
TLV1544_SCLK <= 1'b0;
end
29:
begin
TLV1544_SCLK <= 1'b1;
rADC_DATA[8] <= TLV1544_SDO;
end
39:
begin
TLV1544_SDI <= ADC_CHSEL[1];
TLV1544_SCLK <= 1'b0;
end
49:
begin
TLV1544_SCLK <= 1'b1;
rADC_DATA[7] <= TLV1544_SDO;
end
59:
begin
TLV1544_SDI <= ADC_CHSEL[0];
TLV1544_SCLK <= 1'b0;
end
69:
begin
TLV1544_SCLK <= 1'b1;
rADC_DATA[6] <= TLV1544_SDO;
end
79:TLV1544_SCLK <= 1'b0;
89:
begin
TLV1544_SCLK <= 1'b1;
rADC_DATA[5] <= TLV1544_SDO;
end
99:TLV1544_SCLK <= 1'b0;
109:
begin
TLV1544_SCLK <= 1'b1;
rADC_DATA[4] <= TLV1544_SDO;
end
119:TLV1544_SCLK <= 1'b0;
129:
begin
TLV1544_SCLK <= 1'b1;
rADC_DATA[3] <= TLV1544_SDO;
end
139:TLV1544_SCLK <= 1'b0;
149:
begin
TLV1544_SCLK <= 1'b1;
rADC_DATA[2] <= TLV1544_SDO;
end
159:TLV1544_SCLK <= 1'b0;
169:
begin
TLV1544_SCLK <= 1'b1;
rADC_DATA[1] <= TLV1544_SDO;
end
179:TLV1544_SCLK <= 1'b0;
189:
begin
TLV1544_SCLK <= 1'b1;
//rADC_DATA[0] <= TLV1544_SDO;//这个时候是把sdo送到radC_DATA【0】里面,但它和下面整体赋值给adc_DATA是非阻塞的,也就是说同时进行的
//所以我们可以把radC_DATA【9:1】和此时的sdo直接一起并值给adc_DATA
if(TLV1544_EOC)
DATA_Valid <= 1'b1;
else
DATA_Valid <= 1'b0;
ADC_DATA <= {rADC_DATA[9:1],TLV1544_SDO};
end
199:
begin
TLV1544_SCLK <= 1'b0;
TLV1544_NCS <= 1'b1;
end
204:AD_DONE <= 1'b1;
default:DATA_Valid <= 1'b0;
endcase
end
endmodule
然后编写test bench看看结果
`timescale 1ns/1ns
`define clk_period 20
module TLV1544_CTRL_tb;
reg Clk;
reg Rst_n;
reg Do_Conv; //开始转换使能信号
reg [3:0]ADC_CHSEL; //通道选择
wire[9:0]ADC_DATA; //采样结果
wire AD_DONE; //转换完成信号
wire DATA_Valid;
reg TLV1544_SDO;
reg TLV1544_EOC;
wire TLV1544_SDI;
wire TLV1544_SCLK;
wire TLV1544_NCS;
wire TLV1544_FS;
TLV1544_CTRL TLV1544_CTRL0(
.Clk(Clk),
.Rst_n(Rst_n),
.Do_Conv(Do_Conv), //开始转换使能信号
.AD_DONE(AD_DONE), //转换完成信号
.ADC_CHSEL(ADC_CHSEL), //通道选择
.ADC_DATA(ADC_DATA), //采样结果
.DATA_Valid(DATA_Valid),
.TLV1544_SDO(TLV1544_SDO),
.TLV1544_SDI(TLV1544_SDI),
.TLV1544_SCLK(TLV1544_SCLK),
.TLV1544_NCS(TLV1544_NCS),
.TLV1544_FS(TLV1544_FS),
.TLV1544_EOC(TLV1544_EOC)
);
initial Clk = 1'b1;
always #(`clk_period/2)Clk = ~Clk;
initial begin
Rst_n = 1'b0;
Do_Conv = 1'b0;
ADC_CHSEL = 4'b0;
TLV1544_SDO = 1'b0;
TLV1544_EOC = 1'b1;
#(`clk_period * 10 +1);//主要是为了让rst_n的释放和我们的clk错开,便于观察信号的变化
Rst_n = 1'b1;
#(`clk_period * 10);
ADC_CHSEL = 0;//选择通道0
Do_Conv = 1'b1;//产生读使能信号
#(`clk_period);
Do_Conv = 1'b0;
@(posedge (TLV1544_CTRL0.LSM_CNT == 8'd189))//在第十个模块时钟的上升沿的时候,模拟EOC等于0,也就是说数据转换完成了
TLV1544_EOC = 1'b0;
#(`clk_period*10 +3);
TLV1544_EOC = 1'b1;
#(`clk_period*1000 );
ADC_CHSEL = 1;
Do_Conv = 1'b1;
#(`clk_period);
Do_Conv = 1'b0;
@(posedge (TLV1544_CTRL0.LSM_CNT == 8'd189))
#(`clk_period);
TLV1544_EOC = 1'b0;
#(`clk_period*10 +3);
TLV1544_EOC = 1'b1;
#(`clk_period*1000 );
$stop;
end
initial begin
forever begin//forever必须在initial块中使用,不能在always块中使用
TLV1544_SDO = ~TLV1544_SDO;
#350;
end
end
endmodule
看是看完了,就是自己不会写,打算自己咸鱼几天看看别人的代码,如果弄懂了会自己试着写一个ad9226双通道采集代码。
本咸鱼需要采集六个大概1MHz左右的电压信号,有没有大佬试过这么高频率的多通道采样呀,求交流