From 985df3cd290220e8fe8c956563d754976472273b Mon Sep 17 00:00:00 2001 From: YEZZFUSL <18398621+yezzfusl@users.noreply.github.com> Date: Mon, 5 Aug 2024 10:31:40 -0400 Subject: [PATCH] Add LIN protocol stack and integrate with existing CAN protocol. --- src/lin_protocol/lin_protocol.vhd | 126 +++++++++++++++++++++++++++ src/lin_protocol/lin_transceiver.vhd | 36 ++++++++ src/top_level.vhd | 66 +++++++++++++- 3 files changed, 225 insertions(+), 3 deletions(-) create mode 100644 src/lin_protocol/lin_protocol.vhd create mode 100644 src/lin_protocol/lin_transceiver.vhd diff --git a/src/lin_protocol/lin_protocol.vhd b/src/lin_protocol/lin_protocol.vhd new file mode 100644 index 0000000..bff23fc --- /dev/null +++ b/src/lin_protocol/lin_protocol.vhd @@ -0,0 +1,126 @@ +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.NUMERIC_STD.ALL; + +entity lin_controller is + Port ( + clk : in STD_LOGIC; + rst : in STD_LOGIC; + rx : in STD_LOGIC; + tx : out STD_LOGIC; + data_in : in STD_LOGIC_VECTOR(63 downto 0); + data_out : out STD_LOGIC_VECTOR(63 downto 0); + data_valid : out STD_LOGIC + ); +end lin_controller; + +architecture Behavioral of lin_controller is + type lin_state_type is (IDLE, SYNC, IDENTIFIER, DATA, CHECKSUM); + signal state : lin_state_type := IDLE; + signal bit_counter : integer range 0 to 63 := 0; + signal byte_counter : integer range 0 to 8 := 0; + signal shift_reg : STD_LOGIC_VECTOR(7 downto 0) := (others => '0'); + signal identifier : STD_LOGIC_VECTOR(5 downto 0) := (others => '0'); + signal data_buffer : STD_LOGIC_VECTOR(63 downto 0) := (others => '0'); + signal checksum : STD_LOGIC_VECTOR(7 downto 0) := (others => '0'); + + constant SYNC_BYTE : STD_LOGIC_VECTOR(7 downto 0) := x"55"; + constant BIT_TIME : integer := 50; -- Assuming 20kbps LIN speed with 1MHz clock + +begin + process(clk, rst) + variable bit_time_counter : integer range 0 to BIT_TIME-1 := 0; + begin + if rst = '1' then + state <= IDLE; + bit_counter <= 0; + byte_counter <= 0; + shift_reg <= (others => '0'); + identifier <= (others => '0'); + data_buffer <= (others => '0'); + checksum <= (others => '0'); + tx <= '1'; + data_valid <= '0'; + elsif rising_edge(clk) then + case state is + when IDLE => + tx <= '1'; + if rx = '0' then -- Start bit detected + state <= SYNC; + bit_counter <= 0; + bit_time_counter := 0; + end if; + + when SYNC => + if bit_time_counter = BIT_TIME-1 then + bit_time_counter := 0; + if bit_counter < 8 then + shift_reg <= shift_reg(6 downto 0) & rx; + bit_counter <= bit_counter + 1; + else + if shift_reg = SYNC_BYTE then + state <= IDENTIFIER; + bit_counter <= 0; + else + state <= IDLE; + end if; + end if; + else + bit_time_counter := bit_time_counter + 1; + end if; + + when IDENTIFIER => + if bit_time_counter = BIT_TIME-1 then + bit_time_counter := 0; + if bit_counter < 6 then + identifier <= identifier(4 downto 0) & rx; + bit_counter <= bit_counter + 1; + else + state <= DATA; + bit_counter <= 0; + byte_counter <= 0; + end if; + else + bit_time_counter := bit_time_counter + 1; + end if; + + when DATA => + if bit_time_counter = BIT_TIME-1 then + bit_time_counter := 0; + if bit_counter < 8 then + shift_reg <= shift_reg(6 downto 0) & rx; + bit_counter <= bit_counter + 1; + else + data_buffer((7-byte_counter)*8+7 downto (7-byte_counter)*8) <= shift_reg; + byte_counter <= byte_counter + 1; + bit_counter <= 0; + if byte_counter = 7 then + state <= CHECKSUM; + end if; + end if; + else + bit_time_counter := bit_time_counter + 1; + end if; + + when CHECKSUM => + if bit_time_counter = BIT_TIME-1 then + bit_time_counter := 0; + if bit_counter < 8 then + checksum <= checksum(6 downto 0) & rx; + bit_counter <= bit_counter + 1; + else + -- Verify checksum (simplified) + if checksum = x"AA" then -- Example checksum + data_out <= data_buffer; + data_valid <= '1'; + end if; + state <= IDLE; + end if; + else + bit_time_counter := bit_time_counter + 1; + end if; + end case; + end if; + end process; + +end Behavioral; diff --git a/src/lin_protocol/lin_transceiver.vhd b/src/lin_protocol/lin_transceiver.vhd new file mode 100644 index 0000000..a802f79 --- /dev/null +++ b/src/lin_protocol/lin_transceiver.vhd @@ -0,0 +1,36 @@ +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; + +entity lin_transceiver is + Port ( + clk : in STD_LOGIC; + rst : in STD_LOGIC; + tx_in : in STD_LOGIC; + rx_out : out STD_LOGIC; + lin_bus : inout STD_LOGIC + ); +end lin_transceiver; + +architecture Behavioral of lin_transceiver is + signal tx_buf : STD_LOGIC; +begin + -- Transmit logic + process(clk, rst) + begin + if rst = '1' then + lin_bus <= 'H'; -- High-impedance state + tx_buf <= '1'; + elsif rising_edge(clk) then + tx_buf <= tx_in; + if tx_buf = '0' then + lin_bus <= '0'; + else + lin_bus <= 'H'; -- Pull-up resistor will pull the bus high + end if; + end if; + end process; + + -- Receive logic + rx_out <= lin_bus; + +end Behavioral; diff --git a/src/top_level.vhd b/src/top_level.vhd index 1840676..01e3aac 100644 --- a/src/top_level.vhd +++ b/src/top_level.vhd @@ -7,9 +7,12 @@ entity top_level is ext_rst : in STD_LOGIC; can_rx : in STD_LOGIC; can_tx : out STD_LOGIC; + lin_rx : in STD_LOGIC; + lin_tx : out STD_LOGIC; data_in : in STD_LOGIC_VECTOR(63 downto 0); data_out : out STD_LOGIC_VECTOR(63 downto 0); - data_valid : out STD_LOGIC + data_valid : out STD_LOGIC; + protocol_select : in STD_LOGIC -- '0' for CAN, '1' for LIN ); end top_level; @@ -17,6 +20,9 @@ architecture Behavioral of top_level is signal clk_1m : STD_LOGIC; signal rst : STD_LOGIC; signal can_rx_internal, can_tx_internal : STD_LOGIC; + signal lin_rx_internal, lin_tx_internal : STD_LOGIC; + signal can_data_out, lin_data_out : STD_LOGIC_VECTOR(63 downto 0); + signal can_data_valid, lin_data_valid : STD_LOGIC; component clock_generator Port ( @@ -57,6 +63,28 @@ architecture Behavioral of top_level is ); end component; + component lin_controller + Port ( + clk : in STD_LOGIC; + rst : in STD_LOGIC; + rx : in STD_LOGIC; + tx : out STD_LOGIC; + data_in : in STD_LOGIC_VECTOR(63 downto 0); + data_out : out STD_LOGIC_VECTOR(63 downto 0); + data_valid : out STD_LOGIC + ); + end component; + + component lin_transceiver + Port ( + clk : in STD_LOGIC; + rst : in STD_LOGIC; + tx_in : in STD_LOGIC; + rx_out : out STD_LOGIC; + lin_bus : inout STD_LOGIC + ); + end component; + begin clock_gen: clock_generator port map ( @@ -79,8 +107,8 @@ begin rx => can_rx_internal, tx => can_tx_internal, data_in => data_in, - data_out => data_out, - data_valid => data_valid + data_out => can_data_out, + data_valid => can_data_valid ); can_xcvr: can_transceiver @@ -93,4 +121,36 @@ begin can_low => can_tx ); + lin_ctrl: lin_controller + port map ( + clk => clk_1m, + rst => rst, + rx => lin_rx_internal, + tx => lin_tx_internal, + data_in => data_in, + data_out => lin_data_out, + data_valid => lin_data_valid + ); + + lin_xcvr: lin_transceiver + port map ( + clk => clk_1m, + rst => rst, + tx_in => lin_tx_internal, + rx_out => lin_rx_internal, + lin_bus => lin_rx + ); + + -- Protocol selection mux + process(protocol_select, can_data_out, lin_data_out, can_data_valid, lin_data_valid) + begin + if protocol_select = '0' then + data_out <= can_data_out; + data_valid <= can_data_valid; + else + data_out <= lin_data_out; + data_valid <= lin_data_valid; + end if; + end process; + end Behavioral;