• 0
rb251415

DDS Compiler 6.0 IP Core for audible sinewave

Question

I am trying to determine if and how a Vivado IP Core can be used to create and audible tone. I have been reviewing the DSS Compiler 6.0 product guide and simulation tutorial ug937. I have configured it as shown in the attached image. I understand the sine wave output should be bits (10 downto 0) of "m_axis_data_tdata". It is asking for s_axis_phase_tvalid, s_axis_phase_tdata for input. 

I cannot seem to get a clear understanding of what these are. Can someone explain in layman's terms?

I also created a clock divider to drop aclk down to 12kHz as an attempt the get my sine wave into the audible range. I get no output on the board or in the simulator.

Ideas???

ConfigCapture03212017.JPG

Share this post


Link to post
Share on other sites

9 answers to this question

  • 0

@rb251415,

The TVALID signal is taken from the AXI specification, even though what you are doing isn't really anything AXI.  It's used to indicate that the phase value you are placing into the core is valid.

As for the phase, you'll probably want to feed that with a counter of some type.  At least with my own stuff, the phase of the output sinewave (or cosine wave, depending on how they set it up) is given by 2pi/2^{NPHASE_BITS}.  For example, if you are creating one output every 8k samples, and you want to create a 440Hz tone, you would then increment this phase by (440/8k*NBITS) on each clock.  If you use 32-bits for your phase (perhaps only feeding the most significant 6 bits into the core), then your counter's step size would be 440/8k*2^32 or 0x0e147ae1.  On the other hand, if you wanted a new value on every clock (no clock divider necessary), and ran your device at 100MHz, then this value would be (440 Hz / 100MHz * 2^32) or stepping by 0x49d2 every clock.  If you choose to do this, you could wire the TVALID signal to 1 and just place the output of your counter/step register into the phase input.  What about the fact that you are only using 6-bits of phase and I just told you how to calculate 32-bits?  Just pass the top bits of this counter into the core and you'll be fine.

Dan

Share this post


Link to post
Share on other sites
  • 0

I did as you suggested. I used the 100MHz clock as aclk. I set s_axis_phase_tvalid to '1', and I used the top bits (Most Significant Bits) of my counter (cntr) for s_axis_phase_tdata. It doesnt show any error, but it will not compile. 

"ERROR: [VRFC 10-665] expression has 6 elements ; formal s_axis_phase_tdata expects 8"

I've tried it with 6, 8 and even all 32-bits and I get the same failure.

Code:

inst_1: dds_compiler_0
    port map ( aclk => clk,
               s_axis_phase_tvalid => '1',
               s_axis_phase_tdata => cntr(31 downto 24),  -- this is line 82 of Wave_top.vhd
               m_axis_data_tvalid => m_axis_data_tvalid,
               m_axis_data_tdata => m_axis_data_tdata);

 

LOG DATA:

Vivado Simulator 2016.4
Copyright 1986-1999, 2001-2016 Xilinx, Inc. All Rights Reserved.
Running: C:/Xilinx/Vivado/2016.4/bin/unwrapped/win64.o/xelab.exe -wto 0fc31941c582466d8f4474edc8fb8bef --debug typical --relax --mt 2 -L xbip_utils_v3_0_7 -L axi_utils_v2_0_3 -L xbip_pipe_v3_0_3 -L xbip_bram18k_v3_0_3 -L mult_gen_v12_0_12 -L xbip_dsp48_wrapper_v3_0_4 -L xbip_dsp48_addsub_v3_0_3 -L xbip_dsp48_multadd_v3_0_3 -L dds_compiler_v6_0_13 -L xil_defaultlib -L secureip -L xpm --snapshot Wave_top_behav xil_defaultlib.Wave_top -log elaborate.log 
Using 2 slave threads.
Starting static elaboration
ERROR: [VRFC 10-665] expression has 6 elements ; formal s_axis_phase_tdata expects 8 [C:/Users/Toshiba-/coregen_sinewave/coregen_sinewave.srcs/sources_1/new/Wave_top.vhd:82]
ERROR: [XSIM 43-3321] Static elaboration of top level VHDL design unit wave_top in library work failed.

 

Share this post


Link to post
Share on other sites
  • 0

@D@n,

Out of frustration I tried to generate a bitstream even though the simulation failed. I got an error message "...17 out of 22 logical ports use I/O standard (IOSTANDARD) value 'DEFAULT', instead of a user assigned value." I guess It does not like

line 81   s_axis_phase_tvalid => '1',

I created a signal tvalid and tied it to my enable switch. The simulation complied and ran ( I forced clk to a 10ns cycle clock, swt to '1', rst to '1' for 5ns then '0'). My simulation ran and I got a dataout signal. But now it will not generate a bitstream. I thought maybe there was a mismatch between the aclk, used with DDS,  and clkdiv, used with my PWM output. I changed my PWM to use clk and still no luck. Here is my top_io code for your review. Any ideas are welcomed.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
-- use IEEE.NUMERIC_STD.ALL;

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

entity Wave_top is
port (clk, swt, rst :in  std_logic;
      dataout, senb: out std_logic;
      s_axis_phase_tvalid : IN STD_LOGIC;
      s_axis_phase_tdata : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
      m_axis_data_tvalid : OUT STD_LOGIC;
      m_axis_data_tdata : INOUT STD_LOGIC_VECTOR(15 DOWNTO 0)
        );
end Wave_top;

architecture Behavioral of Wave_top is

signal clkdiv: std_logic;
signal cntr: std_logic_vector(31 downto 0);
signal PWM_IN: std_logic_vector(10 downto 0);
signal PWM_ACC: std_logic_vector(11 downto 0):= (others => '0');
signal PWM_OUT: std_logic;
signal tvalid: std_logic;

COMPONENT dds_compiler_0
  PORT (
    aclk : IN STD_LOGIC;
    s_axis_phase_tvalid : IN STD_LOGIC;
    s_axis_phase_tdata : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
    m_axis_data_tvalid : OUT STD_LOGIC;
    m_axis_data_tdata : OUT STD_LOGIC_VECTOR(15 DOWNTO 0)
  );
END COMPONENT;
begin

senb <= swt;
tvalid <= swt;

DIVIDER:process(clk, rst)
begin
  if rst = '1' then
    cntr <= (others=> '0');
  else
   if (rising_edge(clk)) then
    cntr <= cntr + 1;
  end if;
 end if;  
end process;

clkdiv <= cntr(13);

inst_1: dds_compiler_0
    port map ( aclk => clk,
               s_axis_phase_tvalid => tvalid,
               s_axis_phase_tdata => cntr(31 downto 24),
               m_axis_data_tvalid => m_axis_data_tvalid,
               m_axis_data_tdata => m_axis_data_tdata);
    
PWM_IN <= m_axis_data_tdata(10 downto 0); 

PWM:process(clk,PWM_IN)
    begin
      if rising_edge(clk) then
        PWM_ACC <= ("0" & PWM_ACC(10 downto 0)) + ("0" & PWM_IN);
      end if;
    end process;
    
 dataout <= PWM_ACC(11);       

end Behavioral;

 

Share this post


Link to post
Share on other sites
  • 0

@D@n,

The issue was that I put 's_axis...' and 'm_axis...' in my entity. This caused a conflict because they went nowhere. I just created signals 'm_axis_data_tvalid' and 'm_axis_data_tdata'.

It generated a bitstream and ran. It sounds like a rhythmic tapping sound. I will review your initial information on the s_axis_phase_tdata input and do a few more trials.

Thanks

Share this post


Link to post
Share on other sites
  • 0

Hmm ... okay, but getting a "rhythmic tapping sound" suggests something's still wrong.

From your code, it looks like you are using some form of PWM for an output.  Have you considered my own PWM controller?  I use it to control a PModAMP2.

For now, and until you get your PWM controller doing anything useful, you might wish to just use the high order bit of a counter to determine your output:

reg [31:0]	phase;
// We'll replace the counter variable with one we call phase,
// just to be more explicit about what's going on.
//
// Further, we step by 18897--a number designed to give us a 440Hz tone
// assuming a 100MHz clock.  (# = Tone_freq / FPGA_freq * 2^32)
always @(posedge i_clk)
	phase <= phase + 32'd18897;

assign pwm_output = phase[31];

Be prepared, though, for a LOUD sound.  (This would be FULL audio volume on a not-so-pleasant "tone")

You can do the same with the DDS as well--ignore all bits but the high order bit.  That'll prove that 1) your audio device works, 2) your PWM code (sort of) works, and 3) (when you add in the DDS) that your DDS works.  Going from that to a nice, sweet sounding, PWM output will take more bits out of the DDS, and more work getting your PWM controller working.

Dan

Share this post


Link to post
Share on other sites
  • 0

@D@n,

I got the code working. I needed to go back to my clockdivider (clkdiv) for my Pulse Width Modulator. I makes a series of tones..kinda cool. I need to do some more experimenting and simulating to understand exactly what is happening inside. Here is the code for anyone that is interested along with the IP Core config at the top of this thread.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
-- use IEEE.NUMERIC_STD.ALL;

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

entity Wave_top is
port (clk, swt, rst :in  std_logic;
      dataout, senb: out std_logic 
        );
end Wave_top;

architecture Behavioral of Wave_top is

signal clkdiv: std_logic;
signal cntr: std_logic_vector(31 downto 0);
signal PWM_IN: std_logic_vector(10 downto 0);
signal PWM_ACC: std_logic_vector(11 downto 0):= (others => '0');
signal PWM_OUT: std_logic;
signal tvalid: std_logic;

signal m_axis_data_tvalid : STD_LOGIC;
signal m_axis_data_tdata : STD_LOGIC_VECTOR(15 DOWNTO 0);

COMPONENT dds_compiler_0
  PORT (
    aclk : IN STD_LOGIC;
    s_axis_phase_tvalid : IN STD_LOGIC;
    s_axis_phase_tdata : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
    m_axis_data_tvalid : OUT STD_LOGIC;
    m_axis_data_tdata : OUT STD_LOGIC_VECTOR(15 DOWNTO 0)
  );
END COMPONENT;
begin

senb <= swt;
tvalid <= swt;

DIVIDER:process(clk, rst)
begin
  if rst = '1' then
    cntr <= (others=> '0');
  else
   if (rising_edge(clk)) then
    cntr <= cntr + 1;
  end if;
 end if;  
end process;

clkdiv <= cntr(13);

inst_1: dds_compiler_0
    port map ( aclk => clk,
               s_axis_phase_tvalid => tvalid,
               s_axis_phase_tdata => cntr(31 downto 24),
               m_axis_data_tvalid => m_axis_data_tvalid,
               m_axis_data_tdata => m_axis_data_tdata);
    
PWM_IN <= m_axis_data_tdata(10 downto 0); 

PWM:process(clkdiv,PWM_IN)
    begin
      if rising_edge(clkdiv) then
        PWM_ACC <= ("0" & PWM_ACC(10 downto 0)) + ("0" & PWM_IN);
      end if;
    end process;
    
 dataout <= PWM_ACC(11);       

end Behavioral;
 

Share this post


Link to post
Share on other sites
  • 0

Here is the PMODAMP2_IO XDC code...


## Clock signal
set_property PACKAGE_PIN W5 [get_ports {clk}]                            
set_property IOSTANDARD LVCMOS33 [get_ports {clk}]

## Switches
set_property PACKAGE_PIN R2 [get_ports {swt}]                    
set_property IOSTANDARD LVCMOS33 [get_ports {swt}]

##Buttons
set_property PACKAGE_PIN W19 [get_ports {rst}]                        
set_property IOSTANDARD LVCMOS33 [get_ports {rst}]

##Pmod Header JB
##Sch name = JB1
set_property PACKAGE_PIN A14 [get_ports {dataout}]                    
set_property IOSTANDARD LVCMOS33 [get_ports {dataout}]
##Sch name = JB4
set_property PACKAGE_PIN B16 [get_ports {senb}]                    
set_property IOSTANDARD LVCMOS33 [get_ports {senb}]

Share this post


Link to post
Share on other sites
  • 0

Hi @rb251415,

I'm glad that you were able to get your project going! Thank you for sharing you code!

cheers,

Jon

Share this post


Link to post
Share on other sites
  • 0

@rb251415,

So ... can you teach it to play any music?  What does it sound like?  Sort of like a flute perhaps?  A pipe organ?

Congratulations again,

Dan

rb251415 likes this

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now