$customHeader
Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 22 Next »

In this simple tutorial we will discuss how to build a Linux image in Petalinux 2018.3, from the BSP, or from scratch using the HDF file that is export from Vivado IP Integrator. The wiki will also discuss key points such as the

on board clocks and these can be programmed via Linux script or via a C application on the A53, that the user can program these to suit their own design needs. The wiki will also discuss the various debug options available to enable the user to fully debug any application targeting the RFDC IP driver.

Building the Linux Image:

Using BSP:

petalinux build bsp
petalinux-create -t project -s <path to BSP>
cd <plnx proj dir>
petalinux-config -c rootfs
	base -> [*] i2c-tools
petalinux-build --sdk
petalinux-package --sysroot

Using zynqMP template:

petalinux build hdf
petalinux-create -t project --template zynqMP -n rfdc_linux
cd rfdc_linux
petalinux-config --get-hw-description=<path to HDF> 
	DTG Settings -> (zcu111-reva) MACHINE_NAME
	Open rfdc_linux\project-spec\meta-user\recipes-core\images\petalinux-image-full.bbappend 
	IMAGE_INSTALL_append = " rfdc"
	IMAGE_INSTALL_append = " rfdc-read-write"
	IMAGE_INSTALL_append = " rfdc-selftest"
petalinux-config -c rootfs
	base -> [*] i2c-tools 
	user packages -> 
		[*] rfdc
		[*] rfdc-read-write
		[*] rfdc-selftest
Add the rfdc-examples folder to project-spec/meta-user/recipes-bsp
Create the rfdc-selftest_%.bbappend and add the content shown below here:
do_compile (){
    make all BOARD_FLAG=-DXPS_BOARD_ZCU111 OUTS=rfdc-selftest RFDC_OBJS=xrfdc_selftest_example.o
}
petalinux-config 
	Yocto Settings -> 
	(zcu111-zynqmp) YOCTO MACHINE NAME
petalinux-build
petalinux-package --boot --fpga system.bit --u-boot
petalinux-build --sdk
petalinux-package --sysroot

petalinux-build --sdk

This steps can take along time ~ 40 mins to complete


The RFDC driver is delivered as a shared object in Linux. The makefile can be seen here and below:

rfdc makefile
APP = rfdc

LIBSOURCES=*.c
OUTS = *.o
NAME := rfdc
MAJOR = 1
MINOR = 1
VERSION = $(MAJOR).$(MINOR)

all: lib$(NAME).so

lib$(NAME).so.$(VERSION): $(OUTS)
	$(CC) $(LDFLAGS) $(OUTS) -shared -Wl,-soname,lib$(NAME).so.$(MAJOR) -o lib$(NAME).so.$(VERSION) -lmetal

lib$(NAME).so: lib$(NAME).so.$(VERSION)
	rm -f lib$(NAME).so.$(MAJOR) lib$(NAME).so
	ln -s lib$(NAME).so.$(VERSION) lib$(NAME).so.$(MAJOR)
	ln -s lib$(NAME).so.$(MAJOR) lib$(NAME).so

%.o: %.c
	$(CC) $(CFLAGS) -c -fPIC $(LIBSOURCES)

clean:
	rm -rf *.o *.so *.so.*

So, this .so is built and delivered in the /usr folder in the root file system. The recipe can be seen here:

rfdc recipe
SUMMARY = "rfdc Library"
SECTION = "rfdc"
LICENSE = "BSD"
LIC_FILES_CHKSUM = "file://${WORKDIR}/git/license.txt;md5=71602ce1bc2917a9be07ceee6fab6711"

inherit pkgconfig

REPO ??= "git://github.com/Xilinx/embeddedsw.git;protocol=https"
BRANCH ??= "release-2018.3"
SRCREV ??= "56f3da2afbc817988c9a45b0b26a7fef2ac91706"
BRANCHARG = "${@['nobranch=1', 'branch=${BRANCH}'][d.getVar('BRANCH', True) != '']}"

COMPATIBLE_MACHINE = "^$"
COMPATIBLE_MACHINE_zynqmpdr = "zynqmpdr"

FILESEXTRAPATHS_prepend := "${THISDIR}/files:"

SRC_URI = " \
	${REPO};${BRANCHARG} \
	"

S = "${WORKDIR}/git/XilinxProcessorIPLib/drivers/rfdc/src/"

PACKAGE_ARCH = "${SOC_FAMILY}${SOC_VARIANT}"

DEPENDS = "libmetal"

PROVIDES = "rfdc"

do_configure() {
    cp ${S}/Makefile.Linux ${S}/Makefile
}

do_install() {
    install -d ${D}${libdir}
    install -d ${D}${includedir}
    oe_libinstall -so librfdc ${D}${libdir}
    install -m 0644 ${S}/xrfdc_hw.h ${D}${includedir}/xrfdc_hw.h
    install -m 0644 ${S}/xrfdc.h ${D}${includedir}/xrfdc.h
    install -m 0644 ${S}/xrfdc_mts.h ${D}${includedir}/xrfdc_mts.h
}

FILES_${PN} = "${libdir}/*.so.*"
FILES_${PN}-dev = "${libdir}/*.so  ${includedir}/*"

We can see this .SO added to the sysroots created above:

These will also be in the respective folder in the rootfs when you boot Linux.

Creating Linux Application in SDK:

The SDK 2018.3 can be used to create the Linux application

File → New → Application Project

sysroots

Point to the Linux System Root that was created using the petalinux-build --sdk step above

Finish, to continue

Right Click on the application in Project Explorer and select the C/C+ Build Settings:

Add the path to the sysroot path to the linker flags:

Add the libraries (highlighted):

If using the ZCU111, then there is code to program the clocks on the board:

As seen above, there is a pre-compiler ifdef. This can be added as a symbol in the C/C++ Build settings too:


In this demo, I will be using the rfdc_selftest that is delivered with the driver. However, the full API suite for the RFDC can be found here.

To add the code, right click on the src folder in Project explorer and select Import:

General → File System:

Browse to your source code and select Finish:

ZCU111 Board Clocks Topology:

The clocking structure on the ZCU111 can be seen on page 54 here. The Clock sources; LMK04208 and LMX2594 are accessible via the I2CSPI over the IC21 bus:

The device-tree node for this can be seen here:

devicetree
i2c@5 {
	#address-cells = <1>;
	#size-cells = <0>;
	reg = <5>;
	sc18is603@2f { /* sc18is602 - u93 */
		compatible = "nxp,sc18is603";
		reg = <0x2f>;
		/* 4 gpios for CS not handled by driver */
		/*
		* USB2ANY cable or
		* LMK04208 - u90 or
		* LMX2594 - u102 or
		* LMX2594 - u103 or
		* LMX2594 - u104
		*/
	};
};

As shown in the sc18is603 device node, there are 4 CS for each clock source:

  1. LE_2494_A (LMX RF1 PLL)  = 0x8
  2. LE_2594_B (LMX RF2 PLL)  = 0x4
  3. LE_4208 (LMK)                      = 0x2
  4. LE_2594_C (LMX RF3 PLL)  = 0x1


ZCU111 Board Clocks Programming:

There is source code provided in the RFDC driver example; xrfdc_clk.c and xrfdc_clk.h (used above) that contain pre-written configure sequence from TI TICS PRO utility,

that is used to program the clock sources on the ZCU111. Users can also use the i2c-tools utility in Linux to program these clocks. Both flows are discussed below

LMK04208:

This is the low noise jitter cleaner that feds the LMK2594. The LMX2594 is programmed using 24-bit shift registers. The shift register consists of a R/W bit (MSB), followed

by a 7-bit address field and a 16-bit data field. For the R/W bit, 0 is for write, and 1 is for read. The address field

ADDRESS[6:0] is used to decode the internal register address. The remaining 16 bits form the data field DATA[15:0].

LMX2594:

The LMX is programmed using 24 bit shift register. This is the clock provides the clock to the tiles on the RFDC:

LMK04208 C Code Programming:

The LMK04208 can be programmed via a C code application delivered with the RFDC driver, the code snippet is shown below.

LMK04208
#ifdef XPS_BOARD_ZCU111
unsigned int LMK04208_CKin[1][26] = {
  {0x00160040,0x80140320,0x80140321,0x80140322,
  0xC0140023,0x40140024,0x80141E05,0x03300006,0x01300007,0x06010008,
  0x55555549,0x9102410A,0x0401100B,0x1B0C006C,0x2302886D,0x0200000E,
  0x8000800F,0xC1550410,0x00000058,0x02C9C419,0x8FA8001A,0x10001E1B,
  0x0021201C,0x0180033D,0x0200033E,0x003F001F }};
#endif
LMX2594 C Code programming:

The LMK04208 can be programmed via a C code application delivered with the RFDC driver, the code snippet is shown below.

There are pre-configured sequences in the code that will allow the user to use one any of the frequencies below:

clock
5120000 3932160 1474560 4915200 6553600 6400000 6389760 6144000 5898240 5734400 4000000 4096000 4423680
4669440 1966080 2048000 2457600 2949120 3072000 3276800 245760 3686400 204800 409600 491520 737280 7340032

These two functions can be called in the user application as shown below:

prog clock
LMK04208ClockConfig(12, LMK04208_CKin);
LMX2594ClockConfig(12, 3932160);

ZCU111 BOARD

If using the rfdc example code, then the user will need to set the #define XPS_BOARD_ZCU111.

This can be passed as a symbol in C/C++ Build Settings in SDK (see above)

Or, via the (zcu111-zynqmp) YOCTO MACHINE NAME in Petalinux/Yocto

Using i2c-tools to program the LMK and LMX devices:

Users can use the i2cdetect utility to read all the devices on the I2C bus. For example:

Here, the driver will “hop” through each mux to show all possible devices in the i2c bus topology.

In order to program the LMK or LMX devices on the ZCU111, users will need to find the SCI18IS60C device on the I2C bus.

To do this, users can do a i2cdetect -y -r busaddr

Where the busaddr would be 0 to 22 in this case (as per the i2cdetect -l command above).

Users can do a grep on the result to see if the 0x2f (as we seen form the device node above is the SCI18IS60C device).

If the i2c bus topology isnt likely to change, then we can just hard-code this address into the script command.

However, if the bus topology is likely to change, ie add remove i2c from PS or AXI I2C in the PL, then user can script around this to dynamically find the SCI18IS60C device

For example, the function below will search through all possible bus addresses, and do a grep until it finds the expected device ID (0x2f):

findsci18is602
fFindSCI18IS602 () {
   printf "Scanning for SCI18IS602... "
   for (( ii=0; ii<30; ii++ )); do
      #ls -l /dev/i2c* | grep i2c-${ii} > /dev/null
      #if [ $? -eq 0 ]; then
      if [ -e /dev/i2c-${ii} ]; then
         # Check for SCI18IS602
         #echo "i2c-${ii} bus:"
         i2cdetect -y -r ${ii} | grep -i $vSCI18IS602Addr > /dev/null
         if [ $? -eq 0 ]; then
            vSCI18IS602Bus=${ii}
            vSCI18IS602Addr="0x${vSCI18IS602Addr}"
            echo "Detected SCI18IS602 at bus=${vSCI18IS602Bus}, address=${vSCI18IS602Addr}."
            vSCI18IS602Found=1
         fi
      fi
   done
   if [ $vSCI18IS602Found -eq 0 ]; then
      echo "Warning: SCI18IS602 device not found!"
   fi
}


Now, that the bus address for the SCI18IS602 device is found. we can access the various clocks by passing the CS. The various CS can be seen below:

  1. LE_2494_A (LMX RF1 PLL)  = 0x8
  2. LE_2594_B (LMX RF2 PLL)  = 0x4
  3. LE_4208 (LMK)                      = 0x2
  4. LE_2594_C (LMX RF3 PLL)  = 0x1

To target the LMK, then the i2cset command would look like:

i2cset_lmk
i2cset -y 12 0x2f 0x2 <32 bit data> i

To target the LMX, then the i2cset command would look like:

i2cset_lmx
i2cset -y 12 0x2f 0x1 <24 bit data> i
i2cset -y 12 0x2f 0x4 <24 bit data> i
i2cset -y 12 0x2f 0x8 <24 bit data> i


The data can be created using the TICS Pro tool from TI. This script can be passed to the Petalinux project as shown below:

bootscript
petalinux-create --type apps --template install --name bootscript –enable

update the project-spec\meta-user\recipes-apps\bootscript\bootscript.bb:

bootscript.bb
#
# This file is the bootscript recipe.
#
 
SUMMARY = "Simple bootscript application"
SECTION = "PETALINUX/apps"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
 
SRC_URI = "file://bootscript \
    "
 
S = "${WORKDIR}"
 
inherit update-rc.d
 
INITSCRIPT_NAME = "bootscript"
INITSCRIPT_PARAMS = "start 99 S ."
 
do_install() {
        install -d ${D}${sysconfdir}/init.d
        install -m 0755 ${S}/bootscript ${D}${sysconfdir}/init.d/bootscript
}
FILES_${PN} += "${sysconfdir}/*"

Then update the project-spec\meta-user\recipes-apps\bootscript\files\bootscript with the i2cset commands (also attached below):

script

The script here is only provided for reference purpose only, and has not been fully tested!


This script should be auto-ran upon boot:

Debugging Linux Application on ZCU111:

Set up the LAN between your board and you PC:

Make sure you can ping your PC from the Linux console.

firewall

You may need to disable your firewall on your PC

Set up the Target Connection:

Drop down the Linux TCF Agent → Linux Agent

Select Add new target connection icon:

Next, right click on your application in Project explorer, and select Debug As → Debug Configurations:

Double Click on Xilinx C/C++ application (System Debugger)

Select Debug to launch the debug perspective.

Creating Linux Application in Petalinux:

Once the user is satisfied that everything works correct, then they can create a Linux Application in Petalinux:

create petalinux app
petalinux-create --type apps --name rfdc-test --enable

Open the makefile at project-spec/meta-user/recipes-apps/rfdc-test/files and make the changes below:

rfdc makefile
APP = rfdc-test
 
# Add any other object files to this list below
APP_OBJS = xrfdc_selftest_example.o
APP_OBJS += xrfdc_clk.o
 
LDLIBS += -lmetal
LDLIBS += -lrfdc

 
all: $(APP)
 
 
$(APP): $(APP_OBJS)
    $(CC) $(LDFLAGS) -o $@ $(APP_OBJS) $(LDLIBS)
 
clean:
    -rm -f $(APP) *.elf *.gdb *.o $(APP_OBJS)
 
%.o: %.c
    $(CC) -c -Wall -O0 -g3 -c -fmessage-length=0 -MT"$@" -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<"

Add the source files to the project-spec/meta-user/recipes-apps/rfdc_test/files directory.

Update the project-spec/meta-user/recipes-apps/rfdc-test/rfdc-test.bbappend file:

bbappend
#
# This file is the rfdc-test recipe.
#

SUMMARY = "Simple rfdc-test application"
SECTION = "PETALINUX/apps"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"

SRC_URI = "file://xrfdc_selftest_example.c \
	   file://xrfdc_clk.c \
	   file://xrfdc_clk.h \
	   file://Makefile \
	   	  "

S = "${WORKDIR}"

DEPENDS = “libmetal"

PROVIDES = "rfdc-test"

do_compile() {
	     oe_runmake
}

do_install() {
	     install -d ${D}${bindir}
	     install -m 0755 rfdc-read-write ${D}${bindir}
}



  • No labels