From 5bdf8632773bbb9258bb4b1e81d1a6b5bc6f22b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Mon, 24 Oct 2016 00:07:41 +0200 Subject: [PATCH] Demo Code for WS2812b LEDs created --- .gitignore | 3 + .library_mapping.xml | 10 ++ .project | 45 +++++ .settings/org.eclipse.core.resources.prefs | 5 + bench/ws2812test_bench.vhd | 42 +++++ src/gamma8bit.vhd | 35 ++++ src/ws2812b-phy/ws2812bphy.vhd | 123 +++++++++++++ src/ws2812test.vhd | 197 +++++++++++++++++++++ 8 files changed, 460 insertions(+) create mode 100644 .gitignore create mode 100644 .library_mapping.xml create mode 100644 .project create mode 100644 .settings/org.eclipse.core.resources.prefs create mode 100644 bench/ws2812test_bench.vhd create mode 100644 src/gamma8bit.vhd create mode 100644 src/ws2812b-phy/ws2812bphy.vhd create mode 100644 src/ws2812test.vhd diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b0d0ec5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.bak +quartus + diff --git a/.library_mapping.xml b/.library_mapping.xml new file mode 100644 index 0000000..226c5d4 --- /dev/null +++ b/.library_mapping.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/.project b/.project new file mode 100644 index 0000000..85fd938 --- /dev/null +++ b/.project @@ -0,0 +1,45 @@ + + + ws2812b + + + + + + org.eclipse.xtext.ui.shared.xtextBuilder + + + + + + com.sigasi.hdt.vhdl.ui.vhdlNature + org.eclipse.xtext.ui.shared.xtextNature + + + + Common Libraries + 2 + virtual:/virtual + + + Common Libraries/DRAG_REUSABLE_LIBRARIES_HERE.txt + 1 + sigasiresource:/vhdl/readme2.txt + + + Common Libraries/IEEE + 2 + sigasiresource:/vhdl/93/IEEE + + + Common Libraries/STD + 2 + sigasiresource:/vhdl/93/STD + + + Common Libraries/IEEE/Synopsys + 2 + sigasiresource:/vhdl/93/IEEE%20Synopsys + + + diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..240a6e2 --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,5 @@ +eclipse.preferences.version=1 +encoding//Common\ Libraries/IEEE=utf-8 +encoding//Common\ Libraries/IEEE/Synopsys=utf-8 +encoding//Common\ Libraries/STD=utf-8 +encoding/Common\ Libraries=utf-8 diff --git a/bench/ws2812test_bench.vhd b/bench/ws2812test_bench.vhd new file mode 100644 index 0000000..a3f1d78 --- /dev/null +++ b/bench/ws2812test_bench.vhd @@ -0,0 +1,42 @@ +library ieee; +library design; + +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use design.all; + +entity ws2812test_bench is +end entity ws2812test_bench; + +architecture RTL of ws2812test_bench is + signal clk : std_logic; + signal rst : std_logic; + signal ws_out : std_logic; + +begin + clock_driver : process + constant period : time := 20 ns; + begin + clk <= '0'; + wait for period / 2; + clk <= '1'; + wait for period / 2; + end process clock_driver; + + resetprovider : process is + begin + rst <= '0'; + wait for 3 ns; + rst <= '1'; + wait; + end process resetprovider; + + ws2812test_inst : entity design.ws2812test + port map( + clk => clk, + reset => rst, + ws_out => ws_out, + gamma_req => '1' + ); + +end architecture RTL; diff --git a/src/gamma8bit.vhd b/src/gamma8bit.vhd new file mode 100644 index 0000000..2ba2a9f --- /dev/null +++ b/src/gamma8bit.vhd @@ -0,0 +1,35 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity gamma8bit is + port( + color_in : in unsigned(7 downto 0); + color_out : out unsigned(7 downto 0) + ); +end entity gamma8bit; + +architecture RTL of gamma8bit is + type gammatable_t is array (0 to 255) of integer range 0 to 255; + signal table : gammatable_t; +begin + table <= (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, + 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, + 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, + 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, + 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25, + 25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36, + 37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50, + 51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68, + 69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89, + 90, 92, 93, 95, 96, 98, 99, 101, 102, 104, 105, 107, 109, 110, 112, 114, + 115, 117, 119, 120, 122, 124, 126, 127, 129, 131, 133, 135, 137, 138, 140, 142, + 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 167, 169, 171, 173, 175, + 177, 180, 182, 184, 186, 189, 191, 193, 196, 198, 200, 203, 205, 208, 210, 213, + 215, 218, 220, 223, 225, 228, 231, 233, 236, 239, 241, 244, 247, 249, 252, 255); + + color_out <= to_unsigned(table(to_integer(color_in)), color_out'length); + +end architecture RTL; diff --git a/src/ws2812b-phy/ws2812bphy.vhd b/src/ws2812b-phy/ws2812bphy.vhd new file mode 100644 index 0000000..f38455e --- /dev/null +++ b/src/ws2812b-phy/ws2812bphy.vhd @@ -0,0 +1,123 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity ws2812bphy is + generic( + constant HIGH1 : integer := 40; + constant LOW1 : integer := 23; + constant HIGH0 : integer := 20; + constant 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 then + counter := counter + 1; + else + bitstate <= LOW; + counter := 0; + end if; + else + if counter < HIGH0 then + counter := counter + 1; + else + bitstate <= LOW; + counter := 0; + end if; + end if; + when LOW => + if color_vector(bitnum) = '1' then + if counter < LOW1 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 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; diff --git a/src/ws2812test.vhd b/src/ws2812test.vhd new file mode 100644 index 0000000..a78b663 --- /dev/null +++ b/src/ws2812test.vhd @@ -0,0 +1,197 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity ws2812test is + port( + clk : in std_logic; + reset : in std_logic; + ws_out : out std_logic; + gamma_req : in std_logic + ); +end entity ws2812test; + +architecture RTL of ws2812test is + constant LEDCNT_c : integer := 60; + constant HEARTBEATMAX_c : integer := 700000; + signal rst : std_logic; + signal ws_busy : std_logic; + signal ws_strb : std_logic; + signal red_gamma : unsigned(7 downto 0); + signal green_gamma : unsigned(7 downto 0); + signal blue_gamma : unsigned(7 downto 0); + + -- Signals for renderer + signal render_active : std_logic; + type transition_t is (RY, YG, GC, CB, BM, MR); + signal transition_active : transition_t; + type color_rec_t is record + red : unsigned(7 downto 0); + green : unsigned(7 downto 0); + blue : unsigned(7 downto 0); + end record color_rec_t; + signal color_active : color_rec_t; + signal lednum : integer range 0 to LEDCNT_c - 1; + -- Signals for rainbow + signal heartbeat : std_logic; + signal transition_start : transition_t; + signal color_start : color_rec_t; + signal red_ws : unsigned(7 downto 0); + signal green_ws : unsigned(7 downto 0); + signal blue_ws : unsigned(7 downto 0); +begin + rst <= not reset; + + beatgen : process(clk, rst) is + variable beat_counter : integer range 0 to HEARTBEATMAX_c := 0; + begin + if rst = '1' then + beat_counter := 0; + heartbeat <= '0'; + elsif rising_edge(clk) then + heartbeat <= '0'; + if beat_counter /= HEARTBEATMAX_c then + beat_counter := beat_counter + 1; + else + beat_counter := 0; + heartbeat <= '1'; + end if; + end if; + end process beatgen; + + gamma_red : entity work.gamma8bit + port map( + color_in => color_active.red, + color_out => red_gamma + ); + gamma_green : entity work.gamma8bit + port map( + color_in => color_active.green, + color_out => green_gamma + ); + + gamma_blue : entity work.gamma8bit + port map( + color_in => color_active.blue, + color_out => blue_gamma + ); + + red_ws <= red_gamma when gamma_req = '1' else color_active.red; + green_ws <= green_gamma when gamma_req = '1' else color_active.green; + blue_ws <= blue_gamma when gamma_req = '1' else color_active.blue; + + ws2812bphy_inst : 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_ws, + green => green_ws, + blue => blue_ws + ); + + rainbow : process(clk, rst) is + procedure increment_col(signal color : inout unsigned(7 downto 0); is_renderer : boolean; next_state : transition_t) is + begin + color <= color + 20; + if color = 220 then + if is_renderer then + transition_active <= next_state; + else + transition_start <= next_state; + end if; + end if; + end procedure increment_col; + + procedure decrement_col(signal color : inout unsigned(7 downto 0); is_renderer : boolean; next_state : transition_t) is + begin + color <= color - 20; + if color = 20 then + if is_renderer then + transition_active <= next_state; + else + transition_start <= next_state; + end if; + end if; + end procedure decrement_col; + + begin + if rst = '1' then + render_active <= '1'; + color_active.red <= to_unsigned(240, color_start.red'length); + color_active.green <= x"00"; + color_active.blue <= x"00"; + + color_start.red <= to_unsigned(240, color_start.red'length); + color_start.green <= x"00"; + color_start.blue <= x"00"; + transition_active <= RY; + transition_start <= RY; + lednum <= 0; + elsif rising_edge(clk) then + -- renderer + if render_active = '1' then + ws_strb <= '0'; + if ws_busy = '0' and ws_strb = '0' then + ws_strb <= '1'; + case transition_active is + when RY => + increment_col(color_active.green, true, YG); + + when YG => + decrement_col(color_active.red, true, GC); + when GC => + increment_col(color_active.blue, true, CB); + when CB => + decrement_col(color_active.green, true, BM); + when BM => + increment_col(color_active.red, true, MR); + when MR => + decrement_col(color_active.blue, true, RY); + end case; + + end if; -- phy ready + if ws_strb = '1' then + if lednum < (LEDCNT_c - 1) then + lednum <= lednum + 1; + else + lednum <= 0; + render_active <= '0'; + end if; + end if; + elsif heartbeat = '1' then + case transition_start is + when RY => + increment_col(color_start.green, false, YG); + + when YG => + decrement_col(color_start.red, false, GC); + when GC => + increment_col(color_start.blue, false, CB); + when CB => + decrement_col(color_start.green, false, BM); + when BM => + increment_col(color_start.red, false, MR); + when MR => + decrement_col(color_start.blue, false, RY); + end case; + color_active <= color_start; + transition_active <= transition_start; + render_active <= '1'; + + end if; -- rainbow + + + end if; -- rising edge + + end process rainbow; + +end architecture RTL;