Line 87... |
Line 87... |
signal addr : std_ulogic_vector(31 downto 0); -- access address
|
signal addr : std_ulogic_vector(31 downto 0); -- access address
|
signal wren : std_ulogic; -- word write enable
|
signal wren : std_ulogic; -- word write enable
|
signal rden : std_ulogic; -- read enable
|
signal rden : std_ulogic; -- read enable
|
|
|
-- Control register bits --
|
-- Control register bits --
|
constant ctrl_enable_c : natural := 0; -- r/w: module enable
|
constant ctrl_en_c : natural := 0; -- r/w: module enable
|
constant ctrl_mode_c : natural := 1; -- r/w: 0 = 24-bit RGB mode, 1 = 32-bit RGBW mode
|
constant ctrl_mode_c : natural := 1; -- r/w: 0 = 24-bit RGB mode, 1 = 32-bit RGBW mode
|
constant ctrl_strobe_c : natural := 2; -- r/w: 0 = send normal data, 1 = send LED strobe command (RESET) on data write
|
constant ctrl_strobe_c : natural := 2; -- r/w: 0 = send normal data, 1 = send LED strobe command (RESET) on data write
|
--
|
--
|
constant ctrl_clksel0_c : natural := 3; -- r/w: prescaler select bit 0
|
constant ctrl_clksel0_c : natural := 3; -- r/w: prescaler select bit 0
|
constant ctrl_clksel1_c : natural := 4; -- r/w: prescaler select bit 1
|
constant ctrl_clksel1_c : natural := 4; -- r/w: prescaler select bit 1
|
Line 151... |
Line 151... |
free : std_ulogic; -- free entry available?
|
free : std_ulogic; -- free entry available?
|
half : std_ulogic; -- half full
|
half : std_ulogic; -- half full
|
end record;
|
end record;
|
signal tx_buffer : tx_buffer_t;
|
signal tx_buffer : tx_buffer_t;
|
|
|
|
-- interrupt generator --
|
|
type irq_t is record
|
|
pending : std_ulogic; -- pending interrupt request
|
|
set : std_ulogic;
|
|
clr : std_ulogic;
|
|
end record;
|
|
signal irq : irq_t;
|
|
|
-- serial transmission engine --
|
-- serial transmission engine --
|
type serial_state_t is (S_IDLE, S_INIT, S_GETBIT, S_PULSE, S_STROBE);
|
type serial_state_t is (S_IDLE, S_INIT, S_GETBIT, S_PULSE, S_STROBE);
|
type serial_t is record
|
type serial_t is record
|
-- state control --
|
-- state control --
|
state : serial_state_t;
|
state : serial_state_t;
|
mode : std_ulogic;
|
mode : std_ulogic;
|
|
done : std_ulogic;
|
busy : std_ulogic;
|
busy : std_ulogic;
|
bit_cnt : std_ulogic_vector(5 downto 0);
|
bit_cnt : std_ulogic_vector(5 downto 0);
|
-- shift register --
|
-- shift register --
|
sreg : std_ulogic_vector(31 downto 0);
|
sreg : std_ulogic_vector(31 downto 0);
|
next_bit : std_ulogic; -- next bit to send
|
next_bit : std_ulogic; -- next bit to send
|
Line 197... |
Line 206... |
-- access acknowledge --
|
-- access acknowledge --
|
ack_o <= wren or rden;
|
ack_o <= wren or rden;
|
|
|
-- write access: control register --
|
-- write access: control register --
|
if (wren = '1') and (addr = neoled_ctrl_addr_c) then
|
if (wren = '1') and (addr = neoled_ctrl_addr_c) then
|
ctrl.enable <= data_i(ctrl_enable_c);
|
ctrl.enable <= data_i(ctrl_en_c);
|
ctrl.mode <= data_i(ctrl_mode_c);
|
ctrl.mode <= data_i(ctrl_mode_c);
|
ctrl.strobe <= data_i(ctrl_strobe_c);
|
ctrl.strobe <= data_i(ctrl_strobe_c);
|
ctrl.clk_prsc <= data_i(ctrl_clksel2_c downto ctrl_clksel0_c);
|
ctrl.clk_prsc <= data_i(ctrl_clksel2_c downto ctrl_clksel0_c);
|
ctrl.irq_conf <= data_i(ctrl_irq_conf_c);
|
ctrl.irq_conf <= data_i(ctrl_irq_conf_c);
|
ctrl.t_total <= data_i(ctrl_t_tot_4_c downto ctrl_t_tot_0_c);
|
ctrl.t_total <= data_i(ctrl_t_tot_4_c downto ctrl_t_tot_0_c);
|
Line 210... |
Line 219... |
end if;
|
end if;
|
|
|
-- read access: control register --
|
-- read access: control register --
|
data_o <= (others => '0');
|
data_o <= (others => '0');
|
if (rden = '1') then -- and (addr = neoled_ctrl_addr_c) then
|
if (rden = '1') then -- and (addr = neoled_ctrl_addr_c) then
|
data_o(ctrl_enable_c) <= ctrl.enable;
|
data_o(ctrl_en_c) <= ctrl.enable;
|
data_o(ctrl_mode_c) <= ctrl.mode;
|
data_o(ctrl_mode_c) <= ctrl.mode;
|
data_o(ctrl_strobe_c) <= ctrl.strobe;
|
data_o(ctrl_strobe_c) <= ctrl.strobe;
|
data_o(ctrl_clksel2_c downto ctrl_clksel0_c) <= ctrl.clk_prsc;
|
data_o(ctrl_clksel2_c downto ctrl_clksel0_c) <= ctrl.clk_prsc;
|
data_o(ctrl_irq_conf_c) <= ctrl.irq_conf or bool_to_ulogic_f(boolean(FIFO_DEPTH = 1)); -- tie to one if FIFO_DEPTH is 1
|
data_o(ctrl_irq_conf_c) <= ctrl.irq_conf or bool_to_ulogic_f(boolean(FIFO_DEPTH = 1)); -- tie to one if FIFO_DEPTH is 1
|
data_o(ctrl_bufs_3_c downto ctrl_bufs_0_c) <= std_ulogic_vector(to_unsigned(index_size_f(FIFO_DEPTH), 4));
|
data_o(ctrl_bufs_3_c downto ctrl_bufs_0_c) <= std_ulogic_vector(to_unsigned(index_size_f(FIFO_DEPTH), 4));
|
Line 239... |
Line 248... |
tx_buffer.clear <= not ctrl.enable;
|
tx_buffer.clear <= not ctrl.enable;
|
|
|
|
|
-- IRQ Generator --------------------------------------------------------------------------
|
-- IRQ Generator --------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
irq_generator: process(clk_i)
|
irq_select: process(ctrl, tx_buffer)
|
begin
|
begin
|
if rising_edge(clk_i) then
|
|
if (ctrl.enable = '0') then
|
|
irq_o <= '0'; -- no interrupt if unit is disabled
|
|
else
|
|
if (FIFO_DEPTH = 1) then
|
if (FIFO_DEPTH = 1) then
|
irq_o <= tx_buffer.free; -- fire IRQ if FIFO is empty
|
irq.set <= tx_buffer.free; -- fire IRQ if FIFO is empty
|
else
|
else
|
if (ctrl.irq_conf = '0') then -- fire IRQ if FIFO is less than half-full
|
if (ctrl.irq_conf = '0') then -- fire IRQ if FIFO is less than half-full
|
irq_o <= not tx_buffer.half;
|
irq.set <= not tx_buffer.half;
|
else -- fire IRQ if FIFO is empty
|
else -- fire IRQ if FIFO is empty
|
irq_o <= tx_buffer.free;
|
irq.set <= tx_buffer.free;
|
end if;
|
end if;
|
end if;
|
end if;
|
|
end process irq_select;
|
|
|
|
-- Interrupt Arbiter --
|
|
irq_generator: process(clk_i)
|
|
begin
|
|
if rising_edge(clk_i) then
|
|
if (ctrl.enable = '0') then
|
|
irq.pending <= '0';
|
|
else
|
|
if (irq.set = '1') and (serial.done = '1') then -- evaluate IRQ condition when transmitter is done again
|
|
irq.pending <= '1';
|
|
elsif (irq.clr = '1') then
|
|
irq.pending <= '0';
|
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process irq_generator;
|
end process irq_generator;
|
|
|
|
-- IRQ request to CPU --
|
|
irq_o <= irq.pending;
|
|
|
|
-- IRQ acknowledge --
|
|
irq.clr <= '1' when (wren = '1') else '0'; -- write data or control register
|
|
|
|
|
-- TX Buffer (FIFO) -----------------------------------------------------------------------
|
-- TX Buffer (FIFO) -----------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
tx_data_fifo: neorv32_fifo
|
tx_data_fifo: neorv32_fifo
|
generic map (
|
generic map (
|
Line 297... |
Line 322... |
begin
|
begin
|
if rising_edge(clk_i) then
|
if rising_edge(clk_i) then
|
-- clock generator --
|
-- clock generator --
|
serial.pulse_clk <= clkgen_i(to_integer(unsigned(ctrl.clk_prsc)));
|
serial.pulse_clk <= clkgen_i(to_integer(unsigned(ctrl.clk_prsc)));
|
|
|
|
-- defaults --
|
|
serial.done <= '0';
|
|
|
-- FSM --
|
-- FSM --
|
if (ctrl.enable = '0') then -- disabled
|
if (ctrl.enable = '0') then -- disabled
|
serial.state <= S_IDLE;
|
serial.state <= S_IDLE;
|
else
|
else
|
case serial.state is
|
case serial.state is
|
Line 340... |
Line 368... |
else -- send one-bit
|
else -- send one-bit
|
serial.t_high <= ctrl.t1_high;
|
serial.t_high <= ctrl.t1_high;
|
end if;
|
end if;
|
if (serial.bit_cnt = "000000") then -- all done?
|
if (serial.bit_cnt = "000000") then -- all done?
|
serial.tx_out <= '0';
|
serial.tx_out <= '0';
|
|
serial.done <= '1'; -- done sending data
|
serial.state <= S_IDLE;
|
serial.state <= S_IDLE;
|
else -- send current data MSB
|
else -- send current data MSB
|
serial.tx_out <= '1';
|
serial.tx_out <= '1';
|
serial.state <= S_PULSE; -- transmit single pulse
|
serial.state <= S_PULSE; -- transmit single pulse
|
end if;
|
end if;
|
Line 376... |
Line 405... |
serial.pulse_cnt <= std_ulogic_vector(unsigned(serial.pulse_cnt) + 1);
|
serial.pulse_cnt <= std_ulogic_vector(unsigned(serial.pulse_cnt) + 1);
|
end if;
|
end if;
|
end if;
|
end if;
|
-- number of LOW periods reached for RESET? --
|
-- number of LOW periods reached for RESET? --
|
if (and_reduce_f(serial.strobe_cnt) = '1') then
|
if (and_reduce_f(serial.strobe_cnt) = '1') then
|
|
serial.done <= '1'; -- done sending RESET
|
serial.state <= S_IDLE;
|
serial.state <= S_IDLE;
|
end if;
|
end if;
|
|
|
when others => -- undefined
|
when others => -- undefined
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|