-- LX Master (Transmitter)
entity lxmaster_transmitter is
+ generic (
+ cycle_cnt_width_g : natural := 12
+ );
port
(
clk_i : in std_logic;
sync_o : out std_logic;
-- Register
register_i : in std_logic;
- register_o : out std_logic;
+ register_o : out std_logic_vector(1 downto 0);
register_we_i : in std_logic;
+ -- Cycle period
+ cycle_reg_i : in std_logic_vector(cycle_cnt_width_g-1 downto 0);
+ cycle_reg_o : out std_logic_vector(cycle_cnt_width_g-1 downto 0);
+ cycle_reg_we_i : in std_logic;
+ -- Watchdog
+ wdog_i : in std_logic;
+ wdog_we_i : in std_logic;
-- BRAM access
mem_clk_i : in std_logic;
mem_en_i : in std_logic;
-- Types
type state_t is (ST_INIT, ST_READY, ST_XFER, ST_CRC, ST_END);
constant frame_length_c : positive := 2500; -- 50 MHz -> 20 kHz
- -- RAM Access (both ARM and Tumbl)
+ constant wdog_length_c : positive := 2500000; -- 50 ms
+ constant msg_max_count_c : positive := 8;
+ -- RAM Access
signal ram_en_s : std_logic;
signal ram_rst_s : std_logic;
- --
signal ram_addr_s : std_logic_vector(8 downto 0);
signal ram_addr_r : std_logic_vector(8 downto 0);
signal ram_data_o_s : std_logic_vector(15 downto 0);
-- State
signal lxmaster_state_s : state_t;
signal lxmaster_state_r : state_t;
- signal lxmaster_not_last_word_s : std_logic;
- signal lxmaster_not_last_word_r : std_logic;
+ signal lxmaster_last_word_s : std_logic;
+ signal lxmaster_last_word_r : std_logic;
-- Data
signal lxmaster_num_data_s : std_logic_vector(7 downto 0); -- If 0 then the peripheral is not active this cycle
signal lxmaster_num_data_r : std_logic_vector(7 downto 0);
signal lxmaster_loaded_data_s : std_logic_vector(15 downto 0);
signal lxmaster_loaded_data_r : std_logic_vector(15 downto 0);
- signal lxmaster_data_counter_s : std_logic_vector(3 downto 0); -- Shift: 0 - 15
- signal lxmaster_data_counter_r : std_logic_vector(3 downto 0);
+ signal lxmaster_data_counter_s : natural range 0 to 15;
+ signal lxmaster_data_counter_r : natural range 0 to 15;
-- Transmission
signal lxmaster_sync_s : std_logic;
signal lxmaster_sync_r : std_logic;
signal lxmaster_sync_last_bit_s : std_logic;
signal lxmaster_sync_last_bit_r : std_logic;
- -- Frame counter
- signal lxmaster_frame_counter_s : natural range 0 to (frame_length_c-1);
+ -- Counters
+ signal lxmaster_wdog_counter_s : natural range 0 to (wdog_length_c-1);
+ signal lxmaster_frame_counter_s : natural range 0 to (2**cycle_cnt_width_g - 1);
+ signal lxmaster_cycle_limit_r : std_logic_vector(cycle_cnt_width_g-1 downto 0);
+ signal lxmaster_msg_counter_s : natural range 0 to (msg_max_count_c-1);
+ signal lxmaster_msg_counter_r : natural range 0 to (msg_max_count_c-1);
-- CRC
signal lxmaster_crc_data_s : std_logic;
signal lxmaster_crc_reset_s : std_logic;
-- RAM reset
signal lxmaster_ram_reset_s : std_logic;
-- Register
- -- Bit 0: Transmitter - use first or second buffer
+ -- Bit 0: Transmitter - use first or second buffer (I/O)
+ -- Bit 1: Watchdog not kicked (O)
signal lxmaster_register_in_s : std_logic;
- signal lxmaster_register_out_s : std_logic;
+ signal lxmaster_register_out_s : std_logic_vector(1 downto 0);
+ -- Output buffers
+ signal sync_s : std_logic;
+ signal sync_r : std_logic;
+ signal mosi_s : std_logic;
+ signal mosi_r : std_logic;
begin
-- Directly route out some signals
clock_o <= clk_i; -- Cannot mix with logic
- sync_o <= not lxmaster_sync_r; -- Active in log. 0
- mosi_o <= '1' when lxmaster_sync_r = '0' and lxmaster_sync_last_bit_r = '0'
+ sync_s <= not lxmaster_sync_r; -- Active in log. 0
+ mosi_s <= '1' when lxmaster_sync_r = '0' and lxmaster_sync_last_bit_r = '0'
else lxmaster_crc_reg_r(0) when lxmaster_state_r = ST_CRC
else lxmaster_loaded_data_r(0);
+ sync_o <= sync_r;
+ mosi_o <= mosi_r;
+
-- CRC
lxmaster_crc_reg_s <= '0' & lxmaster_crc_reg_r(7 downto 1) when lxmaster_state_r = ST_CRC else lxmaster_crc_out_s;
lxmaster_crc_data_s <= '1' when lxmaster_state_r = ST_CRC else lxmaster_loaded_data_r(0);
- lxmaster_crc_reset_s <= '1' when lxmaster_state_r = ST_READY or reset_i = '1' else '0';
+ lxmaster_crc_reset_s <= '1' when lxmaster_state_r /= ST_XFER or reset_i = '1' else '0';
- -- Register
+ -- Registers output
register_o <= lxmaster_register_out_s;
+ cycle_reg_o <= lxmaster_cycle_limit_r;
-ram: xilinx_dualport_bram_write_first
+ram: xilinx_dualport_bram
generic map
(
we_width => 2,
byte_width => 8,
- address_width => 9
+ address_width => 9,
+ port_a_type => WRITE_FIRST,
+ port_b_type => READ_FIRST
)
port map
(
-- Update
-- TODO: Maybe some exception handling (overflows etc.)
transmitter_update:
- process (ram_data_o_s, ram_addr_r, lxmaster_state_r, lxmaster_loaded_data_r, lxmaster_num_data_r, lxmaster_not_last_word_r,
- lxmaster_data_counter_r, reset_i, lxmaster_frame_counter_s, lxmaster_register_in_s)
+ process (ram_data_o_s, ram_addr_r, lxmaster_state_r, lxmaster_loaded_data_r, lxmaster_num_data_r, lxmaster_msg_counter_r,
+ lxmaster_last_word_r, lxmaster_data_counter_r, reset_i, lxmaster_frame_counter_s, lxmaster_register_in_s, lxmaster_wdog_counter_s)
variable ram_addr_v : std_logic_vector(8 downto 0);
begin
lxmaster_loaded_data_s <= lxmaster_loaded_data_r;
lxmaster_data_counter_s <= lxmaster_data_counter_r;
lxmaster_num_data_s <= lxmaster_num_data_r;
- lxmaster_not_last_word_s <= lxmaster_not_last_word_r;
+ lxmaster_msg_counter_s <= lxmaster_msg_counter_r;
+ lxmaster_last_word_s <= lxmaster_last_word_r;
if reset_i = '1' then
lxmaster_num_data_s <= x"00";
lxmaster_loaded_data_s <= x"0000";
lxmaster_state_s <= ST_END;
lxmaster_sync_s <= '0';
+ lxmaster_last_word_s <= '0';
--
ram_addr_s <= '0' & x"00";
ram_en_s <= '0';
lxmaster_state_s <= ST_END; --Nothing
else
lxmaster_state_s <= ST_READY; -- Make next read init the transfer
+ ram_addr_v := ram_addr_r(8) & ram_data_o_s(15 downto 8); -- Update address
+ ram_addr_s <= ram_addr_v;
+ lxmaster_num_data_s <= std_logic_vector(unsigned(ram_addr_v(7 downto 0)) + unsigned(ram_data_o_s(7 downto 0)));
+ ram_en_s <= '1'; -- Read
end if;
- -- Regardless, write the number of data
- lxmaster_num_data_s <= ram_data_o_s(7 downto 0);
-
- -- And schedule reading
- ram_addr_s <= ram_addr_r + 1; -- Update address
- ram_en_s <= '1'; -- Read
+ -- Prepare message counter
+ lxmaster_msg_counter_s <= 0;
when ST_READY =>
-- We are ready to begin transferring
lxmaster_loaded_data_s <= ram_data_o_s;
lxmaster_sync_s <= '1'; -- Transferring data next cycle
- lxmaster_data_counter_s <= x"0"; -- Reset counter
+ lxmaster_data_counter_s <= 0; -- Reset counter
lxmaster_state_s <= ST_XFER; --Go to transfer loop
- lxmaster_not_last_word_s <= '0'; -- Not last word
when ST_XFER =>
lxmaster_loaded_data_s <= '0' & lxmaster_loaded_data_r(15 downto 1); -- Shift it
lxmaster_sync_s <= '1'; -- Transferring data next cycle
- if lxmaster_data_counter_r = x"E" and ram_addr_r(7 downto 0) /= lxmaster_num_data_r then
- -- At 14th bit, we need to read from RAM if more words are to come
- ram_addr_s <= ram_addr_r + 1; -- Update address
+ if lxmaster_data_counter_r = 14 then
lxmaster_data_counter_s <= lxmaster_data_counter_r + 1; -- Increment
- ram_en_s <= '1'; -- Read
- lxmaster_not_last_word_s <= '1';
- elsif lxmaster_data_counter_r = x"F" then
- -- At 15th bit, we either stop if ram_addr_r equals lxmaster_num_data_r (wasn't updated so it would not overflow)
- if ram_addr_r(7 downto 0) = lxmaster_num_data_r and lxmaster_not_last_word_r = '0' then
+
+ if (ram_addr_r(7 downto 0) + 1) /= lxmaster_num_data_r then
+ -- At 14th bit, we need to read from RAM if more words are to come
+ ram_addr_s <= ram_addr_r(8) & (ram_addr_r(7 downto 0) + 1); -- Update address
+ ram_en_s <= '1'; -- Read
+ lxmaster_last_word_s <= '0';
+ else
+ lxmaster_last_word_s <= '1';
+ end if;
+
+ elsif lxmaster_data_counter_r = 15 then
+ -- At 15th bit, we either stop if ram_addr_r equals lxmaster_num_data_r
+ if lxmaster_last_word_r = '1' then
lxmaster_state_s <= ST_CRC;
- lxmaster_data_counter_s <= x"0";
+ lxmaster_data_counter_s <= 0;
else
lxmaster_loaded_data_s <= ram_data_o_s;
- lxmaster_data_counter_s <= x"0";
- lxmaster_not_last_word_s <= '0';
+ lxmaster_data_counter_s <= 0;
end if;
else
-- Increment
when ST_CRC =>
-- Check if this is last command, first read one more
- if lxmaster_data_counter_r = x"0" then
- if (ram_addr_r(7 downto 0) = x"FF") then
- lxmaster_ram_reset_s <= '1'; -- Make sure we read 0 in this case
+ if lxmaster_data_counter_r = 0 then
+ if lxmaster_msg_counter_r = (msg_max_count_c - 1) then
+ lxmaster_ram_reset_s <= '1'; -- Make sure we read 0 if we are on the last message
+ else
+ lxmaster_msg_counter_s <= lxmaster_msg_counter_r + 1;
end if;
- ram_addr_s <= ram_addr_r + 1; -- Update address
+ ram_addr_s <= ram_addr_r(8) & std_logic_vector(to_unsigned(lxmaster_msg_counter_r + 1, ram_addr_r'length - 1)); -- Update address
ram_en_s <= '1'; -- Read
- elsif lxmaster_data_counter_r = x"1" then
- if ram_data_o_s(7 downto 0) /= x"00" then -- Need to read first command
+ elsif lxmaster_data_counter_r = 1 then
+
+ if ram_data_o_s(15 downto 8) >= msg_max_count_c then -- Need to read first command, make sure it's valid
ram_addr_v := ram_addr_r(8) & ram_data_o_s(15 downto 8); -- Update address
ram_addr_s <= ram_addr_v;
lxmaster_num_data_s <= std_logic_vector(unsigned(ram_addr_v(7 downto 0)) + unsigned(ram_data_o_s(7 downto 0)));
end if;
- if lxmaster_data_counter_r = x"7" then -- Ending
- lxmaster_data_counter_s <= x"0";
+ if lxmaster_data_counter_r = 7 then -- Ending
+ lxmaster_data_counter_s <= 0;
- if lxmaster_num_data_r(7 downto 0) = x"00" then
+ if lxmaster_num_data_r = x"00" then
lxmaster_state_s <= ST_END; -- Last command
else
- -- We are at init at the moment
- lxmaster_state_s <= ST_READY; -- Sync goes inactive for a cycle
+ -- Begin transmission of next data
+ lxmaster_loaded_data_s <= ram_data_o_s;
+ lxmaster_sync_s <= '1'; -- Transferring data next cycle
+ lxmaster_data_counter_s <= 0; -- Reset counter
+ lxmaster_state_s <= ST_XFER; --Go to transfer loop
end if;
else
- if lxmaster_data_counter_r /= x"6" then
+ -- Sync goes inactive to signalize termination if we're on last message
+ if lxmaster_data_counter_r /= 6 or lxmaster_num_data_r /= x"00" then
lxmaster_sync_s <= '1';
else
lxmaster_sync_last_bit_s <= '1';
end if;
when ST_END =>
- if lxmaster_frame_counter_s = (frame_length_c - 1) then
+ if lxmaster_frame_counter_s < 2 then
-- Initialize first step
lxmaster_state_s <= ST_INIT;
ram_addr_s <= lxmaster_register_in_s & x"00";
ram_en_s <= '1';
+ -- Watchdog - make sure we read 0 if not kicked
+ if lxmaster_wdog_counter_s = (wdog_length_c - 1) then
+ lxmaster_ram_reset_s <= '1';
+ end if;
end if;
end case;
wait until clk_i'event and clk_i = '1';
-- State update
- ram_addr_r <= ram_addr_s;
- lxmaster_state_r <= lxmaster_state_s;
- lxmaster_loaded_data_r <= lxmaster_loaded_data_s;
- lxmaster_data_counter_r <= lxmaster_data_counter_s;
- lxmaster_num_data_r <= lxmaster_num_data_s;
- lxmaster_not_last_word_r <= lxmaster_not_last_word_s;
- lxmaster_crc_reg_r <= lxmaster_crc_reg_s;
+ ram_addr_r <= ram_addr_s;
+ lxmaster_state_r <= lxmaster_state_s;
+ lxmaster_loaded_data_r <= lxmaster_loaded_data_s;
+ lxmaster_data_counter_r <= lxmaster_data_counter_s;
+ lxmaster_num_data_r <= lxmaster_num_data_s;
+ lxmaster_crc_reg_r <= lxmaster_crc_reg_s;
+ lxmaster_msg_counter_r <= lxmaster_msg_counter_s;
+ lxmaster_last_word_r <= lxmaster_last_word_s;
-- Increment counter
if reset_i = '1' then
- lxmaster_frame_counter_s <= (frame_length_c - 1);
- lxmaster_register_in_s <= '0';
- lxmaster_register_out_s <= '0';
+
+ lxmaster_frame_counter_s <= 1;
+ lxmaster_wdog_counter_s <= 0;
+ lxmaster_register_in_s <= '0';
+ lxmaster_register_out_s <= (others => '0');
+ lxmaster_last_word_r <= '1';
+ lxmaster_cycle_limit_r <= std_logic_vector(to_unsigned(frame_length_c,
+ lxmaster_cycle_limit_r'length));
+
else
if register_we_i = '1' then
- lxmaster_register_in_s <= register_i;
+ lxmaster_register_in_s <= register_i;
+ end if;
+
+ if lxmaster_frame_counter_s < 2 then
+ lxmaster_register_out_s(0) <= lxmaster_register_in_s;
+ lxmaster_frame_counter_s <= to_integer(unsigned(lxmaster_cycle_limit_r));
+ else
+ lxmaster_frame_counter_s <= lxmaster_frame_counter_s - 1;
end if;
- if lxmaster_frame_counter_s = (frame_length_c - 1) then
- lxmaster_register_out_s <= lxmaster_register_in_s;
- lxmaster_frame_counter_s <= 0;
+ if wdog_we_i = '1' and wdog_i = '1' then
+ lxmaster_wdog_counter_s <= 0;
+ lxmaster_register_out_s(1) <= '0';
+ elsif lxmaster_wdog_counter_s /= (wdog_length_c - 1) then
+ lxmaster_wdog_counter_s <= lxmaster_wdog_counter_s + 1;
+ lxmaster_register_out_s(1) <= '0';
else
- lxmaster_frame_counter_s <= lxmaster_frame_counter_s + 1;
+ lxmaster_register_out_s(1) <= '1';
+ end if;
+
+ if cycle_reg_we_i = '1' then
+ lxmaster_cycle_limit_r <= cycle_reg_i;
end if;
end if;
- lxmaster_sync_r <= lxmaster_sync_s;
- lxmaster_sync_last_bit_r <= lxmaster_sync_last_bit_s;
+ lxmaster_sync_r <= lxmaster_sync_s;
+ lxmaster_sync_last_bit_r <= lxmaster_sync_last_bit_s;
+
+ end process;
+
+update_outputs:
+ process
+ begin
+ wait until clk_i'event and clk_i = '0';
+ sync_r <= sync_s;
+ mosi_r <= mosi_s;
end process;
end Behavioral;