Модули буфера, упаковки кадров и UART

FIFO, сборка кадра с CRC-16, передатчик UART и индикация переносятся
из имеющегося наработанного тракта без изменения логики. В STATUS бит1
переопределён под насыщение дециматора: DRDY здесь нет.
This commit is contained in:
nikit3s
2026-08-14 15:54:53 +03:00
commit 2d66c49031
5 changed files with 688 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
# Вывод Gowin IDE, кроме настроек синтеза/PnR
impl/*
!impl/*_process_config.json
*.gprj.user
# Даташиты: большие, не трекаем
docs/*.pdf
docs/*.PDF
docs/Primer_25K/
# Захваченные данные
*.bin
*.raw
*.log
# Симуляция
build/
*.cf
*.ghw
__pycache__/
+288
View File
@@ -0,0 +1,288 @@
----------------------------------------------------------------------------------
-- Company:
-- Engineer:
-- Create Date:
-- Design Name:
-- Module Name: Packets_creator - Behavioral
-- Project Name: DigMic_prj
-- Target Devices: Gowin GW5A-25
-- Description:
-- Кадр (157 байт при 50 отсчётах):
-- SYNC 2 байта A5 5A
-- FRAME_CNT 2 байта uint16 BE
-- STATUS 1 байт бит0 переполнение FIFO, бит1 насыщение дециматора
-- DATA 150 байт 50 отсчётов x 24 бита, MSB first
-- CRC16 2 байта CCITT, poly 0x1021, init 0xFFFF, по FRAME_CNT..DATA
--
-- Байты SYNC в CRC не входят: они нужны приёмнику для ресинхронизации
-- до того, как он начнёт что-либо считать.
----------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity Packets_creator is
generic (
SAMPLES_PER_FRAME : integer := 50
);
port (
clk : in std_logic;
rst_n : in std_logic;
-- Со стороны FIFO
data_ADC : in std_logic_vector(23 downto 0); -- голова очереди
dready : in std_logic; -- набрался полный кадр
rd_en : out std_logic;
-- Для флагов состояния
wr_en : in std_logic; -- запись в FIFO, вместе с fifo_full даёт переполнение
fifo_full : in std_logic;
err_overrun : in std_logic; -- ошибка тракта, уходит в бит1 STATUS
-- Со стороны UART
busy_uart : in std_logic;
ena_uart : out std_logic;
dout : out std_logic_vector(7 downto 0);
fault : out std_logic -- была хотя бы одна ошибка с момента сброса
);
end entity Packets_creator;
architecture Behavioral of Packets_creator is
constant SYNC0 : std_logic_vector(7 downto 0) := x"A5";
constant SYNC1 : std_logic_vector(7 downto 0) := x"5A";
type fstate_t is (F_WAIT, F_SYNC0, F_SYNC1, F_CNT_H, F_CNT_L, F_STATUS,
F_FETCH, F_FETCH1, F_FETCH2, F_DATA, F_CRC_H, F_CRC_L);
signal fstate : fstate_t := F_WAIT;
signal waiting : std_logic := '0';
signal byte_go : std_logic := '0';
signal byte_val : std_logic_vector(7 downto 0) := (others => '0');
signal byte_ack : std_logic := '0';
signal sample_reg : std_logic_vector(23 downto 0) := (others => '0');
signal sample_no : integer range 0 to SAMPLES_PER_FRAME - 1 := 0;
signal byte_idx : integer range 0 to 2 := 0;
signal frame_cnt : unsigned(15 downto 0) := (others => '0');
signal status_lat : std_logic_vector(7 downto 0) := (others => '0');
signal crc_reg : std_logic_vector(15 downto 0) := (others => '1');
signal ovf_sticky : std_logic := '0';
signal err_sticky : std_logic := '0';
signal fault_r : std_logic := '0';
type tstate_t is (T_IDLE, T_SEND, T_WAIT);
signal tstate : tstate_t := T_IDLE;
signal hold : std_logic_vector(7 downto 0) := (others => '0');
-- CRC-16/CCITT по одному байту, MSB-first
function crc16_upd(crc : std_logic_vector(15 downto 0);
d : std_logic_vector(7 downto 0))
return std_logic_vector is
variable c : std_logic_vector(15 downto 0) := crc;
variable fb : std_logic;
begin
for i in 7 downto 0 loop
fb := c(15) xor d(i);
c := c(14 downto 0) & '0';
if fb = '1' then
c := c xor x"1021";
end if;
end loop;
return c;
end function;
begin
fault <= fault_r;
-- Отдача байта в UART: ждём освобождения передатчика, даём однотактовый ena,
-- подтверждаем вызывающему по факту взведения busy_uart
tx_proc : process (clk, rst_n)
begin
if rst_n = '0' then
tstate <= T_IDLE;
hold <= (others => '0');
ena_uart <= '0';
dout <= (others => '0');
byte_ack <= '0';
elsif rising_edge(clk) then
ena_uart <= '0';
byte_ack <= '0';
case tstate is
when T_IDLE =>
if byte_go = '1' then
hold <= byte_val;
tstate <= T_SEND;
end if;
when T_SEND =>
if busy_uart = '0' then
dout <= hold;
ena_uart <= '1';
tstate <= T_WAIT;
end if;
when T_WAIT =>
if busy_uart = '1' then
byte_ack <= '1';
tstate <= T_IDLE;
end if;
end case;
end if;
end process tx_proc;
frame_proc : process (clk, rst_n)
variable b : std_logic_vector(7 downto 0);
begin
if rst_n = '0' then
fstate <= F_WAIT;
waiting <= '0';
byte_go <= '0';
byte_val <= (others => '0');
rd_en <= '0';
sample_reg <= (others => '0');
sample_no <= 0;
byte_idx <= 0;
frame_cnt <= (others => '0');
status_lat <= (others => '0');
crc_reg <= (others => '1');
ovf_sticky <= '0';
err_sticky <= '0';
fault_r <= '0';
elsif rising_edge(clk) then
byte_go <= '0';
rd_en <= '0';
if waiting = '1' then
if byte_ack = '1' then
waiting <= '0';
case fstate is
when F_SYNC0 => fstate <= F_SYNC1;
when F_SYNC1 => fstate <= F_CNT_H;
when F_CNT_H => fstate <= F_CNT_L;
when F_CNT_L => fstate <= F_STATUS;
when F_STATUS =>
sample_no <= 0;
fstate <= F_FETCH;
when F_DATA =>
if byte_idx = 2 then
byte_idx <= 0;
if sample_no = SAMPLES_PER_FRAME - 1 then
fstate <= F_CRC_H;
else
sample_no <= sample_no + 1;
fstate <= F_FETCH;
end if;
else
byte_idx <= byte_idx + 1;
end if;
when F_CRC_H => fstate <= F_CRC_L;
when F_CRC_L =>
frame_cnt <= frame_cnt + 1;
fstate <= F_WAIT;
when others => fstate <= F_WAIT;
end case;
end if;
else
case fstate is
when F_WAIT =>
-- Кадр начинаем только когда отсчётов набралось на полный кадр:
-- иначе передатчик упрётся в пустой FIFO посреди кадра
if dready = '1' then
crc_reg <= (others => '1');
status_lat <= (1 => err_sticky, 0 => ovf_sticky, others => '0');
ovf_sticky <= '0';
err_sticky <= '0';
fstate <= F_SYNC0;
end if;
when F_SYNC0 =>
byte_val <= SYNC0;
byte_go <= '1';
waiting <= '1';
when F_SYNC1 =>
byte_val <= SYNC1;
byte_go <= '1';
waiting <= '1';
when F_CNT_H =>
b := std_logic_vector(frame_cnt(15 downto 8));
byte_val <= b;
crc_reg <= crc16_upd(crc_reg, b);
byte_go <= '1';
waiting <= '1';
when F_CNT_L =>
b := std_logic_vector(frame_cnt(7 downto 0));
byte_val <= b;
crc_reg <= crc16_upd(crc_reg, b);
byte_go <= '1';
waiting <= '1';
when F_STATUS =>
byte_val <= status_lat;
crc_reg <= crc16_upd(crc_reg, status_lat);
byte_go <= '1';
waiting <= '1';
-- Импульс rd_en, и очередное слово
-- появляется на data_ADC со следующего такта. Два такта ожидания
-- вместо одного -- запас, обмен всё равно идёт раз в три байта UART.
when F_FETCH =>
rd_en <= '1';
fstate <= F_FETCH1;
when F_FETCH1 =>
fstate <= F_FETCH2;
when F_FETCH2 =>
sample_reg <= data_ADC;
byte_idx <= 0;
fstate <= F_DATA;
when F_DATA =>
case byte_idx is
when 0 => b := sample_reg(23 downto 16);
when 1 => b := sample_reg(15 downto 8);
when others => b := sample_reg(7 downto 0);
end case;
byte_val <= b;
crc_reg <= crc16_upd(crc_reg, b);
byte_go <= '1';
waiting <= '1';
when F_CRC_H =>
byte_val <= crc_reg(15 downto 8);
byte_go <= '1';
waiting <= '1';
when F_CRC_L =>
byte_val <= crc_reg(7 downto 0);
byte_go <= '1';
waiting <= '1';
end case;
end if;
-- Флаги ошибок взводятся после автомата, чтобы взвод не потерялся
-- на такте очистки в начале кадра
if wr_en = '1' and fifo_full = '1' then
ovf_sticky <= '1';
fault_r <= '1';
end if;
if err_overrun = '1' then
err_sticky <= '1';
fault_r <= '1';
end if;
end if;
end process frame_proc;
end architecture Behavioral;
+198
View File
@@ -0,0 +1,198 @@
--------------------------------------------------------------------------------
--
-- FileName: uart.vhd
-- Dependencies: none
-- Design Software: Quartus II 64-bit Version 13.1.0 Build 162 SJ Web Edition
--
-- HDL CODE IS PROVIDED "AS IS." DIGI-KEY EXPRESSLY DISCLAIMS ANY
-- WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING BUT NOT
-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
-- PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL DIGI-KEY
-- BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL
-- DAMAGES, LOST PROFITS OR LOST DATA, HARM TO YOUR EQUIPMENT, COST OF
-- PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
-- BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF),
-- ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER SIMILAR COSTS.
--
-- Version History
-- Version 1.0 5/26/2017 Scott Larson
-- Initial Public Release
-- Version 1.1 8/3/2021 Scott Larson
-- Corrected rx start bit error checking
--
--------------------------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY uart IS
GENERIC(
clk_freq : INTEGER := 50_000_000; --frequency of system clock in Hertz
baud_rate : INTEGER := 921600; --data link baud rate in bits/second
os_rate : INTEGER := 16; --oversampling rate to find center of receive bits (in samples per baud period)
d_width : INTEGER := 8; --data bus width
parity : INTEGER := 0; --0 for no parity, 1 for parity
parity_eo : STD_LOGIC := '0'); --'0' for even, '1' for odd parity
PORT(
clk : IN STD_LOGIC; --system clock
reset_n : IN STD_LOGIC; --ascynchronous reset
tx_ena : IN STD_LOGIC; --initiate transmission
tx_data : IN STD_LOGIC_VECTOR(d_width-1 DOWNTO 0); --data to transmit
rx : IN STD_LOGIC; --receive pin
rx_busy : OUT STD_LOGIC; --data reception in progress
rx_error : OUT STD_LOGIC; --start, parity, or stop bit error detected
rx_data : OUT STD_LOGIC_VECTOR(d_width-1 DOWNTO 0); --data received
tx_busy : OUT STD_LOGIC; --transmission in progress
tx : OUT STD_LOGIC); --transmit pin
END uart;
ARCHITECTURE logic OF uart IS
TYPE tx_machine IS(idle, transmit); --tranmit state machine data type
TYPE rx_machine IS(idle, receive); --receive state machine data type
SIGNAL tx_state : tx_machine; --transmit state machine
SIGNAL rx_state : rx_machine; --receive state machine
SIGNAL baud_pulse : STD_LOGIC := '0'; --periodic pulse that occurs at the baud rate
SIGNAL os_pulse : STD_LOGIC := '0'; --periodic pulse that occurs at the oversampling rate
SIGNAL parity_error : STD_LOGIC; --receive parity error flag
SIGNAL rx_parity : STD_LOGIC_VECTOR(d_width DOWNTO 0); --calculation of receive parity
SIGNAL tx_parity : STD_LOGIC_VECTOR(d_width DOWNTO 0); --calculation of transmit parity
SIGNAL rx_buffer : STD_LOGIC_VECTOR(parity+d_width DOWNTO 0) := (OTHERS => '0'); --values received
SIGNAL tx_buffer : STD_LOGIC_VECTOR(parity+d_width+1 DOWNTO 0) := (OTHERS => '1'); --values to be transmitted
BEGIN
--generate clock enable pulses at the baud rate and the oversampling rate
PROCESS(reset_n, clk)
VARIABLE count_baud : INTEGER RANGE 0 TO clk_freq/baud_rate-1 := 0; --counter to determine baud rate period
VARIABLE count_os : INTEGER RANGE 0 TO clk_freq/baud_rate/os_rate-1 := 0; --counter to determine oversampling period
BEGIN
IF(reset_n = '0') THEN --asynchronous reset asserted
baud_pulse <= '0'; --reset baud rate pulse
os_pulse <= '0'; --reset oversampling rate pulse
count_baud := 0; --reset baud period counter
count_os := 0; --reset oversampling period counter
ELSIF(clk'EVENT AND clk = '1') THEN
--create baud enable pulse
IF(count_baud < clk_freq/baud_rate-1) THEN --baud period not reached
count_baud := count_baud + 1; --increment baud period counter
baud_pulse <= '0'; --deassert baud rate pulse
ELSE --baud period reached
count_baud := 0; --reset baud period counter
baud_pulse <= '1'; --assert baud rate pulse
count_os := 0; --reset oversampling period counter to avoid cumulative error
END IF;
--create oversampling enable pulse
IF(count_os < clk_freq/baud_rate/os_rate-1) THEN --oversampling period not reached
count_os := count_os + 1; --increment oversampling period counter
os_pulse <= '0'; --deassert oversampling rate pulse
ELSE --oversampling period reached
count_os := 0; --reset oversampling period counter
os_pulse <= '1'; --assert oversampling pulse
END IF;
END IF;
END PROCESS;
--receive state machine
PROCESS(reset_n, clk)
VARIABLE rx_count : INTEGER RANGE 0 TO parity+d_width+2 := 0; --count the bits received
VARIABLE os_count : INTEGER RANGE 0 TO os_rate-1 := 0; --count the oversampling rate pulses
BEGIN
IF(reset_n = '0') THEN --asynchronous reset asserted
os_count := 0; --clear oversampling pulse counter
rx_count := 0; --clear receive bit counter
rx_busy <= '0'; --clear receive busy signal
rx_error <= '0'; --clear receive errors
rx_data <= (OTHERS => '0'); --clear received data output
rx_state <= idle; --put in idle state
ELSIF(clk'EVENT AND clk = '1' AND os_pulse = '1') THEN --enable clock at oversampling rate
CASE rx_state IS
WHEN idle => --idle state
rx_busy <= '0'; --clear receive busy flag
IF(rx = '0') THEN --start bit might be present
IF(os_count < os_rate/2) THEN --oversampling pulse counter is not at start bit center
os_count := os_count + 1; --increment oversampling pulse counter
rx_state <= idle; --remain in idle state
ELSE --oversampling pulse counter is at bit center
os_count := 0; --clear oversampling pulse counter
rx_count := 0; --clear the bits received counter
rx_busy <= '1'; --assert busy flag
rx_buffer <= rx & rx_buffer(parity+d_width DOWNTO 1); --shift the start bit into receive buffer
rx_state <= receive; --advance to receive state
END IF;
ELSE --start bit not present
os_count := 0; --clear oversampling pulse counter
rx_state <= idle; --remain in idle state
END IF;
WHEN receive => --receive state
IF(os_count < os_rate-1) THEN --not center of bit
os_count := os_count + 1; --increment oversampling pulse counter
rx_state <= receive; --remain in receive state
ELSIF(rx_count < parity+d_width) THEN --center of bit and not all bits received
os_count := 0; --reset oversampling pulse counter
rx_count := rx_count + 1; --increment number of bits received counter
rx_buffer <= rx & rx_buffer(parity+d_width DOWNTO 1); --shift new received bit into receive buffer
rx_state <= receive; --remain in receive state
ELSE --center of stop bit
rx_data <= rx_buffer(d_width DOWNTO 1); --output data received to user logic
rx_error <= rx_buffer(0) OR parity_error OR NOT rx; --output start, parity, and stop bit error flag
rx_busy <= '0'; --deassert received busy flag
rx_state <= idle; --return to idle state
END IF;
END CASE;
END IF;
END PROCESS;
--receive parity calculation logic
rx_parity(0) <= parity_eo;
rx_parity_logic: FOR i IN 0 to d_width-1 GENERATE
rx_parity(i+1) <= rx_parity(i) XOR rx_buffer(i+1);
END GENERATE;
WITH parity SELECT --compare calculated parity bit with received parity bit to determine error
parity_error <= rx_parity(d_width) XOR rx_buffer(parity+d_width) WHEN 1, --using parity
'0' WHEN OTHERS; --not using parity
--transmit state machine
PROCESS(reset_n, clk)
VARIABLE tx_count : INTEGER RANGE 0 TO parity+d_width+3 := 0; --count bits transmitted
BEGIN
IF(reset_n = '0') THEN --asynchronous reset asserted
tx_count := 0; --clear transmit bit counter
tx <= '1'; --set tx pin to idle value of high
tx_busy <= '1'; --set transmit busy signal to indicate unavailable
tx_state <= idle; --set tx state machine to ready state
ELSIF(clk'EVENT AND clk = '1') THEN
CASE tx_state IS
WHEN idle => --idle state
IF(tx_ena = '1') THEN --new transaction latched in
tx_buffer(d_width+1 DOWNTO 0) <= tx_data & '0' & '1'; --latch in data for transmission and start/stop bits
IF(parity = 1) THEN --if parity is used
tx_buffer(parity+d_width+1) <= tx_parity(d_width); --latch in parity bit from parity logic
END IF;
tx_busy <= '1'; --assert transmit busy flag
tx_count := 0; --clear transmit bit count
tx_state <= transmit; --proceed to transmit state
ELSE --no new transaction initiated
tx_busy <= '0'; --clear transmit busy flag
tx_state <= idle; --remain in idle state
END IF;
WHEN transmit => --transmit state
IF(baud_pulse = '1') THEN --beginning of bit
tx_count := tx_count + 1; --increment transmit bit counter
tx_buffer <= '1' & tx_buffer(parity+d_width+1 DOWNTO 1); --shift transmit buffer to output next bit
END IF;
IF(tx_count < parity+d_width+3) THEN --not all bits transmitted
tx_state <= transmit; --remain in transmit state
ELSE --all bits transmitted
tx_state <= idle; --return to idle state
END IF;
END CASE;
tx <= tx_buffer(0); --output last bit in transmit transaction buffer
END IF;
END PROCESS;
--transmit parity calculation logic
tx_parity(0) <= parity_eo;
tx_parity_logic: FOR i IN 0 to d_width-1 GENERATE
tx_parity(i+1) <= tx_parity(i) XOR tx_data(i);
END GENERATE;
END logic;
+104
View File
@@ -0,0 +1,104 @@
----------------------------------------------------------------------------------
-- Company:
-- Engineer:
-- Create Date:
-- Design Name:
-- Module Name: fifo_top - Behavioral
-- Project Name: DigMic_prj
-- Target Devices: Gowin GW5A-25
-- Description:
----------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity fifo_top is
generic (
DWIDTH : natural := 24; -- разрядность слова
DEPTH : natural := 128; -- глубина
AF_LEVEL : natural := 50 -- порог Almost_Full
);
port (
Data : in std_logic_vector(DWIDTH - 1 downto 0);
WrClk : in std_logic;
RdClk : in std_logic;
WrEn : in std_logic;
RdEn : in std_logic;
Q : out std_logic_vector(DWIDTH - 1 downto 0);
Empty : out std_logic;
Almost_Full : out std_logic;
Full : out std_logic
);
end entity fifo_top;
architecture rtl of fifo_top is
type mem_t is array (0 to DEPTH - 1) of std_logic_vector(DWIDTH - 1 downto 0);
signal mem : mem_t;
signal wr_ptr : integer range 0 to DEPTH - 1 := 0;
signal rd_ptr : integer range 0 to DEPTH - 1 := 0;
signal count : integer range 0 to DEPTH := 0;
signal full_i : std_logic;
signal empty_i : std_logic;
signal wr_ok : std_logic;
signal rd_ok : std_logic;
begin
full_i <= '1' when count = DEPTH else '0';
empty_i <= '1' when count = 0 else '0';
Full <= full_i;
Empty <= empty_i;
Almost_Full <= '1' when count >= AF_LEVEL else '0';
-- Запись при полном буфере и чтение при пустом игнорируются, как у ядра
wr_ok <= WrEn and not full_i;
rd_ok <= RdEn and not empty_i;
-- Содержимое памяти намеренно не сбрасывается: сброс массива не даёт
-- синтезатору вывести блочную память
mem_proc : process (WrClk)
begin
if rising_edge(WrClk) then
if wr_ok = '1' then
mem(wr_ptr) <= Data;
end if;
-- Q меняется только по состоявшемуся чтению: со следующего такта
-- после RdEn на нём лежит очередное слово
if rd_ok = '1' then
Q <= mem(rd_ptr);
end if;
end if;
end process mem_proc;
ptr_proc : process (WrClk)
begin
if rising_edge(WrClk) then
if wr_ok = '1' then
if wr_ptr = DEPTH - 1 then
wr_ptr <= 0;
else
wr_ptr <= wr_ptr + 1;
end if;
end if;
if rd_ok = '1' then
if rd_ptr = DEPTH - 1 then
rd_ptr <= 0;
else
rd_ptr <= rd_ptr + 1;
end if;
end if;
if wr_ok = '1' and rd_ok = '0' then
count <= count + 1;
elsif wr_ok = '0' and rd_ok = '1' then
count <= count - 1;
end if;
end if;
end process ptr_proc;
end architecture rtl;
+77
View File
@@ -0,0 +1,77 @@
----------------------------------------------------------------------------------
-- Company:
-- Engineer:
-- Create Date:
-- Design Name:
-- Module Name: led_status - Behavioral
-- Project Name: DigMic_prj
-- Target Devices: Gowin GW5A-25
-- Description: Индикация состояния тракта.
-- не меняется — тактирования на clk нет вообще
-- медленно — тактирование есть, отсчёты с дециматора не приходят
-- быстро — отсчёты идут. Значит тракт PDM -> CIC -> FIR работает.
--
-- Сброс намеренно не используется: мигание должно доказывать наличие клока
-- даже если остальной тракт по какой-то причине стоит.
----------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
entity led_status is
generic (
SYS_CLK_HZ : integer := 50_000_000;
SLOW_HZ : integer := 2; -- нет отсчётов
FAST_HZ : integer := 10; -- отсчёты идут
ALIVE_MS : integer := 200 -- за какое время без отсчётов считаем, что их нет
);
port (
clk : in std_logic;
data_event : in std_logic; -- строб прихода отсчёта
led : out std_logic
);
end entity led_status;
architecture rtl of led_status is
constant HALF_SLOW : integer := SYS_CLK_HZ / (2 * SLOW_HZ);
constant HALF_FAST : integer := SYS_CLK_HZ / (2 * FAST_HZ);
constant ALIVE_TMO : integer := (SYS_CLK_HZ / 1000) * ALIVE_MS;
signal alive_cnt : integer range 0 to ALIVE_TMO := 0;
signal data_alive : std_logic := '0';
signal blk_cnt : integer range 0 to HALF_SLOW - 1 := 0;
signal blink : std_logic := '0';
begin
led <= blink;
led_proc : process (clk)
variable half : integer range 0 to HALF_SLOW;
begin
if rising_edge(clk) then
if data_event = '1' then
alive_cnt <= 0;
data_alive <= '1';
elsif alive_cnt = ALIVE_TMO then
data_alive <= '0';
else
alive_cnt <= alive_cnt + 1;
end if;
if data_alive = '1' then
half := HALF_FAST;
else
half := HALF_SLOW;
end if;
if blk_cnt >= half - 1 then
blk_cnt <= 0;
blink <= not blink;
else
blk_cnt <= blk_cnt + 1;
end if;
end if;
end process led_proc;
end architecture rtl;