Counting Debounced Events
Counting...
Please Log In for full access to the web site.
Note that this link will take you to an external site (https://shimmer.mit.edu) to authenticate, and then you will be redirected back to this page.
Getting Started
Just like last time, create a new project folder. Repeat the file structure we used in Lab 01, except call this one lab02
or something relevant, with the following folders:
hdl
: to hold all your Verilog files that will be synthesized (built on the FPGA)xdc
: to hold the XDC file for mapping and activating pinssim
: to hold all Python files that are for simulating/testbenchingobj
: to hold all output files from your Vivado builds
Take the generic build tcl script and place it in the root of your lab folder. A starting version of the the xdc file for this lab should be placed in your xdc folder.
Create a top level file called top_level.sv
in hdl
. Use the following starting skeleton for your top_level.sv
:
`default_nettype none // prevents system from inferring an undeclared logic (good practice)
module top_level(
input wire clk_100mhz, //100 MHz onboard clock
input wire [15:0] sw, //all 16 input slide switches
input wire [3:0] btn, //all four momentary button switches
output logic [15:0] led, //16 green output LEDs (located right above switches)
output logic [2:0] rgb0, //RGB channels of RGB LED0
output logic [2:0] rgb1, //RGB channels of RGB LED1
output logic [3:0] ss0_an,//anode control for upper four digits of seven-seg display
output logic [3:0] ss1_an,//anode control for lower four digits of seven-seg display
output logic [6:0] ss0_c, //cathode controls for the segments of upper four digits
output logic [6:0] ss1_c //cathode controls for the segments of lower four digits
);
//shut up those rgb LEDs for now (active high):
assign rgb1 = 0; //set to 0.
assign rgb0 = 0; //set to 0. Change later!!
//have btnd control system reset
logic sys_rst;
assign sys_rst = btn[0];
//how many button presses have we seen so far?
//wire this up to the LED display
logic [15:0] btn_count; //use me to keep track of counting
assign led = btn_count;
//downstream/display variables:
logic [31:0] val_to_display; //either the spi data or the btn_count data (default)
logic [6:0] ss_c; //used to grab output cathode signal for 7s leds
// debouncer for the button. we wrote this in lecture together.
//TODO: make a variable for the debounced
//button output, and feed it into your edge detector
debouncer btn1_db(.clk_in(clk_100mhz),
.rst_in(sys_rst),
.dirty_in(btn[1]),
.clean_out(/* your variable here */));
// this signal should go high for one cycle on the ..
//rising edge of the (debounced) button output
logic btn_pulse;
//TODO: write your edge detector for part 1 of the lab here!
//the button-press counter.
//TODO: finish this during part 1 of the lab
evt_counter msc(.clk_in(clk_100mhz),
.rst_in(sys_rst),
.evt_in(btn_pulse),
.count_out(btn_count));
//for starters just display button count:
assign val_to_display = btn_count;
//uncomment seven segment module for part 2!
//
//seven_segment_controller mssc(.clk_in(clk_100mhz),
// .rst_in(sys_rst),
// .val_in(val_to_display),
// .cat_out(ss_c),
// .an_out({ss0_an, ss1_an}));
//
assign {ss0_an, ss1_an} = 8'h00; // Remove this for part 2!
assign ss0_c = ss_c; //control upper four digit's cathodes!
assign ss1_c = ss_c; //same as above but for lower four digits!
endmodule // top_level
`default_nettype wire
Make sure to uncomment the appropriate lines in the top_level.xdc
corresponding with the inputs and outputs of top_level.sv
.
As a reminder/refersher, the pins above are the following:
clk_100mhz
: Our clock; make sure to uncomment both related lines to this at the top of the xdcled[15:0]
: All sixteen green LEDs (above the switches)- All 8
an
anode pins of the seven-segment display, which are split into two "banks":ss0_an[3:0]
which control the on/off nature of each of the four upper digits (active low)ss1_an[3:0]
which controls the on/off nature of each of the four lower digits (active low)
- The cathode pins of the seven-segment display, which are split into two "banks":
ss0_c[6:0]
which controls the segments of all four upper digits (active low)ss1_c[6:0]
which controls the segments of all four lower digits (active low)
btn[1]
: This button will be debounced and countedbtn[0]
: We'll use this button as a global resetbtn[2]
: We'll eventually use this to show either the button count or the transmit/receive pair of datargb1[2:0]
andrgb0[2:0]
: Which we set to 0 since otherwise the circuit that drives them floats high and turns them on and they are annoyingly bright.
Inside your hdl
folder you should also create the following files:
debouncer.sv
: A module we gave you after we built it in lecture (find it again here!)evt_counter.sv
: A module that will count events (and be resettable). Can be blank for the moment; a skeleton is provided in the text below.seven_segment_controller.sv
: A module that will control your entire 8 digit, 7-segment display. Can be blank for the moment; a skeleton is provided in part two of the lab.spi_con.sv
: Your SPI (Serial Peripheral Interface) controller module from the exercise this week (to be written after checkoff 2 so can also be blank for the moment).
Button Counting
You'll now be implementing this design:
Parts of this signal pipeline are already in place in the source provided, but others are missing. In building this pipeline, we'll work backwards: First we'll make a counter, then we'll handle edge-detection (i.e., emit a pulse when the button is first pressed), and finally we'll drop in your debouncer module.
Adding a Counter
Last week you wrote a counting module that had a maximum count that was
user-specifiable. There's lots of other variations on counters that you'll come
across...it is a very common thing you'll need to build. One variation of a
counter that is particularly useful in designs is something that tallies the
occurences of an event. We'll be doing that for the first part of lab by
creating a module called evt_counter
that has three inputs:
clk_in
: The system clockrst_in
: A reset for the systemevt_in
: The event to be counted; whenevt_in
is HIGH on a rising edge ofclk_in
, the counter should increment by onecount_out[15:0]
: The output of the counter module; note that this value is 16 bits, so it should be able to count from16'b0000_0000_0000_0000
to16'b1111_1111_1111_1111
In addition:
- If
rst_in
is asserted,count_out
is reset to zero synchronously (on the rising edge of the clock). It should stay set to zero whilerst_in
is asserted. - If
rst_in
is not asserted andevt_in
is high on a rising clock edge, the count should be increased by 1. - Don't worry about overflowing the counter.
We provide a starting skeleton below. Your job is to finish it based on the spec above.
`default_nettype none
module evt_counter
( input wire clk_in,
input wire rst_in,
input wire evt_in,
output logic[15:0] count_out
);
always_ff @(posedge clk_in) begin
if (rst_in) begin
count_out <= 16'b0;
end else begin
/* your code here */
end
end
endmodule
`default_nettype wire
Since there's a lot of moving parts going into this lab's checkoff 1, it would be a good idea to test and verify the behavior of this module prior to integration. We provide a testbench for this module here: test_evt_counter.py.
Run this testbench like you did last week. There are some assertions in this code that do some checks. In addition, you studying the output wave files is important.
In simulation, unless things get explicitly set to a value, they will stay undefined! These undefined values will propagate through the simulation. Notice how in your waveform, count
variable is XXXX
(and red) at the very beginning of the trace. This means that the output has yet to be driven! If you started using our evt_counter
skeleton, you'll notice that only on the rising edge of rst_in
and clk_in
does count
become 0. In reality, when synthesized and placed on a device, even if signals are not initialized, they will generally start at 0. Regardless though, it's good practice to get rid of these demonic 'XXX's when possible (:
Once you've inspected your testbench waveform output and it seems to be working and counting and resetting where appropriate, move onto to the next part.
Edge Detector
Debouncing the switch "cleans" up the switch signal so upon push or release, it only transitions exactly once. However with the way our evt_counter
module is written, if we feed the debounced input directly into the counter, one push may result in literally hundreds of thousands of "events" depending how long we push the button for (question: why? Make sure that makes sense since we will ask you about it during checkoff). We instead should only count the event of a push as it happens.
In other words, we need to create a rising-edge signal that lasts for only one clock cycle whenever the button is pressed. A simple way of generating an edge signal is to remember the previous value of a signal, and use that to look for a rising edge. In your top_level
module, write some code that looks for the rising edge of the output of debounce
, and goes high when that happens. Because this code must happen over time it must be getting evaluated in a always_ff
block.
Debouncer
The final piece to add is right at the beginning of the signal pipeline - the debouncer, which we wrote together in class. This module should take in the button signal which may be "bouncy" and "dirty" and clean it up so that there are no unfortunate back-forth-back-forth signal transitions that may arise. Integrate this module into your system.
Make sure the output of your counter is tied to the sixteen LEDs, and build + show that it works. As a reminder, the command to flash your output bitstream (let's say it's obj/final.bit
) is:
openFPGALoader -b arty_s7_50 obj/final.bit
At the link below is a video of the thing working as expected. Make sure your system counts btn[1]
pushes robustly and can be reset by pushing btn[0]
.
Show us your event counter working in simulation (in the waveform viewer) and on the FPGA. Be prepared to answer some questions. Note, you're also welcome to move onto the next section, and do checkoff 1 and checkoff 2 at the same time since they build on eachother. Just make sure to ask for Checkoff 1 and Checkoff 2 via the website when you get there since we can't give you a checkoff without you asking for it via your own web page.
All Done? Move on and get started on Part Two of this week's assignments.