§ регистры хранящие значение фазы (phase REG)регистры хранящие значение частоты (freq REG)
§ таблица значения синуса (SIN ROM)
§ 10-битный ЦАП с дифференциальным выходом
§ интерфейс для программирования
Весь проект DDS будет состоять из 32-битного аккумулятора фазы, 32-битного регистра, задающего значение выходной частоты, 12-битного регистра, задающего начальное значение фазы и 40-битного сумматора, а также таблицы значения синуса на 2^12 = 4096 значений.
library IEEE; use IEEE.STD_LOGIC_1164.ALL; USE IEEE.numeric_std.ALL; entity DDS_SIN is generic (Rb : integer:=12; -- разрядность по амплитуде для -- синусойды Nrom : integer:=12; -- Размерность таблицы: 2^Nrom Nph_reg : integer:= 32; -- Разрядность регистра, -- хранящего шаг фазы. Nacc_reg : integer:= 32 -- Разрядность регистра-аккумулятора ); Port ( RESET : in std_logic; -- Вход асинхронного сброса. CLK : in std_logic; -- Вход тактовой частоты. SIN_OUT : out signed(11 downto 0) -- Выход сигнала ); end DDS_SIN; architecture rtl of DDS_SIN is -- Список сигналов type sin_coeff is array (0 to 2**Nrom-1) of signed (0 to Rb-1); signal sin_table : sin_coeff :=(to_signed(0,Rb).....); -- таблица -- значений синуса (вырезано) ATTRIBUTE ramstyle : string; ATTRIBUTE ramstyle of sin_table : signal is "M9K , no_rw_check"; signal acc_reg : unsigned(0 to Nacc_reg-1); signal freq_reg: unsigned(0 to Nph_reg-1); signal phase_reg: unsigned(0 to Nph_reg-1); signal clk1_trigger : std_logic; signal clk2_trigger : std_logic; begin ---------------------------------------------------------- Процесс генерации сигналов синусойды.-------------------------------------------------------- DDS_SIN_MAIN: process (CLK, RESET) begin -- Асинхронный сброс. Сбрасываем все что надо. if RESET='1' then acc_reg <= (others => '0'); SIN_OUT <= (others => '0'); phase_reg <= (others => '0'); freq_reg <= X"0CCC_CCCD"; -- Fout = FREQ_REG*Fs/2^32; -- FREQ_REG = Fout*2^32/Fs elsif rising_edge(CLK) then acc_reg <= acc_reg + phase_reg + freq_reg; SIN_OUT <= sin_table(to_integer(acc_reg(0 to Nrom-1))); end if; end process DDS_SIN_MAIN; end rtl;
Выходная частота DDS генератора задается с помощью инициализации регистра FREQ_REG и рассчитывается по формуле:
Сдвиг фазы сигнала задается с помощью PHASE_REG, формула следующая:
PH = 2*pi*PHASE_REG/2^32, PHASE_REG=0..2^32;
Аккумулятор фазы работает с постоянным переполнением, обеспечивая сложение по модулю 2^32. Необходимо заполнить таблицу синуса правильными значениями. Для этого используется Mathlab. Код, формирующий таблицу синуса для DDS генератора следующий:
% Генерация таблицы значений синусойдного сигнала для метода % прямого цифрового синтеза (DDS) % % Дата создания файла: 21.04.12 % clear all; disp('+++ Старт Программы'); %Генерируем таблицу преобразования фазы в выборки для синуса. Rb=12; %разрядность выходных данных Nrom=12; %Размерность таблицы: 2^Nrom Nph_reg = 32; %Разрядность регистра, хранящего шаг фазы. Nacc_reg = 32; %Разрядность регистра-аккумулятора Ph_step =2*pi/(2^Nrom-1); %шаг изменения фазы Ph = 0:Ph_step:2*pi; %Массив со всеми возможными значениями фаз %Генерируем значения синуса для периода 0..2pi, %по всем значениям фаз. Sin_table = sin(Ph); %Преобразуем последовательность в бинарную (разрешение - Rb бит) %Формат данных: прямой код (0..2^Rb) SIN_ROMTABLE = uencode(Sin_table,Rb,1,'signed'); % Записываем таблицу в файл для последующей загрузки в ПЛИС. outfile = fopen('C:\sin_table.txt','w'); fprintf(outfile, 'to_signed(%d,Rb),', SIN_ROMTABLE(1:end-1) ); fprintf(outfile, 'to_signed(%d,Rb));', SIN_ROMTABLE(end) ); fclose(outfile); disp('+++ Файл записан. Программа завершена.');
После выполнения программы в Mathlab создается файл, с заполненной таблицей синуса, эти значения необходимо перенести в VHDL проект генератора DDS, инициализировав сигнал sin_table.
Таблицу синуса необходимо синтезировать с помощью блочной памяти, в коде VHDL указаны соответствующие атрибуты для сигнала sin_table. Синтез дал следующий результат:
Total logic elements
Total registers
Total memory bits
Embedded multiplier
Автоматически отброшены лишние регистры из проекта, поскольку они не меняют своего значения во время выполнения, оставив только аккумулятор фазы. Получен DDS генератор. Занимаемую память можно уменьшить, учитывая свойство симметрии синуса, можно хранить только 1/4 периода, получая значения для остальных аргументов сдвигом, однако это усложнит адресацию нужного адреса в таблице. На практике, конечно, потребуется интерфейс для загрузки значения частоты, и начального сдвига фазы.