implemented first draft

This commit is contained in:
Mario Hüttel 2018-04-15 20:33:13 +02:00
commit 660765e332
6 changed files with 704 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*.o
*~

187
bench.vhd Normal file
View File

@ -0,0 +1,187 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity bench is
end entity bench;
architecture sim of bench is
signal clk : std_logic;
signal rst_hw : std_logic;
signal sck : std_logic;
signal mosi : std_logic;
signal cs : std_logic;
signal ready : std_logic;
signal ws_out : std_logic;
begin -- architecture sim
top_1 : entity work.top
port map (
clk => clk,
rst_hw => rst_hw,
sck => sck,
mosi => mosi,
cs => cs,
ready => ready,
ws_out => ws_out);
clk_gen : process is
begin
clk <= '0';
wait for 10 ns;
clk <= '1';
wait for 10 ns;
end process clk_gen;
rst_gen : process is
begin
rst_hw <= '1';
wait for 15 ns;
rst_hw <= '0';
wait;
end process rst_gen;
sck_gen : process is
begin
sck <= '0';
wait for 40 ns;
sck <= '1';
wait for 40 ns;
end process sck_gen;
send_spi : process is
procedure send24(dat : in std_logic_vector(23 downto 0)) is
variable data : std_logic_vector(dat'range);
begin
cs <= '1';
if ready /= '1' then
wait until ready = '1';
end if;
wait for 30 ns;
data := dat;
wait until falling_edge(sck);
cs <= '0';
mosi <= data(23);
data := data(22 downto 0) & '0';
wait until falling_edge(sck);
cs <= '0';
mosi <= data(23);
data := data(22 downto 0) & '0';
wait until falling_edge(sck);
cs <= '0';
mosi <= data(23);
data := data(22 downto 0) & '0';
wait until falling_edge(sck);
cs <= '0';
mosi <= data(23);
data := data(22 downto 0) & '0';
wait until falling_edge(sck);
cs <= '0';
mosi <= data(23);
data := data(22 downto 0) & '0';
wait until falling_edge(sck);
cs <= '0';
mosi <= data(23);
data := data(22 downto 0) & '0';
wait until falling_edge(sck);
cs <= '0';
mosi <= data(23);
data := data(22 downto 0) & '0';
wait until falling_edge(sck);
cs <= '0';
mosi <= data(23);
data := data(22 downto 0) & '0';
wait until falling_edge(sck);
cs <= '0';
mosi <= data(23);
data := data(22 downto 0) & '0';
wait until falling_edge(sck);
cs <= '0';
mosi <= data(23);
data := data(22 downto 0) & '0';
wait until falling_edge(sck);
cs <= '0';
mosi <= data(23);
data := data(22 downto 0) & '0';
wait until falling_edge(sck);
cs <= '0';
mosi <= data(23);
data := data(22 downto 0) & '0';
wait until falling_edge(sck);
cs <= '0';
mosi <= data(23);
data := data(22 downto 0) & '0';
wait until falling_edge(sck);
cs <= '0';
mosi <= data(23);
data := data(22 downto 0) & '0';
wait until falling_edge(sck);
cs <= '0';
mosi <= data(23);
data := data(22 downto 0) & '0';
wait until falling_edge(sck);
cs <= '0';
mosi <= data(23);
data := data(22 downto 0) & '0';
wait until falling_edge(sck);
cs <= '0';
mosi <= data(23);
data := data(22 downto 0) & '0';
wait until falling_edge(sck);
cs <= '0';
mosi <= data(23);
data := data(22 downto 0) & '0';
wait until falling_edge(sck);
cs <= '0';
mosi <= data(23);
data := data(22 downto 0) & '0';
wait until falling_edge(sck);
cs <= '0';
mosi <= data(23);
data := data(22 downto 0) & '0';
wait until falling_edge(sck);
cs <= '0';
mosi <= data(23);
data := data(22 downto 0) & '0';
wait until falling_edge(sck);
cs <= '0';
mosi <= data(23);
data := data(22 downto 0) & '0';
wait until falling_edge(sck);
cs <= '0';
mosi <= data(23);
data := data(22 downto 0) & '0';
wait until falling_edge(sck);
cs <= '0';
mosi <= data(23);
data := data(22 downto 0) & '0';
wait until falling_edge(sck);
cs <= '1';
end send24;
begin
cs <= '1';
wait for 50 ns;
send24(x"FF0055");
send24(x"CCFFAA");
send24(x"FF0055");
send24(x"CCFFAA");
send24(x"FF0055");
send24(x"CCFFAA");
send24(x"FF0055");
send24(x"CCFFAA");
send24(x"FF0055");
send24(x"CCFFAA");
send24(x"FF0055");
send24(x"CCFFAA");
send24(x"FF0055");
send24(x"CCFFAA");
send24(x"FF0055");
send24(x"CCFFAA");
send24(x"FF0055");
send24(x"CCFFAA");
send24(x"FF0055");
send24(x"CCFFAA");
wait;
end process send_spi;
end architecture sim;

96
fifo.vhd Normal file
View File

@ -0,0 +1,96 @@
-- Thanks to: http://www.deathbylogic.com/2013/07/vhdl-standard-fifo/
library IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;
entity STD_FIFO is
Generic (
DATA_WIDTH : positive := 8;
FIFO_DEPTH : positive := 256
);
Port (
CLK : in STD_LOGIC;
RST : in STD_LOGIC;
WriteEn : in STD_LOGIC;
DataIn : in STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0);
ReadEn : in STD_LOGIC;
DataOut : out STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0);
Empty : out STD_LOGIC;
Full : out STD_LOGIC
);
end STD_FIFO;
architecture Behavioral of STD_FIFO is
begin
-- Memory Pointer Process
fifo_proc : process (CLK)
type FIFO_Memory is array (0 to FIFO_DEPTH - 1) of STD_LOGIC_VECTOR (DATA_WIDTH - 1 downto 0);
variable Memory : FIFO_Memory;
variable Head : natural range 0 to FIFO_DEPTH - 1;
variable Tail : natural range 0 to FIFO_DEPTH - 1;
variable Looped : boolean;
begin
if rising_edge(CLK) then
if RST = '1' then
Head := 0;
Tail := 0;
Looped := false;
Full <= '0';
Empty <= '1';
else
if (ReadEn = '1') then
if ((Looped = true) or (Head /= Tail)) then
-- Update data output
DataOut <= Memory(Tail);
-- Update Tail pointer as needed
if (Tail = FIFO_DEPTH - 1) then
Tail := 0;
Looped := false;
else
Tail := Tail + 1;
end if;
end if;
end if;
if (WriteEn = '1') then
if ((Looped = false) or (Head /= Tail)) then
-- Write Data to Memory
Memory(Head) := DataIn;
-- Increment Head pointer as needed
if (Head = FIFO_DEPTH - 1) then
Head := 0;
Looped := true;
else
Head := Head + 1;
end if;
end if;
end if;
-- Update Empty and Full flags
if (Head = Tail) then
if Looped then
Full <= '1';
else
Empty <= '1';
end if;
else
Empty <= '0';
Full <= '0';
end if;
end if;
end if;
end process;
end Behavioral;

113
spi_slave.vhd Normal file
View File

@ -0,0 +1,113 @@
-------------------------------------------------------------------------------
-- Title : simple SPI slave
-- Project :
-------------------------------------------------------------------------------
-- File : spi_slave.vhd
-- Author : Mario Hüttel <mario.huettel@gmx.net>
-- Company :
-- Created : 2018-04-15
-- Last update: 2018-04-15
-- Platform :
-- Standard : VHDL'93/02
-------------------------------------------------------------------------------
-- Description: This SPI slaves samples the SPI's sck line
-- Therefore freq(clk) > 2.5 * freq(sck)
-------------------------------------------------------------------------------
-- Copyright (c) 2018
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity spi_slave is
generic (
DAT_WIDTH : natural := 8);
port (
clk : in std_logic;
rst : in std_logic;
cs : in std_logic;
sck : in std_logic;
miso : out std_logic;
mosi : in std_logic;
dat_o : out std_logic_vector(DAT_WIDTH - 1 downto 0);
dat_i : in std_logic_vector(DAT_WIDTH - 1 downto 0);
dat_o_strb : out std_logic;
dat_i_ack : out std_logic);
end entity spi_slave;
architecture RTL of spi_slave is
signal sck_old : std_logic;
signal sck_sync : std_logic;
signal mosi_sync : std_logic;
signal cs_sync : std_logic;
signal pos_edge : std_logic;
signal neg_edge : std_logic;
signal miso_int : std_logic;
signal cnt : integer range 0 to DAT_WIDTH-1;
signal shift_reg : std_logic_vector(DAT_WIDTH -1 downto 0);
begin -- architecture RTL
sync : process (clk, rst) is
begin -- process sck_sync
if rst = '1' then -- asynchronous reset (active high)
sck_sync <= '0';
mosi_sync <= '0';
cs_sync <= '0';
elsif rising_edge(clk) then -- rising clock edge
cs_sync <= cs;
mosi_sync <= mosi;
sck_sync <= sck;
end if;
end process sync;
edge_detector : process (clk, rst) is
begin -- process edge_detector
if rst = '1' then -- asynchronous reset (active high)
pos_edge <= '0';
neg_edge <= '0';
elsif rising_edge(clk) then -- rising clock edge
neg_edge <= '0';
pos_edge <= '0';
sck_old <= sck_sync;
if sck_old = '1' and sck_sync = '0' then
neg_edge <= '1';
elsif sck_old = '0' and sck_sync = '1' then
pos_edge <= '1';
end if;
end if;
end process edge_detector;
shifter : process (clk, rst) is
begin -- process shifter
if rst = '1' then -- asynchronous reset (active high)
shift_reg <= (others => '0');
dat_i_ack <= '0';
dat_o <= (others => '0');
miso_int <= '0';
cnt <= 0;
elsif rising_edge(clk) then -- rising clock edge
dat_i_ack <= '0';
dat_o_strb <= '0';
if pos_edge = '1' and cs_sync = '0' then
shift_reg <= shift_reg(DAT_WIDTH-2 downto 0) & mosi_sync;
miso_int <= shift_reg(7);
if cnt < DAT_WIDTH-1 then
cnt <= cnt + 1;
else
cnt <= 0;
end if;
if cnt = DAT_WIDTH - 1 then
dat_o <= shift_reg(DAT_WIDTH -2 downto 0) & mosi_sync;
dat_o_strb <= '1';
shift_reg <= dat_i;
dat_i_ack <= '1';
end if;
end if;
end if;
end process shifter;
miso <= miso_int when cs = '0' else 'Z';
end architecture RTL;

184
top.vhd Normal file
View File

@ -0,0 +1,184 @@
-------------------------------------------------------------------------------
-- Title : Top Level of SPI => WS2812b
-- Project :
-------------------------------------------------------------------------------
-- File : top.vhd
-- Author : Mario Hüttel <mario.huettel@gmx.net>
-- Company :
-- Created : 2018-04-15
-- Last update: 2018-04-15
-- Platform :
-- Standard : VHDL'93/02
-------------------------------------------------------------------------------
-- Description:
-------------------------------------------------------------------------------
-- Copyright (c) 2018 GPLv2
-------------------------------------------------------------------------------
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;
sck : in std_logic;
mosi : in std_logic;
cs : in std_logic;
ready : out std_logic; -- goes high when at least 10 LEDs can
-- be accepted
ws_out : out std_logic);
end entity top;
architecture RTL of top is
constant FIFO_DEPTH : positive := 20;
signal rst : std_logic;
signal fifo_empty : std_logic;
signal fifo_full : std_logic;
signal fifo_wr : std_logic;
signal fifo_rd : std_logic;
signal fifo_i : std_logic_vector(23 downto 0);
signal fifo_o : std_logic_vector(23 downto 0);
signal spi_dat_o : std_logic_vector(23 downto 0);
signal spi_dat_o_strb : std_logic;
signal fifo_fill_cnt : integer range 0 to FIFO_DEPTH;
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_busy : std_logic;
signal fifo_inc : std_logic;
signal fifo_dec : std_logic;
signal fifo_data_req : std_logic;
signal fifo_data_avail : std_logic;
begin -- architecture RTL
reset_sync : process (clk, rst_hw) is
begin -- process reset_sync
if rst_hw = '1' then -- asynchronous reset (active high)
rst <= '1';
elsif rising_edge(clk) then -- rising clock edge
rst <= rst_hw;
end if;
end process reset_sync;
STD_FIFO_1 : entity work.STD_FIFO
generic map (
DATA_WIDTH => 24,
FIFO_DEPTH => FIFO_DEPTH) -- 20 LEDs FIFO depth
port map (
CLK => clk,
RST => rst,
WriteEn => fifo_wr,
DataIn => fifo_i,
ReadEn => fifo_rd,
DataOut => fifo_o,
Empty => fifo_empty,
Full => fifo_full);
spi_slave_1 : entity work.spi_slave
generic map (
DAT_WIDTH => 24)
port map (
clk => clk,
rst => rst,
cs => cs,
sck => sck,
miso => open,
mosi => mosi,
dat_o => spi_dat_o,
dat_i => (others => '0'),
dat_o_strb => spi_dat_o_strb,
dat_i_ack => open);
ws2812bphy_1 : 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);
fill_cnt_proc : process (clk, rst) is
variable inc_dec : std_logic_vector(1 downto 0);
begin -- process fill_cnt_proc
if rst = '1' then -- asynchronous reset (active high)
fifo_fill_cnt <= 0;
elsif rising_edge(clk) then -- rising clock edge
inc_dec := fifo_inc & fifo_dec;
if inc_dec = "10" then
fifo_fill_cnt <= fifo_fill_cnt + 1;
elsif inc_dec = "01" then
fifo_fill_cnt <= fifo_fill_cnt -1;
end if;
end if;
end process fill_cnt_proc;
ready <= '1' when fifo_fill_cnt <= 10 else '0';
spi2fifo_proc : process (clk, rst) is
begin -- process spi2fifo_proc
if rst = '1' then -- asynchronous reset (active high)
fifo_inc <= '0';
fifo_wr <= '0';
fifo_i <= (others => '0');
elsif rising_edge(clk) then -- rising clock edge
fifo_wr <= '0';
fifo_inc <= '0';
if spi_dat_o_strb = '1' and fifo_full /= '1' then
fifo_wr <= '1';
fifo_i <= spi_dat_o;
fifo_inc <= '1';
end if;
end if;
end process spi2fifo_proc;
fifo2ws_proc : process (clk, rst) is
begin -- process fifo2ws_proc
if rst = '1' then -- asynchronous reset (active high)
fifo_rd <= '0';
fifo_dec <= '0';
ws_strb <= '0';
red <= x"00";
blue <= x"00";
green <= x"00";
fifo_data_req <= '0';
fifo_data_avail <= '0';
elsif rising_edge(clk) then -- rising clock edge
fifo_rd <= '0';
ws_strb <= '0';
fifo_dec <= '0';
-- TODO: Write following lines as statemachine
if fifo_empty = '0' and fifo_data_req = '0' and fifo_data_avail = '0' then
fifo_data_req <= '1';
fifo_rd <= '1';
fifo_dec <= '1';
end if;
if fifo_data_req = '1' then
fifo_data_avail <= '1';
fifo_data_req <= '0';
end if;
if ws_busy = '0' and ws_strb = '0' and fifo_data_avail = '1' then
red <= unsigned(fifo_o(23 downto 16));
green <= unsigned(fifo_o(15 downto 8));
blue <= unsigned(fifo_o(7 downto 0));
ws_strb <= '1';
fifo_data_avail <= '0';
end if;
end if;
end process fifo2ws_proc;
end architecture RTL;

121
ws2812/ws2812bphy.vhd Normal file
View File

@ -0,0 +1,121 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity ws2812bphy is
generic(
HIGH1 : integer := 40;
LOW1 : integer := 23;
HIGH0 : integer := 20;
LOW0 : integer := 43);
port(
clk : in std_logic;
rst : in std_logic;
busy : out std_logic;
ws_out : out std_logic;
strb : in std_logic;
red : in unsigned(7 downto 0);
green : in unsigned(7 downto 0);
blue : in unsigned(7 downto 0));
end entity ws2812bphy;
architecture RTL of ws2812bphy is
type ws_output_state_t is (IDLE, TRANSMITTING, INTERLEDDELAY);
signal ws_output_state : ws_output_state_t;
type bitstate_t is (LOW, HIGH);
signal bitstate : bitstate_t;
begin
ws_output : process(clk, rst) is
variable counter : integer range 0 to 255 := 0;
variable color_vector : std_logic_vector(23 downto 0);
variable bitnum : integer range 0 to 23;
begin
if rst = '1' then
ws_output_state <= IDLE;
color_vector := (others => '0');
counter := 0;
bitstate <= LOW;
bitnum := 0;
elsif rising_edge(clk) then
case ws_output_state is
when IDLE =>
bitstate <= LOW;
if strb = '1' then
ws_output_state <= TRANSMITTING;
bitnum := 23;
color_vector := std_logic_vector(green) & std_logic_vector(red) & std_logic_vector(blue);
counter := 0;
bitstate <= HIGH;
end if;
when TRANSMITTING =>
case bitstate is
when HIGH =>
if color_vector(bitnum) = '1' then
if counter < HIGH1 - 1 then
counter := counter + 1;
else
bitstate <= LOW;
counter := 0;
end if;
else
if counter < HIGH0 -1 then
counter := counter + 1;
else
bitstate <= LOW;
counter := 0;
end if;
end if;
when LOW =>
if color_vector(bitnum) = '1' then
if counter < LOW1 -1 then
counter := counter + 1;
else
bitstate <= HIGH;
counter := 0;
if bitnum = 0 then
ws_output_state <= INTERLEDDELAY;
counter := 0;
bitstate <= LOW;
else
bitnum := bitnum - 1;
end if;
end if;
else
if counter < LOW0 - 1 then
counter := counter + 1;
else
bitstate <= HIGH;
counter := 0;
if bitnum = 0 then
ws_output_state <= INTERLEDDELAY;
counter := 0;
bitstate <= LOW;
else
bitnum := bitnum - 1;
end if;
end if;
end if;
end case;
when INTERLEDDELAY =>
if counter < HIGH1+LOW1+LOW1 then
counter := counter + 1;
else
counter := 0;
ws_output_state <= IDLE;
end if;
end case;
end if;
end process ws_output;
busy <= '0' when ws_output_state = IDLE else '1';
ws_out <= '1' when bitstate = HIGH else '0';
end architecture RTL;