Codice DDS (Direct Digital Synthesis)
Posted: 25 May 2012, 11:36
Ho implementato un semplice DDS che tramite un contatore incrementa la fase della funzione seno e scrive in uscita i valori secondo una tabella di 16 valori, ecco il codice:
Vorrei creare un generatore di funzioni simile ai prodotti commerciali con una frequenza impostabile da 0 fino a 10 MHz.
Per il momento il modulo DDS genera una sinusoide alla frequenza CLOCK / 16 poiché per generare un periodo sono necessari 16 colpi di clock per i valori a diversi angoli di fase.
Per generare 10 MHz necessiterei di un clock di 160 MHz, decisamente troppo elevato, avevo pensato a scrivere i valori di uscita sia sui fronti di salita che di discesa per raddoppiare le prestazioni, è una buona idea?
In alternativa potrei ridurre il numero di angoli di fase ma perderei risoluzione, come posso fare per avere la moglie ubriaca e la botte piena?
Per impostare la frequenza attualmente ho creato un modulo divisore di clock programmabile tramite 8 linee di IO esterne:
per rendere impostabile con un DIP Switch la frequenza direttamente in binario per la comodità del'utente, questo modulo è ancora diciamo in debug poichè ha un piccolo problema ma in linea di principio il funzionamento è quello che si può dedurre dal codice.
Allego lo schematico del DDS, qualsiasi consiglio è ben accetto
Ciao
- Code: Select all
library ieee;
use ieee.std_logic_1164.all;
-- TODO: Replace with ieee.numeric_std.all
use ieee.std_logic_unsigned.all;
entity dds is
port
(
-- Input ports
rst : in std_logic;
clk : in std_logic;
-- Output ports
data_out : out std_logic_vector(7 downto 0)
);
end dds;
architecture arc of dds is
signal counter: std_logic_vector(3 downto 0);
signal phase: std_logic_vector(3 downto 0);
signal sine : std_logic_vector(7 downto 0);
begin
-- Increment phase
process(clk, rst)
begin
if rst = '0' then
counter <= x"0";
elsif(rising_edge(clk)) then
counter <= counter + 1;
end if;
end process;
phase <= counter;
process(clk, rst)
begin
if rst = '0' then
--phase <= x"0";
sine <= x"00";
elsif(rising_edge(clk)) then --(sin(x)*127.5)+127.5
case phase is -- Value Sine(x°)
when x"0" => sine <= x"7F"; -- 127 0
when x"1" => sine <= x"B0"; -- 176 22.5
when x"2" => sine <= x"DA"; -- 218 45
when x"3" => sine <= x"F5"; -- 245 67.5
when x"4" => sine <= x"FF"; -- 255 90
when x"5" => sine <= x"F5"; -- 245 112.5
when x"6" => sine <= x"DA"; -- 218 135
when x"7" => sine <= x"B0"; -- 176 157.5
when x"8" => sine <= x"7F"; -- 127 180
when x"9" => sine <= x"4F"; -- 79 202.5
when x"A" => sine <= x"25"; -- 37 225
when x"B" => sine <= x"0A"; -- 10 247.5
when x"C" => sine <= x"00"; -- 0 270
when x"D" => sine <= x"0A"; -- 10 292.5
when x"E" => sine <= x"25"; -- 37 315
when x"F" => sine <= x"4F"; -- 79 337.5
when others => sine <= x"00";
end case;
end if;
end process;
data_out <= sine;
end arc;
Vorrei creare un generatore di funzioni simile ai prodotti commerciali con una frequenza impostabile da 0 fino a 10 MHz.
Per il momento il modulo DDS genera una sinusoide alla frequenza CLOCK / 16 poiché per generare un periodo sono necessari 16 colpi di clock per i valori a diversi angoli di fase.
Per generare 10 MHz necessiterei di un clock di 160 MHz, decisamente troppo elevato, avevo pensato a scrivere i valori di uscita sia sui fronti di salita che di discesa per raddoppiare le prestazioni, è una buona idea?
In alternativa potrei ridurre il numero di angoli di fase ma perderei risoluzione, come posso fare per avere la moglie ubriaca e la botte piena?
Per impostare la frequenza attualmente ho creato un modulo divisore di clock programmabile tramite 8 linee di IO esterne:
- Code: Select all
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity clk_div is
port (
-- Input ports
rst : in std_logic;
clk_in : in std_logic;
clk_div : in std_logic_vector(7 downto 0);
-- Output ports
clk_out : out std_logic
);
end entity;
architecture arc_clk_div of clk_div is
signal counter: std_logic_vector(8 downto 0);
begin
process(clk_in, rst)
begin
if rst = '0' then
counter <= "000000000";
elsif(rising_edge(clk_in)) then
counter <= std_logic_vector(unsigned(counter) + unsigned(clk_div));
end if;
end process;
clk_out <= counter(8);
end arc_clk_div;
per rendere impostabile con un DIP Switch la frequenza direttamente in binario per la comodità del'utente, questo modulo è ancora diciamo in debug poichè ha un piccolo problema ma in linea di principio il funzionamento è quello che si può dedurre dal codice.
Allego lo schematico del DDS, qualsiasi consiglio è ben accetto
Ciao