Merge pull request #167 from WhiteNinjaZ/button_controll
De-bounce example
This commit is contained in:
commit
12840ae407
|
@ -47,7 +47,7 @@ shift
|
|||
|
||||
examples="$@"
|
||||
if [ "$fpga_family" == "xc7" -a -z "$examples" ]; then
|
||||
examples="counter picosoc litex litex_linux"
|
||||
examples="counter picosoc litex litex_linux button_controller"
|
||||
elif [ "$fpga_family" == "eos-s3" -a -z "$examples" ]; then
|
||||
examples="counter"
|
||||
fi
|
||||
|
@ -55,6 +55,7 @@ fi
|
|||
# activate conda and enter example dir
|
||||
|
||||
snippets="docs/building-examples.rst:export-install-dir,fpga-fam-$fpga_family,conda-prep-env-$fpga_family,conda-act-env,enter-dir-$fpga_family"
|
||||
additionalDesigns="docs/building-examples.rst:export-install-dir,fpga-fam-$fpga_family,conda-prep-env-$fpga_family,conda-act-env,enter-dir-$fpga_family,additional_examples"
|
||||
|
||||
# Xilinx 7-Series examples
|
||||
if [ "$fpga_family" = "xc7" ]; then
|
||||
|
@ -72,6 +73,11 @@ if [ "$fpga_family" = "xc7" ]; then
|
|||
"litex_linux")
|
||||
snippets="${snippets} xc7/linux_litex_demo/README.rst:example-litex-*-group"
|
||||
;;
|
||||
|
||||
#Additional examples:
|
||||
"button_controller")
|
||||
snippets="${additionalDesigns} xc7/additional_examples/button_controller/README.rst:example-debouncer-basys3"
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: Unknown example name: $example" >&2
|
||||
exit 1
|
||||
|
|
|
@ -57,6 +57,15 @@ jobs:
|
|||
- {fpga-fam: "xc7", os: "debian", os-version: "buster", example: "litex_linux"}
|
||||
- {fpga-fam: "xc7", os: "debian", os-version: "bullseye", example: "litex_linux"}
|
||||
- {fpga-fam: "xc7", os: "debian", os-version: "sid", example: "litex_linux"}
|
||||
|
||||
- {fpga-fam: "xc7", os: "ubuntu", os-version: "xenial", example: "button_controller"}
|
||||
- {fpga-fam: "xc7", os: "ubuntu", os-version: "bionic", example: "button_controller"}
|
||||
- {fpga-fam: "xc7", os: "ubuntu", os-version: "focal", example: "button_controller"}
|
||||
- {fpga-fam: "xc7", os: "centos", os-version: "7", example: "button_controller"}
|
||||
- {fpga-fam: "xc7", os: "centos", os-version: "8", example: "button_controller"}
|
||||
- {fpga-fam: "xc7", os: "debian", os-version: "buster", example: "button_controller"}
|
||||
- {fpga-fam: "xc7", os: "debian", os-version: "bullseye", example: "button_controller"}
|
||||
- {fpga-fam: "xc7", os: "debian", os-version: "sid", example: "button_controller"}
|
||||
|
||||
env:
|
||||
LANG: "en_US.UTF-8"
|
||||
|
|
|
@ -91,6 +91,16 @@ Enter the directory that contains examples for Xilinx 7-Series FPGAs:
|
|||
.. jinja:: xc7_linux_litex_demo
|
||||
:file: templates/example.jinja
|
||||
|
||||
Additional Examples
|
||||
-------------------
|
||||
|
||||
In addition to the designs we have gone over here, you can also find several other exciting designs
|
||||
for the basys3 board in the additional_examples directory:
|
||||
|
||||
.. code-block:: bash
|
||||
:name: additional_examples
|
||||
|
||||
cd additional_examples
|
||||
|
||||
QuickLogic EOS S3
|
||||
-----------------
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 12 MiB |
Binary file not shown.
After Width: | Height: | Size: 3.3 MiB |
|
@ -0,0 +1,8 @@
|
|||
current_dir := ${CURDIR}
|
||||
TARGET := basys3
|
||||
TOP := top
|
||||
SOURCES := ${current_dir}/*.sv
|
||||
|
||||
XDC := ${current_dir}/basys3.xdc
|
||||
|
||||
include ${current_dir}/../../../common/Makefile
|
|
@ -0,0 +1,41 @@
|
|||
Button Controller
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
This example demonstrates using a button debouncer state machine to count the number of presses on the
|
||||
center button of the basys3 board. The number of presses counted by the debouncer state machine will
|
||||
be given on the two right most digits of the display. The two left most digits record the number of
|
||||
presses counted without the debouncer. You can reset the button counter by pressing the up button on
|
||||
the board. To build the design first navigate to the additional examples directory:
|
||||
|
||||
.. code-block:: bash
|
||||
:name: additional-examples
|
||||
|
||||
cd additional_examples
|
||||
|
||||
Then run make to compile the design:
|
||||
|
||||
.. code-block:: bash
|
||||
:name: example-debouncer-basys3
|
||||
|
||||
make -C button_controller
|
||||
|
||||
|
||||
At completion, the bitstream is located in the build directory:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd button_controller/build/basys3
|
||||
|
||||
Now, you can upload the design with:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
openocd -f ${INSTALL_DIR}/${FPGA_FAM}/conda/envs/${FPGA_FAM}/share/openocd/scripts/board/digilent_arty.cfg -c "init; pld load 0 top.bit; exit"
|
||||
|
||||
The following is an example of the debouncer in action:
|
||||
|
||||
.. image:: ../images/debounce.gif
|
||||
:align: center
|
||||
:width: 50%
|
||||
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
# Clock
|
||||
set_property PACKAGE_PIN W5 [get_ports { clk }];
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports { clk }];
|
||||
|
||||
# Buttons
|
||||
set_property PACKAGE_PIN U18 [get_ports { btnc }];
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports { btnc }];
|
||||
|
||||
set_property PACKAGE_PIN T18 [get_ports { btnu }];
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports { btnu }];
|
||||
|
||||
# Seven-Segment Display
|
||||
set_property PACKAGE_PIN W7 [get_ports { segment[0] }];
|
||||
set_property PACKAGE_PIN W6 [get_ports { segment[1] }];
|
||||
set_property PACKAGE_PIN U8 [get_ports { segment[2] }];
|
||||
set_property PACKAGE_PIN V8 [get_ports { segment[3] }];
|
||||
set_property PACKAGE_PIN U5 [get_ports { segment[4] }];
|
||||
set_property PACKAGE_PIN V5 [get_ports { segment[5] }];
|
||||
set_property PACKAGE_PIN U7 [get_ports { segment[6] }];
|
||||
set_property PACKAGE_PIN V7 [get_ports { segment[7] }];
|
||||
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports { segment[0] }];
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports { segment[1] }];
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports { segment[2] }];
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports { segment[3] }];
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports { segment[4] }];
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports { segment[5] }];
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports { segment[6] }];
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports { segment[7] }];
|
||||
|
||||
# Anodes
|
||||
set_property PACKAGE_PIN U2 [get_ports { anode[0] }];
|
||||
set_property PACKAGE_PIN U4 [get_ports { anode[1] }];
|
||||
set_property PACKAGE_PIN V4 [get_ports { anode[2] }];
|
||||
set_property PACKAGE_PIN W4 [get_ports { anode[3] }];
|
||||
|
||||
# Clock constraints
|
||||
create_clock -period 10.0 [get_ports {clk}]
|
|
@ -0,0 +1,71 @@
|
|||
`timescale 1ns / 1ps `default_nettype none
|
||||
|
||||
module top (
|
||||
input wire logic clk,
|
||||
btnu,
|
||||
btnc,
|
||||
output logic [3:0] anode,
|
||||
output logic [7:0] segment
|
||||
);
|
||||
|
||||
|
||||
logic sync;
|
||||
logic syncToDebounce;
|
||||
logic debounceToOneShot;
|
||||
logic f1, f2;
|
||||
logic f3, f4;
|
||||
logic oneShotToCounter;
|
||||
logic [7:0] counterToSevenSegment;
|
||||
logic [7:0] counterToSevenSegment2;
|
||||
logic oneShotToCounter2;
|
||||
logic s0, s1;
|
||||
debounce d0 (
|
||||
.clk(clk),
|
||||
.reset(btnu),
|
||||
.noisy(syncToDebounce),
|
||||
.debounced(debounceToOneShot)
|
||||
);
|
||||
|
||||
assign oneShotToCounter = f1 && ~f2;
|
||||
|
||||
assign oneShotToCounter2 = f3 && ~f4;
|
||||
|
||||
timer #(.MOD_VALUE(256), .BIT_WIDTH(8)) T0 (
|
||||
.clk(clk),
|
||||
.reset(btnu),
|
||||
.increment(oneShotToCounter),
|
||||
.rolling_over(s0),
|
||||
.count(counterToSevenSegment)
|
||||
);
|
||||
|
||||
timer #(.MOD_VALUE(256), .BIT_WIDTH(8)) T1 (
|
||||
.clk(clk),
|
||||
.reset(btnu),
|
||||
.increment(oneShotToCounter2),
|
||||
.rolling_over(s1),
|
||||
.count(counterToSevenSegment2)
|
||||
);
|
||||
|
||||
|
||||
display_control DC0 (
|
||||
.clk(clk),
|
||||
.reset(btnu),
|
||||
.dataIn({counterToSevenSegment2, counterToSevenSegment}),
|
||||
.digitDisplay(4'b1111),
|
||||
.digitPoint(4'b0000),
|
||||
.anode(anode),
|
||||
.segment(segment)
|
||||
);
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
|
||||
sync <= btnc;
|
||||
syncToDebounce <= sync;
|
||||
|
||||
f1 <= debounceToOneShot;
|
||||
f2 <= f1;
|
||||
|
||||
f3 <= syncToDebounce;
|
||||
f4 <= f3;
|
||||
end
|
||||
endmodule
|
|
@ -0,0 +1,64 @@
|
|||
`timescale 1ns / 1ps `default_nettype none
|
||||
|
||||
module debounce (
|
||||
input wire logic clk,
|
||||
reset,
|
||||
noisy,
|
||||
output logic debounced
|
||||
);
|
||||
|
||||
logic timerDone, clrTimer;
|
||||
|
||||
typedef enum logic [1:0] {
|
||||
s0,
|
||||
s1,
|
||||
s2,
|
||||
s3,
|
||||
ERR = 'X
|
||||
} state_type_e;
|
||||
state_type_e ns, cs;
|
||||
|
||||
logic [18:0] tA;
|
||||
|
||||
timer #(.MOD_VALUE(500000), .BIT_WIDTH(19)) T0 (
|
||||
.clk(clk),
|
||||
.reset(clrTimer),
|
||||
.increment(1'b1),
|
||||
.rolling_over(timerDone),
|
||||
.count(tA)
|
||||
);
|
||||
|
||||
always_comb begin
|
||||
ns = ERR;
|
||||
clrTimer = 0;
|
||||
debounced = 0;
|
||||
|
||||
if (reset) ns = s0;
|
||||
else
|
||||
case (cs)
|
||||
s0: begin
|
||||
clrTimer = 1'b1;
|
||||
if (noisy) ns = s1;
|
||||
else ns = s0;
|
||||
end
|
||||
s1:
|
||||
if (noisy && timerDone) ns = s2;
|
||||
else if (noisy && ~timerDone) ns = s1;
|
||||
else ns = s0;
|
||||
s2: begin
|
||||
debounced = 1'b1;
|
||||
clrTimer = 1'b1;
|
||||
if (noisy) ns = s2;
|
||||
else ns = s3;
|
||||
end
|
||||
s3: begin
|
||||
debounced = 1'b1;
|
||||
if (~noisy && timerDone) ns = s0;
|
||||
else if (~noisy && ~timerDone) ns = s3;
|
||||
else ns = s2;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
always_ff @(posedge clk) cs <= ns;
|
||||
endmodule
|
|
@ -0,0 +1,67 @@
|
|||
`default_nettype none
|
||||
|
||||
module display_control (
|
||||
input wire logic clk,
|
||||
input wire logic reset,
|
||||
input wire logic [15:0] dataIn,
|
||||
input wire logic [ 3:0] digitDisplay,
|
||||
input wire logic [ 3:0] digitPoint,
|
||||
output logic [ 3:0] anode,
|
||||
output logic [ 7:0] segment
|
||||
);
|
||||
|
||||
parameter integer COUNT_BITS = 17;
|
||||
|
||||
logic [COUNT_BITS-1:0] count_val;
|
||||
logic [ 1:0] anode_select;
|
||||
logic [ 3:0] cur_anode;
|
||||
logic [ 3:0] cur_data_in;
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
if (reset) count_val <= 0;
|
||||
else count_val <= count_val + 1;
|
||||
end
|
||||
|
||||
assign anode_select = count_val[COUNT_BITS-1:COUNT_BITS-2];
|
||||
|
||||
assign cur_anode =
|
||||
(anode_select == 2'b00) ? 4'b1110 :
|
||||
(anode_select == 2'b01) ? 4'b1101 :
|
||||
(anode_select == 2'b10) ? 4'b1011 :
|
||||
4'b0111;
|
||||
|
||||
|
||||
assign anode = cur_anode | (~digitDisplay);
|
||||
|
||||
assign cur_data_in =
|
||||
(anode_select == 2'b00) ? dataIn[3:0] :
|
||||
(anode_select == 2'b01) ? dataIn[7:4] :
|
||||
(anode_select == 2'b10) ? dataIn[11:8] :
|
||||
dataIn[15:12] ;
|
||||
|
||||
assign segment[7] =
|
||||
(anode_select == 2'b00) ? ~digitPoint[0] :
|
||||
(anode_select == 2'b01) ? ~digitPoint[1] :
|
||||
(anode_select == 2'b10) ? ~digitPoint[2] :
|
||||
~digitPoint[3] ;
|
||||
|
||||
assign segment[6:0] =
|
||||
(cur_data_in == 0) ? 7'b1000000 :
|
||||
(cur_data_in == 1) ? 7'b1111001 :
|
||||
(cur_data_in == 2) ? 7'b0100100 :
|
||||
(cur_data_in == 3) ? 7'b0110000 :
|
||||
(cur_data_in == 4) ? 7'b0011001 :
|
||||
(cur_data_in == 5) ? 7'b0010010 :
|
||||
(cur_data_in == 6) ? 7'b0000010 :
|
||||
(cur_data_in == 7) ? 7'b1111000 :
|
||||
(cur_data_in == 8) ? 7'b0000000 :
|
||||
(cur_data_in == 9) ? 7'b0010000 :
|
||||
(cur_data_in == 10) ? 7'b0001000 :
|
||||
(cur_data_in == 11) ? 7'b0000011 :
|
||||
(cur_data_in == 12) ? 7'b1000110 :
|
||||
(cur_data_in == 13) ? 7'b0100001 :
|
||||
(cur_data_in == 14) ? 7'b0000110 :
|
||||
7'b0001110;
|
||||
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,28 @@
|
|||
`timescale 1ns / 1ps `default_nettype none
|
||||
|
||||
module timer #(
|
||||
parameter MOD_VALUE = 1,
|
||||
parameter BIT_WIDTH = 1
|
||||
) (
|
||||
input wire logic clk,
|
||||
reset,
|
||||
increment,
|
||||
output logic rolling_over,
|
||||
output logic [BIT_WIDTH-1:0] count = 0
|
||||
);
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
if (reset) count <= 0;
|
||||
else if (increment) begin
|
||||
if (rolling_over) count <= 0;
|
||||
else count <= count + 1'b1;
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
if (increment && (count == MOD_VALUE - 1)) rolling_over = 1'b1;
|
||||
else rolling_over = 1'b0;
|
||||
end
|
||||
|
||||
endmodule
|
Binary file not shown.
After Width: | Height: | Size: 14 MiB |
Loading…
Reference in New Issue