基于ICE40UP5K的FPGA学习平台
制作数字电压表
一项目介绍
利用ADC制作一个数字电压表,旋转电位计可以产生0-3.3V的电压,利用板上的串行ADC对电压进行转换,将电压值在板上的OLED屏幕上显示出来。
二设计思路和框图
借助一颗高速比较器来实现对模拟信号的量化,Lattice的官网上一篇文章就介绍了如何制作一个简易的Sigma Delta ADC,所以使用本次活动的板卡,UP5K的FPGA的两个端口搭配一个高速的比较器来实现Lattice官网上推荐的简易Sigma Delta ADC的功能。具体的过程如图3所示,滑动变阻器产生变化的电压值,FPGA以及比较器采集这个电压值,数字低通滤波器进行滤波,转码并显示在OLED屏幕上。
图1莱迪思的原理图
图2本次简易adc的原理图
图3简单的流程
三硬件介绍
这次用到的平台是硬禾学堂2022年寒假活动中基于ICE40UP5K的FPGA学习平台,基于Lattice的ICE40UP5K FPGA,板载LPC11U35下载器,可以通过USB-C接口进行FPGA的配置,支持在ICE40UP5K上对RISC-V软核的移植以及开源的FPGA开发工具链,板上RGB三色LED灯用于简单的调试,总计28个IO用于扩展使用,同USB直接连接的5V输出以及经板上LDO产生的3.3V直流电压输出,可以给扩展板供电,电流为200mA,板上晶体振荡器时钟产生12MHz供FPGA和LPC11U35工作,FPGA可以通过内部锁相环工作于48MHz。扩展板上具有12个WS2812BRGB三色灯,1个OLED屏幕,1个可调电位计以及8位R-2R电阻网构成的DAC等丰富的外设,具体内容参考https://www.eetree.cn/project/detail/131。
如图所示,核心板板载一个高速比较器TP1961TR,Ain2为底板滑动变阻器产生的模拟号,PWM_V2和C_OUT2分别连接到FPGA的一个端口,PWM_V2连接的端口产生PWM波,C_OUT2连接的端口得到比较器的输出结果,这个结果通过FPGA的处理最终得到电压的数值,并显示在OLED屏幕上。
图4
图5
四实现的功能及图片展示
实现了一个数字电压表的功能,旋转底板上的电位计可以产生0-3.3V的电压,板上的串行ADC对电压进行转换,将电压值在板上的OLED屏幕上显示出来。
图6
五主要代码片段及说明
如下图所示,主要包括ADC_top.v,bin2num.v,box_ove.v,OLED12864.v,sigmadelta_adc.v五个文件,ADC_top.v为顶层文件,首先定义了自己的输入输出和一些参数,然后就是例化一个sigmadelta_adc的程序实现模拟电压的采集,得到的数据再通过例化一个bin2num的程序实现转码,最终通过OLED12864.v实现的驱动OLED屏幕显示电压值,box_ove为sigmadelta_adc.v文件中例化完成,是数字低通滤波器模块,用来做平滑滤波。
图7
这是ADC_top.v中定义了自己的输入输出和一些参数。
module ADC_top (
//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 [3:0] digital_out, // connected to LED field on control demo bd.
output oled_rst, //OLCD液晶屏复位
output oled_dcn, //OLCD数据指令控制
output oled_clk, //OLCD时钟信号
output oled_dat //OLCD数据信号
);
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 = 1; // 0: DIRECT: Analog input directly connected to + input of comparitor
这是例化一个sigmadelta_adc的程序实现模拟电压的采集。
sigmadelta_adc #(
.ADC_WIDTH(ADC_WIDTH),
.ACCUM_BITS(ACCUM_BITS),
.LPF_DEPTH_BITS(LPF_DEPTH_BITS)
)
SSD_ADC(
.clk(clk),
.rstn(rstn),
.analog_cmp(analog_cmp),
.digital_out(digital_out_i),
.analog_out(analog_out_i),
.sample_rdy(sample_rdy_i)
);
这是例化一个bin2num的程序实现转码。
wire [15:0] bin_code = digital_out_i * 16'd130;
wire [19:0] bcd_code;
bin2num bin2bcd_u1(
.rst_n (rstn),
.bin_code (bin_code),
.bcd_code (bcd_code)
);
这是驱动OLED屏幕显示电压值。
OLED12864 OLED( //OLED显示模块
.clk(clk_in),
.rst_n(rstn),
.data(bcd_code[19:12]), //输入键值
.oled_csn(oled_csn),
.oled_rst(oled_rst),
.oled_dcn(oled_dcn),
.oled_clk(oled_clk),
.oled_dat(oled_dat)
);
六遇到的主要难题及解决方法
第一个问题是模拟电路基础不扎实,很多年前学过的模拟电路基础基本上忘光了,所以比较器那边找来了一些资料仔细研究了半天,才把FPGA加比较器实现简易的Sigma Delta ADC的原理看了个大概,好在莱迪思官网提供了比较详细的代码和介绍,因此最终实现了这个数字电压表。
第二个问题就是Verilog编程以及FPGA的并行处理需要一定的基础和思维才能适应这次开发,因此主要通过请教和自学一些基础知识才能实现这次开发。
第三个问题,保管不善,回家的路上可能由于颠簸导致OLED屏幕坏了,自己打算更换一个oled屏幕,结果把电路板都搞废了,没办法让同学帮忙做了验证。
七未来的计划或建议
通过这此寒假活动,学习了模拟电路的基础,初步掌握了Verilog编程和FPGA的并行处理,后续还需要进一步打牢基础,继续用这块板子学习Verilog编程和FPGA开发。
去年通过Funpack和寒假活动,接触到了很多的硬件软件开发知识,开拓了视野,增加了见识,对于嵌入式开发来说,我这个业余爱好者还有很多需要学习的地方,尤其是嵌入式的硬件软件发展很迅速,尤其是在这个物联网的时代,人工智能的时代,嵌入式必将大有作为,希望硬禾学堂继续开发新的嵌入式开发平台,在这些活动中把嵌入式培训教育办的越来越好!