FPGA Reaction Timer
Updated: Sep 21, 2020
Electronic devices operate at remarkably fast speeds, with the typical delay through today's logic gates being less than a nanosecond. This project aims to use a logic circuit to measure the speed of a much slower type of device—a person. In short, a circuit was designed and coded in Verilog and implemented on the MAX 10 FPGA to determine the reaction time of a person to a specific event.
How it works
The circuit will illuminate an LED on the DE10-LITE board a random amount of time after a “start” button is pushed and released (button key 0). The goal is for the player to switch on the “stop” switch that corresponds to a randomly lit LED as quickly as possible. The reaction time will be displayed in milliseconds on the board’s seven-segment display after the stop switch is turned on. Furthermore, if the start or stop inputs triggered before the LED is lit, then the random timer is stopped, and everything is reset. An asynchronous reset switch also resets the game to display the latest high score. The DE10-LITE board inputs and outputs are described below.
The Verilog modules are summarized in the block diagram that follows.
The Finite State Machine
A finite state machine was chosen to implement the reaction timer concept due to its sequential nature. The FSM is a Mealy machine because its output values are determined by both its current state and the current inputs, more specifically the switches and buttons. Here's state diagram illustrating transitions between states with a description below it.
The machine begins in the s0 state where the reaction timer is not running, but the current high score is displayed. Then, if switch 1 is turned on, the state becomes s1 where the reaction timer sits idle, but nothing is being displayed on either the HEXs or LEDs. If in state s1 and the button KEY0 is pressed, the machine transitions to s2 which acts as a random delay period before a random LED lights. Then, after that delay has been counted by a down-counter, the state automatically switches to s3 as a random LED illuminates. s3 is the state in which the user must switch the corresponding switch under the randomly lit LED to stop the timer as quickly as possible. Once the correct switch as been switched, the machine moves to state s4 which displays that score. If at any time switch 0 is turned off, the state goes back to s0 to show the current high score. Bored yet? Concise descriptions of the states are shown here.
The inputs are summarized below.
As displayed by the block diagram in above, Project2_Top takes in the two buttons and ten switches as inputs, and utilizes the BCD Counter, Delay Down Counter, Clock Divider, LFSR, and BCD Decoder modules to create outputs for the ten LEDs and four seven-segment display units. The FSM is implemented in Project2_Top with a series of conditional statements that change every time the clock changes. The top module also functions as a decoder converting the LED selector to a series of bits that represents the LEDs.
The clock divider is one of the most important modules as it keeps everything in sync. Both a 1kHz and 1Hz clock were created from the 10MHz clock on board by dividing it by the correct parameter. To achieve 1kHz, for instance, every 10MHz positive edge clock cycle was counted until the 5,000-parameter value was reached at which point the new clock would switch from high to low or vice versa. 5,000 was chosen even though the clock is being divided by 10,000 because the new 1kHz clock cycle should be high for 5,000 cycles of that period and low for the other 5,000 cycles (a period). The same method was executed for the 1Hz clock, except with a larger division parameter of 5,000,000.
The BCD Counter counts in decimal digits from 0 to 9999 to be output to the seven segment displays for the user to see their time. The counter counts in milliseconds because it is passed the 1000Hz clock that was created in the Clock_Divider module as described above. 1000kHz translates to 1/1000 of a second, which is simply 1 millisecond. Hence, the BCD Counter counts every one millisecond.
This module simply counts down from the LFSR output value until it reaches 0 at which time the LED illuminates. Hence, the Down_Counter module was imperative in executing the random delay.
The LFSR, or linear feedback shift register, was creates a random number for counting random delays before LED illumination and in choosing a random LED to be lit for the more difficult game. The LFSR outputs a random number between 0 and 15 that was then computed with modulus 7 to get a remainder output between 0 and 7. This “random” delay (random is in quotes because LFSRs actual follow a linear pattern) was tested 64 times, and the outputs of this test are shown in the following histogram.
Hence, although the delay is not completely random nor perfectly distributed as some outputs appear more than others, this minute difference in frequency will be unnoticeable by a human user. For the random LED illumination, 2 was added to the 0-7 range in order to span 2-9 and represent the LEDs above the stop switches. Furthermore, since the LSFR is always running, that number changes, and different LEDs light up over time, making the game that much harder.
This module takes in binary inputs and outputs proper hexadecimal 8 bit binary to light up the LEDs on the seven-segment display. It is important to note that the LEDs on the seven segment displays are high by default.
The purpose of this project was to create a reaction timer using an FPGA and Verilog code in Quartus Prime. This goal was met aside from a minor inconsistency. That difference unfolds between the random delay after the start button has been pressed, and the display of the high score. For an unknown reason, when the random number from the LSFR is capable of executing a random delay, the high score function did not work as planned. Similarly, when the high score was storing that score in a register after comparing it to the current reaction time, there was no delay at all before an LED had been illuminated. After countless hours looking for a fix, a compromise was reached, and two versions of code with respective functionalities were created. With this being the only issue, everything else went according to plan. The states change on the proper inputs and the seven segment displays display the correct outputs when they are supposed to. Furthermore, an extra bit of randomness was added by illuminating a random LED that corresponds to the switch that needs to be “stopped” to stop the timer. To go further, the LED that lights up changes every second (because it is on the 1Hz clock cycle), so if the user misses the first LED switch, they must follow it to the second, bringing more challenge to the game. In conclusion, although creation of the modules themselves went well, getting the modules to work together in sync became the most difficult part of the project. If I were to do the project again, I would likely start by designing the FSM at the logic gate level before jumping into Verilog code.
The first video exhibits the reaction timer in action with a random delay before an LED lights.
The second video illustrates the high score functionality.