From 72780da2e1704f38196d6d154e43c75e830e1f87 Mon Sep 17 00:00:00 2001 From: "Christian, Glenn (DLSLtd,RAL,LSCI)" Date: Tue, 25 Jun 2024 18:48:48 +0100 Subject: [PATCH] Fix for SSI and BiSS encoder modules to correctly detect encoder loss * Encoder loss deduced from serial data from encoder not clock * Loss detection common to master and sniffer * For BiSS, just check for clock at startup as CRC will check data * integrity. Serial clock is needed to interpret data frame. --- common/hdl/encoders/biss_sniffer.vhd | 3 +- common/hdl/encoders/encoders.vhd | 36 ++++++++++----- common/hdl/encoders/ssi_error_detect.vhd | 58 ++++++++++++++++++++++++ common/hdl/encoders/ssi_master.vhd | 16 ++++++- common/hdl/encoders/ssi_sniffer.vhd | 22 +++------ modules/inenc/inenc.block.ini | 2 +- 6 files changed, 107 insertions(+), 30 deletions(-) create mode 100644 common/hdl/encoders/ssi_error_detect.vhd diff --git a/common/hdl/encoders/biss_sniffer.vhd b/common/hdl/encoders/biss_sniffer.vhd index 6ff287287..d6cec2687 100644 --- a/common/hdl/encoders/biss_sniffer.vhd +++ b/common/hdl/encoders/biss_sniffer.vhd @@ -128,6 +128,7 @@ begin if (reset = '1') then biss_fsm <= IDLE; biss_frame <= '0'; + link_up_o <= '0'; else -- Unidirectional point-to-point BiSS communication case biss_fsm is @@ -165,6 +166,7 @@ begin -- Set active biss frame flag for link disconnection if (biss_fsm = IDLE and serial_clock = '0') then biss_frame <= '1'; + link_up_o <= '1'; elsif (biss_fsm = TIMEOUT) then biss_frame <= '0'; end if; @@ -322,7 +324,6 @@ end process; -- link_down -- Encoder CRC error -------------------------------------------------------------------------- -link_up_o <= link_up; health_o <= health_biss_sniffer; error_o <= crc_strobe when (crc /= crc_calc or nError(1) = '0') else '0'; diff --git a/common/hdl/encoders/encoders.vhd b/common/hdl/encoders/encoders.vhd index 63b5ce0eb..6d8db7953 100644 --- a/common/hdl/encoders/encoders.vhd +++ b/common/hdl/encoders/encoders.vhd @@ -97,6 +97,9 @@ signal homed_qdec : std_logic_vector(31 downto 0); signal linkup_incr : std_logic; signal linkup_incr_std32 : std_logic_vector(31 downto 0); signal linkup_ssi : std_logic; +signal ssi_frame : std_logic; +signal ssi_frame_sniffer : std_logic; +signal ssi_frame_master : std_logic; signal linkup_biss_sniffer : std_logic; signal health_biss_sniffer : std_logic_vector(31 downto 0); signal linkup_biss_master : std_logic; @@ -307,7 +310,8 @@ port map ( ssi_sck_o => clk_out_encoder_ssi, ssi_dat_i => DATA_IN, posn_o => posn_ssi, - posn_valid_o => open + posn_valid_o => open, + ssi_frame_o => ssi_frame_master ); -- SSI Sniffer @@ -317,11 +321,23 @@ port map ( reset_i => reset_i, ENCODING => INENC_ENCODING_i, BITS => INENC_BITS_i, - link_up_o => linkup_ssi, error_o => open, ssi_sck_i => CLK_IN, ssi_dat_i => DATA_IN, - posn_o => posn_ssi_sniffer + posn_o => posn_ssi_sniffer, + ssi_frame_o => ssi_frame_sniffer +); + +ssi_frame <= ssi_frame_sniffer when DCARD_MODE_i(3 downto 1) = DCARD_MONITOR + else ssi_frame_master; + +-- Frame checker for SSI +ssi_err_det_inst: entity work.ssi_error_detect +port map ( + clk_i => clk_i, + serial_dat_i => DATA_IN, + ssi_frame_i => ssi_frame, + link_up_o => linkup_ssi ); -------------------------------------------------------------------------- @@ -384,18 +400,16 @@ begin when "001" => -- SSI & Loopback if (DCARD_MODE_i(3 downto 1) = DCARD_MONITOR) then posn <= posn_ssi_sniffer; - STATUS_o(0) <= linkup_ssi; - if (linkup_ssi = '0') then - INENC_HEALTH_o <= TO_SVECTOR(2,32); - else - INENC_HEALTH_o <= (others => '0'); - end if; else -- DCARD_CONTROL posn <= posn_ssi; - STATUS_o <= (others => '0'); - INENC_HEALTH_o <= (others=>'0'); end if; HOMED_o <= TO_SVECTOR(1,32); + STATUS_o(0) <= linkup_ssi; + if (linkup_ssi = '0') then + INENC_HEALTH_o <= TO_SVECTOR(2,32); + else + INENC_HEALTH_o <= (others => '0'); + end if; when "010" => -- BISS & Loopback if (DCARD_MODE_i(3 downto 1) = DCARD_MONITOR) then diff --git a/common/hdl/encoders/ssi_error_detect.vhd b/common/hdl/encoders/ssi_error_detect.vhd new file mode 100644 index 000000000..64dcd8f95 --- /dev/null +++ b/common/hdl/encoders/ssi_error_detect.vhd @@ -0,0 +1,58 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +use work.support.all; + +entity ssi_error_detect is +port ( + clk_i : in std_logic; + serial_dat_i : in std_logic; + ssi_frame_i : in std_logic; + link_up_o : out std_logic +); +end ssi_error_detect; + +architecture rtl of ssi_error_detect is + +constant ENCODER_TIMEOUT : natural := 125 * 10; -- 10usec (Minimum timeout/2) + +signal ssi_frame_prev : std_logic; +signal timeout_cnt_en : std_logic; +signal timeout_ctr : unsigned(LOG2(ENCODER_TIMEOUT-1) downto 0); +signal frame_start : std_logic; +signal frame_end : std_logic; + +begin + +frame_err_det: process(clk_i) +begin + if rising_edge(clk_i) then + + ssi_frame_prev <= ssi_frame_i; + + if ssi_frame_i = '1' and ssi_frame_prev = '0' then -- rising edge + -- Encoder must drive the line high when IDLE + frame_start <= serial_dat_i; + timeout_cnt_en <= '0'; + elsif ssi_frame_i = '0' and ssi_frame_prev = '1' then --falling edge + timeout_cnt_en <= '1'; + timeout_ctr <= (others => '0'); + elsif timeout_cnt_en = '1' then + if timeout_ctr = ENCODER_TIMEOUT-1 then + -- Encoder must drive the line low during TIMEOUT dwell time + frame_end <= serial_dat_i; + timeout_ctr <= (others => '0'); + timeout_cnt_en <= '0'; + else + timeout_ctr <= timeout_ctr + 1; + end if; + end if; + + -- Link is up when line is high during IDLE and low during TIMEOUT + link_up_o <= frame_start and not frame_end; + end if; +end process; + +end rtl; + diff --git a/common/hdl/encoders/ssi_master.vhd b/common/hdl/encoders/ssi_master.vhd index 5092ad10d..468c7363f 100644 --- a/common/hdl/encoders/ssi_master.vhd +++ b/common/hdl/encoders/ssi_master.vhd @@ -41,7 +41,8 @@ port ( ssi_sck_o : out std_logic; ssi_dat_i : in std_logic; posn_o : out std_logic_vector(31 downto 0); - posn_valid_o : out std_logic + posn_valid_o : out std_logic; + ssi_frame_o : out std_logic ); end entity; @@ -50,10 +51,12 @@ architecture rtl of ssi_master is signal frame_pulse : std_logic; signal serial_clock : std_logic; signal serial_clock_prev : std_logic; +signal shift_enable_prev : std_logic; signal shift_enable : std_logic; signal shift_clock : std_logic; signal shift_data : std_logic; signal shift_in : std_logic_vector(31 downto 0); +signal ssi_frame : std_logic; -- Shift length in integer signal intBITS : natural range 0 to 2**BITS'length-1; @@ -62,6 +65,7 @@ begin -- Connect outputs ssi_sck_o <= serial_clock; +ssi_frame_o <= ssi_frame; -- Generate Internal SSI Frame from system clock frame_presc : entity work.prescaler @@ -93,8 +97,18 @@ begin if rising_edge(clk_i) then if reset_i = '1' then serial_clock_prev <= '0'; + shift_enable_prev <= '0'; + ssi_frame <= '0'; else serial_clock_prev <= serial_clock; + shift_enable_prev <= shift_enable; + -- Check for initial falling edge of serial clock for start of frame + if shift_clock = '1' and ssi_frame = '0' then + ssi_frame <= '1'; + -- check for falling edge of shift_enable to reset ssi_frame + elsif shift_enable = '0' and shift_enable_prev = '1' then + ssi_frame <= '0'; + end if; end if; end if; end process; diff --git a/common/hdl/encoders/ssi_sniffer.vhd b/common/hdl/encoders/ssi_sniffer.vhd index f10f87160..c5804582a 100644 --- a/common/hdl/encoders/ssi_sniffer.vhd +++ b/common/hdl/encoders/ssi_sniffer.vhd @@ -24,13 +24,13 @@ port ( -- Configuration interface ENCODING : in std_logic_vector(1 downto 0); BITS : in std_logic_vector(7 downto 0); - link_up_o : out std_logic; - error_o : out std_logic; + error_o : out std_logic := '0'; -- Physical SSI interface ssi_sck_i : in std_logic; ssi_dat_i : in std_logic; -- Block outputs - posn_o : out std_logic_vector(31 downto 0) + posn_o : out std_logic_vector(31 downto 0); + ssi_frame_o : out std_logic ); end ssi_sniffer; @@ -44,8 +44,6 @@ signal uBITS : unsigned(7 downto 0); signal intBITS : natural range 0 to 2**BITS'length-1; signal reset : std_logic; -signal serial_data_prev : std_logic; -signal serial_data_rise : std_logic; signal serial_clock : std_logic; signal serial_clock_prev : std_logic; signal link_up : std_logic; @@ -58,9 +56,10 @@ signal serial_clock_rise : std_logic; signal shift_counter : unsigned(7 downto 0); signal shift_enabled : std_logic; - begin +ssi_frame_o <= ssi_frame; + -------------------------------------------------------------------------- -- Internal signal assignments -------------------------------------------------------------------------- @@ -76,14 +75,12 @@ process (clk_i) begin if (rising_edge(clk_i)) then serial_clock_prev <= serial_clock; - serial_data_prev <= serial_data; end if; end process; -- Shift source synchronous data on the Falling egde of clock serial_clock_fall <= not serial_clock and serial_clock_prev; serial_clock_rise <= serial_clock and not serial_clock_prev; -serial_data_rise <= serial_data and not serial_data_prev; -------------------------------------------------------------------------- -- Detect link if clock is asserted for > 5us. @@ -178,12 +175,5 @@ begin end if; end process; --------------------------------------------------------------------------- --- Module status outputs --- link_down --- Encoder CRC error --------------------------------------------------------------------------- -link_up_o <= link_up; -error_o <= '0'; -- n/a - end rtl; + diff --git a/modules/inenc/inenc.block.ini b/modules/inenc/inenc.block.ini index 31df86960..1eb519367 100644 --- a/modules/inenc/inenc.block.ini +++ b/modules/inenc/inenc.block.ini @@ -85,7 +85,7 @@ type: read enum description: Table status 0: OK 1: Linkup error (=not CONN) -2: Timeout error (for BISS, monitor SSI) +2: Timeout error (for BISS, SSI) 3: CRC error (for BISS) 4: Error bit active (for BISS) 5: ENDAT not implemented