Files
digital_microphone/src/cic_decim.vhd
T
nikit3s 668c0564e9 Порядок CIC 3 вместо 4: аккумуляторы шире 18 бит не работают в кристалле
Тракт молча отдавал нули: 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 чистый, на входе живой звук.
2026-08-18 12:06:43 +03:00

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;