FPGA初级项目9——基于SPI的ADC芯片进行模数转换

server/2025/3/16 22:30:45/

FPGA初级项目9——基于SPI的ADC芯片进行模数转换

ADC芯片介绍


ADC(Analog-to-Digital Converter)芯片是一种将连续变化的模拟信号转换为离散数字信号的电子器件,广泛应用于电子系统中,是连接现实世界与数字世界的桥梁。可将电压、电流等模拟量转换为二进制数字信号,供计算机、微控制器等数字设备处理。

关键参数


分辨率:以位数表示(如 12 位、16 位)表示将一个模拟量转换为多少位的数字量,例如8位分辨率可表示的范围为0~255(十进制)。
采样率:每秒转换的样本数(单位 Hz),需满足 Nyquist 定理(至少 2 倍信号最高频率)。
转换精度:实际输出与理论值的偏差,受噪声、非线性等因素影响。
输入范围:可转换的模拟信号电压范围(如 0~5V、±10V)。
功耗:低功耗设计适用于电池供电设备
 


SPI 协议基础


SPI(Serial Peripheral Interface,串行外设接口)是一种高速、全双工、同步的通信协议(是一种规则),广泛用于微控制器(如 Arduino、STM32)与外设(如 ADC、传感器、存储器)之间的短距离通信。


SPI由来

SPI最初由摩托罗拉(现 NXP)于 1980 年代开发,并未通过 ISO、IEEE 等国际组织的正式认证。但由于其简单高效,逐渐成为事实上的工业标准,被全球半导体厂商(如 ADI、TI、Microchip)广泛支持主流 MCU(如 Arduino、STM32、ESP32)均内置硬件 SPI 控制器,且 ADC、传感器等外设芯片的 SPI 接口严格遵循摩托罗拉定义的时序规则。这种生态共识使 SPI 成为嵌入式领域的 “通用语言”。

SPI参数

主从架构:一个主设备(如 MCU或FPGA)控制多个从设备(如 ADC 芯片)。
四线通信
SCK(时钟线):主设备发送时钟信号,同步数据传输。
MOSI(主出从入):主设备向从设备发送数据。
MISO(主入从出):从设备向主设备返回数据。
CS(片选线):主设备通过拉低特定从设备的 CS 线选择目标。
高速传输:支持兆赫兹级速率(如 STM32 可达 42MHz),适合高频数据场景。
全双工:数据可同时双向传输。

SPI规则


SPI怎么用,需要自己编写吗?

需要强调的是:是否需要自己编写 SPI 逻辑代码,取决于你使用的开发环境、硬件平台以及具体需求。
1. 有些较为基础、低成本的微控制器可能没有内置 SPI 硬件模块,例如一些简单的 8 位单片机。在这种情况下,你只能通过软件来模拟 SPI 的通信逻辑,也就是自己编写代码来控制通用输入输出引脚(GPIO),模拟时钟信号(SCK)、数据传输(MOSI 和 MISO)以及片选信号(CS)的时序。
2. 当你有特殊的通信需求,比如需要修改 SPI 的通信时序、协议格式,或者实现一些自定义的通信规则时,就可能需要自己编写 SPI 逻辑代码。例如,你可能需要调整时钟极性(CPOL)和时钟相位(CPHA)来满足特定 ADC 芯片的通信要求。
3. 大多数现代微控制器,如常见的 STM32 系列、Arduino 的部分型号等,都内置了 SPI 硬件外设。这些硬件外设可以直接配置和使用,芯片厂商通常会提供相应的库函数来简化 SPI 通信的操作。



工作原理


ADC 芯片通过 SPI 接口接收主设备的控制指令(如启动转换、配置参数),并将转换后的数字信号通过 SPI 返回给主设备。我们需要完成的任务即ADC芯片的驱动逻辑,依照芯片手册实现其逻辑代码编写(严格遵循SPI协议)。

问题分析


1. 我们需要编写的是芯片ADC128S102的驱动逻辑,有4个主要端口:cs_n(片选端); sclk(ADC芯片时钟); DIN(模拟量输入端口); DOUT(数字量输出端口); 根据芯片手册要满足其时序要求。其中SCLK频率为12.5HZ。


 

2. 我们依旧使用线性序列机(LSM)的思想来定义每个时刻该做的事情。以SCLK半个周期为最小时间单元。DOUT端口靠ADC芯片来驱动,FPGA端来接收。每个输出的数据信号在SCLK下降沿改变,同时FPGA在SCLK上升沿读取(此时信号已稳定);而DIN信号决定ADC芯片的哪个通道输入,在SCLK下降沿FPGA将信号输入到ADC芯片。详细参数可参照文末代码!

3. 同时还有一些额外的端口需要设置,例如用户的通道选择输入端口[2:0]addr(因ADC芯片有8个选择输入端口,所以需要3位来表示);数字数据输出端口[11:0](因芯片为12位分辨率);采样信号(决定什么时候采样)与采样完成信号端口的设置等。

4. 根据芯片时序手册,处理完一轮数据周期需要35个时钟,所以counter1的计数最大值为35,即需要6位二进制数来表示,所以为[5:0]counter1。ADC芯片的电路结构如下所示可作为了解,但是我们需要再次强调我们所写的是该芯片的驱动电路!!!

好的分析完上述问题,我们上代码


代码展示

//定义输入输出端口
module ADC_driver(clk,reset_n,conv_go,//采样请求信号addr,//用户输入选择通道端口conv_done,//采样完成信号data,//已经转换完成的数字信号sclk,cs_n,DOUT,DIN);input clk;input reset_n;input conv_go;input [2:0]addr;output reg conv_done;output reg [11:0]data;output reg sclk;output reg cs_n;output reg DIN;input DOUT;//定义相关时钟参数parameter clock_freq = 50_000_000;parameter sclk_freq = 12_500_000;//ADC芯片SCLK频率parameter mcnt = clock_freq / (sclk_freq * 2) - 1;//定义最小时间单元counter0reg en_counter0;reg [7:0]counter0;
always@(posedge clk or negedge reset_n)
if(!reset_n)counter0 <= 0;
else if(en_counter0) beginif(counter0 == mcnt)counter0 <= 0;else counter0 <= counter0 +1'd1;end
elsecounter0 <= 0;//定义位计数器counter1reg [5:0]counter1;
always@(posedge clk or negedge reset_n)
if(!reset_n)counter1 <= 6'd0;
else if(counter0 == mcnt) beginif(counter1 == 6'd34)//处理完一轮数据需要35个周期时钟counter1 <= 6'd0;elsecounter1 <= counter1 + 1'd1;end
elsecounter1 <= counter1;//定义存储器,防止数据发生变化reg [2:0]r_addr;
always@(posedge clk)
if(conv_go)r_addr <= addr;
elser_addr <= r_addr;//定义数据处理完成信号与处理后的数据存贮reg [11:0]data_r;
always@(posedge clk or negedge reset_n)
if(!reset_n) begindata <= 12'd0;conv_done <= 0;end
else if((counter1 == 34)&&(counter0 == mcnt)) begindata <= data_r;conv_done <= 1'd1;end
else begindata <= data;conv_done <= 0;end//定义使能信号en_counter0
always@(posedge clk or negedge reset_n)
if(!reset_n) en_counter0 <= 1'd0;
else if(conv_go)en_counter0 <= 1'd1;
else if((counter1 == 34)&&(counter0 == mcnt))en_counter0 <= 1'd0;
elseen_counter0 <= en_counter0;               //定义每个时间点的操作,按照时序图来填表即可
always@(posedge clk or negedge reset_n)
if(!reset_n)begindata_r <= 12'd0;sclk <= 1'd1;DIN <= 1'd1;cs_n <= 1'd1;end
else if(counter0 == mcnt)begincase(counter1)0:begin cs_n <= 1'd1; sclk <= 1'd1; end1:begin sclk <= 1'd0; end2:begin sclk <= 1'd0; end3:begin sclk <= 1'd1; end4:begin sclk <= 1'd0; end5:begin sclk <= 1'd1; end6:begin sclk <= 1'd0; DIN <= r_addr[2];end7:begin sclk <= 1'd1; end8:begin sclk <= 1'd0; DIN <= r_addr[21];end9:begin sclk <= 1'd1; end10:begin sclk <= 1'd0; DIN <= r_addr[0];end11:begin sclk <= 1'd1; data_r[11] <= DOUT;end12:begin sclk <= 1'd0; end13:begin sclk <= 1'd1; data_r[10] <= DOUT;end14:begin sclk <= 1'd0; end15:begin sclk <= 1'd1; data_r[9] <= DOUT;end16:begin sclk <= 1'd0; end17:begin sclk <= 1'd1; data_r[8] <= DOUT;end18:begin sclk <= 1'd0; end19:begin sclk <= 1'd1; data_r[7] <= DOUT;end20:begin sclk <= 1'd0; end21:begin sclk <= 1'd1; data_r[6] <= DOUT;end22:begin sclk <= 1'd0; end23:begin sclk <= 1'd1; data_r[5] <= DOUT;end24:begin sclk <= 1'd0; end25:begin sclk <= 1'd1; data_r[4] <= DOUT;end26:begin sclk <= 1'd0; end27:begin sclk <= 1'd1; data_r[3] <= DOUT;end28:begin sclk <= 1'd0; end29:begin sclk <= 1'd1; data_r[2] <= DOUT;end30:begin sclk <= 1'd0; end31:begin sclk <= 1'd1; data_r[1] <= DOUT;end32:begin sclk <= 1'd0; end33:begin sclk <= 1'd1; data_r[0] <= DOUT;end34:begin sclk <= 1'd0; enddefault: cs_n <= 1'd1;endcase
endendmodule


综合出来的底层系统逻辑图schematic如下:
 


http://www.ppmy.cn/server/175540.html

相关文章

骑士74CMS_v3.34.0SE版uniapp全开源小程序怎么编译admin和member流程一篇文章说清楚

有粉丝一直问我骑士系统怎么编译后台和小程序目前骑士人才系统74CMS分标准版&#xff0c;创业板&#xff0c;专业版&#xff0c;其除功能不同外其配置方法完全一致有喜欢系统的也可以私信我或者找我获取 一.安装打包环境[Nodejs]这个就不用我说了吧&#xff0c;用不小于V20的版…

hadoop集群配置-scp的使用

1.推送。在hadoop100机器上&#xff0c;把文件推送到hadoop101机器上 在101和102中新建文件夹 在100中输入命令将jdk拷贝到101中 scp -r jdk1.8.0_212/ roothadoop101:/opt/module 用同样的方法拷贝hadoop scp -r hadoop-3.1.3/ roothadoop101:/opt/module 2.拉取。在hadoop1…

零信任架构实战手册-企业安全升级

🔐 开篇痛点暴击: “又被黑客钓鱼了?VPN漏洞补到心累?😫” 传统边界安全像纸糊的墙,内鬼渗透、APT攻击防不胜防! 别慌!零信任架构(Zero Trust)用「永不信任,持续验证」原则,让安全等级飙升10倍! 🚦 零信任3大核心武器(附实操步骤): 1. 🌟 身份即边界!抛…

玩转python:通俗易懂掌握高级数据结构-collections模块之ChainMap

引言 ChainMap是Python中collections模块提供的一个强大工具&#xff0c;用于将多个字典或映射合并为一个逻辑视图。它允许我们在不修改原始字典的情况下&#xff0c;对多个字典进行统一的查找和操作。ChainMap非常适合用于配置管理、多层作用域模拟等场景。本文将详细介绍Cha…

vue3实现跨页面缓存

避免频繁向后端发送请求,vue3中,可以用缓存机制,为了实现跨页面缓存,可以把缓存放到localsotrage里面 关键代码: const globalCache JSON.parse(localStorage.getItem(globalCache)) || {}; 然后加一个forceRefresh关键字, const fetchData async (forceRefresh false) …

Spring Boot集成HikariCP:原理剖析与实战指南

一、HikariCP连接池的底层实现剖析 1. 连接池核心数据结构 HikariCP的核心数据结构采用ConcurrentBag与FastList实现高性能并发管理&#xff1a; &#xff08;1&#xff09;ConcurrentBag 无锁设计&#xff1a;通过ThreadLocal缓存和CopyOnWriteArrayList实现高并发下的高效…

3.12-1 html讲解

一、html介绍 1、定义&#xff1a;一个超文本标记语言&#xff0c;不是一种编程性语言 2、标记&#xff1a;记号&#xff08;绰号&#xff09; 3、超文本&#xff1a;就是页面内容包含图片、链接、音乐、视频等素材 4、为什么学习html&#xff1f;a测试页面功能&#xff0c…

Microsoft Dragon Copilot:医疗AI革命开启,用语音终结手写病历时代

微软正式发布全球首个医疗行业一体化语音AI助手Microsoft Dragon Copilot,标志着临床工作流程正式迈入“人机协作”新时代。这款工具通过语音+文本混合架构,将医生口述内容实时转化为结构化病历,并深度整合电子健康记录(EHR)系统,彻底颠覆了传统手写病历模式。根据微软官…