289 lines
9.4 KiB
VHDL
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;
|