- Pre-Lab preparation
- Part 1: Finite State Machine (FSM)
- Part 2: Button bounce
- Part 3: FSM debouncer in VHDL
- Part 4: Edge detector
- Challenges
- References
- Understand the philosophy and use of finite state machines
- Use state diagrams
- Understand the difference between Mealy and Moore type of FSM in VHDL
- Understand the button bounce effect and how to debounce it
- Use edge detectors
-
The Nexys A7 board provides five push buttons. See schematic or reference manual of the Nexys A7 board and find out the connection of these push-buttons and their active level.
-
Optional: See video tutorial Implementing the candy-lock FSM in VHDL
A Finite State Machine (FSM) is a mathematical model used to describe and represent the behavior of systems that can be in a finite number of states at any given time. It consists of a set of states, transitions between these states, and actions associated with these transitions.
The main properties of using FSMs include:
-
Determinism: FSMs are deterministic if, for each state and input, there is exactly one transition to a next state. This property simplifies analysis and implementation.
-
State Memory: FSMs inherently have memory as they retain information about their current state. This allows them to model systems with sequential behavior.
-
Simplicity: FSMs are relatively simple and intuitive to understand, making them useful for modeling and designing systems with discrete and sequential behavior.
-
Parallelism: FSMs can represent parallelism by having multiple state machines working concurrently, each handling different aspects of the system.
The main types of FSMs include Moore Machine and Mealy Machine. In a Moore machine, outputs are associated with states (see figure bellow), while in a Mealy machine, outputs are associated with transitions between states. This means that Moore machines produce outputs only after transitioning to a new state, while Mealy machines can produce outputs immediately upon receiving an input.
One widely used method to illustrate a finite state machine is through a state diagram, comprising circles connected by directed arcs. Each circle denotes a machine state labeled with its name, and, in the case of a Moore machine, an output value associated with the state.
Directed arcs signify the transitions between states in a finite state machine (FSM). For a Mealy machine, these arcs are labeled with input/output pairs, while for a Moore machine, they are labeled solely with inputs.
A bouncy button, also known as a "bouncing switch" or "switch bounce," refers to the phenomenon where the electrical contacts in a mechanical switch make multiple, rapid transitions between open and closed states when pressed or released. This can lead to multiple erroneous signals being sent to a circuit. Examples of real push buttons can be seen below. (Note that, the active level of the button here is low.)
The main methods to debounce a bouncy button are:
-
Hardware Debouncing: Hardware debouncing involves adding additional circuitry or components to the switch or input signal path to eliminate or reduce the effects of bouncing, such as capacitors, resistors, and Schmitt triggers.
-
Software Debouncing: This method involves using software algorithms to filter out the noise and ensure that only a single, stable signal transition is recognized. Common techniques include implementing delay-based algorithms, state machines, or using timers.
-
Combination Approach: Often, a combination of software and hardware debouncing methods is employed to achieve robust debouncing.
-
Run Vivado, create a new project and implement an FSM version of software debouncer with clock enable and reset:
-
Project name:
fsm
-
Project location: your working folder, such as
Documents
-
Project type: RTL Project
-
Create a VHDL source file:
debounce
-
Do not add any constraints now
-
Choose a default board:
Nexys A7-50T
-
Click Finish to create the project
-
Define I/O ports of new module:
Port name Direction Type Description clk
input std_logic
Main clock rst
input std_logic
High-active synchronous reset en
input std_logic
Clock enable input bouncey
input std_logic
Bouncey button input clean
output std_logic
Debounced button output
-
-
The inactive level of the on-board push buttons is low. Periodically read the button signal, and if the value is high, start counting a sequence of consecutive high values. If there is an uninterrupted sequence of
N_VALUES = 4
high values, consider the button pressed. The counter resets to zero upon receiving a low sample. When releasing the button, the FSM counts the same number of low-value samples before considering the button released.Define four states for the FSM and an internal counter in the architecture declaration section to count a sequence of unchanged button signal values. Additionally, define a debounced signal required later for the edge detector.
architecture behavioral of debounce is -- Define states for the FSM type state_type is (IDLE, COUNT_1, PRESSED, COUNT_0); signal state : state_type; -- Define number of values for debounce counter constant N_VALUES : integer := 4; -- Define signals for debounce counter signal sig_count : integer range 0 to N_VALUES; -- Debounced signal signal sig_clean : std_logic; begin ...
-
Complete the architecture body section according to the state diagram above.
begin -- Process implementing a finite state machine (FSM) for -- button debouncing. Handles transitions between different -- states based on clock signal and bouncey button input. p_fsm : process (clk) is begin if rising_edge(clk) then if (rst = '1') then -- Active-high reset state <= IDLE; elsif (en = '1') then -- Clock enable case state is -- Define transitions between states when IDLE => -- If bouncey = 1 then clear counter and go to COUNT_1; when COUNT_1 => -- If bouncey = 1 increment counter -- if counter = N_VALUES-1 go to PRESSED -- else go to IDLE when PRESSED => -- If bouncey = 0 then clear counter and go to COUNT_0; when COUNT_0 => -- If bouncey = 0 then increment counter -- if counter = N_VALUES-1 go to IDLE; -- else clear counter and go to PRESSED; -- Prevent unhandled cases when others => null; end case; end if; end if; end process p_fsm; -- Set clean signal to 1 when states PRESSED or COUNT_0 -- Assign output debounced signal clean <= sig_clean; end architecture behavioral;
-
Use Flow > Open Elaborated design and see the schematic after RTL analysis.
-
Generate a simulation source named
tb_debounce
, create bouncey signal, execute the simulation, and validate the functionality of enable, reset, and debouncing.Note: To display internal signal values, follow these steps:
Your simulation should be similar to the following figure.
A positive edge detector generates a single clock pulse when the input signal transitions from low to high, while a negative edge detector generates a pulse when the input transitions from high to low. The VHDL code captures these transitions by comparing the current signal state with the previous one using and
and not
gates, outputting single clock pulses accordingly.
Note: Listing of Wavedrom code for the figure above:
{ signal: [ {name: "clk", wave: 'P.................'}, {name: "clean", wave: 'l...h.......l.....'}, {name: "delayed", wave: 'l....h.......l....'}, {}, {name: "pos_edge", wave: 'l...hl............'}, {name: "neg_edge", wave: 'l...........hl....'}, ], }
-
Add both edge detectors to
debounce
component:-
Define new entity outputs
pos_edge
andneg_edge
asstd_logic
-
In architecture declaration part, define
sig_delayed
signal asstd_logic
-
In architecture body, add new
p_edge_detector
process and definepos_edge
andneg_edge
output values usingand
andnot
gates-- Remember the previous value of a signal and generates single -- clock pulses for positive and negative edges of the debounced signal. p_edge_detector : process (clk) is begin if rising_edge(clk) then if (rst = '1') then sig_delayed <= '0'; else sig_delayed <= sig_clean; end if; end if; end process p_edge_detector; -- Assign output signals for edge detector end architecture behavioral;
-
-
Add new edge detector outputs to the simulation source
tb_debounce
and relaunch the simulation. Ensure that your simulations resemble the figure below:
-
Create a VHDL design source named
top_level
and implement a button-triggered 4-bit simple counter on the Nexys A7 board. ReadBTNR
button every 2 milliseconds and on rising edge of clean/debounced signal increment the counter value on the LEDs.Use component declarations and instantiations of
clock_enable
,debounce
andsimple_counter
, and define the top-level architecture as follows. Use reserved keywordopen
when you instantiate a module that has an output that is not needed.Note: The
clock_enable
andsimple_counter
components from the previous labs are required. Do not forget to copy both files toYOUR-PROJECT-FOLDER/debounce.srcs/sources_1/new/
folder and add them to the project.Note: Use online template for your constraints XDC file
nexys-a7-50t
and uncomment the used pins according to the top_level entity. -
Move
clock_enable
instanciation to thedebounce
component. -
Instead of LEDs, use a Pmod port of the Nexys A7 board and display counter values on oscilloscope or logic analyser.
-
Use iterative
generate
statement from the previous lab and extend the instantiation ofdebounce
component to several buttons.
-
David Williams. Implementing a Finite State Machine in VHDL
-
MIT OpenCourseWare. L06: Finite State Machines
-
VHDLwhiz. One-process vs two-process vs three-process state machine
-
Clive Maxfield. How to Implement Hardware Debounce for Switches and Relays When Software Debounce Isn’t Appropriate