From a9a179723659f575cce894896c897f7733524eea Mon Sep 17 00:00:00 2001 From: Xiretza Date: Mon, 20 Jun 2022 11:42:17 +0200 Subject: [PATCH] feat: double buffering --- vhdl/splink.vhdl | 109 ++++++++++++++++++++--------------------------- 1 file changed, 47 insertions(+), 62 deletions(-) diff --git a/vhdl/splink.vhdl b/vhdl/splink.vhdl index 69aa3cb..d5d7797 100644 --- a/vhdl/splink.vhdl +++ b/vhdl/splink.vhdl @@ -29,25 +29,16 @@ architecture a of splink is constant BITS_PER_LED: natural := 24; signal led_addr : std_logic_vector(7 downto 0); + signal led_data : std_logic_vector(BITS_PER_LED * NUM_STRANDS - 1 downto 0); signal led_colors : colors_vector(NUM_STRANDS-1 downto 0); - type led_data_t is record - was_written : std_logic; - end record; - - type led_data_arr_t is array(0 to NUM_STRANDS-1) of led_data_t; - signal led_data_arr : led_data_arr_t; - signal active_strand: natural range 0 to NUM_STRANDS-1; signal num_pixels: natural range 1 to MAX_STRAND_LEN; signal current_frame: unsigned(31 downto 0); signal pixels_received: natural range 0 to MAX_STRAND_LEN-1; signal run : std_logic; - signal clear_write_flags : std_logic; - - signal all_strands_written : std_logic; - signal some_strands_written : std_logic; + signal sender_done : std_logic; -- "PIXL" constant MAGIC_NUMBER : std_logic_vector(31 downto 0) := x"5049584c"; @@ -57,6 +48,9 @@ architecture a of splink is type receive_state_t is (MAGIC, FRAME_NUM, STRAND_NUM, DATA, DROP); constant RESET_STATE : receive_state_t := MAGIC; signal receive_state : receive_state_t; + + type bank_t is (BANK_A, BANK_B); + signal output_bank : bank_t; begin ws2812_inst: entity work.ws2812_parallel generic map ( @@ -70,12 +64,13 @@ begin T1H => 0.7 us, T1L => 0.55 us, - T_RES => 80 us + T_RES => 100 us ) port map ( n_reset => not reset, clk => clk, run => run, + done => sender_done, led_addr => led_addr, @@ -84,61 +79,49 @@ begin dout => drivers ); - driver_gen: for i in 0 to NUM_STRANDS-1 generate - writer: process(clk) - type strand_store_t is array(0 to MAX_STRAND_LEN-1) of color_t; - variable strand_store: strand_store_t; + process(led_data) + function make_color(data_in: std_logic_vector(BITS_PER_LED-1 downto 0)) return color_t is begin - if rising_edge(clk) then - led_colors(i) <= strand_store(to_integer(unsigned(led_addr))); - - if udp_valid = '1' and receive_state = DATA and active_strand = i then - strand_store(pixels_received) := ( - red => udp_data(23 downto 16), - green => udp_data(15 downto 8), - blue => udp_data(7 downto 0) - ); - - if pixels_received = num_pixels - 1 and udp_last = '1' then - led_data_arr(i).was_written <= '1'; - end if; - end if; - - if clear_write_flags then - led_data_arr(i).was_written <= '0'; - end if; - end if; - end process; - end generate; - - process(led_data_arr) + return ( + red => data_in(23 downto 16), + green => data_in(15 downto 8), + blue => data_in(7 downto 0) + ); + end function; begin - all_strands_written <= '1'; - some_strands_written <= '0'; - for i in 0 to NUM_STRANDS-1 loop - if led_data_arr(i).was_written then - some_strands_written <= '1'; - else - all_strands_written <= '0'; - end if; + led_colors(i) <= make_color(led_data((i+1) * BITS_PER_LED - 1 downto i * BITS_PER_LED)); end loop; end process; fsm: process(clk) + type strand_buffer_t is array(0 to MAX_STRAND_LEN-1) of std_logic_vector(BITS_PER_LED * NUM_STRANDS - 1 downto 0); + type strand_banks_t is array(bank_t) of strand_buffer_t; + + variable strand_banks : strand_banks_t; + + variable received_strands : std_logic_vector(NUM_STRANDS-1 downto 0); + variable input_bank : bank_t; begin if rising_edge(clk) then - clear_write_flags <= '0'; - run <= '0'; + led_data <= strand_banks(output_bank)(to_integer(unsigned(led_addr))); - if all_strands_written then - frame_number <= current_frame; - clear_write_flags <= '1'; + if (and received_strands) and sender_done then + output_bank <= input_bank; run <= '1'; + + case input_bank is + when BANK_A => input_bank := BANK_B; + when BANK_B => input_bank := BANK_A; + end case; + frame_number <= current_frame; + received_strands := (others => '0'); + else + run <= '0'; end if; if reset then - clear_write_flags <= '1'; + received_strands := (others => '0'); receive_state <= RESET_STATE; elsif udp_valid then if udp_last then @@ -150,13 +133,11 @@ begin when MAGIC => if udp_data /= MAGIC_NUMBER then receive_state <= DROP; + elsif (unsigned(udp_length) - HEADER_LEN) / 4 > MAX_STRAND_LEN then + receive_state <= DROP; else - if (unsigned(udp_length) - HEADER_LEN) / 4 > MAX_STRAND_LEN then - receive_state <= DROP; - else - num_pixels <= (to_integer(unsigned(udp_length)) - HEADER_LEN) / 4; - receive_state <= STRAND_NUM; - end if; + num_pixels <= (to_integer(unsigned(udp_length)) - HEADER_LEN) / 4; + receive_state <= STRAND_NUM; end if; when STRAND_NUM => @@ -168,20 +149,24 @@ begin end if; when FRAME_NUM => - if not some_strands_written then + if not (or received_strands) then current_frame <= unsigned(udp_data); elsif current_frame /= unsigned(udp_data) then current_frame <= unsigned(udp_data); - clear_write_flags <= '1'; + received_strands := (others => '0'); end if; pixels_received <= 0; receive_state <= DATA; when DATA => + strand_banks(input_bank)(pixels_received)((active_strand+1) * BITS_PER_LED - 1 downto active_strand * BITS_PER_LED) := udp_data(23 downto 0); + if pixels_received /= num_pixels - 1 then pixels_received <= pixels_received + 1; - elsif not udp_last then + elsif udp_last then + received_strands(active_strand) := '1'; + else -- packet too long receive_state <= DROP; end if;