Initial commit

This commit is contained in:
Markus Koch 2016-10-16 11:40:21 +02:00
commit e21415b367
7 changed files with 909 additions and 0 deletions

12
README.MD Normal file
View File

@ -0,0 +1,12 @@
# WS2812B CONTROLLER FOR FPGAS
A controller for the WorldSemi WS2812B RGB LEDs written in plain VHDL.
## Entity description
### ws2812b_phy
Low level driver for the WorldSemi WS2812B RGB LEDs. Handles bit timing and command separation.
### ws2812b_controller
WS2812B Controller to render picture data from SRAM.
## License
This work is released under the Mozilla Public License (MPL) Version 2. It may be interpreted in the same way the Open Hardware Description License (OHDL) by Julius Baxter does. Read more about it here: http://juliusbaxter.net/ohdl/ohdl.txt

View File

@ -0,0 +1,90 @@
-- ----------------------------------------------------------------------------
-- WS2812B CONTROLLER FOR FPGAS
-- ----------------------------------------------------------------------------
-- bench_ws2812b_controller.vhd : Testbench for the SRAM controller module
-- : to drive the WS2812B LEDs.
-- ----------------------------------------------------------------------------
-- Author : Markus Koch <markus@notsyncing.net>
-- Contributors : None
-- Created on : 2016/10/16
-- License : Mozilla Public License (MPL) Version 2
-- ----------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
library design;
use design.all;
entity bench_ws2812b_controller is
end entity bench_ws2812b_controller;
architecture RTL of bench_ws2812b_controller is
constant length : integer := 4;
signal clk : std_logic;
signal rst : std_logic;
signal so : std_logic;
signal addr : std_logic_vector(integer(ceil(log2(real(length - 1)))) downto 0);
signal data_red : std_logic_vector(7 downto 0);
signal data_green : std_logic_vector(7 downto 0);
signal data_blue : std_logic_vector(7 downto 0);
signal dataOut_red : std_logic_vector(7 downto 0);
signal dataOut_green : std_logic_vector(7 downto 0);
signal dataOut_blue : std_logic_vector(7 downto 0);
signal we : std_logic;
signal render : std_logic;
signal vsync : std_logic;
begin
ws2812b_controller_inst : entity design.ws2812b_controller
generic map(
length => length,
f_clk => 100000000)
port map(
clk => clk,
rst => rst,
so => so,
addr => addr,
data_red => data_red,
data_green => data_green,
data_blue => data_blue,
dataOut_red => dataOut_red,
dataOut_green => dataOut_green,
dataOut_blue => dataOut_blue,
we => we,
render => render,
vsync => vsync
);
clock_driver : process
constant period : time := 10 ns;
begin
clk <= '0';
wait for period / 2;
clk <= '1';
wait for period / 2;
end process clock_driver;
test : process is
begin
rst <= '1';
addr <= (others => '0');
data_red <= (others => '0');
data_green <= (others => '0');
data_blue <= (others => '0');
render <= '0';
wait for 20 ns;
rst <= '0';
wait for 60 ns;
render <= '1';
wait for 20 ns;
render <= '0';
wait;
end process test;
end architecture RTL;

View File

@ -0,0 +1,83 @@
-- ----------------------------------------------------------------------------
-- WS2812B CONTROLLER FOR FPGAS
-- ----------------------------------------------------------------------------
-- bench_ws2812b_phy.vhd : Development testbench for the WS2812B phy module.
-- ----------------------------------------------------------------------------
-- Author : Markus Koch <markus@notsyncing.net>
-- Contributors : None
-- Created on : 2016/10/16
-- License : Mozilla Public License (MPL) Version 2
-- ----------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library design;
use design.all;
entity bench_ws2812b_phy is
end entity bench_ws2812b_phy;
architecture RTL of bench_ws2812b_phy is
signal clk : std_logic;
signal rst : std_logic;
signal so : std_logic;
signal pixData_red : std_logic_vector(7 downto 0);
signal pixData_green : std_logic_vector(7 downto 0);
signal pixData_blue : std_logic_vector(7 downto 0);
signal pixData_valid : std_logic;
signal pixData_next : std_logic;
begin
clock_driver : process
constant period : time := 10 ns;
begin
clk <= '0';
wait for period / 2;
clk <= '1';
wait for period / 2;
end process clock_driver;
ws2812b_phy_inst : entity design.ws2812b_phy
generic map(
f_clk => 100000000
)
port map(
clk => clk,
rst => rst,
so => so,
pixData_red => pixData_red,
pixData_green => pixData_green,
pixData_blue => pixData_blue,
pixData_valid => pixData_valid,
pixData_next => pixData_next
);
test : process is
begin
pixData_red <= x"00";
pixData_green <= x"80";
pixData_blue <= x"01";
pixData_valid <= '0';
rst <= '1';
wait for 20 ns;
rst <= '0';
wait for 20 ns;
pixData_valid <= '1';
wait until pixData_next = '1'; -- Pix 0
wait until pixData_next = '1'; -- Pix 1
pixData_valid <= '0';
wait until pixData_next = '1'; -- Reset ack
pixData_valid <= '1';
wait until pixData_next = '1'; -- Pix 0
wait until pixData_next = '1'; -- Pix 1
pixData_valid <= '0';
wait until pixData_next = '1'; -- Reset ack
wait;
end process test;
end architecture RTL;

128
design/top.vhd Normal file
View File

@ -0,0 +1,128 @@
-- ----------------------------------------------------------------------------
-- WS2812B CONTROLLER FOR FPGAS
-- ----------------------------------------------------------------------------
-- top.vhd : Top level design to test the WS2812B controller modules.
-- : Real demo applications coming soon.
-- ----------------------------------------------------------------------------
-- Author : Markus Koch <markus@notsyncing.net>
-- Contributors : None
-- Created on : 2016/10/16
-- License : Mozilla Public License (MPL) Version 2
-- ----------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
entity top is
port(
clk : in std_logic;
rst_hw : in std_logic;
btn_n : in std_logic;
so : out std_logic
);
end entity top;
architecture RTL of top is
constant length : integer := 120;
signal rst : std_logic;
signal addr : std_logic_vector(integer(ceil(log2(real(length - 1)))) downto 0);
signal data_red : std_logic_vector(7 downto 0);
signal data_green : std_logic_vector(7 downto 0);
signal data_blue : std_logic_vector(7 downto 0);
signal dataOut_red : std_logic_vector(7 downto 0);
signal dataOut_green : std_logic_vector(7 downto 0);
signal dataOut_blue : std_logic_vector(7 downto 0);
signal we : std_logic;
signal render : std_logic;
signal vsync : std_logic;
signal done : std_logic;
signal foo : std_logic_vector(1 downto 0);
begin
rst <= not rst_hw;
foo <= addr(1 downto 0);
ws2812b_controller_inst : entity work.ws2812b_controller
generic map(
length => length,
f_clk => 50000000
)
port map(
clk => clk,
rst => rst,
so => so,
addr => addr,
data_red => data_red,
data_green => data_green,
data_blue => data_blue,
dataOut_red => dataOut_red,
dataOut_green => dataOut_green,
dataOut_blue => dataOut_blue,
we => we,
render => render,
vsync => vsync
);
prog : process(clk, rst) is
variable colRot : unsigned(1 downto 0);
variable c2 : integer range 0 to 25000000;
begin
if rst = '1' then
addr <= (others => '1');
data_red <= (others => '0');
data_green <= (others => '0');
data_blue <= (others => '0');
we <= '0';
done <= '1';
c2 := 0;
colRot := "00";
render <= '0';
elsif rising_edge(clk) then
we <= '0';
render <= '0';
if done = '0' then
addr <= std_logic_vector(unsigned(addr) + 1);
if to_integer(unsigned(addr)) = length - 1 then
done <= '1';
render <= '1';
end if;
if unsigned(foo) = colRot then
data_red <= (others => '1');
data_green <= (others => '0');
data_blue <= (others => '0');
elsif unsigned(foo) = colRot + 1 then
data_red <= (others => '0');
data_green <= (others => '1');
data_blue <= (others => '0');
elsif unsigned(foo) = colRot + 2 then
data_red <= (others => '0');
data_green <= (others => '0');
data_blue <= (others => '1');
else
data_red <= std_logic_vector(to_unsigned(127, 8));
data_green <= std_logic_vector(to_unsigned(127, 8));
data_blue <= (others => '0');
end if;
if (btn_n = '0') then
data_red <= (others => '1');
data_green <= (others => '1');
data_blue <= (others => '1');
end if;
we <= '1';
else
if c2 = 10000000 then
done <= '0';
c2 := 0;
colRot := colRot + 1;
else
c2 := c2 + 1;
end if;
end if;
end if;
end process prog;
end architecture RTL;

View File

@ -0,0 +1,146 @@
-- ----------------------------------------------------------------------------
-- WS2812B CONTROLLER FOR FPGAS
-- ----------------------------------------------------------------------------
-- ws2812b_controller.vhd : WS2812B Controller to render picture data from
-- : SRAM.
-- ----------------------------------------------------------------------------
-- Author : Markus Koch <markus@notsyncing.net>
-- Contributors : None
-- Created on : 2016/10/16
-- License : Mozilla Public License (MPL) Version 2
-- ----------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
entity ws2812b_controller is
generic(
length : integer := 16; -- Amount of LEDs on the link
f_clk : natural := 50000000;
T0H : real := 0.00000035;
T1H : real := 0.0000009;
T0L : real := 0.0000009;
T1L : real := 0.00000035;
DEL : real := 0.0000001; -- Must be bigger than others
RES : real := 0.0000050
);
port(
clk : in std_logic;
rst : in std_logic;
-- Hardware Connection
so : out std_logic; -- Serial output to WS2812B
-- Data Link
addr : in std_logic_vector(integer(ceil(log2(real(length - 1)))) downto 0); -- Address of the LED
data_red : in std_logic_vector(7 downto 0);
data_green : in std_logic_vector(7 downto 0);
data_blue : in std_logic_vector(7 downto 0);
dataOut_red : out std_logic_vector(7 downto 0);
dataOut_green : out std_logic_vector(7 downto 0);
dataOut_blue : out std_logic_vector(7 downto 0);
we : in std_logic; -- Write to RAM
render : in std_logic; -- Send data to LEDs
vsync : out std_logic -- Finished sending data out
);
end entity ws2812b_controller;
architecture RTL of ws2812b_controller is
type memory_t is array (length - 1 downto 0) of std_logic_vector(23 downto 0);
signal memory : memory_t;
signal rdaddr : std_logic_vector(integer(ceil(log2(real(length - 1)))) downto 0);
type state_t is (IDLE, PRESENT, WAITEMPTY);
signal state : state_t;
signal pixData_red : std_logic_vector(7 downto 0);
signal pixData_green : std_logic_vector(7 downto 0);
signal pixData_blue : std_logic_vector(7 downto 0);
signal pixData_valid : std_logic;
signal pixData_next : std_logic;
begin
-- -----------------------
-- Bit Timing Driver
-- -----------------------
ws2812b_phy_inst : entity work.ws2812b_phy
generic map(
f_clk => f_clk,
T0H => T0H,
T1H => T1H,
T0L => T0L,
T1L => T1L,
DEL => DEL,
RES => RES
)
port map(
clk => clk,
rst => rst,
so => so,
pixData_red => pixData_red,
pixData_green => pixData_green,
pixData_blue => pixData_blue,
pixData_valid => pixData_valid,
pixData_next => pixData_next
);
-- -----------------------
-- Memory Interface
-- -----------------------
mem_writer : process(rst, clk) is
begin
if rst = '1' then
dataOut_red <= (others => '0');
dataOut_green <= (others => '0');
dataOut_blue <= (others => '0');
elsif rising_edge(clk) then
dataOut_red <= memory(to_integer(unsigned(addr)))(23 downto 16);
dataOut_green <= memory(to_integer(unsigned(addr)))(15 downto 8);
dataOut_blue <= memory(to_integer(unsigned(addr)))(7 downto 0);
if we = '1' then
memory(to_integer(unsigned(addr))) <= data_red & data_green & data_blue;
end if;
end if;
end process mem_writer;
-- -----------------------
-- Main Controller FSM
-- -----------------------
main : process(rst, clk) is
begin
if rst = '1' then
rdaddr <= (others => '0');
state <= IDLE;
vsync <= '0';
elsif rising_edge(clk) then
vsync <= '0';
case state is
when IDLE =>
rdaddr <= (others => '0');
if render = '1' then
report "SIZE=" & integer'image(integer(ceil(log2(real(length - 1)))));
state <= PRESENT;
end if;
when PRESENT =>
if pixData_next = '1' then
if to_integer(unsigned(rdaddr)) = length - 1 then
rdaddr <= (others => '0');
state <= WAITEMPTY;
vsync <= '1';
else
rdaddr <= std_logic_vector(unsigned(rdaddr) + 1);
end if;
end if;
when WAITEMPTY =>
rdaddr <= (others => '0');
if pixData_next = '1' then
state <= IDLE;
end if;
end case;
end if;
end process main;
pixData_valid <= '1' when state = PRESENT else '0';
pixData_red <= memory(to_integer(unsigned(rdaddr)))(23 downto 16);
pixData_green <= memory(to_integer(unsigned(rdaddr)))(15 downto 8);
pixData_blue <= memory(to_integer(unsigned(rdaddr)))(7 downto 0);
end architecture RTL;

285
design/ws2812b_gamma.vhd Normal file
View File

@ -0,0 +1,285 @@
-- ----------------------------------------------------------------------------
-- WS2812B CONTROLLER FOR FPGAS
-- ----------------------------------------------------------------------------
-- ws2812b_gamma.vhd : Gamma correction RAM for the WS2812B LEDs.
-- : Not yet implemented.
-- ----------------------------------------------------------------------------
-- Author : Markus Koch <markus@notsyncing.net>
-- Contributors : None
-- Created on : 2016/10/16
-- License : Mozilla Public License (MPL) Version 2
-- ----------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity ws2812b_gamma is
port(
clk : in std_logic;
rst : in std_logic
);
end entity ws2812b_gamma;
architecture RTL of ws2812b_gamma is
type gamma_table_t is array (0 to 255) of std_logic_vector(7 downto 0);
constant gamme_table : gamma_table_t := (
0 => std_logic_vector(to_unsigned(0, 8)),
1 => std_logic_vector(to_unsigned(0, 8)),
2 => std_logic_vector(to_unsigned(0, 8)),
3 => std_logic_vector(to_unsigned(0, 8)),
4 => std_logic_vector(to_unsigned(0, 8)),
5 => std_logic_vector(to_unsigned(0, 8)),
6 => std_logic_vector(to_unsigned(0, 8)),
7 => std_logic_vector(to_unsigned(0, 8)),
8 => std_logic_vector(to_unsigned(0, 8)),
9 => std_logic_vector(to_unsigned(0, 8)),
10 => std_logic_vector(to_unsigned(0, 8)),
11 => std_logic_vector(to_unsigned(0, 8)),
12 => std_logic_vector(to_unsigned(0, 8)),
13 => std_logic_vector(to_unsigned(0, 8)),
14 => std_logic_vector(to_unsigned(0, 8)),
15 => std_logic_vector(to_unsigned(0, 8)),
16 => std_logic_vector(to_unsigned(0, 8)),
17 => std_logic_vector(to_unsigned(0, 8)),
18 => std_logic_vector(to_unsigned(0, 8)),
19 => std_logic_vector(to_unsigned(0, 8)),
20 => std_logic_vector(to_unsigned(0, 8)),
21 => std_logic_vector(to_unsigned(0, 8)),
22 => std_logic_vector(to_unsigned(1, 8)),
23 => std_logic_vector(to_unsigned(1, 8)),
24 => std_logic_vector(to_unsigned(1, 8)),
25 => std_logic_vector(to_unsigned(1, 8)),
26 => std_logic_vector(to_unsigned(1, 8)),
27 => std_logic_vector(to_unsigned(1, 8)),
28 => std_logic_vector(to_unsigned(1, 8)),
29 => std_logic_vector(to_unsigned(2, 8)),
30 => std_logic_vector(to_unsigned(2, 8)),
31 => std_logic_vector(to_unsigned(2, 8)),
32 => std_logic_vector(to_unsigned(2, 8)),
33 => std_logic_vector(to_unsigned(2, 8)),
34 => std_logic_vector(to_unsigned(2, 8)),
35 => std_logic_vector(to_unsigned(3, 8)),
36 => std_logic_vector(to_unsigned(3, 8)),
37 => std_logic_vector(to_unsigned(3, 8)),
38 => std_logic_vector(to_unsigned(3, 8)),
39 => std_logic_vector(to_unsigned(3, 8)),
40 => std_logic_vector(to_unsigned(4, 8)),
41 => std_logic_vector(to_unsigned(4, 8)),
42 => std_logic_vector(to_unsigned(4, 8)),
43 => std_logic_vector(to_unsigned(4, 8)),
44 => std_logic_vector(to_unsigned(5, 8)),
45 => std_logic_vector(to_unsigned(5, 8)),
46 => std_logic_vector(to_unsigned(5, 8)),
47 => std_logic_vector(to_unsigned(5, 8)),
48 => std_logic_vector(to_unsigned(6, 8)),
49 => std_logic_vector(to_unsigned(6, 8)),
50 => std_logic_vector(to_unsigned(6, 8)),
51 => std_logic_vector(to_unsigned(7, 8)),
52 => std_logic_vector(to_unsigned(7, 8)),
53 => std_logic_vector(to_unsigned(7, 8)),
54 => std_logic_vector(to_unsigned(8, 8)),
55 => std_logic_vector(to_unsigned(8, 8)),
56 => std_logic_vector(to_unsigned(8, 8)),
57 => std_logic_vector(to_unsigned(9, 8)),
58 => std_logic_vector(to_unsigned(9, 8)),
59 => std_logic_vector(to_unsigned(9, 8)),
60 => std_logic_vector(to_unsigned(10, 8)),
61 => std_logic_vector(to_unsigned(10, 8)),
62 => std_logic_vector(to_unsigned(11, 8)),
63 => std_logic_vector(to_unsigned(11, 8)),
64 => std_logic_vector(to_unsigned(11, 8)),
65 => std_logic_vector(to_unsigned(12, 8)),
66 => std_logic_vector(to_unsigned(12, 8)),
67 => std_logic_vector(to_unsigned(13, 8)),
68 => std_logic_vector(to_unsigned(13, 8)),
69 => std_logic_vector(to_unsigned(13, 8)),
70 => std_logic_vector(to_unsigned(14, 8)),
71 => std_logic_vector(to_unsigned(14, 8)),
72 => std_logic_vector(to_unsigned(15, 8)),
73 => std_logic_vector(to_unsigned(15, 8)),
74 => std_logic_vector(to_unsigned(16, 8)),
75 => std_logic_vector(to_unsigned(16, 8)),
76 => std_logic_vector(to_unsigned(17, 8)),
77 => std_logic_vector(to_unsigned(17, 8)),
78 => std_logic_vector(to_unsigned(18, 8)),
79 => std_logic_vector(to_unsigned(18, 8)),
80 => std_logic_vector(to_unsigned(19, 8)),
81 => std_logic_vector(to_unsigned(19, 8)),
82 => std_logic_vector(to_unsigned(20, 8)),
83 => std_logic_vector(to_unsigned(21, 8)),
84 => std_logic_vector(to_unsigned(21, 8)),
85 => std_logic_vector(to_unsigned(22, 8)),
86 => std_logic_vector(to_unsigned(22, 8)),
87 => std_logic_vector(to_unsigned(23, 8)),
88 => std_logic_vector(to_unsigned(23, 8)),
89 => std_logic_vector(to_unsigned(24, 8)),
90 => std_logic_vector(to_unsigned(25, 8)),
91 => std_logic_vector(to_unsigned(25, 8)),
92 => std_logic_vector(to_unsigned(26, 8)),
93 => std_logic_vector(to_unsigned(27, 8)),
94 => std_logic_vector(to_unsigned(27, 8)),
95 => std_logic_vector(to_unsigned(28, 8)),
96 => std_logic_vector(to_unsigned(29, 8)),
97 => std_logic_vector(to_unsigned(29, 8)),
98 => std_logic_vector(to_unsigned(30, 8)),
99 => std_logic_vector(to_unsigned(31, 8)),
100 => std_logic_vector(to_unsigned(31, 8)),
101 => std_logic_vector(to_unsigned(32, 8)),
102 => std_logic_vector(to_unsigned(33, 8)),
103 => std_logic_vector(to_unsigned(34, 8)),
104 => std_logic_vector(to_unsigned(34, 8)),
105 => std_logic_vector(to_unsigned(35, 8)),
106 => std_logic_vector(to_unsigned(36, 8)),
107 => std_logic_vector(to_unsigned(37, 8)),
108 => std_logic_vector(to_unsigned(37, 8)),
109 => std_logic_vector(to_unsigned(38, 8)),
110 => std_logic_vector(to_unsigned(39, 8)),
111 => std_logic_vector(to_unsigned(40, 8)),
112 => std_logic_vector(to_unsigned(40, 8)),
113 => std_logic_vector(to_unsigned(41, 8)),
114 => std_logic_vector(to_unsigned(42, 8)),
115 => std_logic_vector(to_unsigned(43, 8)),
116 => std_logic_vector(to_unsigned(44, 8)),
117 => std_logic_vector(to_unsigned(45, 8)),
118 => std_logic_vector(to_unsigned(46, 8)),
119 => std_logic_vector(to_unsigned(46, 8)),
120 => std_logic_vector(to_unsigned(47, 8)),
121 => std_logic_vector(to_unsigned(48, 8)),
122 => std_logic_vector(to_unsigned(49, 8)),
123 => std_logic_vector(to_unsigned(50, 8)),
124 => std_logic_vector(to_unsigned(51, 8)),
125 => std_logic_vector(to_unsigned(52, 8)),
126 => std_logic_vector(to_unsigned(53, 8)),
127 => std_logic_vector(to_unsigned(54, 8)),
128 => std_logic_vector(to_unsigned(55, 8)),
129 => std_logic_vector(to_unsigned(56, 8)),
130 => std_logic_vector(to_unsigned(57, 8)),
131 => std_logic_vector(to_unsigned(58, 8)),
132 => std_logic_vector(to_unsigned(59, 8)),
133 => std_logic_vector(to_unsigned(60, 8)),
134 => std_logic_vector(to_unsigned(61, 8)),
135 => std_logic_vector(to_unsigned(62, 8)),
136 => std_logic_vector(to_unsigned(63, 8)),
137 => std_logic_vector(to_unsigned(64, 8)),
138 => std_logic_vector(to_unsigned(65, 8)),
139 => std_logic_vector(to_unsigned(66, 8)),
140 => std_logic_vector(to_unsigned(67, 8)),
141 => std_logic_vector(to_unsigned(68, 8)),
142 => std_logic_vector(to_unsigned(69, 8)),
143 => std_logic_vector(to_unsigned(70, 8)),
144 => std_logic_vector(to_unsigned(71, 8)),
145 => std_logic_vector(to_unsigned(72, 8)),
146 => std_logic_vector(to_unsigned(73, 8)),
147 => std_logic_vector(to_unsigned(74, 8)),
148 => std_logic_vector(to_unsigned(76, 8)),
149 => std_logic_vector(to_unsigned(77, 8)),
150 => std_logic_vector(to_unsigned(78, 8)),
151 => std_logic_vector(to_unsigned(79, 8)),
152 => std_logic_vector(to_unsigned(80, 8)),
153 => std_logic_vector(to_unsigned(81, 8)),
154 => std_logic_vector(to_unsigned(83, 8)),
155 => std_logic_vector(to_unsigned(84, 8)),
156 => std_logic_vector(to_unsigned(85, 8)),
157 => std_logic_vector(to_unsigned(86, 8)),
158 => std_logic_vector(to_unsigned(88, 8)),
159 => std_logic_vector(to_unsigned(89, 8)),
160 => std_logic_vector(to_unsigned(90, 8)),
161 => std_logic_vector(to_unsigned(91, 8)),
162 => std_logic_vector(to_unsigned(93, 8)),
163 => std_logic_vector(to_unsigned(94, 8)),
164 => std_logic_vector(to_unsigned(95, 8)),
165 => std_logic_vector(to_unsigned(96, 8)),
166 => std_logic_vector(to_unsigned(98, 8)),
167 => std_logic_vector(to_unsigned(99, 8)),
168 => std_logic_vector(to_unsigned(100, 8)),
169 => std_logic_vector(to_unsigned(102, 8)),
170 => std_logic_vector(to_unsigned(103, 8)),
171 => std_logic_vector(to_unsigned(104, 8)),
172 => std_logic_vector(to_unsigned(106, 8)),
173 => std_logic_vector(to_unsigned(107, 8)),
174 => std_logic_vector(to_unsigned(109, 8)),
175 => std_logic_vector(to_unsigned(110, 8)),
176 => std_logic_vector(to_unsigned(111, 8)),
177 => std_logic_vector(to_unsigned(113, 8)),
178 => std_logic_vector(to_unsigned(114, 8)),
179 => std_logic_vector(to_unsigned(116, 8)),
180 => std_logic_vector(to_unsigned(117, 8)),
181 => std_logic_vector(to_unsigned(119, 8)),
182 => std_logic_vector(to_unsigned(120, 8)),
183 => std_logic_vector(to_unsigned(121, 8)),
184 => std_logic_vector(to_unsigned(123, 8)),
185 => std_logic_vector(to_unsigned(124, 8)),
186 => std_logic_vector(to_unsigned(126, 8)),
187 => std_logic_vector(to_unsigned(128, 8)),
188 => std_logic_vector(to_unsigned(129, 8)),
189 => std_logic_vector(to_unsigned(131, 8)),
190 => std_logic_vector(to_unsigned(132, 8)),
191 => std_logic_vector(to_unsigned(134, 8)),
192 => std_logic_vector(to_unsigned(135, 8)),
193 => std_logic_vector(to_unsigned(137, 8)),
194 => std_logic_vector(to_unsigned(138, 8)),
195 => std_logic_vector(to_unsigned(140, 8)),
196 => std_logic_vector(to_unsigned(142, 8)),
197 => std_logic_vector(to_unsigned(143, 8)),
198 => std_logic_vector(to_unsigned(145, 8)),
199 => std_logic_vector(to_unsigned(146, 8)),
200 => std_logic_vector(to_unsigned(148, 8)),
201 => std_logic_vector(to_unsigned(150, 8)),
202 => std_logic_vector(to_unsigned(151, 8)),
203 => std_logic_vector(to_unsigned(153, 8)),
204 => std_logic_vector(to_unsigned(155, 8)),
205 => std_logic_vector(to_unsigned(157, 8)),
206 => std_logic_vector(to_unsigned(158, 8)),
207 => std_logic_vector(to_unsigned(160, 8)),
208 => std_logic_vector(to_unsigned(162, 8)),
209 => std_logic_vector(to_unsigned(163, 8)),
210 => std_logic_vector(to_unsigned(165, 8)),
211 => std_logic_vector(to_unsigned(167, 8)),
212 => std_logic_vector(to_unsigned(169, 8)),
213 => std_logic_vector(to_unsigned(170, 8)),
214 => std_logic_vector(to_unsigned(172, 8)),
215 => std_logic_vector(to_unsigned(174, 8)),
216 => std_logic_vector(to_unsigned(176, 8)),
217 => std_logic_vector(to_unsigned(178, 8)),
218 => std_logic_vector(to_unsigned(179, 8)),
219 => std_logic_vector(to_unsigned(181, 8)),
220 => std_logic_vector(to_unsigned(183, 8)),
221 => std_logic_vector(to_unsigned(185, 8)),
222 => std_logic_vector(to_unsigned(187, 8)),
223 => std_logic_vector(to_unsigned(189, 8)),
224 => std_logic_vector(to_unsigned(191, 8)),
225 => std_logic_vector(to_unsigned(193, 8)),
226 => std_logic_vector(to_unsigned(194, 8)),
227 => std_logic_vector(to_unsigned(196, 8)),
228 => std_logic_vector(to_unsigned(198, 8)),
229 => std_logic_vector(to_unsigned(200, 8)),
230 => std_logic_vector(to_unsigned(202, 8)),
231 => std_logic_vector(to_unsigned(204, 8)),
232 => std_logic_vector(to_unsigned(206, 8)),
233 => std_logic_vector(to_unsigned(208, 8)),
234 => std_logic_vector(to_unsigned(210, 8)),
235 => std_logic_vector(to_unsigned(212, 8)),
236 => std_logic_vector(to_unsigned(214, 8)),
237 => std_logic_vector(to_unsigned(216, 8)),
238 => std_logic_vector(to_unsigned(218, 8)),
239 => std_logic_vector(to_unsigned(220, 8)),
240 => std_logic_vector(to_unsigned(222, 8)),
241 => std_logic_vector(to_unsigned(224, 8)),
242 => std_logic_vector(to_unsigned(227, 8)),
243 => std_logic_vector(to_unsigned(229, 8)),
244 => std_logic_vector(to_unsigned(231, 8)),
245 => std_logic_vector(to_unsigned(233, 8)),
246 => std_logic_vector(to_unsigned(235, 8)),
247 => std_logic_vector(to_unsigned(237, 8)),
248 => std_logic_vector(to_unsigned(239, 8)),
249 => std_logic_vector(to_unsigned(241, 8)),
250 => std_logic_vector(to_unsigned(244, 8)),
251 => std_logic_vector(to_unsigned(246, 8)),
252 => std_logic_vector(to_unsigned(248, 8)),
253 => std_logic_vector(to_unsigned(250, 8)),
254 => std_logic_vector(to_unsigned(252, 8)),
255 => std_logic_vector(to_unsigned(255, 8))
);
begin
end architecture RTL;

165
design/ws2812b_phy.vhd Normal file
View File

@ -0,0 +1,165 @@
-- ----------------------------------------------------------------------------
-- WS2812B CONTROLLER FOR FPGAS
-- ----------------------------------------------------------------------------
-- ws2812b_phy.vhd : Low level driver for the WorldSemi WS2812B RGB LEDs.
-- Handles bit timing and command separation.
-- ----------------------------------------------------------------------------
-- Author : Markus Koch <markus@notsyncing.net>
-- Contributors : None
-- Created on : 2016/10/16
-- License : Mozilla Public License (MPL) Version 2
-- ----------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity ws2812b_phy is
generic(
f_clk : natural := 50000000;
T0H : real := 0.00000035;
T1H : real := 0.0000009;
T0L : real := 0.0000009;
T1L : real := 0.00000035;
DEL : real := 0.0000000; -- 0.0000001
RES : real := 0.00005000 -- Must be bigger than others
);
port(
-- Global Signals
clk : in std_logic; -- System clock @ f_clk
rst : in std_logic; -- Asynchronous reset
-- Hardware Connection
so : out std_logic; -- Serial output to WS2812B
-- Data Link
pixData_red : in std_logic_vector(7 downto 0);
pixData_green : in std_logic_vector(7 downto 0);
pixData_blue : in std_logic_vector(7 downto 0);
pixData_valid : in std_logic;
pixData_next : out std_logic
);
end entity ws2812b_phy;
architecture RTL of ws2812b_phy is
-- WS2812B Bit Encoder Signals and Definitions
constant CYC_T0H : natural := natural(T0H / (real(1) / real(f_clk))) - 1;
constant CYC_T1H : natural := natural(T1H / (real(1) / real(f_clk))) - 1;
constant CYC_T0L : natural := natural(T0L / (real(1) / real(f_clk))) - 1;
constant CYC_T1L : natural := natural(T1L / (real(1) / real(f_clk))) - 1;
constant CYC_DEL : natural := natural(DEL / (real(1) / real(f_clk))) - 1;
constant CYC_RES : natural := natural(RES / (real(1) / real(f_clk))) - 1;
type state_t is (HIGH, LOW);
signal bitState : state_t;
signal bitCnt : integer range 0 to CYC_RES; -- Timing counter
signal bitData_i : std_logic;
signal bitData : std_logic_vector(1 downto 0); -- 00: send 0 <br> 01: send 1 <br> 10: send reset <br> 11: send led-separator
signal bitData_valid : std_logic; -- Applied data is valid -> TX request (keep valid until data_next)
signal bitData_next : std_logic; -- Apply next bit or release valid to terminate transmission
-- Serializer Signals and Definitions
signal shiftreg : std_logic_vector(23 downto 0);
signal pixCnt : integer range 0 to 25;
begin
-- -----------------------
-- WS2812B Bit Encoder
-- -----------------------
bitEncoder : process(rst, clk) is
begin
if rst = '1' then
bitCnt <= 0;
bitState <= LOW;
bitData_next <= '0';
elsif rising_edge(clk) then
bitData_next <= '0';
if bitCnt /= 0 then
bitCnt <= bitCnt - 1;
end if;
case bitState is
when HIGH =>
if bitCnt = 0 then
bitState <= LOW;
if bitData_i = '0' then
bitCnt <= CYC_T0L;
else
bitCnt <= CYC_T1L;
end if;
end if;
when LOW =>
if bitCnt = 0 then
if bitData_valid = '1' then
bitData_next <= '1';
bitData_i <= bitData(0);
if bitData(0) = '0' then
bitCnt <= CYC_T0H;
else
bitCnt <= CYC_T1H;
end if;
if bitData(1) = '0' then
bitState <= HIGH;
else
if bitData(0) = '0' then
bitCnt <= CYC_RES;
else
bitCnt <= CYC_DEL;
end if;
bitState <= LOW;
end if;
end if;
end if;
end case;
end if;
end process bitEncoder;
so <= '1' when bitState = HIGH else '0';
-- -----------------------
-- Pixel Data Serializer
-- -----------------------
pixSerializer : process(rst, clk) is
begin
if rst = '1' then
bitData_valid <= '0';
pixData_next <= '0';
pixCnt <= 0;
elsif rising_edge(clk) then
pixData_next <= '0';
if bitData_next = '1' then
pixCnt <= pixCnt - 1;
if pixCnt = 2 then -- End of data
bitData(1) <= '1'; -- Control sequence
if pixData_valid = '1' then
shiftreg(23) <= '1'; -- Trigger DEL sequence
report "WS2812B: Send DELAY" severity note;
else
shiftreg(23) <= '0'; -- Trigger RES sequence
report "WS2812B: Send RESET" severity note;
pixData_next <= '1'; -- Acknowledge that the reset has been latched
end if;
elsif pixCnt = 1 then -- End of control
bitData_valid <= '0';
else
shiftreg <= shiftreg(22 downto 0) & '0';
end if;
end if;
if pixCnt = 0 then -- End of DEL
pixCnt <= pixCnt;
if pixData_valid = '1' then
report "WS2812B: Latch pixel data" severity note;
pixData_next <= '1';
shiftreg <= pixData_green & pixData_red & pixData_blue;
bitData_valid <= '1';
pixCnt <= 25;
bitData(1) <= '0'; -- Data bit
-- else
-- bitData(1) <= '1'; -- Control sequence
-- shiftreg(23) <= '1'; -- Trigger RES sequence
end if;
end if;
end if;
end process pixSerializer;
bitData(0) <= shiftreg(23);
end architecture RTL;