Jump to content
  • 0

Audio Processor


melpin@digilent

Question

I am building an audio processor with effects in my final year project using Spartan 6 and there is a problem i am facing. Since my project guide has left my institute , I am facing a few difficulties of which this is one of them. The following is the code for audio playback . When i use it without the clock divider (On board clock of 4 MHz) process i am able to hear the audio . When i change the ADC Clock (Clock Divider from 4 MHz to 44.1 KHz ) i am unable to hear anything . Why is it so. The test bench shows that the ADC clock is divided to 44.1 KHz but its not giving an on board output.

 

----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date:    17:19:31 01/03/2016
-- Design Name:
-- Module Name:    ADC_DAC_interface - Behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
library UNISIM;
use UNISIM.VComponents.all;

entity ADC_DAC_interface is
    Port (
          ------- FPGA global inputs --------
          F_RESET : in  STD_LOGIC;
        F_CLK_4MHz : in  STD_LOGIC;
              
          --------------- ADC interface (AD7938) ------------
          F_IL : IN STD_LOGIC_VECTOR (1 downto 0); -- Switches for ADC i/p channel selection
        F_ADC_D : inout  STD_LOGIC_VECTOR (11 downto 0);
          F_ADC_CLK : out  STD_LOGIC; -- ADC clock
        F_ADC_CS_BAR    : out std_logic; --chip select
        F_ADC_CONVST_BAR: out std_logic; --conversion start
           F_ADC_WR_BAR    : out std_logic; --write
           F_ADC_RD_BAR    : out std_logic; --read

             
          --------------- DAC interface (TLV5619) ------------
          F_DAC_D : out  STD_LOGIC_VECTOR (11 downto 0);
        F_WE_BAR : out  STD_LOGIC;--13/2
          F_CS1_BAR : out  STD_LOGIC;
        F_CS2_BAR : out  STD_LOGIC;
        F_CS3_BAR : out  STD_LOGIC;
        F_CS4_BAR : out  STD_LOGIC
--        chipscope_clk : out STD_LOGIC
          );
          
end ADC_DAC_interface;


architecture Behavioral of ADC_DAC_interface is

type state is (reset_s, write_cr, write_cr2, start_conv, check_count_done, read_data);
signal prsnt_s, next_s : state;

signal control_word : std_logic_vector(11 downto 0);

 

-- signals to count upto 16 instead of using BUSY pin --
signal count_16 : std_logic_vector(3 downto 0):= "0000";
signal start_count : std_logic:= '0';
signal count_done: std_logic:= '0';
signal reset_counter : std_logic:= '1';
signal Clk_in : std_logic;
signal Clk_mod : std_logic;
signal divide_value : integer;
signal counter,divide : integer := 90;
signal data_out_s: std_logic;
signal CLK : STD_LOGIC;

begin
CLK <= F_CLK_4MHz;
Clk_in <= CLK;
divide_value <= divide;

process(Clk_in)
begin
    if( rising_edge(Clk_in) ) then
        if(counter < divide/2-1) then
            counter <= counter + 1;
            Clk_mod <= '0';
        elsif(counter < divide-1) then
            counter <= counter + 1;
            Clk_mod <= '1';
        else
            Clk_mod <= '0';
            counter <= 0;
        end if;
    end if;
    
end process;
F_ADC_CLK <= Clk_mod;  

 


--   BUFG_inst : BUFG
--   port map (
--      O => clk,     -- Clock buffer output
--      I => F_CLK_4MHz      -- Clock buffer input
--   );

 

--address_s <= channel_switch(1 downto 0);
control_word <= "00010" & F_IL(1) & F_IL(0) & "00001";

-- Count 16 clock cycles (time taken for ADC to convert the sampled input)
process(reset_counter, clk, start_count,f_reset)
begin
    if(F_RESET = '1' or reset_counter = '1') then
        count_16 <= "0000";
    elsif (start_count = '1') then
        if(clk'event and clk = '1') then
        count_16 <= count_16 + '1';
        end if;
    end if;    
end process;

count_done <= count_16(0) and count_16(1) and count_16(2) and count_16(3);

-------------------------- State Transition -------------------------
process(F_RESET, clk)
begin
    if(F_RESET = '1') then
        prsnt_s <= reset_s;
    elsif(clk'event and clk = '1') then
        prsnt_s <= next_s;
    end if;
end process;

------------------ Conditions for State change ---------------------
process(F_RESET, prsnt_s, count_done)
begin
    case prsnt_s is
        
        when reset_s =>
            if F_RESET = '1' then
                next_s <= reset_s;            -- When reset becomes 0,
            else                                    -- change state to write_cr
                next_s <= write_cr;
            end if;
        
        when write_cr =>
            next_s <= write_cr2;

        when write_cr2 =>
            next_s <= start_conv;
            
        when start_conv =>
            next_s <= check_count_done;
        
        when check_count_done =>
            if count_done = '0' then
                next_s <= check_count_done;    -- ADC AD7938 takes 13 cycles to convert a
            else                                        -- sampled data. So a 4-bit counter is used here.
                next_s <= read_data;                        -- (Previously, BUSY pin was checked. When busy = 0,
            end if;                                            -- change state to read_data)
            
        when read_data =>
            next_s <= write_cr;    

        when others =>
            next_s <= reset_s;
    end case;
end process;

--------------------- Outputs at each state ---------------------------------
process(prsnt_s, control_word,clk)
begin
    case prsnt_s is
        when reset_s =>
            F_ADC_CS_BAR <= '1';
            F_ADC_CONVST_BAR <= '1';
            F_ADC_WR_BAR <= '1';            -- RESET State    
            F_ADC_RD_BAR <= '1';        
           data_out_s <= '0';
            F_CS1_BAR <= '1';  
            F_CS2_BAR <= '1';
            F_CS3_BAR <= '1';
            F_CS4_BAR <= '1';
            F_WE_BAR <= '0';
            start_count <= '0';
            reset_counter <= '1';
            
        when write_cr =>
            F_ADC_CS_BAR <= '0';
            F_ADC_CONVST_BAR <= '1';
            F_ADC_WR_BAR <= '0';            -- Write Control Word
            F_ADC_RD_BAR <= '1';            -- into Control register of ADC 7938
           data_out_s <= '1';
            F_CS1_BAR <= '1';  
            F_CS2_BAR <= '1';
            F_CS3_BAR <= '1';
            F_CS4_BAR <= '1';
            F_WE_BAR <= '0';
            start_count <= '0';
            reset_counter <= '1';
            
        when write_cr2 =>
            F_ADC_CS_BAR <= '0';
            F_ADC_CONVST_BAR <= '1';
            F_ADC_WR_BAR <= '1';            -- Control Word is latched into ADC 7938
            F_ADC_RD_BAR <= '1';            -- at the rising edge of WR-bar signal
           data_out_s <= '1';
            F_CS1_BAR <= '1';  
            F_CS2_BAR <= '1';
            F_CS3_BAR <= '1';
            F_CS4_BAR <= '1';
            F_WE_BAR <= '0';
            start_count <= '0';
            reset_counter <= '1';
            
        when start_conv =>
            F_ADC_CS_BAR <= '1';
            F_ADC_CONVST_BAR <= '0';        -- Conversion is started.  
            F_ADC_WR_BAR <= '1';            -- ADC drives BUSY output pin HIGH
            F_ADC_RD_BAR <= '1';
           data_out_s <= '0';
            F_CS1_BAR <= '1';  
            F_CS2_BAR <= '1';
            F_CS3_BAR <= '1';
            F_CS4_BAR <= '1';
            F_WE_BAR <= '0';
            start_count <= '1';
            reset_counter <= '0';
            
        when check_count_done =>
            F_ADC_CS_BAR <= '1';
            F_ADC_CONVST_BAR <= '0';        -- CONVST_BAR pin is driven LOW until
            F_ADC_WR_BAR <= '1';            -- ADC-BUSY pin goes LOW
            F_ADC_RD_BAR <= '1';
           data_out_s <= '0';            
            F_CS1_BAR <= '1';  
            F_CS2_BAR <= '1';
            F_CS3_BAR <= '1';
            F_CS4_BAR <= '1';
            F_WE_BAR <= '0';
            start_count <= '1';
            reset_counter <= '0';
            
        when read_data =>
            F_ADC_CS_BAR <= '0';            -- Once ADC-BUSY goes LOW, data is
            F_ADC_CONVST_BAR <= '1';        -- read from ADC and applied to DAC
            F_ADC_WR_BAR <= '1';
            F_ADC_RD_BAR <= '0';
           data_out_s <= '0';
            F_CS1_BAR <= '0';  
            F_CS2_BAR <= '0';
            F_CS3_BAR <= '0';
            F_CS4_BAR <= '0';
            F_WE_BAR <= NOT clk;
            start_count <= '0';
            reset_counter <= '1';
            
    end case;
end process;

------ Controlling bidirectional operation of databus --------
F_ADC_D(11 downto 0) <=  control_word when data_out_s = '1' else        
                                 (others => 'Z');


F_DAC_D <= F_ADC_D;

--process(F_RESET, clk)
--begin
--    if(F_RESET = '1') then
--        F_DAC_D <= (others=>'0');
--    elsif(clk'event and clk = '1') then
--        F_DAC_D <= F_ADC_D;
--    end if;
--end process;
end Behavioral;

 

Link to comment
Share on other sites

3 answers to this question

Recommended Posts

Hi melpin,

I have moved this thread to a more appropriate section of the forum.

It took some digging on my part to figure out what ADC you were using since the Spartan-6 does not have one of it's own, but after finding out you are using the Analog Devices AD7938, the reason the module does not work when you change the ADC clock to 44.1 kHz is because that frequency is outside of the range of that chip. According to it's datasheet (here), it only accepts clock rates from 700 kHz to 10 MHz.

If you are using a Digilent board, there is a chance that we might have a project that works with audio; however, all of our Spartan-6 based boards have been depreciated so we will only be able to offer limited support working with them.

Thanks,
JColvin

Link to comment
Share on other sites

Hi melpin,

In FPGA is better to use the sequential digital electronic. For example, the best practice is to use a flip flop using a synchronous reset:

process(clk)

begin

    if(clk'event and clk = '1') then

        if(reset = '1') then

            q <= '0';

        else

            q <= y;

        end if;

    end if;

end process;

instead of asynchronous reset:

process(clk, reset)

begin   

   if(reset = '1') then

        q <= '0';

   elsif(clk'event and clk = '1') then

            q <= y;

    end if;

end process;

 

Each process should begin with rising / falling edge and all logic should be done in that rising edge IF.

If you want to divide a clock, then you should use a construction similar with a Flip Flop with Clock Enable (CE) pin:

counter_divider: process(clk)

begin

    if(clk'event and clk = '1') then

        if(clk_divider = "1111_1111") then          --here you should replace with your value

            clk_divider <= (others => '0');

            clk_CE <= '1';

        else

            clk_divider <= clk_divider + '1';

            clk_CE <= '0';

        end if;

    end if;

end process;

your_process: process(clk)

begin

    if(clk'event and clk = '1') then

        if(clk_CE = '1') then

           --your logic

        end if;

    end if;

end process;

 

For example, the following code is not ok, here you should use clk rising edge first:

--------------------- Outputs at each state ---------------------------------
process(prsnt_s, control_word,clk)
begin
    case prsnt_s is ..............

 

Cristian

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...