---------------------------------------------------------------------------------- -- 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;