Files
AD7766_fw/src/Packets_creator.vhd
T

289 lines
9.4 KiB
VHDL

----------------------------------------------------------------------------------
-- Company:
-- Engineer:
-- Create Date:
-- Design Name:
-- Module Name: Packets_creator - Behavioral
-- Project Name: AD7766_prj
-- Target Devices: Gowin GW5A-25
-- Description:
-- Кадр (157 байт при 50 отсчётах):
-- SYNC 2 байта A5 5A
-- FRAME_CNT 2 байта uint16 BE
-- STATUS 1 байт бит0 переполнение FIFO, бит1 срыв чтения DRDY
-- 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;
-- Со стороны 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;