2022寒假在家一起练-用iCE40 FPGA平台完成数字电压表
使用高速比较器构造ADC,制作一个数字电压表并显示在128*64OLED屏幕上
标签
FPGA
显示
ICE40
2022寒假在家练
sigma delta ADC
模拟量测量
Huang
更新2022-03-04
华南理工大学
829

一、项目需求和功能实现

-旋转电位计可以产生0-3.3V的电压

-利用板上的串行ADC对电压进行转换

-将电压值在板上的OLED屏幕上显示出来

使用了高速比较器TP1961TR作为积分器,整体实现了sigma-delta型ADC采集电压值。并将得到的8bit二进制数据映射为3.3V电压值,再转化成BCD码,显示在OLED屏幕上。

项目整体功能框图如下:

FjVmqOw894YnXLa2inFc6fbRRfKR

二、具体功能模块

2.1 模拟电压采集(ADC)

ADC采集的整体功能如下所示

Fr3g2lPWkXMtGAi1EDxIskbqMkW2

这是顶层模块对应的接口

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显示驱动

FnJaTuFJLxdPsk5KC1vZystIPzWi

以下是数值映射部分的模块代码

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 资源占用

Fo90YzL3PRwSNfX7AFnm0IY-FeyJ

整个设计所消耗的资源为:1188个四输入查找表和303个寄存器。器件iCE40UP5K可用的查找表和寄存器资源均为5280个。设计的资源占用率分别为22.5%LUTs和5.7%Registers。

 

三、收获和感想

在这个项目中,我的主要收获是学会了Σ-Δ型ADC的实现方法。此前也在模拟电路课程中简单接触过这一类型的ADC,但仅限于了解积分器和微分器这些抽象的概念。这一次的实践让我明白应该如何去构建能够使用的ADC,也让我对直接阅读官方例程、文档来学习提升有了很大的兴趣。此外,在同时钟且频率不高的情形下,模块与模块之间的单周期信号传递可以之间读取电平而不用采集较早的边沿。以后继续努力~

附件下载
voltage_capture_measure_impl_1.rbt
voltage_capture_measure.zip
工程文件(含源码)
团队介绍
华南理工大学 黄宇康
团队成员
Huang
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号