概述
ADC和DAC是FPGA與外部信號(hào)的接口,從數(shù)據(jù)接口類型的角度劃分,有低速的串行接口和高速的并行接口。FPGA經(jīng)常用來(lái)采集中高頻信號(hào),因此使用并行ADC和DAC居多。本文將介紹如何使用FPGA驅(qū)動(dòng)并行ADC和并行DAC芯片。
并行接口包括兩種數(shù)字編碼方式:帶符號(hào)數(shù)signed與無(wú)符號(hào)數(shù)unsigned。本文還將介紹使用不同編碼方式的ADC與DAC時(shí)需要注意的問(wèn)題。
接口協(xié)議
以ADI公司的32M、8位ADC芯片AD9280和125M、8位DAC芯片AD9708為例(這是淘寶上最容易買(mǎi)到的AD/DA模塊)。
AD9280的時(shí)序圖如下:
AD9708的時(shí)序圖如下:
由時(shí)序圖可知,AD9280在每個(gè)輸入clock的上升沿對(duì)輸入的模擬信號(hào)做一次采集,采集數(shù)據(jù)由數(shù)據(jù)總線data輸出;AD9708也是在每個(gè)輸入clock的上升沿讀取數(shù)據(jù)總線DB0-DB7上的數(shù)據(jù),將其轉(zhuǎn)換為相應(yīng)的電流IOUTA/IOUTB輸出。
這兩個(gè)芯片的管腳雖然很多,但大多數(shù)都是與硬件設(shè)計(jì)有關(guān)。其實(shí)幾乎所有的并行ADC和并行DAC與FPGA之間的接口只有一條時(shí)鐘線與一組數(shù)據(jù)總線,數(shù)據(jù)總線的位寬即為ADC/DAC的位數(shù)。每個(gè)時(shí)鐘周期ADC都會(huì)完成一次采集(DAC完成一次輸出),因此時(shí)鐘頻率也就是ADC和DAC的采樣頻率。
FPGA設(shè)計(jì)
并行ADC和DAC的接口時(shí)序驅(qū)動(dòng)非常簡(jiǎn)單,只要利用Quartus或Vivado自帶的時(shí)鐘管理IP核生成預(yù)期采樣頻率的時(shí)鐘信號(hào),驅(qū)動(dòng)時(shí)鐘線,從數(shù)據(jù)總線上讀出或?qū)懭霐?shù)據(jù)即可。
比如下面的代碼實(shí)現(xiàn)了將ADC采集到的數(shù)據(jù)再通過(guò)DAC輸出
`timescale 1ns / 1ps
//-----------------------------------------------
// 將ADC采集到的數(shù)據(jù)通過(guò)DAC輸出
//-----------------------------------------------
module adda_test
(
input clk,
output daclk,
output [7:0] dadata, //DA data
output adclk,
input [7:0] addata //AD data
);
PLL PLL_inst
(
.clk_in1(clk), // IN
// Clock out ports
.clk_out1(adclk), // OUT 32Mhz
.clk_out2(daclk), // OUT 32Mhz
// Status and control signals
.reset(1'b0), // IN
.locked()
);
assign dadata = addata;
endmodule
上述代碼中實(shí)例化了一個(gè)PLL IP核產(chǎn)生ADC和DAC所需頻率的時(shí)鐘,Quartus中該IP核叫做“PLL”,Vivado中該IP核叫做“Clocking Wizard”。
為了保證DAC輸出與ADC采集到的信號(hào)相同,將兩者時(shí)鐘頻率設(shè)置相同,且連接二者的數(shù)據(jù)總線。上述代碼可以使用開(kāi)發(fā)板和AD/DA模塊進(jìn)行實(shí)際測(cè)試。
編碼方式問(wèn)題
上文用到的AD9280和AD9708都是無(wú)符號(hào)數(shù)編碼,而我們知道無(wú)論是Vivado還是Quartus中大多數(shù)的IP核采用的都是帶符號(hào)數(shù)二進(jìn)制補(bǔ)碼的編碼方式,這就導(dǎo)致ADC/DAC的數(shù)據(jù)總線不能與IP核接口直接對(duì)接,必須做一定的轉(zhuǎn)換處理。
考慮到上述數(shù)字系統(tǒng)的特點(diǎn),市場(chǎng)上也存在不少以帶符號(hào)數(shù)二進(jìn)制補(bǔ)碼接口的ADC/DAC,比如65M、12位ADC芯片AD9226。如果使用這種編碼方式的芯片,數(shù)據(jù)總線就可以直接與IP核接口對(duì)接,不需要做特殊處理。
但是,我們總會(huì)不可避免的遇到類似這樣的情況:
1. ADC或DAC是無(wú)符號(hào)數(shù)編碼,而設(shè)計(jì)中需要使用一些帶符號(hào)數(shù)接口的IP核;
2. ADC是帶符號(hào)數(shù)編碼,而設(shè)計(jì)中僅需獲取測(cè)量值,并不需要與其它帶符號(hào)數(shù)接口的模塊對(duì)接。
當(dāng)遇到情況1時(shí),需要進(jìn)行無(wú)符號(hào)數(shù)編碼與帶符號(hào)數(shù)編碼之間的轉(zhuǎn)換。將ADC采集到的8位無(wú)符號(hào)數(shù)轉(zhuǎn)換為帶符號(hào)數(shù)補(bǔ)碼形式的代碼如下:
/**** 將addata轉(zhuǎn)化為帶符號(hào)二進(jìn)制補(bǔ)碼形式 ****/
reg [7:0] ad_data;
always @ (posedge clk or negedge rst_n)
if (!rst_n) ad_data <= 8'd0;
else ad_data <= addata - 128;? ? //AD9280采集輸入
將帶符號(hào)數(shù)補(bǔ)碼轉(zhuǎn)換為8位無(wú)符號(hào)數(shù)通過(guò)DAC輸出的代碼如下:
/**** 將dadata轉(zhuǎn)化為無(wú)符號(hào)數(shù)形式 ****/
reg [7:0] da_data;
always @ (posedge clk or negedge rst_n)
if (!rst_n) da_data <= 8'd0;
else da_data <= dadata + 128;? ? //AD9708輸出
當(dāng)遇到情況2時(shí),需要將不易直接觀察的帶符號(hào)數(shù)補(bǔ)碼形式轉(zhuǎn)換為帶符號(hào)數(shù)原碼形式,使其更加直觀。代碼如下:
always @(posedge ad_clk) //AD9226采集
if(ad_ch1[11]==1'b1) begin //如果是負(fù)電壓
ch1_reg<=12'hfff - ad_ch1 + 1'b1;
ch1_sig <= 45;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //'-' asic碼
end
else begin
ch1_reg<=ad_ch1;
ch1_sig<=43;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //'-' asic碼
end
轉(zhuǎn)換的依據(jù)是一個(gè)簡(jiǎn)單的運(yùn)算關(guān)系:“補(bǔ)碼的整數(shù)值”+“原碼絕對(duì)值的整數(shù)值”=2^B,B為位寬。比如帶符號(hào)數(shù)原碼1110的補(bǔ)碼為1010:1110取絕對(duì)值0110為6;1010為10,二者加起來(lái)為2^4=16。
上述代碼便是利用了這個(gè)運(yùn)算關(guān)系。為了節(jié)省位寬,先用12’hfff減掉補(bǔ)碼,再加1,達(dá)到同樣的效果,得到帶符號(hào)數(shù)原碼的絕對(duì)值。根據(jù)符號(hào)位便可以知道這個(gè)原碼的正負(fù)情況。
原文標(biāo)題:FPGA學(xué)習(xí)—并行ADC與DAC
文章出處:【微信公眾號(hào):FPGA設(shè)計(jì)論壇】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
-
FPGA
+關(guān)注
關(guān)注
1629文章
21729瀏覽量
602986 -
adc
+關(guān)注
關(guān)注
98文章
6495瀏覽量
544461 -
dac
+關(guān)注
關(guān)注
43文章
2291瀏覽量
190975
原文標(biāo)題:FPGA學(xué)習(xí)—并行ADC與DAC
文章出處:【微信號(hào):gh_9d70b445f494,微信公眾號(hào):FPGA設(shè)計(jì)論壇】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論