ws2812b-eth/top.vhd

397 lines
9.9 KiB
VHDL

-------------------------------------------------------------------------------
-- Title : Ethernet controlled WS2812b
-- Project :
-------------------------------------------------------------------------------
-- File : top.vhd
-- Author : Mario Hüttel <mario.huettel@gmx.net>
-- Company :
-- Created : 2018-04-05
-- Last update: 2018-04-13
-- Platform :
-- Standard : VHDL'93/02
-------------------------------------------------------------------------------
-- Description:
-------------------------------------------------------------------------------
-- Copyright (c) 2018
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity top is
port (
clk : in std_logic;
rst_hw : in std_logic;
mdio : inout std_logic;
mdc : out std_logic;
rx : in std_logic_vector(1 downto 0);
dv : in std_logic;
led1 : out std_logic;
led2 : out std_logic;
dat_cnt : out std_logic_vector(3 downto 0);
ws_out : out std_logic);
end entity top;
architecture RTL of top is
constant DELAYCNTVAL : integer := 100000; -- set to low value for
-- simulation
constant STARTUPDELAY : integer := 50000000;
constant DEFMAC : std_logic_vector(47 downto 0) := x"00DEADBEEF00";
type smi_state_t is (IDLE, STROBE);
type smi_init_state_t is (SMI_POR, SMI_PORDELAY, RESET, INIT, DELAY, INIT_COMPLETE);
type ws_send_t is (WS_READY, WS_SYNC, WS_RED, WS_GREEN, WS_BLUE, WS_PIPE, WS_POST);
type receive_t is (PRE, DESTMAC, HEADER, RECV, WAITFORACK);
signal rst : std_logic;
signal dat_cnt_s : unsigned(3 downto 0);
signal sendstate : smi_state_t;
signal initstate : smi_init_state_t := SMI_POR;
signal rst_rxtx : std_logic;
signal delaycounter : unsigned(26 downto 0);
signal smi_reg : std_logic_vector(4 downto 0);
signal smi_dat : std_logic_vector(15 downto 0);
signal smi_strb : std_logic;
signal smi_busy : std_logic;
---
signal sof : std_logic;
signal eof : std_logic;
signal eth_dat : std_logic_vector(7 downto 0);
signal eth_strb : std_logic;
signal crc_valid : std_logic;
--
signal fifo_in : std_logic_vector(7 downto 0);
signal fifo_out : std_logic_vector(7 downto 0);
signal fifo_wr : std_logic;
signal fifo_rd : std_logic;
signal fifo_rst : std_logic;
signal fifo_full : std_logic;
signal fifo_empty : std_logic;
--
signal fifo_data_avail : std_logic;
signal fifo_data_ack : std_logic;
signal recv_state : receive_t;
signal mac : std_logic_vector(47 downto 0);
signal recv_cnt : integer range 0 to 15;
--
signal ws_busy : std_logic;
signal ws_strb : std_logic;
signal red : unsigned(7 downto 0);
signal green : unsigned(7 downto 0);
signal blue : unsigned(7 downto 0);
--
signal ws_state : ws_send_t;
begin -- architecture RTL
reset_sync : process(clk, rst_hw) is
begin
if rst_hw = '0' then
rst <= '1';
elsif rising_edge(clk) then
if rst_hw = '1' then
rst <= '0';
end if;
end if;
end process reset_sync;
smi_1 : entity work.smi
generic map (
clockdiv => 64)
port map (
clk_i => clk,
rst_i => rst,
mdio_io => mdio,
mdc_o => mdc,
busy_o => smi_busy,
data_o => open,
phyaddr_i => "00001",
regaddr_i => smi_reg,
data_i => smi_dat,
strb_i => smi_strb,
rw_i => '0');
ethmac_rx_1 : entity work.ethmac_rx
port map (
clk_50 => clk,
rst => rst_rxtx,
rmii_rx => rx,
rmii_dv => dv,
start_of_frame => sof,
end_of_frame => eof,
data_out => eth_dat,
data_strb => eth_strb,
crc_check_valid => crc_valid);
-- fifo_dc_1 : entity work.fifo_dc
-- port map (
-- Data => fifo_in,
-- WrClock => clk,
-- RdClock => clk,
-- WrEn => fifo_wr,
-- RdEn => fifo_rd,
-- Reset => fifo_rst,
-- RPReset => fifo_rst,
-- Q => fifo_out,
-- Empty => fifo_empty,
-- Full => fifo_full,
-- AlmostEmpty => open,
-- AlmostFull => open);
STD_FIFO_1 : entity work.STD_FIFO
generic map (
DATA_WIDTH => 8,
FIFO_DEPTH => 360*3)
port map (
CLK => clk,
RST => fifo_rst,
WriteEn => fifo_wr,
DataIn => fifo_in,
ReadEn => fifo_rd,
DataOut => fifo_out,
Empty => fifo_empty,
Full => fifo_full);
wsphy1 : entity work.ws2812bphy
generic map (
HIGH1 => 40,
LOW1 => 23,
HIGH0 => 20,
LOW0 => 43)
port map (
clk => clk,
rst => rst,
busy => ws_busy,
ws_out => ws_out,
strb => ws_strb,
red => red,
green => green,
blue => blue);
initphy : process(clk, rst) is
procedure sendsmi(regaddr : in std_logic_vector(4 downto 0);
data : in std_logic_vector(15 downto 0);
nextstate : in smi_init_state_t) is
begin
case sendstate is
when IDLE =>
smi_reg <= regaddr;
smi_dat <= data;
if smi_busy = '0' then
smi_strb <= '1';
sendstate <= STROBE;
end if;
when STROBE =>
initstate <= nextstate;
sendstate <= IDLE;
end case;
end procedure sendsmi;
begin
if rst = '1' then
smi_reg <= (others => '0');
smi_dat <= (others => '0');
smi_strb <= '0';
rst_rxtx <= '1';
initstate <= SMI_POR;
sendstate <= IDLE;
delaycounter <= (others => '0');
elsif rising_edge(clk) then
smi_strb <= '0';
rst_rxtx <= '1';
case initstate is
when SMI_POR =>
delaycounter <= (others => '0');
initstate <= SMI_PORDELAY;
when SMI_PORDELAY =>
delaycounter <= delaycounter + 1;
if delaycounter = STARTUPDELAY then
initstate <= RESET;
end if;
when RESET =>
delaycounter <= (others => '0');
sendsmi((others => '0'), x"8000", DELAY);
when DELAY =>
delaycounter <= delaycounter + 1;
if delaycounter = DELAYCNTVAL then -- Set to 100000
initstate <= INIT;
end if;
when INIT =>
sendsmi((others => '0'), "00" & '1' & '1' & "000" & '1' & "00000000", INIT_COMPLETE);
when INIT_COMPLETE =>
initstate <= INIT_COMPLETE;
if smi_busy = '0' then
rst_rxtx <= '0';
end if;
end case;
end if;
end process initphy;
receive_fifo : process (clk, rst) is
begin -- process receive_fifo
if rst = '1' then -- asynchronous reset (active high)
fifo_rst <= '1';
fifo_wr <= '0';
fifo_in <= (others => '0');
fifo_data_avail <= '0';
recv_state <= PRE;
dat_cnt_s <= (others => '0');
led1 <= '1';
led2 <= '1';
recv_cnt <= 0;
mac <= (others => '0');
elsif rising_edge(clk) then -- rising clock edge
fifo_rst <= '0';
fifo_wr <= '0';
case recv_state is
when PRE =>
if sof = '1' then
recv_cnt <= 0;
mac <= (others => '0');
recv_state <= DESTMAC;
led1 <= '1';
led2 <= '1';
end if;
when DESTMAC =>
if eof = '1' then
recv_state <= PRE;
elsif eth_strb = '1' then
recv_cnt <= recv_cnt + 1;
mac <= mac(39 downto 0) & eth_dat;
if recv_cnt = 5 then
recv_cnt <= 0;
recv_state <= HEADER;
end if;
end if;
when HEADER =>
led1 <= '0';
if eof = '1' then
recv_state <= PRE;
elsif eth_strb = '1' then
recv_cnt <= recv_cnt + 1;
if recv_cnt = 7 then
if mac = DEFMAC then
recv_state <= RECV;
dat_cnt_s <= (others => '0');
else
recv_state <= PRE;
end if;
end if;
end if;
when RECV =>
led2 <= '0';
if eth_strb = '1' and fifo_full /= '1' then
fifo_in <= eth_dat;
fifo_wr <= '1';
dat_cnt_s <= dat_cnt_s +1;
end if;
if eof = '1' then
if crc_valid = '1' then -- or crc_valid = '0' then
recv_state <= WAITFORACK;
fifo_data_avail <= '1';
--led2 <= '0';
else
--led2 <= '1';
fifo_rst <= '1';
recv_state <= PRE;
end if;
end if;
when WAITFORACK =>
fifo_data_avail <= '1';
if fifo_data_ack = '1' then
recv_state <= PRE;
fifo_data_avail <= '0';
-- fifo_rst <= '1';
end if;
when others => null;
end case;
end if;
end process receive_fifo;
ws_write : process (clk, rst) is
-- variable ws_send_cnt : integer range 0 to 7 := 0;
begin -- process ws_write
if rst = '1' then -- asynchronous reset (active high)
red <= (others => '0');
green <= (others => '0');
blue <= (others => '0');
ws_strb <= '0';
fifo_rd <= '0';
fifo_data_ack <= '0';
ws_state <= WS_READY;
elsif rising_edge(clk) then -- rising clock edge
ws_strb <= '0';
fifo_rd <= '0';
fifo_data_ack <= '0';
case ws_state is
when WS_READY =>
if fifo_data_avail = '1' then
if fifo_empty = '0' then
ws_state <= WS_SYNC;
fifo_rd <= '1'; -- read red
else
ws_state <= WS_POST;
end if;
end if;
when WS_SYNC =>
if fifo_empty = '1' then
ws_state <= WS_POST;
else
fifo_rd <= '1'; --read green
ws_state <= WS_RED;
end if;
when WS_RED =>
if fifo_empty = '1' then
ws_state <= WS_POST;
else
fifo_rd <= '1'; --read blue
red <= unsigned(fifo_out);
ws_state <= WS_GREEN;
end if;
when WS_GREEN =>
if fifo_empty = '1' then
ws_state <= WS_POST;
else
green <= unsigned(fifo_out);
ws_state <= WS_BLUE;
end if;
when WS_BLUE =>
blue <= unsigned(fifo_out);
ws_state <= WS_PIPE;
when WS_PIPE =>
if ws_busy = '0' and ws_strb = '0' then
ws_strb <= '1';
if fifo_empty = '0' then
ws_state <= WS_SYNC;
fifo_rd <= '1'; -- read
else
ws_state <= WS_POST;
end if;
end if;
when WS_POST =>
if ws_busy = '0' and fifo_data_ack = '0' then
fifo_data_ack <= '1';
elsif fifo_data_ack = '1' and fifo_data_avail = '1' then
ws_state <= WS_READY;
end if;
end case;
end if;
end process ws_write;
dat_cnt <= std_logic_vector(dat_cnt_s);
end architecture RTL;