Skip to content

Commit a29d9f3

Browse files
PeterOgdenschelleg
authored andcommitted
Add Yocto support for PYNQ (#803)
* Remove hard dependencies from PYNQ All but numpy are now soft dependencies to make it easier to install PYNQ in restricted environments. * Support Cross-compilation for PYNQ Update all of the various build scripts to correctly handle any cross compilation flags. * Don't do anything fancy if notebooks_dir is explicitly empty * Add a filesystem layer to meta-pynq Yocto layer
1 parent 69ddb19 commit a29d9f3

File tree

21 files changed

+449
-36
lines changed

21 files changed

+449
-36
lines changed

pynq/lib/_pynq/_audio/Makefile

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
CC = gcc
2-
CPP = g++
3-
41
ifeq ($(BOARD), Pynq-Z1)
52
C_SRC += audio_direct.cpp
63
OBJSC += audio_direct.o
@@ -14,6 +11,6 @@ OBJSC += audio_adau1761.o \
1411
endif
1512

1613
all:
17-
$(CC) -fPIC -c -g3 -ggdb $(C_SRC)
18-
$(CPP) -g3 -ggdb -shared -fPIC -rdynamic $(OBJSC) -Wl,--start-group $(LIBS) -Wl,--end-group -o libaudio.so
14+
$(CC) -fPIC -c -g3 -ggdb $(C_SRC) $(CFLAGS)
15+
$(CXX) -g3 -ggdb -shared -fPIC -rdynamic $(OBJSC) -Wl,--start-group $(LIBS) -Wl,--end-group -o libaudio.so $(CFLAGS) $(LDFLAGS)
1916
rm *.o

pynq/lib/_pynq/_displayport/Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ CC ?= gcc
22
CXX ?= g++
33

44
OBJSC = displayport.o
5-
INC = -I/usr/include/libdrm
5+
INC = -I${PYNQ_BUILD_ROOT}/usr/include/libdrm
66

77
all:
8-
$(CXX) -fPIC $(INC) -c -g -std=c++11 displayport.cpp
9-
$(CXX) -shared -fPIC -rdynamic $(OBJSC) -ldrm -o libdisplayport.so
8+
$(CXX) -fPIC $(INC) -c -g -std=c++11 displayport.cpp $(CFLAGS)
9+
$(CXX) -shared -fPIC -rdynamic $(OBJSC) -ldrm -o libdisplayport.so $(CFLAGS) $(LDFLAGS)
1010
rm *.o

pynq/lib/_pynq/embeddedsw_lib.mk

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ EMBEDDEDSW_DIR ?= embeddedsw
99
# INC - include directory with the -I prefix
1010

1111
# ARCH := $(shell uname -p)
12-
ARCH := $(shell uname -p)
12+
PYNQ_BUILD_ARCH ?= $(shell uname -p)
1313
ESW_SRC := $(filter-out %_g.c, $(foreach lib, $(ESW_LIBS), $(wildcard $(EMBEDDEDSW_DIR)/XilinxProcessorIPLib/drivers/$(lib)/src/*.c)))
1414
ESW_INC := $(patsubst %, -I$(EMBEDDEDSW_DIR)/XilinxProcessorIPLib/drivers/%/src, $(ESW_LIBS))
1515
OS_INC := -I$(EMBEDDEDSW_DIR)/lib/bsp/standalone/src/common -I$(EMBEDDEDSW_DIR)/lib/bsp/standalone/src/arm/common/gcc -I$(EMBEDDEDSW_DIR)/lib/bsp/standalone/src/arm/common
@@ -22,10 +22,10 @@ COMMON_INC := -Icommon
2222
COMMON_INC_aarch64 := -Icommon/aarch64
2323
COMMON_INC_armv7l := -Icommon/armv7l
2424

25-
ALL_SRC := $(SRC) $(COMMON_SRC) $(COMMON_SRC_$(ARCH)) $(ESW_SRC)
26-
ALL_INC := $(INC) $(COMMON_INC) $(COMMON_INC_$(ARCH)) $(ESW_INC) $(OS_INC) $(OS_INC_$(ARCH))
25+
ALL_SRC := $(SRC) $(COMMON_SRC) $(COMMON_SRC_$(PYNQ_BUILD_ARCH)) $(ESW_SRC)
26+
ALL_INC := $(INC) $(COMMON_INC) $(COMMON_INC_$(PYNQ_BUILD_ARCH)) $(ESW_INC) $(OS_INC) $(OS_INC_$(PYNQ_BUILD_ARCH))
2727

2828
all: $(LIB_NAME)
2929

3030
$(LIB_NAME): $(EMBEDDEDSW_DIR)
31-
gcc -o $(LIB_NAME) -shared -fPIC $(ALL_INC) $(ALL_SRC)
31+
$(CC) -o $(LIB_NAME) -shared -fPIC $(ALL_INC) $(ALL_SRC) $(CFLAGS) $(LDFLAGS)

pynq/lib/arduino/arduino_lcd18.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
from math import ceil
3232
import asyncio
3333
import os
34-
from PIL import Image
3534
from numpy import array
3635
from pynq import Xlnk
3736
from . import Arduino
@@ -201,6 +200,8 @@ def display_async(self, img_path, x_pos=0, y_pos=127,
201200
None
202201
203202
"""
203+
from PIL import Image
204+
204205
if x_pos not in range(160):
205206
raise ValueError("Valid x_pos is 0 - 159.")
206207
if y_pos not in range(128):

pynq/lib/logictools/boolean_generator.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@
3131
import re
3232
from copy import deepcopy
3333
from collections import OrderedDict
34-
from pyeda.inter import exprvar
35-
from pyeda.inter import expr2truthtable
3634
from pynq import Register
3735
from .constants import *
3836
from .logictools_controller import LogicToolsController
@@ -195,6 +193,12 @@ def setup(self, expressions, frequency_mhz=DEFAULT_CLOCK_FREQUENCY_MHZ):
195193
The frequency of the captured samples, in MHz.
196194
197195
"""
196+
try:
197+
from pyeda.inter import exprvar
198+
from pyeda.inter import expr2truthtable
199+
except ImportError:
200+
raise ImportError("Using Logictools requires pyeda")
201+
198202
if not MIN_CLOCK_FREQUENCY_MHZ <= frequency_mhz <= \
199203
MAX_CLOCK_FREQUENCY_MHZ:
200204
raise ValueError("Clock frequency out of range "

pynq/lib/logictools/fsm_generator.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@
3232
from copy import deepcopy
3333
from math import ceil, log
3434
import numpy as np
35-
import pygraphviz as pgv
36-
from IPython.display import Image, display
3735
from .constants import *
3836
from .logictools_controller import LogicToolsController
3937
from .trace_analyzer import TraceAnalyzer
@@ -1009,6 +1007,9 @@ def show_state_diagram(self, file_name='fsm_spec.png', save_png=False):
10091007
Whether to save the PNG showing the state diagram.
10101008
10111009
"""
1010+
import pygraphviz as pgv
1011+
from IPython.display import Image, display
1012+
10121013
if self.logictools_controller.status[
10131014
self.__class__.__name__] == 'RESET':
10141015
raise ValueError(

pynq/lib/logictools/waveform.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@
3636
import base64
3737
from xml.dom import minidom
3838
import numpy as np
39-
import IPython.core.display
40-
import IPython.display
4139
from .constants import *
4240

4341

@@ -224,6 +222,8 @@ def _draw_javascript(data):
224222
A dump of a Json formatted data.
225223
226224
"""
225+
import IPython.core.display
226+
import IPython.display
227227
wavedrom_js = 'wavedrom.js'
228228
wavedromskin_js = 'wavedromskin.js'
229229

@@ -277,6 +277,8 @@ def _copy_javascripts():
277277

278278

279279
def _draw_phantomjs(data, phantomjs, wavedrom_cli):
280+
import IPython.core.display
281+
import IPython.display
280282
"""Draw the wavedrom using PhantomJS.
281283
282284
This method requires the PhantomJS to be properly installed on the board.

pynq/lib/pynqmicroblaze/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,8 @@
3939
from .compile import MicroblazeProgram
4040
from .rpc import MicroblazeRPC
4141
from .rpc import MicroblazeLibrary
42-
from .magic import MicroblazeMagics
42+
try:
43+
__IPYTHON__
44+
from .magic import MicroblazeMagics
45+
except NameError:
46+
pass

pynq/lib/wifi.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929

3030
import os
3131
import subprocess as sproc
32-
import netifaces
3332

3433
__author__ = "Luca Cerina"
3534
__copyright__ = "Copyright 2016, NECST Laboratory, Politecnico di Milano"
@@ -65,6 +64,11 @@ def __init__(self, interface='wlan0'):
6564
The name of the network interface.
6665
6766
"""
67+
try:
68+
import netifaces
69+
except ImportError:
70+
raise ImportError("netifaces must be installed to configure WiFi")
71+
6872
self.wifi_port = None
6973
net_device_list = netifaces.interfaces()
7074

pynq/pmbus.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2929

3030
import cffi
31-
import pandas as pd
3231
import threading
3332
import time
3433
import warnings
@@ -225,7 +224,7 @@
225224

226225
try:
227226
_ffi.cdef(_c_header)
228-
_lib = _ffi.dlopen("libsensors.so")
227+
_lib = _ffi.dlopen("libsensors.so.4")
229228
except Exception as e:
230229
warnings.warn("Could not initialise libsensors library")
231230
_lib = None
@@ -469,5 +468,6 @@ def frame(self):
469468
Sensors* : one column per sensor
470469
471470
"""
471+
import pandas as pd
472472
return pd.DataFrame(self._data, columns=self._columns,
473473
index=pd.to_datetime(self._times, unit="s"))

sdbuild/boot/meta-pynq/README.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
PYNQ and PetaLinux
2+
==================
3+
4+
The PYNQ environment is primarily designed to run inside of a Ubuntu-based
5+
filesystem with the kernel being provided by PetaLinux. This is the flow which
6+
the sdbuild directory supports. It is possible, however, to install PYNQ inside
7+
of a PetaLinux root filesystem with the following caveats:
8+
9+
1) No overlays will be installed
10+
2) Jupyter is not supported - only the PYNQ library
11+
3) Parts of logictools require libraries not available in PetaLinux
12+
13+
The rest of this guide describes how to configure a PetaLinux project to
14+
include PYNQ. It is specific to version 2018.2.
15+
16+
Add the required layers
17+
-----------------------
18+
19+
Run `petalinux-config` in the PetaLinux project and add this directory as a user layer
20+
21+
Add PYNQ to the filesystem target
22+
---------------------------------
23+
24+
Edit `project-spec/meta-user/recipes-core/images/petalinux-image.bbappend` and
25+
add the following line
26+
27+
```
28+
IMAGE_INSTALL_append = " python3-pynq"
29+
```
30+
31+
Next run `petalinux-config -c rootfs` and you will find the option to select
32+
`python3-pynq` under `user packages`. Select it to add it to the filesystem.
33+
If the base notebooks are required then the python3-pynq-notebooks package can
34+
be added as well.
35+
36+
Note that by default the BOARD environment will not be set in the root filesystem
37+
and overlays will not be installed.
38+
39+
The PYNQ bbclass
40+
----------------
41+
42+
There is also a pynq-package bbclass that is designed to adapt third party
43+
packages by installing the notebooks into a separate -notebooks package and
44+
setting the BOARD environment variable during installation. Note that the BOARD
45+
will need to be changed inside the layer to support the board you are
46+
targetting.
47+
48+
Build the filesystem
49+
--------------------
50+
51+
run `petalinux-build` to build all of the components
52+
run `petalinux-pacakge --boot --u-boot --fpga` to create `BOOT.BIN`
53+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
PYNQ_NOTEBOOK_DIR ?= "/home/root/notebooks"
2+
3+
PYNQ_BOARD ?= ZCU104
4+
5+
do_compile_prepend() {
6+
export PYNQ_JUPYTER_NOTEBOOKS="${D}${PYNQ_NOTEBOOK_DIR}"
7+
export BOARD=${PYNQ_BOARD}
8+
}
9+
10+
do_install_prepend() {
11+
export PYNQ_JUPYTER_NOTEBOOKS="${D}${PYNQ_NOTEBOOK_DIR}"
12+
export BOARD=${PYNQ_BOARD}
13+
}
14+
15+
FILES_${PN}-notebooks = "${PYNQ_NOTEBOOK_DIR}"
16+
PACKAGES += "${PN}-notebooks"
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#!/bin/sh
2+
### BEGIN INIT INFO
3+
# Provides:
4+
# Required-Start: $remote_fs $syslog
5+
# Required-Stop: $remote_fs $syslog
6+
# Default-Start: 2 3 4 5
7+
# Default-Stop: 0 1 6
8+
# Short-Description: Start daemon at boot time
9+
# Description: Enable service provided by daemon.
10+
### END INIT INFO
11+
12+
dir=""
13+
cmd="start_pl_server.py"
14+
user=""
15+
16+
name="pl_server"
17+
pid_file="/var/run/$name.pid"
18+
stdout_log="/var/log/$name.log"
19+
stderr_log="/var/log/$name.err"
20+
21+
get_pid() {
22+
cat "$pid_file"
23+
}
24+
25+
is_running() {
26+
[ -f "$pid_file" ] && (ps -o"pid" | grep '^ '`get_pid`'$') > /dev/null 2>&1
27+
}
28+
29+
case "$1" in
30+
start)
31+
if is_running; then
32+
echo "Already started"
33+
else
34+
echo "Starting $name"
35+
cd "$dir"
36+
$cmd >> "$stdout_log" 2>> "$stderr_log" &
37+
echo $! > "$pid_file"
38+
if ! is_running; then
39+
echo "Unable to start, see $stdout_log and $stderr_log"
40+
exit 1
41+
fi
42+
fi
43+
;;
44+
stop)
45+
if is_running; then
46+
echo -n "Stopping $name.."
47+
kill `get_pid`
48+
for i in 1 2 3 4 5 6 7 8 9 10
49+
# for i in `seq 10`
50+
do
51+
if ! is_running; then
52+
break
53+
fi
54+
55+
echo -n "."
56+
sleep 1
57+
done
58+
echo
59+
60+
if is_running; then
61+
echo "Not stopped; may still be shutting down or shutdown may have failed"
62+
exit 1
63+
else
64+
echo "Stopped"
65+
if [ -f "$pid_file" ]; then
66+
rm "$pid_file"
67+
fi
68+
fi
69+
else
70+
echo "Not running"
71+
fi
72+
;;
73+
restart)
74+
$0 stop
75+
if is_running; then
76+
echo "Unable to stop, will not attempt to start"
77+
exit 1
78+
fi
79+
$0 start
80+
;;
81+
status)
82+
if is_running; then
83+
echo "Running"
84+
else
85+
echo "Stopped"
86+
exit 1
87+
fi
88+
;;
89+
*)
90+
echo "Usage: $0 {start|stop|restart|status}"
91+
exit 1
92+
;;
93+
esac
94+
95+
exit 0
96+

0 commit comments

Comments
 (0)