Our programmable logic designs are often deployed in applications which can be electrically noisy. This noise can affect the signals that are received by the design implemented in programmable logic. For example, it could cause glitches on the signal or bouncing which if not addressed properly, can lead to issues in the design and operation.
Glitches will be of random duration and are not synchronous to the clock edge. As a result, they can result in corruption of downstream information.
The most common way of dealing with this is to use a glitch filter used to filter out glitches and bounce. We implement a glitch filter on many of our designs if we think the application is going to be noisy and needs IO filtering.
Our glitch filter uses a selectable length shift register into which the noisy signal is applied. This is then shifted in until all values of the shift register agree. At that point, the signal can be seen as stable. We do, of course, have to determine how long the potential glitches and bounce could be to ensure the correct sizing of the register for the clock period. This is why our glitch filter is flexible and uses generics to ensure it can be sized appropriately for each application requirement.
The filter should be able to take a noisy input and filter out glitches with a duration of multiple clock pulses.
Since we use VHDL, we will leverage some VHDL 2008 features in the development of the glitch filter. We want to be able to simulate this in all conditions e.g., when using I2C interfaces where we might use H for example to indicate the pull ups on SCL, SDA. Using the to_01 function provided by numeric std ensures that each element of the resultant vector is 0 or 1. We can then use simple signal attributes to ensure all the elements of the array are either one or zero.
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity glitch_filter is generic( G_FILER_LEN : integer := 8 ); port( i_clk : in std_ulogic; i_noisy : in std_ulogic; o_clean : out std_ulogic ); end glitch_filter; architecture behaviour of glitch_filter is signal s_delay_line : std_ulogic_vector(G_FILER_LEN - 1 downto 0); signal s_delay_and : std_ulogic; signal s_delay_nor : std_ulogic; signal s_output_clean : std_ulogic; begin o_clean <= s_output_clean; --Delay disctete using delay line synchroniser_process : process (i_clk) begin if rising_edge(i_clk) then s_delay_line <= s_delay_line(G_FILER_LEN - 2 downto 0) & i_noisy; end if; end process; --Generate AND and NOR of delay line bits s_delay_and <= '1' when to_01(s_delay_line) = (s_delay_line'range => '1') else '0'; s_delay_nor <= '1' when to_01(s_delay_line) = (s_delay_line'range => '0') else '0'; --Set discrete based on delay line output_process : process (i_clk) begin if rising_edge(i_clk) then if s_delay_nor = '1' then s_output_clean <= '0'; elsif s_delay_and = '1' then s_output_clean <= '1'; end if; end if; end process; end behaviour;
To test this module, I have created a simple test bench which injects a random number of glitches into the signal. The test bench is driving either one or zero into the module. A number of random glitches are input onto the signal just after the signal changes state. If the filter is performing correctly, these are not visible on the output clean signal generated by the glitch filter.
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use ieee.math_real.all; entity glitch_filter_tb is end; architecture bench of glitch_filter_tb is component glitch_filter generic ( G_FILER_LEN : integer ); port ( i_clk : in std_ulogic; i_noisy : in std_ulogic; o_clean : out std_ulogic ); end component; -- Clock period constant clk_period : time := 10 ns; -- Generics constant G_FILER_LEN : integer := 8; -- Ports signal i_clk : std_ulogic :='0'; signal i_noisy : std_ulogic; signal o_clean : std_ulogic; begin i_clk <= not i_clk after (clk_period/2); glitch_filter_inst : glitch_filter generic map ( G_FILER_LEN => G_FILER_LEN ) port map ( i_clk => i_clk, i_noisy => i_noisy, o_clean => o_clean ); uut : process variable glitch_duration : integer; variable seed1 : positive := 1; variable seed2 : positive := 283647823; impure function integer_random(min, max : integer) return integer is variable random : real; begin uniform(seed1, seed2, random); return integer(round(random * real(max - min) + real(min))); end function; begin i_noisy <= '0'; wait until rising_edge(i_clk); wait for G_FILER_LEN * clk_period; test: for i in 0 to 1 loop i_noisy <= '1'; wait until rising_edge(i_clk); glitch_duration := integer_random(1,5); for x in 0 to glitch_duration loop i_noisy <= not i_noisy; wait until rising_edge(i_clk); end loop; i_noisy <= '1'; wait for 20 * clk_period; report "loop high completed" severity note; i_noisy <= '0'; wait until rising_edge(i_clk); glitch_duration := integer_random(1,5); for x in 0 to glitch_duration loop i_noisy <= not i_noisy; wait until rising_edge(i_clk); end loop; i_noisy <= '0'; wait for 20 * clk_period; report "loop low completed" severity note; end loop; report "Simulation complete" severity failure; end process; end;
Running the test bench shows a random number of pulses being applied after the change of state of the signal. However, examining the output signals show that the filter has correctly filtered out the glitches which might be present on the input signal.
As I said at the beginning, filters like this are very useful to deploy in environments which might be electrically noisy. Combined with other mitigation strategies such as EDAC on BRAMs etc., this is one of the key methods that can be used to implement design resilience.
Hopefully this technique is useful when you design your system for a noisy operation.
Workshops and Webinars
If you enjoyed the blog why not take a look at the free webinars, workshops and training courses we have created over the years. Highlights include
Introduction to Vivado learn how to use AMD Vivado
Ultra96, MiniZed & ZU1 three day course looking at HW, SW and Petalinux
Arty Z7-20 Class looking at HW, SW and Petalinux
Mastering MicroBlaze learn how to create MicroBlaze solutions
HLS Hero Workshop learn how to create High Level Synthesis based solutions
Perfecting Petalinux learn how to create and work with petalinux OS
Embedded System Book Do you want to know more about designing embedded systems from scratch? Check out our book on creating embedded systems. This book will walk you through all the stages of requirements, architecture, component selection, schematics, layout, and FPGA / software design. We designed and manufactured the board at the heart of the book! The schematics and layout are available in Altium here Learn more about the board (see previous blogs on Bring up, DDR validation, USB, Sensors) and view the schematics here.
Sponsored by AMD Xilinx