Intel FPGA (7):adc adc128s102

Intel FPGA (7):adc adc128s102

前提摘要

  1. 个人说明:

    • 限于时间紧迫以及作者水平有限,本文错误、疏漏之处恐不在少数,恳请读者批评指正。意见请留言或者发送邮件至:“Email:noahpanzzz@gmail.com”
    • 本博客的工程文件均存放在:GitHub:https://github.com/panziping。
    • 本博客的地址:CSDN:https://blog.csdn.net/ZipingPan
  2. 参考:

    • 芯片型号:Intel EP4CE10F17C8(Cyclone IV E)
    • 《数字电子技术基础》-阎石
    • 《FPGA自学笔记—设计与验证》袁玉卓,曾凯锋,梅雪松
    • 《Verilog 数字系统设计教程》夏宇闻
    • 《Verilog HDL 高级数字设计》Michael D.Ciletti
    • 《Intel FPGA/CPLD设计》(基础篇)王欣 王江宏等
    • 《Intel FPGA/CPLD设计》(高级篇)王江宏 蔡海宁等
    • 《综合与时序分析的设计约束 Synopsys设计约束(SDC)实用指南》Sridhar Gangadharan
  3. 日期:

    • 2024-01-01

正文

模数转换器(英语:analog to Digital converter,英文缩写:ADC)是一种将模拟信号(例如麦克风拾取的声音或进入数码相机的光线)转换为数字信号的系统。

SPS(sample per second,每秒采样次数),是衡量模数转换(ADC)时采样速率的单位。采样率定义为对输入信号输入信的采样频率,采样率不仅表示模数转换器的转换速度,同时也决定了系统可处理信号的带宽范围。

比如这款ADC芯片adc128s102,使用的是SPI进行传输,完整传输一次数据所需要花费的时间是16个sclk周期。

这里假设sclk的时钟频率为8MHz
一次采样周期 = 16 ∗ 1 f s c l k = 16 ∗ 125 n s = 2000 n s S P S = 1 s 2000 n s = 500000 = 500 K S P S 一次采样周期=16*\frac{1}{f_{sclk}}=16*125ns = 2000ns\\ SPS = \frac{1 s}{2000 ns} = 500 000 = 500KSPS 一次采样周期=16fsclk1=16125ns=2000nsSPS=2000ns1s=500000=500KSPS
本篇采用的ADC芯片是adc128s102。这是一款8通道,500KSPS到1MSPS,12bit的ADC。

硬件电路

在这里插入图片描述

ADC128S102

这里截取了AC128S102的部分数据手册,读者自行阅读。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

ADC为12位分辨率,因此1bit代表的电压值为 V A V_{A} VA/4096。当模拟输入电压低于 V A V_{A} VA/8192时,输出数据为0000_0000_0000b。同理由于芯片本身内部构造当输出数据0000_0000_0000b变为0000_0000_0001b时,实际输入电压变化为 V A V_{A} VA/8192而不是 V A V_{A} VA/4096。当输入电压大于或等于 V A V_{A} VA-1.5 V A V_{A} VA/4096时,输出数据即为1111_1111_1111b。*

代码展示

adc128s102底层驱动代码:

module adc128s102_driver(clk,rst_n,adc_addr,adc_convert_en_go,adc_cs_n,adc_sclk,adc_dout,adc_din,adc_convert_busy,adc_data,adc_data_convert_valid_go
);input clk;input rst_n;input [2:0] adc_addr;input adc_convert_en_go;output adc_cs_n;output adc_sclk;input  adc_dout;output adc_din;output adc_convert_busy;output [11:0] adc_data;output adc_data_convert_valid_go;reg [2:0] r_adc_addr;always@(posedge clk or negedge rst_n) beginif(!rst_n)r_adc_addr <= 3'd0;else if(adc_convert_en_go == 1'b1)r_adc_addr <= adc_addr;elser_adc_addr <= r_adc_addr;endreg r_adc_convert_en;wire w_adc_convert_end;always@(posedge clk or negedge rst_n) beginif(!rst_n)r_adc_convert_en <= 1'b0;else if(adc_convert_en_go == 1'b1)r_adc_convert_en <= 1'b1;else if(w_adc_convert_end == 1'b1)r_adc_convert_en <= 1'b0;elser_adc_convert_en <= r_adc_convert_en;endassign adc_convert_busy = r_adc_convert_en;localparam SYSCLK = 50_000_000;localparam SPI_CLK = 6_250_000;localparam SPI_CLK_DR = SYSCLK / SPI_CLK;reg [$clog2(SPI_CLK_DR)-1:0] r_div_cnt;always@(posedge clk or negedge rst_n) beginif(!rst_n)r_div_cnt <= 'd0;else if(r_adc_convert_en == 1'b1) beginif(r_div_cnt == SPI_CLK_DR - 1'b1)r_div_cnt <= 'd0;elser_div_cnt <= r_div_cnt + 1'b1;endelser_div_cnt <= 'd0;endwire w_sclk_pluse;assign w_sclk_pluse = (r_div_cnt == 'd1) ? 1'b1 : 1'b0; reg [5:0] r_bit_cnt;always@(posedge clk or negedge rst_n) beginif(!rst_n)r_bit_cnt <= 6'd0;else if(r_adc_convert_en == 1'b1) beginif(w_sclk_pluse == 1'b1)r_bit_cnt <= r_bit_cnt + 1'b1;elser_bit_cnt <= r_bit_cnt;endelser_bit_cnt <= 6'd0;endassign w_adc_convert_end = (r_bit_cnt == 6'd35) ? 1'b1 : 1'b0;//fpga negedge output addr data,adc posedge collect addr data//fpga posedge collect adc data,adc negedge output adc datareg r_adc_cs_n;reg [11:0] r_adc_data;reg r_adc_sclk;reg r_adc_din;always@(posedge clk or negedge rst_n) beginif(!rst_n) beginr_adc_data <= 12'd0;r_adc_cs_n <= 1'd1;r_adc_sclk <= 1'b1;r_adc_din <= 1'b1;endelse begincase(r_bit_cnt)6'd0: begin r_adc_cs_n <= 1'b1; r_adc_sclk <= 1'b1; r_adc_din <= 1'b1; end6'd1: begin r_adc_cs_n <= 1'b0; r_adc_sclk <= 1'b1; r_adc_din <= 1'b1; end6'd2: begin r_adc_sclk <= 1'b0; r_adc_din <= 1'b1; end6'd3: begin r_adc_sclk <= 1'b1; r_adc_din <= 1'b1; end6'd4: begin r_adc_sclk <= 1'b0; r_adc_din <= 1'b1; end6'd5: begin r_adc_sclk <= 1'b1; r_adc_din <= 1'b1; end6'd6: begin r_adc_sclk <= 1'b0; r_adc_din <= r_adc_addr[2]; end6'd7: begin r_adc_sclk <= 1'b1; end6'd8: begin r_adc_sclk <= 1'b0; r_adc_din <= r_adc_addr[1]; end6'd9: begin r_adc_sclk <= 1'b1; end	6'd10: begin r_adc_sclk <= 1'b0; r_adc_din <= r_adc_addr[0]; end6'd11: begin r_adc_sclk <= 1'b1; r_adc_data[11] <= adc_dout; end6'd12: begin r_adc_sclk <= 1'b0; end6'd13: begin r_adc_sclk <= 1'b1; r_adc_data[10] <= adc_dout; end		6'd14: begin r_adc_sclk <= 1'b0; end6'd15: begin r_adc_sclk <= 1'b1; r_adc_data[9] <= adc_dout; end	6'd16: begin r_adc_sclk <= 1'b0; end6'd17: begin r_adc_sclk <= 1'b1; r_adc_data[8] <= adc_dout; end	6'd18: begin r_adc_sclk <= 1'b0; end6'd19: begin r_adc_sclk <= 1'b1; r_adc_data[7] <= adc_dout; end				6'd20: begin r_adc_sclk <= 1'b0; end6'd21: begin r_adc_sclk <= 1'b1; r_adc_data[6] <= adc_dout; end			6'd22: begin r_adc_sclk <= 1'b0; end6'd23: begin r_adc_sclk <= 1'b1; r_adc_data[5] <= adc_dout; end			6'd24: begin r_adc_sclk <= 1'b0; end6'd25: begin r_adc_sclk <= 1'b1; r_adc_data[4] <= adc_dout; end				6'd26: begin r_adc_sclk <= 1'b0; end6'd27: begin r_adc_sclk <= 1'b1; r_adc_data[3] <= adc_dout; end			6'd28: begin r_adc_sclk <= 1'b0; end6'd29: begin r_adc_sclk <= 1'b1; r_adc_data[2] <= adc_dout; end	6'd30: begin r_adc_sclk <= 1'b0; end6'd31: begin r_adc_sclk <= 1'b1; r_adc_data[1] <= adc_dout; end		6'd32: begin r_adc_sclk <= 1'b0; end6'd33: begin r_adc_sclk <= 1'b1; r_adc_data[0] <= adc_dout; end	6'd34: begin r_adc_cs_n <= 1'b1; r_adc_sclk <= 1'b1; r_adc_din <= 1'b1;end	6'd35: begin r_adc_cs_n <= 1'b1; r_adc_sclk <= 1'b1; r_adc_din <= 1'b1;end		default:begin r_adc_cs_n <= 1'd1;r_adc_sclk <= 1'b1; r_adc_din <= 1'b1;endendcaseendendassign adc_cs_n = r_adc_cs_n;assign adc_sclk = r_adc_sclk;assign adc_din = r_adc_din;assign adc_data = r_adc_data;reg r_adc_data_valid_go;always@(posedge clk or negedge rst_n) beginif(!rst_n)r_adc_data_valid_go <= 1'b0;else if(r_bit_cnt == 6'd34 && r_div_cnt == SPI_CLK_DR - 1'b1) r_adc_data_valid_go <= 1'b1;elser_adc_data_valid_go <= 1'b0;endassign adc_data_convert_valid_go = r_adc_data_valid_go;endmodule

ADC控制代码:

module adc_ctrl(clk,rst_n,adc_addr,key_press_valid_go,adc_cs_n,adc_sclk,adc_dout,adc_din,adc_data,adc_data_valid_go
);input 			clk;input 			rst_n;input 			key_press_valid_go;input [2:0]		adc_addr;output 			adc_cs_n;output 			adc_sclk;input  			adc_dout;output 			adc_din;output [11:0] adc_data;output 		  adc_data_valid_go;wire w_adc_convert_en_go;wire w_adc_convert_busy;wire [11:0] w_adc_data;wire w_adc_data_convert_valid_go;
adc128s102_driver adc_driver(.clk(clk),.rst_n(rst_n),.adc_addr(adc_addr),.adc_convert_en_go(w_adc_convert_en_go),.adc_cs_n(adc_cs_n),.adc_sclk(adc_sclk),.adc_dout(adc_dout),.adc_din(adc_din),.adc_convert_busy(w_adc_convert_busy),.adc_data(w_adc_data),.adc_data_convert_valid_go(w_adc_data_convert_valid_go)
);reg [1:0]r_adc_convert_busy_sync;//wire w_adc_convert_busy_pedge;wire w_adc_convert_busy_nedge;always@(posedge clk or negedge rst_n) beginif(!rst_n)r_adc_convert_busy_sync <= 2'd0;elser_adc_convert_busy_sync <= {r_adc_convert_busy_sync[0],w_adc_convert_busy};end//assign w_adc_convert_busy_pedge = (r_adc_convert_busy_sync == 2'b01) ? 1'b1 : 1'b0;assign w_adc_convert_busy_nedge = (r_adc_convert_busy_sync == 2'b10) ? 1'b1 : 1'b0; localparam ADC_COLLECT_TIMES = 100;localparam S_IDLE  	= 4'b0001;localparam S_START 	= 4'b0010;localparam S_SAMPLE = 4'b0100;localparam S_DONE 	= 4'b1000;reg [3:0] r_current_state;reg [3:0] r_next_state;reg [$clog2(ADC_COLLECT_TIMES)-1:0] r_sample_cnt;always@(posedge clk or negedge rst_n) beginif(!rst_n)r_current_state <= S_IDLE;elser_current_state <= r_next_state;endalways@(*) begincase(r_current_state)S_IDLE: beginif(key_press_valid_go == 1'b1)r_next_state = S_START;elser_next_state = S_IDLE;endS_START: beginif(w_adc_data_convert_valid_go == 1'b1)r_next_state = S_SAMPLE;elser_next_state = S_START;endS_SAMPLE: beginif(r_sample_cnt == ADC_COLLECT_TIMES)r_next_state = S_DONE;elser_next_state = S_SAMPLE;endS_DONE: beginif(w_adc_convert_busy_nedge == 1'b1)r_next_state = S_IDLE;elser_next_state = S_DONE;enddefault: r_next_state = S_IDLE;endcaseendalways@(posedge clk or negedge rst_n) beginif(!rst_n)r_sample_cnt <= 'd0;else if(r_current_state == S_SAMPLE) beginif(w_adc_data_convert_valid_go == 1)r_sample_cnt <= r_sample_cnt + 1'b1;elser_sample_cnt <= r_sample_cnt;endelser_sample_cnt <= 'd0;endreg r_adc_convert_en_go;always@(posedge clk or negedge rst_n) beginif(!rst_n)r_adc_convert_en_go <= 1'b0;else if(r_current_state == S_IDLE && r_next_state == S_START)r_adc_convert_en_go <= 1'b1;else if(r_current_state == S_SAMPLE && w_adc_convert_busy_nedge == 1'b1)r_adc_convert_en_go <= 1'b1;elser_adc_convert_en_go <= 1'b0;endassign w_adc_convert_en_go = r_adc_convert_en_go;reg r_adc_data_valid_go;always@(posedge clk or negedge rst_n) beginif(!rst_n) beginr_adc_data_valid_go <= 'd0;endelse if(r_current_state == S_SAMPLE && w_adc_data_convert_valid_go == 1 'b1)r_adc_data_valid_go <= 1'b1;elser_adc_data_valid_go <= 1'b0;endassign adc_data_valid_go = r_adc_data_valid_go;assign adc_data = w_adc_data;endmodule

ADC控制代码有几点需要注意:

  1. adc128s102在输入地址之后,adc输出的数据并不是当前地址通道的数据,而是在下一次输入地址之后得到想要的数据。所以状态机中START跳转到SAMPLE的条件是第一次转换完成脉冲信号(脉冲信号的宽度必须是一个时钟周期!!!)。那么在SAMPLE状态中就能得到想要的数据。

总结

本文后续将AD采集到数据通过uart输出。具体工程为adda,如有需要请至github仓库查看!!!


本文均为原创,欢迎转载,请注明文章出处:CSDN:https://blog.csdn.net/ZipingPan。百度和各类采集站皆不可信,搜索请谨慎鉴别。技术类文章一般都有时效性,本人习惯不定期对自己的博文进行修正和更新,因此请访问出处以查看本文的最新版本。

非原创博客会在文末标注出处,由于时效原因,可能并不是原创作者地址(已经无法溯源)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/786480.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用Python实现办公自动化(自动化处理PDF文件)

自动化处理 PDF 文件 目录 自动化处理 PDF 文件 谷歌浏览器 Chrome与浏览器驱动ChromeDriver安装 &#xff08;一&#xff09;批量下载 PDF 文件 1.使用Selenium模块爬取多页内容 2.使用Selenium模块下载PDF文件 3.使用urllib模块来进行网页的下载和保存 4.使用urllib…

关于OcenaBase v4.2中,分区转移和负载均衡的技术解读

OceanBase​​​​​​​​​​​​​​作为一款原生分布式数据库&#xff0c;其核心的技术特性之一是高可扩展性&#xff0c;其具体表现在两个方面&#xff1a; 首先&#xff0c;是灵活的扩缩容能力&#xff0c;包括垂直扩缩容和水平扩缩容&#xff1a; 垂直扩缩容&#xff…

神经网络汇聚层

文章目录 最大汇聚层平均汇聚层自适应平均池化层 最大汇聚层 汇聚窗口从输入张量的左上角开始&#xff0c;从左往右、从上往下的在输入张量内滑动。在汇聚窗口到达的每个位置&#xff0c;它计算该窗口中输入子张量的最大值或平均值。计算最大值或平均值是取决于使用了最大汇聚…

RISC-V/ARM mcu OpenOCD 调试架构解析

Risc-v/ARM mcu OpenOCD 调试架构解析 最近有使用到risc-v的单片机&#xff0c;所以了解了下risc-v单片机的编译与调试环境的搭建&#xff0c;面试时问到risc-v的调试可参看以下内容。 risc-v根据官方的推荐&#xff0c;调试器服务是选择OpenOCD&#xff0c;DopenOCD(开放片上…

Python反爬案例——验证码的识别

验证码的识别 使用打码平台识别验证码 利用打码平台可以轻松识别各种各样的验证码&#xff0c;图形验证码、滑动验证码、点选验证码和逻辑推理验证码。打码平台提供了一系列API&#xff0c;只需要向API上传验证码图片&#xff0c;它便会返回对应的识别结果。 使用超级鹰平台…

深入理解指针1:指针变量、指针运算、野指针、const修饰指针

生活中我们把门牌号也叫地址&#xff0c;在计算机中我们把内存单元的编号也称为地址。C语⾔中给地址起 了新的名字叫&#xff1a;指针。 所以我们可以理解为&#xff1a;内存单元的编号地址指针 1、指针变量 我们知道的是&#xff1a;数组名是数组首元素的地址。也就是说&…

中断服务程序模板

通常定时器初始化过程如下: ①对 TMOD赋值,以确定TO和T1的工作方式。 ②计算初值,并将初值写入THO、TLO或TH1、TL1。 ③中断方式时&#xff0c;则对IE赋值&#xff0c;开放中断。 ④使TRO或TR1置位&#xff0c;启动定时器/计数器定时或计数。 代码 利用定时器0工作方式1&…

轻松设置Facebook自动隐藏评论和删除评论功能

Facebook作为海外营销的最大流量平台之一&#xff0c;是很多跨境卖家争夺的市场&#xff0c;希望可以通过Facebook这个全球性的平台来推广自己的产品或服务。身处这个竞争激烈的市场&#xff0c;任何一条负面评论或不当言论出现在你的品牌页面上都可能影响到品牌形象&#xff0…

臻奶惠无人售货机:新零售时代的便捷消费革命

臻奶惠无人售货机&#xff1a;新零售时代的便捷消费革命 在新零售的浪潮中&#xff0c;智能无人售货机作为一个创新的消费模式&#xff0c;已经成为距离消费者最近的便捷购物点之一。这种模式不仅能够满足居民对消费升级的需求&#xff0c;还能通过建立多样化和多层次的消费体…

k8s练习-创建一个Deployment

创建Deployment 创建一个nginx deployment [rootk8s-master home]# cat nginx-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata:name: nginx-deployment spec:selector:matchLabels:app: nginx # 配置pod的labelsreplicas: 2 # 声明2个副本template:metada…

spring boot自动配置原理-怎样回答这个问题

首先我们说一下自动配置的概念。 自动配置&#xff1a;遵循约定大约配置的原则&#xff0c;在boot程序启动后&#xff0c;起步依赖中的一些bean对象会自动注入到ioc容器 例子 程序引入spring-boot-starter-web 起步依赖&#xff0c;启动后&#xff0c;会自动往ioc容器中注入…

记一次 pdfplumber 内存泄漏导致的服务器宕机

有一个项目需求&#xff0c;要在每天凌晨5点的时候执行一个任务&#xff0c;获取一系列的PDF文件并解析。 后端是Django框架&#xff0c;定时任务用Celery来实现的。 本地跑没什么问题&#xff0c;但是一放到服务器上跑就会宕机&#xff0c;而且是毫无征兆的宕机&#xff0c;…

黑马HTMLCSS基础

黑马的笔记和资料都是提供好了的&#xff0c;这个文档非常适合回顾复习。我在黑马提供的笔记上做了一些微不足道的补充&#xff0c;以便自己复习查阅。该笔记比较重要的部分是 表单&#xff0c;http请求 第一章. HTML 与 CSS HTML 是什么&#xff1a;即 HyperText Markup lan…

使用虚拟引擎为AR体验提供动力

Powering AR Experiences with Unreal Engine ​​​​​​​ 目录 1. 虚拟引擎概述 2. 虚拟引擎如何为AR体验提供动力 3. 虚拟引擎中AR体验的组成部分是什么&#xff1f; 4. 使用虚拟引擎创建AR体验 5. 虚拟引擎中AR的优化提示 6. 将互动性融入AR与虚拟引擎 7. 在AR中…

5G PLMN相关概念

PLMN PLMN&#xff08;Public Land Mobile Network&#xff0c;公用陆地移动网络&#xff09;&#xff0c;是由政府或其批准的经营者为公众提供陆地移动通信业务而建立、经营的网络。PLMN与公众交换电话网&#xff08;PSTN&#xff09;互连&#xff0c;形成整个地区或国家规模…

AR和VR如何改变客户体验?

How AR and VR are transforming customer experiences&#xff1f; How AR and VR are transforming customer experiences AR和VR如何改变客户体验 AR and VR technology was largely expedited by the past pandemic with at least 93.3 million and 58.9 million users r…

运筹学经典问题(八):CVRP和VRP-TW

文章目录 问题描述问题建模决策变量数学建模基于容量的消除子环的约束 &#xff08;load-based SECs&#xff09; CVRP完整的数学模型加上时间窗限制的CVRP 问题描述 给定一个图&#xff0c;图上的点代表客户&#xff0c;边代表客户之间的路线&#xff0c;边的权重代表客户之间…

Day60:WEB攻防-XMLXXE安全无回显方案OOB盲注DTD外部实体黑白盒挖掘

目录 XML&XXE-传输-原理&探针&利用&玩法 XXE 黑盒发现 XXE 白盒发现 XXE修复防御方案 有回显 无回显 XML&XXE-黑盒-JSON&黑盒测试&类型修改 XML&XXE-白盒-CMS&PHPSHE&无回显 知识点&#xff1a; 1、XXE&XML-原理-用途&…

MATLAB绘制堆叠填充图--巧用句柄

MATLAB绘制堆叠填充图–巧用句柄 目录 MATLAB绘制堆叠填充图--巧用句柄1. 主要原理讲解1.1 主要函数1.2 句柄原理 2. 绘图示例2.1 准备数据2.2 绘制堆叠填充图-使用句柄控制图形属性2.3 设置填充颜色和样式2.4 添加标题和标签2.5 绘图效果 3. 结语 堆叠填充图是一种常见的数据可…

政安晨:【Keras机器学习实践要点】(十三)—— 利用 TensorFlow 进行多 GPU 分布式训练

目录 前言 设置 单主机、多设备同步培训 工作原理 如何使用 使用回调确保容错 tf.data 性能提示 数据集批处理注意事项 调用 dataset.cache() 调用 dataset.prefetch(buffer_size) 政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏:…