Модули буфера, упаковки кадров и UART
FIFO, сборка кадра с CRC-16, передатчик UART и индикация переносятся из имеющегося наработанного тракта без изменения логики. В STATUS бит1 переопределён под насыщение дециматора: DRDY здесь нет.
This commit is contained in:
+21
@@ -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__/
|
||||
@@ -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
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
Reference in New Issue
Block a user