The Zynqberry has been one of my favorite boards, and up to this point I feel like I've mostly just spent time updating my base designs for it to the latest version of Xilinx's IDEs before I get pulled away from it again. Luckily, this time my update to version 2019.2 was smooth enough that my little Zynqberry is ready to grow its own little garden of projects (sorry for the terrible pun, I couldn't resist).
My first thought naturally was how I could start porting over my previous Raspberry Pi projects since the Zynqberry was designed as a Raspberry Pi FPGA alternative. The base design for the Zynqberry that I created in my previous project here covers the hardware framework necessary to utilize all of the peripherals on the Zynqberry board. With an equivalent hardware design to the Raspberry Pi, this left the main differentiator being the embedded Linux image on the Zynqberry.
To get the OS on the Zynqberry to a more equivocal state to the common Raspberry Pi images such was Raspbian, installing Python and its features such as the package installer, pip, jumped out to me as the first step.
The Yocto framework that the PetaLinux environment is built from, contains bitbake recipes to allow for almost any standard Linux library to be included in a build.
To add a library to your build, add the line "CONFIG_<library name>" to the user-rootfsconfig file located in the <PetaLinux project path>/project-spec/meta-user/conf/ directory.
# System tools
CONFIG_gsl
CONFIG_nano
CONFIG_cmake
# Python3
CONFIG_python3
CONFIG_python3-pip
CONFIG_python3-cffi
CONFIG_python3-numpy
CONFIG_python3-shell
CONFIG_python3-pyserial
CONFIG_python3-threading
CONFIG_python3-multiprocessing
I chose to add Python3 packages since most of my Raspberry Pi projects are based on Adafruit's CircuitPython which depends on Python3. A few other common libraries/tools I noticed I used on my Raspberry Pi's were cmake (open source toolset for building and packaging software), GSL (GNU Scientific Library), and nano (text editor).
After adding the libraries to the projects, enable them in the image by running the configuration editor for the root filesystem:
petalinux-config -c rootfs
Then under User Packages, select each of the libraries and enable them using the 'Y' key.
Since package managers such as Python's pip will automatically work to resolve any missing dependencies when installing a specified package, an internet connection is needed. To enable the Ethernet port and make it available in the Linux user-space the kernel needs to be edited and the core recipe for the basic TCP/IP networking init scripts and configuration files needs for be created.
To edit the kernel, run the kernel configuration editor:
petalinux-config -c kernel
Configure the kernel with the following options:
CONFIG_MII=y
CONFIG_XILINX_GMII2RGMII=y
CONFIG_USB_USBNET=y
CONFIG_USB_NET_AX8817X=y
CONFIG_USB_NET_AX88179_178A=y
CONFIG_USB_NET_CDCETHER=y
# CONFIG_USB_NET_CDC_EEM is not set
CONFIG_USB_NET_CDC_NCM=y
# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set
# CONFIG_USB_NET_CDC_MBIM is not set
# CONFIG_USB_NET_DM9601 is not set
# CONFIG_USB_NET_SR9700 is not set
# CONFIG_USB_NET_SR9800 is not set
# CONFIG_USB_NET_SMSC75XX is not set
CONFIG_USB_NET_SMSC95XX=y
# CONFIG_USB_NET_GL620A is not set
CONFIG_USB_NET_NET1080=y
# CONFIG_USB_NET_PLUSB is not set
# CONFIG_USB_NET_MCS7830 is not set
# CONFIG_USB_NET_RNDIS_HOST is not set
CONFIG_USB_NET_CDC_SUBSET_ENABLE=y
CONFIG_USB_NET_CDC_SUBSET=y
# CONFIG_USB_ALI_M5632 is not set
# CONFIG_USB_AN2720 is not set
CONFIG_USB_BELKIN=y
CONFIG_USB_ARMLINUX=y
# CONFIG_USB_EPSON2888 is not set
# CONFIG_USB_KC2190 is not set
CONFIG_USB_NET_ZAURUS=y
# CONFIG_USB_NET_CX82310_ETH is not set
# CONFIG_USB_NET_KALMIA is not set
# CONFIG_USB_NET_QMI_WWAN is not set
# CONFIG_USB_NET_INT51X1 is not set
# CONFIG_USB_SIERRA_NET is not set
# CONFIG_USB_VL600 is not set
# CONFIG_USB_NET_CH9200 is not set
CONFIG_FB_SIMPLE=y
# CONFIG_FRAMEBUFFER_CONSOLE is not set
CONFIG_SND_SIMPLE_CARD_UTILS=y
CONFIG_SND_SIMPLE_CARD=y
CONFIG_USBIP_CORE=y
# CONFIG_USBIP_VHCI_HCD is not set
# CONFIG_USBIP_HOST is not set
# CONFIG_USBIP_VUDC is not set
# CONFIG_USBIP_DEBUG is not set
Create the directory for the core recipe of the basic TCP/IP networking init scripts and configuration files:
mkdir <PetaLinux project path>/project-spec/meta-user/recipes-core/init-ifupdown/init-ifupdown-1.0
Create the interfaces file,
cat ./interfaces
and add the following to it:
auto lo
iface lo inet loopback
## Static IP example
#auto eth0
#iface eth0 inet static
# address 192.168.1.190
# netmask 255.255.255.0
# network 192.168.1.0
# gateway 192.168.1.1
## DHCP Example
auto eth0
iface eth0 inet dhcp
Then create the bitbake file for the init-ifupdown package one directory up in <PetaLinux project path>/project-spec/meta-user/recipes-core/init-ifupdown titled init-ifupdown_1.0.bbappend and add the following line to it:
FILESEXTRAPATHS_prepend := "${THISDIR}/init-ifupdown-1.0:"
The kernel needs the hooks for the ethernet hardware specified to it via the device tree. Edit the user-configurable device tree source file, system-user.dtsi, in the <PetaLinux project path>/project-spec/meta-user/recipes-bsp/device-tree/files/ directory. The following is a mostly comprehensive device tree for all peripherals on the Zynqberry:
/include/ "system-conf.dtsi"
/ {
aliases{
eth0 = &usb0;
};
};
/ {
#address-cells = <1>;
#size-cells = <1>;
reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
ranges;
hdmi_fb_reserved_region@1FC00000 {
compatible = "removed-dma-pool";
no-map;
// 512M (M modules)
reg = <0x1FC00000 0x400000>;
// 128M (R modules)
//reg = <0x7C00000 0x400000>;
};
camera_fb_reserved_region@1FC00000 {
compatible = "removed-dma-pool";
no-map;
// 512M (M modules)
reg = <0x1FC00000 0x400000>;
// 128M (R modules)
//reg = <0x7800000 0x400000>;
};
};
hdmi_fb: framebuffer@0x1FC00000 { // HDMI out
compatible = "simple-framebuffer";
// 512M (M modules)
reg = <0x1FC00000 (1280 * 720 * 4)>; // 720p
// 128M (R modules)
//reg = <0x7C00000 (1280 * 720 * 4)>; // 720p
width = <1280>; // 720p
height = <720>; // 720p
stride = <(1280 * 4)>; // 720p
format = "a8b8g8r8";
status = "okay";
};
camera_fb: framebuffer@0x1FC00000 { // CAMERA in
compatible = "simple-framebuffer";
// 512M (M modules)
reg = <0x1FC00000 (1280 * 720 * 4)>; // 720p
// 128M (R modules)
//reg = <0x7800000 (1280 * 720 * 4)>; // 720p
width = <1280>; // 720p
height = <720>; // 720p
stride = <(1280 * 4)>; // 720p
format = "a8b8g8r8";
};
vcc_3V3: fixedregulator@0 {
compatible = "regulator-fixed";
regulator-name = "vccaux-supply";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
};
};
&qspi {
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
flash0: flash@0 {
compatible = "jedec,spi-nor";
reg = <0x0>;
#address-cells = <1>;
#size-cells = <1>;
spi-max-frequency = <50000000>;
partition@0x00000000 {
label = "boot";
reg = <0x00000000 0x00500000>;
};
partition@0x00500000 {
label = "bootenv";
reg = <0x00500000 0x00020000>;
};
partition@0x00520000 {
label = "kernel";
reg = <0x00520000 0x00a80000>;
};
partition@0x00fa0000 {
label = "spare";
reg = <0x00fa0000 0x00000000>;
};
};
};
/*
* We need to disable Linux VDMA driver as VDMA
* already configured in FSBL
*/
&video_in_axi_vdma_0 {
status = "disabled";
};
&video_out_axi_vdma_0 {
status = "disabled";
};
&video_out_v_tc_0 {
//xilinx-vtc: probe of 43c20000.v_tc failed with error -2
status = "disabled";
};
&gpio0 {
interrupt-controller;
#interrupt-cells = <2>;
};
&i2c1 {
#address-cells = <1>;
#size-cells = <0>;
i2cmux0: i2cmux@70 {
compatible = "nxp,pca9544";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x70>;
i2c1@0 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
id_eeprom@50 {
compatible = "atmel,24c32";
reg = <0x50>;
};
};
i2c1@1 { // Display Interface Connector
#address-cells = <1>;
#size-cells = <0>;
reg = <1>;
};
i2c1@2 { // HDMI Interface Connector
#address-cells = <1>;
#size-cells = <0>;
reg = <2>;
};
i2c1@3 { // Camera Interface Connector
#address-cells = <1>;
#size-cells = <0>;
reg = <3>;
};
};
};
/{
usb_phy0: usb_phy@0 {
compatible = "ulpi-phy";
#phy-cells = <0>;
reg = <0xe0002000 0x1000>;
view-port = <0x0170>;
drv-vbus;
};
};
&usb0 {
usb-phy = <&usb_phy0>;
};
/*
* Sound configuration
*/
/{
// Custom driver based on spdif-transmitter
te_audio: dummy_codec_te {
compatible = "te,te-audio";
#sound-dai-cells = <0>;
};
// Simple Audio Card from AXI_I2S and custom XADC audio input and
// PWM audio output cores
sound {
compatible = "simple-audio-card";
simple-audio-card,name = "TE0726-PWM-Audio";
simple-audio-card,format = "i2s";
simple-audio-card,widgets =
"Microphone", "In Jack",
"Line", "Line In Jack",
"Line", "Line Out Jack",
"Headphone", "Out Jack";
simple-audio-card,routing =
"Out Jack", "te-out",
"te-in", "In Jack";
simple-audio-card,cpu {
sound-dai = <&audio_axi_i2s_adi_0>;
};
simple-audio-card,codec {
sound-dai = <&te_audio>;
};
};
};
&audio_axi_i2s_adi_0 {
compatible = "adi,axi-i2s-1.00.a";
reg = <0x43c00000 0x1000>;
clocks = <&clkc 15>, <&clkc 18>; // FCLK_CLK0, FCLK_CLK3
clock-names = "axi", "ref";
dmas = <&dmac_s 0 &dmac_s 1>;
dma-names = "tx", "rx";
#sound-dai-cells = <0>;
};
/*
* We need to disable Linux XADC driver to use XADC for audio recording
*/
&adc {
status = "disabled";
};
The Zynq chip on the Zynqberry board doesn't have direct access to the ethernet port. The four USB ports and the ethernet port are actually connected to a USB PHY hub that is connected to the USB0 MIO port of the Zynq chip. This is why the ethernet device, eth0, is tied to the USB0 node in the device tree.
At this point, save and close all files then build the project.
petalinux-build
Package the boot image and program it onto the QSPI flash memory of the Zynqberry using Vitis. Then copy the kernel, device tree blob, and root filesystem to an SD card. (I've covered these steps already in my last Zynqberry project post here).
Boot up the Zynqberry and login with the default username 'root' and default password 'root' (unless you opted to change it in the system configuration editor). You can either plug the Zynqberry's ethernet port directly into your router, or use internet sharing from your PC. I opt for the later option since my router is not in a convent location to me to access for this purpose. I also switch back over to the Mac side for this part since Ubuntu is running in a virtual machine on my computer.
Via a USB-C to ethernet bridge adapter, I configure it as a mini router between the Zynqberry and my MacBook. I do this by giving the LAN bridge a different IP address on the same network and subnet mask as what I configured the interfaces file with on the Zynqberry.
Side note: do NOT add your router's gateway address to the LAN bridge configuration, this will conflict with your computer's connection with your router.
I then enabled Internet Sharing with the LAN bridge:
To test the initial connection between the MacBook and the Zynqberry, I opened a terminal window and ping the IP address assigned via DHCP by my router to the Zynqberry:
I then tested the internet connection by installing one of the basic Adafruit libraries:
pip3 install adafruit-blinka
Stay tuned for my next project covering how to install Adafruit's CircuitPython on the Zynqberry!
Comments