基于FPGA的AD7303/ADCS7476模拟数字转换VHDL开发

欢迎订阅《FPGA学习入门100例教程》、《MATLAB学习入门100例教程

目录

一、理论基础

二、核心程序

三、测试结果


一、理论基础

        AD7303是一款12位并行输入、串行输出的模拟数字转换器(ADC),而ADCS7476是一款12位逐次逼近型模拟数字转换器。这两款芯片都具有不同的特性和应用场景。

       AD7303是一款适合单通道或双通道输入的ADC。它的采样频率可以达到200kHz,输入信号频率为0~20kHz。其主要接口包括CS片选接口、SCLK时钟、SDATA数据等。在FPGA上,可以通过SPI接口对AD7303进行初始化,然后通过状态机的形式进行数据的读取。

       ADCS7476是一款具有四通道输入的ADC。它的采样频率也可以达到100kHz,输入信号频率为0~10kHz。与AD7303类似,ADCS7476也可以通过SPI接口进行初始化,然后通过状态机的形式进行数据的读取。

       在这两款芯片中,AD7303适合用于对输入信号频率要求较高,同时需要并行输入的应用场景。而ADCS7476则适合用于需要多通道输入,同时对采样频率要求较高的应用场景。在实际应用中,还需要根据具体的需求和硬件环境进行相应的调整和优化,以保证系统的稳定性和性能。

在FPGA上编写AD模数驱动需要以下步骤:

  1. 了解AD芯片的规格和特性:首先需要了解要使用的AD芯片的规格和特性,例如采样速度、分辨率、输入信号范围等。这有助于确定FPGA的硬件设计要求和软件编写方式。
  2. 设计硬件电路:根据AD芯片的规格和特性,设计适合的硬件电路。需要包括AD芯片的接口设计、电源、时钟等。
  3. 编写AD驱动程序:根据硬件电路和AD芯片的规格,编写适合的AD驱动程序。驱动程序应该能够正确初始化AD芯片、读取转换数据并处理错误等。
  4. 测试和验证:在编写完驱动程序后,需要进行测试和验证,以确保其能够正确地读取AD芯片的转换数据。

在编写驱动程序时,需要注意以下几点:

  1. 时钟频率和信号时序:AD芯片需要正确的时钟频率和信号时序才能正常工作。需要根据AD芯片的数据手册,正确设置FPGA的时钟和信号时序。
  2. SPI通信协议:许多AD芯片使用SPI通信协议进行初始化、读取数据等操作。需要编写适合的SPI通信程序,确保与AD芯片的通信正常。
  3. 数据格式:AD芯片的输出数据可能有特定的格式要求,例如需要包含校准数据、偏移量等。需要编写适合的数据处理程序,以正确处理AD芯片的输出数据。
  4. 错误处理:在读取AD芯片的数据时,可能会出现错误,例如数据溢出、信号失真等。需要在驱动程序中添加适当的错误处理程序,以避免出现错误导致系统崩溃或数据不准确等问题。

       需要注意的是,不同的FPGA和不同的AD芯片可能需要不同的驱动程序和电路设计。需要根据具体情况进行相应的调整和修改。


       在Altera NIOS板上设计和实现一个格式转换系统,该系统读取模拟输入,将其转换为数字数据,然后将其反向转换为模拟格式。这将通过使用SPI MCP3202 12位A/D转换器进行模拟输入来实现,以生成数字数据流,然后使用Analog Devices 8位SPI AD7303 D/A转换器将数字数据用于生成模拟输出。数字输出还通过中间的低通滤波器(FIR)。分配给我的采样频率和截止频率分别为23 kHz和2.3 kHz。

12bit位宽的ADCS7476,根据技术文档datasheet可知:

      主要接口包括CS片选接口,SCLK时钟,SDATA数据,然后这个芯片是2路信号,然后我这里接口都预留了,然后实际用一个就可以了。

      他的时序如下所示:

然后看AD7303。

这个的话,确实得按这个状态图进行设计。通过状态机的方式实现。

二、核心程序

 
LIBRARY ieee;
   USE ieee.std_logic_1164.all;
   USE ieee.std_logic_unsigned.all;

ENTITY adcs7476 IS
   PORT (
      
      clk        : IN STD_LOGIC;
      rst        : IN STD_LOGIC;
      adc_cs_b   : OUT STD_LOGIC;
      adc_clk    : OUT STD_LOGIC;
      adc_data0  : IN STD_LOGIC;
      adc_data1  : IN STD_LOGIC;
      v0         : OUT STD_LOGIC_VECTOR(11 DOWNTO 0);
      v1         : OUT STD_LOGIC_VECTOR(11 DOWNTO 0);
      rdy        : OUT STD_LOGIC;
      delay      : OUT STD_LOGIC_VECTOR(31 DOWNTO 0);
      count      : OUT STD_LOGIC_VECTOR(6 DOWNTO 0)
   );
END adcs7476;

ARCHITECTURE trans OF adcs7476 IS
   
   SIGNAL tmp0           : STD_LOGIC_VECTOR(11 DOWNTO 0);
   SIGNAL tmp1           : STD_LOGIC_VECTOR(11 DOWNTO 0);
   
   -- Declare intermediate signals for referenced outputs
   SIGNAL adc_cs_b_Reg1 : STD_LOGIC;
   SIGNAL adc_clk_Reg0  : STD_LOGIC;
   SIGNAL v0_Reg5       : STD_LOGIC_VECTOR(11 DOWNTO 0);
   SIGNAL v1_Reg6       : STD_LOGIC_VECTOR(11 DOWNTO 0);
   SIGNAL rdy_Reg4      : STD_LOGIC;
   SIGNAL delay_Reg3    : STD_LOGIC_VECTOR(31 DOWNTO 0);
   SIGNAL count_Reg2    : STD_LOGIC_VECTOR(6 DOWNTO 0);
BEGIN
   -- Drive referenced outputs
   adc_cs_b <= adc_cs_b_Reg1;
   adc_clk <= adc_clk_Reg0;
   v0 <= v0_Reg5;
   v1 <= v1_Reg6;
   rdy <= rdy_Reg4;
   delay <= delay_Reg3;
   count <= count_Reg2;
   PROCESS (clk, rst)
   BEGIN
      IF (rst = '1') THEN
         delay_Reg3 <= "00000000000000000000000000000000";
      ELSIF (clk'EVENT AND clk = '1') THEN
         IF (delay_Reg3 = "00000000000000000000000000000010") THEN
            delay_Reg3 <= "00000000000000000000000000000000";
         ELSE
            delay_Reg3 <= delay_Reg3 + "00000000000000000000000000000001";
         END IF;
      END IF;
   END PROCESS;
   
	
	
   PROCESS (clk, rst)
   BEGIN
      IF (rst = '1') THEN
         count_Reg2 <= "0000000";
      ELSIF (clk'EVENT AND clk = '1') THEN
         IF (delay_Reg3 = "00000000000000000000000000000000") THEN
            IF (count_Reg2 = "0101110") THEN
               count_Reg2 <= "0000000";
            ELSE
               count_Reg2 <= count_Reg2 + "0000001";
            END IF;
         END IF;
      END IF;
   END PROCESS;
   
   PROCESS (clk, rst)
   BEGIN
      IF (rst = '1') THEN
         adc_cs_b_Reg1 <= '0';
         adc_clk_Reg0 <= '0';
         rdy_Reg4 <= '0';
      ELSIF (clk'EVENT AND clk = '1') THEN
         IF (count_Reg2 < "0100000") THEN
            adc_cs_b_Reg1 <= '0';
         ELSE
            adc_cs_b_Reg1 <= '1';
         END IF;
         IF (count_Reg2 = "0100000") THEN
            rdy_Reg4 <= '1';
         ELSE
            rdy_Reg4 <= '0';
         END IF;
         adc_clk_Reg0 <= count_Reg2(0);
      END IF;
   END PROCESS;
   
   
   PROCESS (clk, rst)
   BEGIN
      IF (rst = '1') THEN
         tmp0 <= "000000000000";
         tmp1 <= "000000000000";
      ELSIF (clk'EVENT AND clk = '1') THEN
         IF (delay_Reg3 = "00000000000000000000000000000000") THEN
            IF (((NOT(adc_clk_Reg0)) = '1' OR adc_cs_b_Reg1 = '1') = true) THEN
               tmp0 <= tmp0;
            ELSE
               tmp0 <= (tmp0(10 DOWNTO 0) & adc_data0);
            END IF;
            
            IF (((NOT(adc_clk_Reg0)) = '1' OR adc_cs_b_Reg1 = '1') = true) THEN
               tmp1 <= tmp1;
            ELSE
               tmp1 <= (tmp1(10 DOWNTO 0) & adc_data1);
            END IF;
         END IF;
      END IF;
   END PROCESS;
   
   
   PROCESS (clk, rst)
   BEGIN
      IF (rst = '1') THEN
         v0_Reg5 <= "000000000000";
         v1_Reg6 <= "000000000000";
      ELSIF (clk'EVENT AND clk = '1') THEN
         IF (delay_Reg3 = "00000000000000000000000000000000") THEN
            IF (rdy_Reg4 = '1') THEN
               v0_Reg5 <= tmp0;
            ELSE
               v0_Reg5 <= v0_Reg5;
            END IF;
            
            IF (rdy_Reg4 = '1') THEN
               v1_Reg6 <= tmp1;
            ELSE
               v1_Reg6 <= v1_Reg6;
            END IF;
         END IF;
      END IF;
   END PROCESS;
   
   
END trans;






LIBRARY ieee;
   USE ieee.std_logic_1164.all;
   USE ieee.std_logic_unsigned.all;

ENTITY AD7303 IS
   PORT (
      
      CS        : OUT STD_LOGIC;
      done      : OUT STD_LOGIC;
      MOSI      : OUT STD_LOGIC;
      SCLK      : OUT STD_LOGIC;
      count     : OUT STD_LOGIC_VECTOR(4 DOWNTO 0);
      state     : OUT STD_LOGIC_VECTOR(5 DOWNTO 0);
      start     : IN STD_LOGIC;
      clock     : IN STD_LOGIC;
      reset     : IN STD_LOGIC;
      data_out  : IN STD_LOGIC_VECTOR(7 DOWNTO 0)
   );
END AD7303;

ARCHITECTURE trans OF AD7303 IS
   

   
   SIGNAL next_state     : STD_LOGIC_VECTOR(5 DOWNTO 0);
   SIGNAL next_count     : STD_LOGIC_VECTOR(4 DOWNTO 0);
   SIGNAL next_shift_out : STD_LOGIC_VECTOR(15 DOWNTO 0);
   SIGNAL shift_out      : STD_LOGIC_VECTOR(15 DOWNTO 0);
   SIGNAL next_MOSI      : STD_LOGIC;
   SIGNAL next_CS        : STD_LOGIC;
   SIGNAL next_SCLK      : STD_LOGIC;
   SIGNAL temp           : STD_LOGIC_VECTOR(15 DOWNTO 0);
   
   -- Declare intermediate signals for referenced outputs
   SIGNAL CS_xhdl0       : STD_LOGIC;
   SIGNAL MOSI_xhdl1     : STD_LOGIC;
   SIGNAL SCLK_xhdl2     : STD_LOGIC;
   SIGNAL count_xhdl3    : STD_LOGIC_VECTOR(4 DOWNTO 0);
   SIGNAL state_xhdl4    : STD_LOGIC_VECTOR(5 DOWNTO 0);
BEGIN
   -- Drive referenced outputs
   CS <= CS_xhdl0;
   MOSI <= MOSI_xhdl1;
   SCLK <= SCLK_xhdl2;
   count <= count_xhdl3;
   state <= state_xhdl4;
   
   PROCESS (clock, reset)
   BEGIN
      IF (reset = '1') THEN
         state_xhdl4 <= "000001";
         SCLK_xhdl2 <= '0';
         CS_xhdl0 <= '1';
         count_xhdl3 <= "00000";
      ELSIF (clock'EVENT AND clock = '1') THEN
         state_xhdl4 <= next_state;
         shift_out <= next_shift_out;
         MOSI_xhdl1 <= next_MOSI;
         SCLK_xhdl2 <= next_SCLK;
         count_xhdl3 <= next_count;
         CS_xhdl0 <= next_CS;
      END IF;
   END PROCESS;
   
   
   PROCESS (state_xhdl4, start, count_xhdl3, data_out, shift_out, MOSI_xhdl1, SCLK_xhdl2, CS_xhdl0, temp)
   BEGIN
      
      done <= '0';
      next_state <= state_xhdl4;
      next_MOSI <= MOSI_xhdl1;
      next_SCLK <= SCLK_xhdl2;
      next_CS <= CS_xhdl0;
      next_count <= count_xhdl3;
      next_shift_out <= shift_out;
      temp(15 DOWNTO 8) <= "01100000";
      temp(7 DOWNTO 0) <= data_out;
      
      CASE state_xhdl4 IS
         WHEN "000001" =>
            
            IF (start = '1') THEN
               
               next_CS <= '0';
               next_state <= "000010";
               next_shift_out <= temp;
               
               next_SCLK <= '0';
            ELSE
               next_CS <= '1';
               next_state <= "000001";
            END IF;
            next_count <= "00000";
         WHEN "000010" =>
            next_MOSI <= shift_out(15);
            next_shift_out <= (shift_out(14 DOWNTO 0) & '0');
            next_state <= "000100";
            next_count <= count_xhdl3 + "00001";
            next_SCLK <= '1';
            next_CS <= '0';
         WHEN "000100" =>
            
            IF (count_xhdl3 = "10000") THEN
               next_state <= "010000";
            ELSE
               next_state <= "000010";
            END IF;
         WHEN "010000" =>
            done <= '1';
            next_CS <= '1';
            next_SCLK <= '0';
            next_state <= "100000";
         WHEN "100000" =>
            next_CS <= '1';
            next_SCLK <= '0';
            IF (start = '1') THEN
               next_state <= "100000";
            ELSE
               next_state <= "000001";
            END IF;
         WHEN OTHERS =>
            next_state <= "000001";
      END CASE;
   END PROCESS;
   
   
END trans;


三、测试结果

ADCS7476然后位宽是12位,根据这些信息,我们的测试仿真结果如下所示:

AD7303

A28-63

  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fpga和matlab

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值