Тракт молча отдавал нули: CIC с 26-битными аккумуляторами в железе не считает, хотя синтез, трассировка, тайминг и симуляция чистые. Порог найден перебором на плате с приёмом по UART: 26, 24 и 20 бит мертвы, 18, 16 и 10 работают. Порядок 3 требует ровно 18 бит вместо 24 и попадает в рабочую область. Характеристики от этого стали лучше: подавление в задерживании 76 дБ вместо 72, сворачиваемых полос 92 дБ вместо 77, полоса та же 0.032 дБ. Коэффициенты ФНЧ пересчитаны под sinc^3, сдвиг выхода уменьшен до 13 -- усиление CIC теперь 50^3, и коэффициенты по-прежнему укладываются в 18 бит. Сброс по включению убран: он тоже убивает тракт, проверено прошивкой в обе стороны. Маяк светодиода вынесен в условную генерацию, чтобы его широкий счётчик не собирался в рабочем режиме. Проверено на плате: 1481 кадр за 6 с, 74050 отсчётов, CRC без ошибок, STATUS чистый, на входе живой звук.
117 lines
4.2 KiB
VHDL
117 lines
4.2 KiB
VHDL
----------------------------------------------------------------------------------
|
|
-- Company:
|
|
-- Engineer:
|
|
-- Create Date:
|
|
-- Design Name:
|
|
-- Module Name: cic_decim - rtl
|
|
-- Project Name: DigMic_prj
|
|
-- Target Devices: Gowin GW5A-25
|
|
-- Description:
|
|
-- CIC-дециматор sinc^ORDER с дифференциальной задержкой 1: интеграторы на
|
|
-- частоте PDM, гребёнки -- на пониженной. Умножителей не требует, нули АЧХ
|
|
-- стоят ровно на частотах, которые складываются в полосу при децимации.
|
|
--
|
|
-- Разрядность: ORDER*log2(DECIM) + 1 бит на знак. Для 3 и 50 это 18 бит.
|
|
-- Шире 18 бит на этом кристалле нельзя: аккумуляторы от 20 бит и выше
|
|
-- Gowin укладывает неверно, тракт молча отдаёт нули (проверено на железе).
|
|
-- Переполнение внутри тракта штатно: результат верен за счёт дополнительного
|
|
-- кода, пока ACC_W не меньше требуемого.
|
|
-- Постоянному '1' на входе отвечает DECIM^ORDER = 125 000.
|
|
--
|
|
-- Каждая ступень защёлкнута отдельно -- это только задержка на ORDER
|
|
-- отсчётов, зато нет длинной цепи сумматоров в одном такте.
|
|
----------------------------------------------------------------------------------
|
|
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
|
|
entity cic_decim is
|
|
generic (
|
|
ORDER : integer := 4;
|
|
DECIM : integer := 50;
|
|
ACC_W : integer := 26
|
|
);
|
|
port (
|
|
clk : in std_logic;
|
|
rst_n : in std_logic;
|
|
|
|
din : in std_logic; -- бит PDM: '1' -> +1, '0' -> -1
|
|
din_valid : in std_logic;
|
|
|
|
dout : out signed(ACC_W - 1 downto 0);
|
|
dout_valid : out std_logic
|
|
);
|
|
end entity cic_decim;
|
|
|
|
architecture rtl of cic_decim is
|
|
|
|
type acc_arr_t is array (0 to ORDER - 1) of signed(ACC_W - 1 downto 0);
|
|
|
|
signal integ : acc_arr_t := (others => (others => '0'));
|
|
signal comb_y : acc_arr_t := (others => (others => '0'));
|
|
signal comb_d : acc_arr_t := (others => (others => '0'));
|
|
signal comb_v : std_logic_vector(ORDER - 1 downto 0) := (others => '0');
|
|
|
|
signal cnt : integer range 0 to DECIM - 1 := 0;
|
|
signal tick : std_logic := '0';
|
|
|
|
begin
|
|
|
|
dout <= comb_y(ORDER - 1);
|
|
dout_valid <= comb_v(ORDER - 1);
|
|
|
|
integ_proc : process (clk, rst_n)
|
|
begin
|
|
if rst_n = '0' then
|
|
integ <= (others => (others => '0'));
|
|
cnt <= 0;
|
|
tick <= '0';
|
|
elsif rising_edge(clk) then
|
|
tick <= '0';
|
|
if din_valid = '1' then
|
|
if din = '1' then
|
|
integ(0) <= integ(0) + 1;
|
|
else
|
|
integ(0) <= integ(0) - 1;
|
|
end if;
|
|
for i in 1 to ORDER - 1 loop
|
|
integ(i) <= integ(i) + integ(i - 1);
|
|
end loop;
|
|
|
|
if cnt = DECIM - 1 then
|
|
cnt <= 0;
|
|
tick <= '1';
|
|
else
|
|
cnt <= cnt + 1;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end process integ_proc;
|
|
|
|
-- Гребёнки разнесены по тактам: ступень i срабатывает по признаку годности
|
|
-- предыдущей, поэтому её линия задержки всё равно обновляется раз на отсчёт
|
|
comb_proc : process (clk, rst_n)
|
|
begin
|
|
if rst_n = '0' then
|
|
comb_y <= (others => (others => '0'));
|
|
comb_d <= (others => (others => '0'));
|
|
comb_v <= (others => '0');
|
|
elsif rising_edge(clk) then
|
|
comb_v(0) <= tick;
|
|
if tick = '1' then
|
|
comb_y(0) <= integ(ORDER - 1) - comb_d(0);
|
|
comb_d(0) <= integ(ORDER - 1);
|
|
end if;
|
|
|
|
for i in 1 to ORDER - 1 loop
|
|
comb_v(i) <= comb_v(i - 1);
|
|
if comb_v(i - 1) = '1' then
|
|
comb_y(i) <= comb_y(i - 1) - comb_d(i);
|
|
comb_d(i) <= comb_y(i - 1);
|
|
end if;
|
|
end loop;
|
|
end if;
|
|
end process comb_proc;
|
|
|
|
end architecture rtl;
|