💾 Git Repository: https://github.com/RockPie/SZ_Firmware
The environment I'm using:
Xilinx Vivado also supports Linux
Using different version of Vivado may need reconfigure IP-cores.
This project uses two on-board LEDs and two buttons.
On the schematic diagrams page 7, the LEDs and the buttons are connected like:
The LEDs are active-high with CMOS standard. The buttons are active-low.
Further, on page 11, we can find the connection between these components and the FPGA:
Then we proceed to write it down in our constraint file.
The constraint file is the bridge between hardware and firmware. Here we use .xdc (xilinx design constraints) format to describe the connections.
The notation KEY1
, KEY2
on PCB correspond to sys_keys[0]
and sys_keys[1]
in the .xdc file (also LED1
-- sys_leds[0]
, and LED2
-- sys_leds[1]
)
set_property PACKAGE_PIN K21 [get_ports {sys_keys[0]}]
set_property PACKAGE_PIN J20 [get_ports {sys_keys[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sys_keys[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sys_keys[1]}]
set_property PACKAGE_PIN P20 [get_ports {sys_leds[0]}]
set_property PACKAGE_PIN P21 [get_ports {sys_leds[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sys_leds[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sys_leds[1]}]
For most signals, we must specify the corresponding IO standards and FPGA pin numbers in the constraint file. Usually the hardware won't change frequently, so we can reuse the constraints in other Smart ZYNQ projects. (Comment unused ones to avoid warnings)
Our purpose here is fair simple, which is controlling our LEDs by using our buttons. In this example, we are going to use combinational logic only.
LED1
will be directly wired to KEY1
. To warm ourselves up, LED2
will be controlled by the XOR result of KEY1
and KEY2
.
The verilog code is very simple. We could choose to use either always@(*)
block or assign
sentences (they funtion the same). Here is an example of the later method.
The core logic is:
assign sys_leds[0] = sys_keys[0];
assign sys_leds[1] = sys_keys[0] ^ sys_keys[1];
After adding the ports and forming a functional module, the code will be:
module leds_keys_top (
input wire[1:0] sys_keys,
output wire[1:0] sys_leds
);
// Core logic here
assign sys_leds[0] = sys_keys[0];
assign sys_leds[1] = sys_keys[0] ^ sys_keys[1];
// End of logic
endmodule
Figures of pushed buttons and blinking LEDs are boring. So here we look at the generated schematics.