一、项目需求和功能实现
-旋转电位计可以产生0-3.3V的电压
-利用板上的串行ADC对电压进行转换
-将电压值在板上的OLED屏幕上显示出来
使用了高速比较器TP1961TR作为积分器,整体实现了sigma-delta型ADC采集电压值。并将得到的8bit二进制数据映射为3.3V电压值,再转化成BCD码,显示在OLED屏幕上。
项目整体功能框图如下:
二、具体功能模块
2.1 模拟电压采集(ADC)
ADC采集的整体功能如下所示
这是顶层模块对应的接口
module ADC_top (
clk_in,
rstn,
digital_out,
analog_cmp,
analog_out,
sample_rdy);
parameter
ADC_WIDTH = 8, // ADC Convertor Bit Precision
ACCUM_BITS = 10, // 2^ACCUM_BITS is decimation rate of accumulator
LPF_DEPTH_BITS = 3, // 2^LPF_DEPTH_BITS is decimation rate of averager
INPUT_TOPOLOGY = 0; // 0: DIRECT: Analog input directly connected to + input of comparitor
// 1: NETWORK:Analog input connected through R divider to - input of comp.
//input ports
input clk_in; // 62.5Mhz on Control Demo board
input rstn;
input analog_cmp; // from LVDS buffer or external comparitor
//output ports
output analog_out; // feedback to RC network
output sample_rdy;
output [7:0] digital_out; // connected to LED field on control demo bd.
这一部分主要ADC_top sigmadelta_adc 和box_ave三个module,参考自Lattice文档《Simple Sigma-Delta ADC Reference Design》以及电子森林的相关应用项目。其中sigmadelta_adc模块和外部高速比较器一起用于构建ADC,将1024个周期内计数的比较器输出数量传递给box_ave模块,这里的计数结果就对应着采集到的8bit模拟值,范围为(0,255)。box_ave用于对得到的计数结果平滑滤波,简单说就是取平均值。这里取16次读取结果的平均值。
这样,在12MHz时钟输入下,ADC的采样率是(12*10^6)/1024/16 = 732次/s。性能并不算高,但在本项目中采集较为静态的电位计分压已经足够了。
2.2 数据格式转换
格式转换的功能如下所示,其中输入来自ADC采集,输出去往OLED显示驱动
以下是数值映射部分的模块代码
module num_convert (
clk_in,
rstn,
raw_digital_in,
sample_rdy,
dout_int1,
dout_point1,
dout_point2,
dout_point3,
display_rdy
);
parameter
ADC_WIDTH = 8,
minimum_resolution = 7; // log2 [3.3v*(10^4)/256], or log2[33000/256]
// get first 4 BCD number of n*33000/256
// maxmimum 32640(3.264v)
//input ports
input clk_in;
input rstn;
input [ADC_WIDTH-1:0] raw_digital_in;
input sample_rdy;
//output ports
output [3:0]dout_int1; // BCD code, decimal 0~9
output [3:0]dout_point1;
output [3:0]dout_point2;
output [3:0]dout_point3;
output display_rdy; // data vaild signal
// wire rawdata_vaild;
wire [17:0] bcd;
wire dout_vaild;
reg [14:0] raw_binary_data;// 2^7 * (256-1) = binary(0111 1111 1000 0000)
// reg sample_rdy_d1;
// reg sample_rdy_d2;
reg convert_begin;
always @(posedge clk_in or negedge rstn) begin
if(~rstn)begin
raw_binary_data <= 'd0;
// sample_rdy_d1 <= 'd0;
// sample_rdy_d2 <= 'd0;
convert_begin <= 'd0;
end
else begin
// sample_rdy_d1 <= sample_rdy;
// sample_rdy_d2 <= sample_rdy_d1;
if(sample_rdy)begin
raw_binary_data <= raw_digital_in << minimum_resolution; //shift left
convert_begin <= 'd1;end
else begin
convert_begin <= 'd0;
end
end
end
// assign rawdata_vaild = !sample_rdy_d1 && sample_rdy_d2; //fall_edge of sample_rdy detect
bin2bcd u_bin2bcd(
.clk_in ( clk_in ), //input
.rstn ( rstn ),
.raw_binary_data ( raw_binary_data ),
.begin_vaild ( convert_begin ),
.bcd ( bcd ), //output
.dout_vaild ( dout_vaild )
);
assign dout_int1 = {2'b0,bcd[17:16]};
assign dout_point1 = bcd[12+:4];
assign dout_point2 = bcd[8+:4];
assign dout_point3 = bcd[4+:4];
assign display_rdy = dout_vaild; //rise-edge, same period of vaild data
//*****************************************
// test condition
//*****************************************
wire [3:0] dout_point4;
assign dout_point4 = bcd[0+:4];
endmodule //num_convert
数据格式转换包括两个方面:1、将(0,255)范围内的数字输出转化成(0,3.3)V范围内的电压输出;2、将二进制编码的电压输出转化成显示驱动模块所能识别的BCD编码格式。
对于映射范围的转换,本项目中使用的方法是直接左移7位,也就是直接将数字输出乘以128。7位是用如下方法计算出来的log2 [3.3v*(10^4)/256], 或者log2[33000/256]。换言之,就是将3.3v乘以一个特定大数,再将其等分成256份。为了简化计算,将等分的最小分辨率归一化为2的7次方。BCD格式的转化则采用了移位和“大四加一”的方法,一共需要16个周期完成转换。
2.3 OLED屏幕显示
屏幕显示模块是此前编写过的,采用有限状态机、利用SPI协议对完成对输入数据的缓存输出。
2.4 按键复位
module botton (
clk_in,
botton,
rstn
);
// input ports
input clk_in;
input botton; // botton k2
// output ports
output rstn;
reg [19:0] counter;
reg rstn = 0;
reg cnt_begin;
reg botton_b1,botton_b2;
wire f_edge;
always @(posedge clk_in ) begin
botton_b1 <= botton;
botton_b2 <= botton_b1;
end
assign f_edge = !botton_b1 && botton_b2; // fall edge detect
always @(posedge clk_in ) begin
if(f_edge)
cnt_begin <= 1'b1;
if(&counter)begin
cnt_begin <= 'd0;
rstn <= ~rstn;
end
end
always @(posedge clk_in ) begin
if(cnt_begin)
counter <= counter + 'd1;
else
counter <= 'd0;
end
endmodule
由于板卡上没有自带拨码开关,无法直接完成异步复位的设置。因此在K2按键上实现了一个异步复位的锁存器。按击一下K2按键使信号rstn置0,旋转电位计屏幕不再发生变化,再次按击恢复正常。
2.5 资源占用
整个设计所消耗的资源为:1188个四输入查找表和303个寄存器。器件iCE40UP5K可用的查找表和寄存器资源均为5280个。设计的资源占用率分别为22.5%LUTs和5.7%Registers。
三、收获和感想
在这个项目中,我的主要收获是学会了Σ-Δ型ADC的实现方法。此前也在模拟电路课程中简单接触过这一类型的ADC,但仅限于了解积分器和微分器这些抽象的概念。这一次的实践让我明白应该如何去构建能够使用的ADC,也让我对直接阅读官方例程、文档来学习提升有了很大的兴趣。此外,在同时钟且频率不高的情形下,模块与模块之间的单周期信号传递可以之间读取电平而不用采集较早的边沿。以后继续努力~