commit 2d66c4903102050c9a5a6c7c75baa86604a81f83 Author: nikit3s Date: Fri Aug 14 15:54:53 2026 +0300 Модули буфера, упаковки кадров и UART FIFO, сборка кадра с CRC-16, передатчик UART и индикация переносятся из имеющегося наработанного тракта без изменения логики. В STATUS бит1 переопределён под насыщение дециматора: DRDY здесь нет. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..97a073c --- /dev/null +++ b/.gitignore @@ -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__/ diff --git a/src/Packets_creator.vhd b/src/Packets_creator.vhd new file mode 100644 index 0000000..6c45f62 --- /dev/null +++ b/src/Packets_creator.vhd @@ -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; diff --git a/src/UART.vhd b/src/UART.vhd new file mode 100644 index 0000000..2b66ef0 --- /dev/null +++ b/src/UART.vhd @@ -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; diff --git a/src/fifo_top.vhd b/src/fifo_top.vhd new file mode 100644 index 0000000..753985c --- /dev/null +++ b/src/fifo_top.vhd @@ -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; diff --git a/src/led_status.vhd b/src/led_status.vhd new file mode 100644 index 0000000..8b44eeb --- /dev/null +++ b/src/led_status.vhd @@ -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;