Merge pull request #166 from WhiteNinjaZ/watch-pwm
Timer and Pulse Width modulation examples
This commit is contained in:
commit
07a6353627
|
@ -47,7 +47,7 @@ shift
|
|||
|
||||
examples="$@"
|
||||
if [ "$fpga_family" == "xc7" -a -z "$examples" ]; then
|
||||
examples="counter picosoc litex litex_linux button_controller"
|
||||
examples="counter picosoc litex litex_linux button_controller timer pulse_width_led"
|
||||
elif [ "$fpga_family" == "eos-s3" -a -z "$examples" ]; then
|
||||
examples="counter"
|
||||
fi
|
||||
|
@ -78,6 +78,12 @@ if [ "$fpga_family" = "xc7" ]; then
|
|||
"button_controller")
|
||||
snippets="${additionalDesigns} xc7/additional_examples/button_controller/README.rst:example-debouncer-basys3"
|
||||
;;
|
||||
"pulse_width_led")
|
||||
snippets="${snippets} xc7/pulse_width_led/README.rst:example-pulse-arty-35t"
|
||||
;;
|
||||
"timer")
|
||||
snippets="${snippets} xc7/timer/README.rst:example-watch-basys3"
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: Unknown example name: $example" >&2
|
||||
exit 1
|
||||
|
|
|
@ -66,6 +66,24 @@ jobs:
|
|||
- {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"}
|
||||
|
||||
- {fpga-fam: "xc7", os: "ubuntu", os-version: "xenial", example: "pulse_width_led"}
|
||||
- {fpga-fam: "xc7", os: "ubuntu", os-version: "bionic", example: "pulse_width_led"}
|
||||
- {fpga-fam: "xc7", os: "ubuntu", os-version: "focal", example: "pulse_width_led"}
|
||||
- {fpga-fam: "xc7", os: "centos", os-version: "7", example: "pulse_width_led"}
|
||||
- {fpga-fam: "xc7", os: "centos", os-version: "8", example: "pulse_width_led"}
|
||||
- {fpga-fam: "xc7", os: "debian", os-version: "buster", example: "pulse_width_led"}
|
||||
- {fpga-fam: "xc7", os: "debian", os-version: "bullseye", example: "pulse_width_led"}
|
||||
- {fpga-fam: "xc7", os: "debian", os-version: "sid", example: "pulse_width_led"}
|
||||
|
||||
- {fpga-fam: "xc7", os: "ubuntu", os-version: "xenial", example: "timer"}
|
||||
- {fpga-fam: "xc7", os: "ubuntu", os-version: "bionic", example: "timer"}
|
||||
- {fpga-fam: "xc7", os: "ubuntu", os-version: "focal", example: "timer"}
|
||||
- {fpga-fam: "xc7", os: "centos", os-version: "7", example: "timer"}
|
||||
- {fpga-fam: "xc7", os: "centos", os-version: "8", example: "timer"}
|
||||
- {fpga-fam: "xc7", os: "debian", os-version: "buster", example: "timer"}
|
||||
- {fpga-fam: "xc7", os: "debian", os-version: "bullseye", example: "timer"}
|
||||
- {fpga-fam: "xc7", os: "debian", os-version: "sid", example: "timer"}
|
||||
|
||||
env:
|
||||
LANG: "en_US.UTF-8"
|
||||
|
|
|
@ -91,6 +91,14 @@ Enter the directory that contains examples for Xilinx 7-Series FPGAs:
|
|||
.. jinja:: xc7_linux_litex_demo
|
||||
:file: templates/example.jinja
|
||||
|
||||
.. jinja:: xc7_timer
|
||||
:file: templates/example.jinja
|
||||
|
||||
.. jinja:: xc7_pulse_width_led
|
||||
:file: templates/example.jinja
|
||||
|
||||
|
||||
|
||||
Additional Examples
|
||||
-------------------
|
||||
|
||||
|
@ -102,6 +110,7 @@ for the basys3 board in the additional_examples directory:
|
|||
|
||||
cd additional_examples
|
||||
|
||||
|
||||
QuickLogic EOS S3
|
||||
-----------------
|
||||
|
||||
|
|
|
@ -63,4 +63,4 @@ ${BOARD_BUILDDIR}/${TOP}.bit: ${BOARD_BUILDDIR}/${TOP}.fasm
|
|||
cd ${BOARD_BUILDDIR} && symbiflow_write_bitstream -d ${BITSTREAM_DEVICE} -f ${TOP}.fasm -p ${PARTNAME} -b ${TOP}.bit
|
||||
|
||||
clean:
|
||||
rm -rf ${BUILDDIR}
|
||||
rm -rf ${BUILDDIR}
|
|
@ -30,7 +30,6 @@ module display_control (
|
|||
(anode_select == 2'b10) ? 4'b1011 :
|
||||
4'b0111;
|
||||
|
||||
|
||||
assign anode = cur_anode | (~digitDisplay);
|
||||
|
||||
assign cur_data_in =
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
current_dir := ${CURDIR}
|
||||
TARGET := arty_35
|
||||
TOP := top
|
||||
SOURCES := ${current_dir}/PWM.v
|
||||
SOURCES += ${current_dir}/pulse_led.v
|
||||
|
||||
XDC := ${current_dir}/arty_35.xdc
|
||||
|
||||
include ${current_dir}/../../common/Makefile
|
|
@ -0,0 +1,14 @@
|
|||
module PWM (
|
||||
input wire clk,
|
||||
input wire [13:0] width,
|
||||
output reg pulse
|
||||
);
|
||||
|
||||
reg [13:0] counter = 0;
|
||||
|
||||
always @(posedge clk) begin
|
||||
counter <= counter + 1;
|
||||
if (counter < width) pulse <= 1'b1;
|
||||
else pulse <= 1'b0;
|
||||
end
|
||||
endmodule
|
|
@ -0,0 +1,36 @@
|
|||
Pulse Width
|
||||
~~~~~~~~~~~~
|
||||
|
||||
|
||||
This example is built specificity for the arty_35T. It demonstrates a greater variety of I/O and
|
||||
a PWM that drives the RGB leds on the board. To build this example run the following
|
||||
commands:
|
||||
|
||||
.. code-block:: bash
|
||||
:name: example-pulse-arty-35t
|
||||
|
||||
make -C pulse_width_led
|
||||
|
||||
|
||||
At completion, the bitstreams are located in the build directory:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd pulse_width_led/build/arty_35
|
||||
|
||||
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"
|
||||
|
||||
After downloading the bitstream, you can experiment with and mix different amounts of red, green, and
|
||||
blue on RGB led 0 by toggling different switches and buttons on and off. From left to right:
|
||||
switches 3, 2, 1 control the intensity of blue, switch 0 and buttons 3 and 2 control the intensity of
|
||||
red, and buttons 1 and 0 control the intensity of green. The following provides an example:
|
||||
|
||||
.. image:: ../../docs/images/pwm.gif
|
||||
:align: center
|
||||
:width: 50%
|
||||
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
|
||||
# Clock signal
|
||||
set_property PACKAGE_PIN E3 [get_ports { clk }];
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports { clk }];
|
||||
|
||||
# Switches
|
||||
set_property -dict { PACKAGE_PIN A8 IOSTANDARD LVCMOS33 } [get_ports { sw[0] }];
|
||||
set_property -dict { PACKAGE_PIN C11 IOSTANDARD LVCMOS33 } [get_ports { sw[1] }];
|
||||
set_property -dict { PACKAGE_PIN C10 IOSTANDARD LVCMOS33 } [get_ports { sw[2] }];
|
||||
set_property -dict { PACKAGE_PIN A10 IOSTANDARD LVCMOS33 } [get_ports { sw[3] }];
|
||||
|
||||
|
||||
# RGB LEDs
|
||||
set_property -dict { PACKAGE_PIN E1 IOSTANDARD LVCMOS33 } [get_ports { pulse_blue }];
|
||||
set_property -dict { PACKAGE_PIN F6 IOSTANDARD LVCMOS33 } [get_ports { pulse_green }];
|
||||
set_property -dict { PACKAGE_PIN G6 IOSTANDARD LVCMOS33 } [get_ports { pulse_red }];
|
||||
|
||||
# Buttons
|
||||
set_property -dict { PACKAGE_PIN D9 IOSTANDARD LVCMOS33 } [get_ports { btn[0] }];
|
||||
set_property -dict { PACKAGE_PIN C9 IOSTANDARD LVCMOS33 } [get_ports { btn[1] }];
|
||||
set_property -dict { PACKAGE_PIN B9 IOSTANDARD LVCMOS33 } [get_ports { btn[2] }];
|
||||
set_property -dict { PACKAGE_PIN B8 IOSTANDARD LVCMOS33 } [get_ports { btn[3] }];
|
||||
|
||||
|
||||
# CLK constraint
|
||||
create_clock -period 10.0 [get_ports {clk}]
|
|
@ -0,0 +1,32 @@
|
|||
module top (
|
||||
input wire clk,
|
||||
input wire [3:0] sw,
|
||||
input wire [3:0] btn,
|
||||
output wire pulse_red,
|
||||
pulse_blue,
|
||||
pulse_green
|
||||
);
|
||||
wire [13:0] pulse_wideR, pulse_wideB, pulse_wideG;
|
||||
|
||||
assign pulse_wideR = {1'b0, sw[3:1], 10'd0};
|
||||
assign pulse_wideG = {1'b0, sw[0], btn[3:2], 10'd0};
|
||||
assign pulse_wideB = {btn[1:0], 11'd0};
|
||||
|
||||
PWM R0 (
|
||||
.clk (clk),
|
||||
.pulse(pulse_red),
|
||||
.width(pulse_wideR)
|
||||
);
|
||||
PWM B0 (
|
||||
.clk (clk),
|
||||
.pulse(pulse_green),
|
||||
.width(pulse_wideB)
|
||||
);
|
||||
PWM G0 (
|
||||
.clk (clk),
|
||||
.pulse(pulse_blue),
|
||||
.width(pulse_wideG)
|
||||
);
|
||||
|
||||
|
||||
endmodule
|
|
@ -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,31 @@
|
|||
Timer
|
||||
~~~~~~
|
||||
|
||||
This example is built specifically for the basys3 and demonstrates a greater variety of I/O
|
||||
then previous designs. It also demonstrates symbiflow's support for code written in System Verilog
|
||||
as well as its support of dictionaries in XDCs. To build this example run the following commands:
|
||||
|
||||
.. code-block:: bash
|
||||
:name: example-watch-basys3
|
||||
|
||||
make -C timer
|
||||
|
||||
|
||||
At completion, the bitstream is located in the build directory:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd timer/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"
|
||||
|
||||
After downloading the bitstream you can start and stop the watch by toggling switch 0 on the board.
|
||||
Press the center button to reset the counter. The following gives a visual example:
|
||||
|
||||
.. image:: ../../docs/images/timer.gif
|
||||
:align: center
|
||||
:width: 50%
|
|
@ -0,0 +1,26 @@
|
|||
|
||||
# Clock
|
||||
set_property -dict { PACKAGE_PIN W5 IOSTANDARD LVCMOS33 } [get_ports { clk }];
|
||||
create_clock -period 10.00 [get_ports {clk}];
|
||||
|
||||
# Buttons
|
||||
set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { btnc }];
|
||||
|
||||
|
||||
# Switches
|
||||
set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { sw }];
|
||||
|
||||
|
||||
# Seven Segment Display
|
||||
set_property -dict { PACKAGE_PIN W7 IOSTANDARD LVCMOS33 } [get_ports { segment[0] }];
|
||||
set_property -dict { PACKAGE_PIN W6 IOSTANDARD LVCMOS33 } [get_ports { segment[1] }];
|
||||
set_property -dict { PACKAGE_PIN U8 IOSTANDARD LVCMOS33 } [get_ports { segment[2] }];
|
||||
set_property -dict { PACKAGE_PIN V8 IOSTANDARD LVCMOS33 } [get_ports { segment[3] }];
|
||||
set_property -dict { PACKAGE_PIN U5 IOSTANDARD LVCMOS33 } [get_ports { segment[4] }];
|
||||
set_property -dict { PACKAGE_PIN V5 IOSTANDARD LVCMOS33 } [get_ports { segment[5] }];
|
||||
set_property -dict { PACKAGE_PIN U7 IOSTANDARD LVCMOS33 } [get_ports { segment[6] }];
|
||||
set_property -dict { PACKAGE_PIN V7 IOSTANDARD LVCMOS33 } [get_ports { segment[7] }];
|
||||
set_property -dict { PACKAGE_PIN U2 IOSTANDARD LVCMOS33 } [get_ports { anode[0] }];
|
||||
set_property -dict { PACKAGE_PIN U4 IOSTANDARD LVCMOS33 } [get_ports { anode[1] }];
|
||||
set_property -dict { PACKAGE_PIN V4 IOSTANDARD LVCMOS33 } [get_ports { anode[2] }];
|
||||
set_property -dict { PACKAGE_PIN W4 IOSTANDARD LVCMOS33 } [get_ports { anode[3] }];
|
|
@ -0,0 +1,31 @@
|
|||
`timescale 1ns / 1ps `default_nettype none
|
||||
|
||||
module top (
|
||||
input wire logic clk,
|
||||
btnc,
|
||||
sw,
|
||||
output logic [3:0] anode,
|
||||
output logic [7:0] segment
|
||||
);
|
||||
|
||||
logic [15:0] digitData;
|
||||
|
||||
timer TC0 (
|
||||
.clk(clk),
|
||||
.reset(btnc),
|
||||
.run(sw),
|
||||
.digit0(digitData[3:0]),
|
||||
.digit1(digitData[7:4]),
|
||||
.digit2(digitData[11:8]),
|
||||
.digit3(digitData[15:12])
|
||||
);
|
||||
display_control SSC0 (
|
||||
.clk(clk),
|
||||
.reset(btnc),
|
||||
.dataIn(digitData),
|
||||
.digitDisplay(4'b1111),
|
||||
.digitPoint(4'b0100),
|
||||
.anode(anode),
|
||||
.segment(segment)
|
||||
);
|
||||
endmodule
|
|
@ -0,0 +1,68 @@
|
|||
`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,26 @@
|
|||
`default_nettype none
|
||||
|
||||
module modify_count #(
|
||||
parameter MOD_VALUE = 10
|
||||
) (
|
||||
input wire logic clk,
|
||||
reset,
|
||||
increment,
|
||||
output logic rolling_over,
|
||||
output logic [3:0] count = 0
|
||||
);
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
if (reset) count <= 4'b0000;
|
||||
else if (increment) begin
|
||||
if (rolling_over) count <= 4'b0000;
|
||||
else count <= count + 4'b0001;
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
if (increment && (count == MOD_VALUE - 1)) rolling_over = 1'b1;
|
||||
else rolling_over = 1'b0;
|
||||
end
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,27 @@
|
|||
`timescale 1ns / 1ps `default_nettype none
|
||||
|
||||
module time_counter #(
|
||||
parameter MOD_VALUE = 1000000
|
||||
) (
|
||||
input wire logic clk,
|
||||
reset,
|
||||
increment,
|
||||
output logic rolling_over,
|
||||
output logic [23: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
|
|
@ -0,0 +1,63 @@
|
|||
`timescale 1ns / 1ps `default_nettype none
|
||||
|
||||
module timer (
|
||||
input wire logic clk,
|
||||
reset,
|
||||
run,
|
||||
output logic [3:0] digit0,
|
||||
digit1,
|
||||
digit2,
|
||||
digit3
|
||||
);
|
||||
|
||||
logic inc0, inc1, inc2, inc3, inc4;
|
||||
|
||||
logic [23:0] timerCount;
|
||||
|
||||
modify_count #(
|
||||
.MOD_VALUE(10)
|
||||
) M0 (
|
||||
.clk(clk),
|
||||
.reset(reset),
|
||||
.increment(inc0),
|
||||
.rolling_over(inc1),
|
||||
.count(digit0)
|
||||
);
|
||||
modify_count #(
|
||||
.MOD_VALUE(10)
|
||||
) M1 (
|
||||
.clk(clk),
|
||||
.reset(reset),
|
||||
.increment(inc1),
|
||||
.rolling_over(inc2),
|
||||
.count(digit1)
|
||||
);
|
||||
modify_count #(
|
||||
.MOD_VALUE(10)
|
||||
) M2 (
|
||||
.clk(clk),
|
||||
.reset(reset),
|
||||
.increment(inc2),
|
||||
.rolling_over(inc3),
|
||||
.count(digit2)
|
||||
);
|
||||
modify_count #(
|
||||
.MOD_VALUE(6)
|
||||
) M3 (
|
||||
.clk(clk),
|
||||
.reset(reset),
|
||||
.increment(inc3),
|
||||
.rolling_over(inc4),
|
||||
.count(digit3)
|
||||
);
|
||||
|
||||
time_counter #(
|
||||
.MOD_VALUE(1000000)
|
||||
) T0 (
|
||||
.clk(clk),
|
||||
.reset(reset),
|
||||
.increment(run),
|
||||
.rolling_over(inc0),
|
||||
.count(timerCount)
|
||||
);
|
||||
endmodule
|
Loading…
Reference in New Issue