TLC549ADC驱动的FPGA实现
程序员文章站
2022-04-01 18:42:28
...
1.引言与相关资料
TLC549是一款8位串行ADC,其采样速率不高,精度也只有8位,但不需要对其进行任何控制就可以自动的进行ADC的工作,需要做的只是在适当的时机按串行方式读出8位AD值就可以。
理论上这款ADC性能其实不咋地,局限性也很大,不过是我购买的FPGA开发板上自带的一款ADC,后续有个设计需要用到它进行AD采样。
相关资料百度上可以找到一篇关于TLC549中文资料。以下是链接:
2.TLC549驱动时序与采样过程
TLC549区别与其他ADC的主要特征就在于:器件内部存在时钟,与外部时钟独立,这个时钟控制ADC进行电平值的转换。也就是说其接口上的Clk管脚实际上只控制读ADC的值,而不直接控制采样频率。具体的采样时序如下:
上述具体过程如下:
1.初始时CS拉高,此时芯片不向外输出AD值。
2.当CS拉低后,芯片通过两个内部时钟来确认这一变化,同时D0端向外输出上一次采样结果AD值的最高位:D7
3.此后CS持续拉低,CLK上来时钟脉冲后,在CLK时钟脉冲的前四个下降沿依次输出D6,D5,D4,D3。
4.同时在第四个下降沿时开始对AD的模拟端进行采样。
5.在之后的3个脉冲依次输出D2,D1以及D0。此时CLK已经经过7个脉冲
6.在第8个脉冲的下降沿,ADC把模拟端的电压保存下来,准备开始转换。
7.同时CS需要拉高,CLK需要持续拉低,ADC开始转换模拟电压,经过36个ADC的内部时钟后,电压值转换完毕。可以进行下一次读取。
从上述过程中,可以获取两个信息:
1.ADC转换过程与I/O管脚CLK无关,但转换期间不能被CLK和CS打扰。属于ADC的等待状态
2.读取信息时下降沿输出数据,从MSB-LSB的顺序输出,属于ADC的读取数据状态
3.TLC549驱动的硬件编写
FPGA的实现比较简单,通过计数器完成CLK时钟的生成和等待时间的定时,利用有限状态机控制CS和CLK信号完成ADC的两种状态之间的切换。以下例子中CLK的频率为500KHz,而等待时间则为40个内部时钟周期。
编写模块实例图如下:
模块信号说明:
I_Adc_Data_In-------------------------------------------ADC输入的串行AD数据
O_CS_n----------------------------------------------------CS控制信号
O_Adc_Clk------------------------------------------------CLK控制时钟
O_Adc_Data_Vaild--------------------------------------标志Data_out端数据是否有效的指示端,有效时会输出一个高电平
O_Adc_Data_Out[7:0]----------------------------------AD采样的8位数据,当Vaild端输出一个高电平脉冲后才表示有效
具体的FPGA程序如下:
module ADC_TLC549(
I_Clk,
I_Rst_n,
I_Adc_Data_In,
O_CS_n,
O_Adc_Clk,
O_Adc_Data_Out,
O_Adc_Data_Vaild
);
//I/O
input I_Clk;
input I_Rst_n;
input I_Adc_Data_In;
output O_CS_n;
output O_Adc_Clk;
output [7:0] O_Adc_Data_Out;
output O_Adc_Data_Vaild;
/*************I/O时钟计数器********************/
parameter IO_Clk_Freq=7'd99; //系统时钟50MHz,500k=50/100->99;
parameter IO_Clk_Freq_div=7'd49;//采样时钟频率的两倍,对应与采样时钟上升沿
parameter IO_Clk_Width=3'd7;
reg [IO_Clk_Width-1:0] R_IO_Clk_Count;
reg R_Clk_En;
always @ (posedge I_Clk)
begin
if (~I_Rst_n)
begin
R_IO_Clk_Count<=7'b0;
end
else
begin
if (R_Clk_En)
begin
if (R_IO_Clk_Count==IO_Clk_Freq)
R_IO_Clk_Count<=7'b0;
else
R_IO_Clk_Count<=R_IO_Clk_Count+7'd1;
end
else
R_IO_Clk_Count<=7'b0;
end
end
assign O_Adc_Clk=(R_IO_Clk_Count>IO_Clk_Freq_div)?1'b1:1'b0;
/***************转换时间计时器*********************************/
parameter Delay_Time=9'd499;//转换时钟为4MHz,总等待时间需要超过34个周期,这里取40个周期,则为500个系统时钟
parameter CS_n_Time=9'd449;
parameter Transfer_Count_Width=4'd9;
reg [Transfer_Count_Width-1:0] R_Transfer_Count;
reg R_Transfer_En;
always @ (posedge I_Clk)
begin
if (~I_Rst_n)
begin
R_Transfer_Count<=9'b0;
end
else
begin
if (R_Transfer_En)
begin
if (R_Transfer_Count==Delay_Time)
R_Transfer_Count<=R_Transfer_Count;
else
R_Transfer_Count<=R_Transfer_Count+9'd1;
end
else
R_Transfer_Count<=9'b0;
end
end
/**************总采样过程状态机***********************/
reg [3:0] R_State;
reg R_CS_n;
reg [7:0] R_Data;
reg R_Vaild;
always @ (posedge I_Clk)
begin
if (~I_Rst_n)
begin
R_State<=4'b0;
R_CS_n<=1'b1;
R_Data<=8'b0;
R_Transfer_En<=1'b0;
R_Clk_En<=1'b0;
R_Vaild<=1'b0;
end
else
case (R_State)
4'd0:
begin
R_Vaild<=1'b0;
R_Transfer_En<=1'b1;
R_Clk_En<=1'b0;
R_CS_n<=1'b1;
if (R_Transfer_Count==CS_n_Time)
R_State<=R_State+4'd1;
else
R_State<=R_State;
end
4'd1:
begin
R_CS_n<=1'b0;
if (R_Transfer_Count==Delay_Time)
begin
R_State<=R_State+4'd1;
R_Transfer_En<=1'b0;
end
else
begin
R_State<=R_State;
R_Transfer_En<=1'b1;
end
end
4'd2,4'd3,4'd4,4'd5,4'd6,4'd7,4'd8,4'd9:
begin
R_Clk_En<=1'b1;
if (R_IO_Clk_Count==IO_Clk_Freq_div)
begin
R_State<=R_State+4'd1;
R_Data<={R_Data[6:0],I_Adc_Data_In};
end
else
R_State<=R_State;
end
4'd10:
begin
if (R_IO_Clk_Count==IO_Clk_Freq)
begin
R_Clk_En<=1'b0;
R_State<=4'd0;
R_Vaild<=1'b1;
R_CS_n<=1'b1;
end
else
begin
R_Clk_En<=1'b1;
R_State<=R_State;
R_Vaild<=1'b0;
R_CS_n<=1'b0;
end
end
default:
begin
R_State<=4'b0;
R_CS_n<=1'b1;
R_Data<=8'b0;
R_Transfer_En<=1'b0;
R_Clk_En<=1'b0;
R_Vaild<=1'b0;
end
endcase
end
assign O_CS_n=R_CS_n;
assign O_Adc_Data_Out=R_Data;
assign O_Adc_Data_Vaild=R_Vaild;
endmodule
通过ChipScope对采样到的值进行观察,结果如下:
没过一段时间,Data端会输出一个稳定的8位数值,为AD的采样值
推荐阅读
-
Springboot基于enable模块驱动的实现
-
大数据时代,如何实现品牌营销的数字化驱动
-
使用devcon.exe实现自动安装驱动的心得总结
-
Angular实现模版驱动表单的自定义校验功能(密码确认为例)
-
使用Ruby实现简单的事物驱动的web应用的教程
-
利用Python如何实现数据驱动的接口自动化测试
-
资深程序员用Python实现数据驱动的接口自动化测试!
-
字符设备驱动开发 Linux 设备号 字符设备驱动开发步骤 open 函数调用流程 设备号的组成 设备号的分配 Linux 应用程序对驱动程序的调用 字符设备注册与注销 实现设备的具体操作函数
-
linux驱动poll机制 mmap的实现 中断下半部的实现
-
linux设备驱动:中断下半部的三种实现机制