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

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

DAC芯片介绍


DAC 芯片(数字模拟转换器)是一种将数字信号转换为连续模拟信号(如电压或电流)的集成电路,广泛应用于电子系统中,连接数字世界与模拟世界。
 

核心功能


数字到模拟转换:将离散的二进制数字信号(如 0 和 1 的组合)转换为连续的模拟信号,使计算机、微控制器等数字设备能够驱动扬声器、显示器、传感器等模拟设备。
应用领域:音频处理(音乐播放器、手机)、视频显示(CRT 显示器)、通信系统(无线信号调制)、工业控制(执行器驱动)等。

关键性能指标


需要明确:输出电压由参考电压决定,输入的数字量起到一个分压作用。
分辨率:表示 DAC 能区分的最小电压变化,通常以位数衡量(如 16 位、24 位)。位数越高,输出越精细。
精度:包括微分非线性(DNL)和积分非线性(INL),反映输出与理想值的偏差,精度越高,信号失真越小。
建立时间:从输入变化到输出稳定所需的时间,高速应用(如通信)需短建立时间。
动态范围:最大信号与噪声的比值,决定 DAC 处理强弱信号的能力(单位:dB)。

典型应用场景


音频设备:如手机、耳机、Hi-Fi 播放器中的 DAC 芯片(如 AK4490、CS43131),直接影响音质。
工业控制:将数字指令转换为模拟信号控制电机、阀门等执行器(如 DAC0832)。
通信系统:生成调制信号用于无线传输。
医疗设备:控制成像设备或监测仪器的模拟输出。


选用芯片

这次使用的DAC芯片为TLV5618,其具体参数为:12位的分辨率;1Msps转换速率;双通道模拟输出(可使用两个通道A,B输出电压);最高可达到20M赫兹时钟输出
且经过换算关系有:输出电压U = 输入数字量code;



问题分析


1. 该模块书写思路与上一篇文章ADC转换大体上一致,同样我们写的是DAC芯片的驱动电路。我们所需明确的学习目标有:学会读芯片手册了解相关信息;学习线性序列机LSM的思想;


2. 根据芯片的时序要求,DAC芯片在SCLK的下降沿采样DIN上的数值(已经稳定),DIN数值在SCLK上升沿变化;值得注意的是:DIN的D15-D12为配置位(配置转换速率与功率;已经相应的通道选择);D11-D0才是正常数据位的传输。

3. 因为TLV5618芯片为双通道。那么如果我想要两个通道同时输出不同的电压值该怎么办呢?例如通道A输出1V,通道B输出2V。解决思路就是利用TLV5618芯片内部结构自带的buffer缓冲器!通过相应的通道选择模式,第一步先将2V输入buffer;第二步再将1V输入通道A,同时buffer输入给通道B。


4. 再有的就是要严格按照芯片的时序要求来设置驱动电路。考虑相关的建立时间与保持时间,例如在开始阶段,将CS电平拉低,DIN,SCLK电平拉高,这样可满足时序要求;同样的在结束阶段,在SCLK最后一个上升沿来临时,要保证CS为低电平,否则很有可能采样不到最后一个数据(芯片手册要求)。

5. 同时还有一些辅助信号的撰写(模仿上篇文章的思路),例如使能信号,采样开始与采样停止信号的触发条件等。(详情看代码)

好的,解决完上述问题,我们来代码


代码展示

//定义端口输入输出
module DAC_driver(
       Clk,
       Rst_n,
       
       DAC_DATA,
       Set_Go,
       Set_Done,
       
       DAC_CS_N,
       DAC_SCLK,
       DAC_DIN
);
       input Clk;
       input Rst_n;
       
       input [15:0]DAC_DATA;
       input Set_Go;
       output reg Set_Done;
       
       output reg DAC_CS_N;
       output reg DAC_SCLK;
       output reg DAC_DIN;
       
       parameter CLOCK_FREQ = 50_000_000;
       parameter SCLK_EREQ = 12_500_000;
       parameter MCNT_DIV_CNT = CLOCK_FREQ / (SCLK_EREQ * 2) - 1;
       
       reg [7:0]DIV_CNT;
       reg [5:0]LSM_CNT;
       reg [15:0]r_DAC_DATA;
  
  
  //一个暂存器,将用户输入的数据暂时存储     
always@(posedge Clk)
if(Set_Go)
   r_DAC_DATA <= DAC_DATA;
else
   r_DAC_DATA <= r_DAC_DATA;
 
 
 //使能信号的确立  
     reg Set_En;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
   Set_En <= 1'd0;
else if(Set_Go)
   Set_En <= 1'd1;
else if((LSM_CNT == 6'd33) && (DIV_CNT == MCNT_DIV_CNT))
   Set_En <= 1'd0;
else
   Set_En <= Set_En;
   
  
   
//最小时间单元
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
   DIV_CNT <= 0;
else if(Set_En)begin
   if(DIV_CNT == MCNT_DIV_CNT) 
     DIV_CNT <= 0;
   else 
     DIV_CNT <= DIV_CNT + 1'd1;
     end
else
     DIV_CNT <= 0;
      
   
 //序列计数器
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
   LSM_CNT <= 6'd0;
else if(DIV_CNT == MCNT_DIV_CNT)begin
   if(LSM_CNT <= 6'd33)
      LSM_CNT <= 6'd0;
   else
      LSM_CNT <= LSM_CNT + 1'd1;
   end
else
    LSM_CNT <= LSM_CNT;
 
 
 
 //线性序列机的驱动输出
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
   DAC_SCLK <= 1'd1;
   DAC_DIN <= 1'd1;
   DAC_CS_N <= 1'd1; 
   end
else if(DIV_CNT == MCNT_DIV_CNT)begin
   case(LSM_CNT)
   0 : begin  DAC_CS_N <= 1'd0; DAC_DIN <= r_DAC_DATA[15]; DAC_SCLK <= 1'd1; end
   1 : begin  DAC_SCLK <= 1'd0; end
   2 : begin  DAC_SCLK <= 1'd1; DAC_DIN <= r_DAC_DATA[14]; end
   3 : begin  DAC_SCLK <= 1'd0; end
   4 : begin  DAC_SCLK <= 1'd1; DAC_DIN <= r_DAC_DATA[13]; end
   5 : begin  DAC_SCLK <= 1'd0; end
   6 : begin  DAC_SCLK <= 1'd1; DAC_DIN <= r_DAC_DATA[12]; end
   7 : begin  DAC_SCLK <= 1'd0; end
   8 : begin  DAC_SCLK <= 1'd1; DAC_DIN <= r_DAC_DATA[11]; end
   9 : begin  DAC_SCLK <= 1'd0; end
   10 : begin  DAC_SCLK <= 1'd1; DAC_DIN <= r_DAC_DATA[10]; end
   11 : begin  DAC_SCLK <= 1'd0; end
   12 : begin  DAC_SCLK <= 1'd1; DAC_DIN <= r_DAC_DATA[9]; end
   13 : begin  DAC_SCLK <= 1'd0; end
   14 : begin  DAC_SCLK <= 1'd1; DAC_DIN <= r_DAC_DATA[8]; end
   15 : begin  DAC_SCLK <= 1'd0; end
   16 : begin  DAC_SCLK <= 1'd1; DAC_DIN <= r_DAC_DATA[7]; end
   17 : begin  DAC_SCLK <= 1'd0; end
   18 : begin  DAC_SCLK <= 1'd1; DAC_DIN <= r_DAC_DATA[6]; end
   19 : begin  DAC_SCLK <= 1'd0; end
   20 : begin  DAC_SCLK <= 1'd1; DAC_DIN <= r_DAC_DATA[5]; end
   21 : begin  DAC_SCLK <= 1'd0; end
   22 : begin  DAC_SCLK <= 1'd1; DAC_DIN <= r_DAC_DATA[4]; end
   23 : begin  DAC_SCLK <= 1'd0; end
   24 : begin  DAC_SCLK <= 1'd1; DAC_DIN <= r_DAC_DATA[3]; end
   25 : begin  DAC_SCLK <= 1'd0; end
   26 : begin  DAC_SCLK <= 1'd1; DAC_DIN <= r_DAC_DATA[2]; end
   27 : begin  DAC_SCLK <= 1'd0; end
   28 : begin  DAC_SCLK <= 1'd1; DAC_DIN <= r_DAC_DATA[1]; end
   29 : begin  DAC_SCLK <= 1'd0; end
   30 : begin  DAC_SCLK <= 1'd1; DAC_DIN <= r_DAC_DATA[0]; end
   31 : begin  DAC_SCLK <= 1'd0; end
   32 : begin  DAC_SCLK <= 1'd1; end
   33 : begin  DAC_CS_N <= 1'd1; end
   default: DAC_CS_N <= 1'd1;
   endcase
 end
 
//产生结束信号 
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
   Set_Done <= 0;
else if((LSM_CNT == 6'd33) && (DIV_CNT == MCNT_DIV_CNT))
   Set_Done <= 1'd1;
else
   Set_Done <= 1'd0;


endmodule


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


### FPGA 实现 DAC 转换的技术概述 FPGA(Field Programmable Gate Array)是一种可编程逻辑器件,在信号处理领域具有广泛的应用场景。通过结合DAC(Digital-to-Analog Converter),可以实现数字信号到模拟信号的转换,这对于通信系统、音频处理以及其他混合信号应用场景至关重要。 #### 1. FPGADAC 的协同工作原理 在现代电子设计中,FPGA 可以作为控制核心来驱动 DAC 进行数据传输和信号生成。具体来说,FPGA 提供精确的时间序列控制能力,能够实时计算并发送数字化的数据流至 DAC 输入端口[^1]。随后,DAC 将这些离散化的数值转化为连续变化的电压或电流输出。 对于特定型号如 **DAC3482**,其内部集成了多种功能模块,包括但不限于倍频内插滤波器(支持 2×, 4×, 8× 或者 16× 插值)、数控振荡器 (NCO),以及正交调制器等功能单元。这使得它非常适合用于高速无线通信链路中的 IF/RF 波形合成任务。 #### 2. 使用 FPGA 控制 DAC 的典型架构 以下是基于 FPGA 构建的一个基本框架描述: - **数据路径管理**: 利用 FPGA 中丰富的资源构建 FIFO 缓冲区或者 DMA 引擎,用来暂存待写入 DAC 寄存器组内的样本点集合;同时还需要考虑如何同步采样率与时钟源之间的关系。 - **配置接口设计**: 配置寄存器映射表定义好之后,可以通过 SPI/I2C 协议完成初始化参数加载过程,比如设置增益系数、偏移量校准等操作。 - **测试验证流程建议** 开发阶段应该注重仿真环节的重要性,借助 ModelSim/Questa 等工具搭建虚拟平台来进行行为级验证。另外实际硬件调试期间也要关注电源噪声干扰可能带来的影响因素分析。 ```verilog // Verilog 示例:简单的SPI控制器部分代码片段 module spi_master ( input wire clk, output reg sclk, inout wire miso, output reg mosi, ... ); always @(posedge clk) begin // 主循环逻辑省略... end endmodule ``` 上述例子展示了如何利用Verilog HDL编写一段基础版的SPI主机模式下的时序发生电路结构图解说明。当然完整的项目往往更加复杂庞大一些,涉及到更多细节方面的考量。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值