Even if Pmods are very practical interfaces to add low-speed expansions cards to FPGA boards, a majority of boards already provide a handful of other basic components such as debug LEDs, push buttons and switchs. In this section, we will see how to interface them using a very straightforward GPIO interface, and user-friendly Vivado pin specification.
The PYNQ-Z2 boards has 4 PL-accessible buttons, next to the SDCard port: we will connect them using a AXI to GPIO controller, and map them to keyboard keys.
The steps are similar to the other peripherals, except that the controller is a “AXI GPIO”, customized it to be single channel, 4-bit, input only. It has also to be wired to the northbridge block on the AXI side.
Map the AXI GPIO controller to address 0x40000000, 64k mapped segment. Note that there is nothing preventing this to be changed, so feel free to put any address you want, as long at is does not overlap with an existing segment.
As the buttons are directly present on the board, we can use a GUI shortcut to connect them to the GPIO controller. Drag the “4 Buttons” entry on the “Board” tab (top-left pane) and connect it to the “AXI GPIO” block.
As we used board interfaces directly from the block design, constraints were automatically inserted. You simply have to run synthesis and flash the bitstream. Yippee!
Here is the documentation of the corresponding device tree nodes for buttons, and here for the GPIO controller.
...
buttonkeys {
compatible = "gpio-keys";
gpio-key0 {
gpios = <&xlnx_gpio 0 0>;
linux,code = <105>; // KEY_LEFT
};
gpio-key1 {
gpios = <&xlnx_gpio 1 0>;
linux,code = <106>; // KEY_RIGHT
};
gpio-key2 {
gpios = <&xlnx_gpio 2 0>;
linux,code = <108>; // KEY_DOWN
};
gpio-key3 {
gpios = <&xlnx_gpio 3 0>;
linux,code = <103>; // KEY_UP
};
};
...
L26: soc {
...
xlnx_gpio: gpio@40000000 {
#gpio-cells = <2>;
compatible = "xlnx,xps-gpio-1.00.a";
gpio-controller;
reg = <0x0 0x40000000 0x0 0x10000>;
xlnx,all-inputs = <0x1>;
xlnx,all-outputs = <0x0>;
xlnx,dout-default = <0x0>;
xlnx,gpio-width = <0x4>;
xlnx,interrupt-present = <0x0>;
xlnx,is-dual = <0x0>;
xlnx,tri-default = <0xffffffff>;
};
...
};
LEDs are piloted using the same GPIO interface than buttons. Here, we will have them blinking once booted. Repeat the same steps and chose an other address for the controller.
Here is the documentation of the corresponding device tree nodes of GPIO leds.. Remember to set <ADDRESS>
to your controller’s address!
leds {
compatible = "gpio-leds";
heartbeat-led0 {
gpios = <&xlnx_gpio 0 0>;
linux,default-trigger = "heartbeat";
retain-state-suspended;
};
heartbeat-led1 {
gpios = <&xlnx_gpio 1 0>;
linux,default-trigger = "heartbeat";
retain-state-suspended;
};
heartbeat-led2 {
gpios = <&xlnx_gpio 2 0>;
linux,default-trigger = "heartbeat";
retain-state-suspended;
};
heartbeat-led3 {
gpios = <&xlnx_gpio 3 0>;
linux,default-trigger = "heartbeat";
retain-state-suspended;
};
};
...
L26: soc {
...
xlnx_gpio: gpio@<ADDRESS> {
#gpio-cells = <2>;
compatible = "xlnx,xps-gpio-1.00.a";
gpio-controller;
reg = <0x0 <ADDRESS> 0x0 0x10000>;
xlnx,all-inputs = <0x0>;
xlnx,all-outputs = <0x1>;
xlnx,dout-default = <0x0>;
xlnx,gpio-width = <0x4>;
xlnx,interrupt-present = <0x0>;
xlnx,is-dual = <0x0>;
xlnx,tri-default = <0xffffffff>;
};
...
};