--- tags: notes, PYNQ, linux, FPGA --- # PYNQ Z2 雜記 有關PYNQ Z2的各種小筆記,雜亂無綱。 [官方參考鏈結](https://pynq.readthedocs.io/en/latest/getting_started.html) ## Setup ### Power SW1旁邊的jumper選擇供電來源:REG為12伏特DC jack輸入,USB為Micro USB輸入供電。 電源開關在Mircro USB母孔旁邊。 ### Communication - **網路線** 1. 板子上電(廢話) 2. 並透過網路線(RJ45)直接跟筆電(or PC)的網路孔對接 3. 指定筆電乙太網路卡靜態IPv4:192.168.2.X,X可以是除了99以外0~254的數字 4. 稍待一兩分鐘後,在瀏覽器輸入`pynq/`及可連到jupyter的web介面 5. 如果輸入`pynq/`不行,試著輸入`192.168.2.99`看看(也可以ping看看有沒有回應) - **USB COM port** 1. 用Micro USB連接板子跟筆電 2. 到裝置管理員查看com port號碼,不同筆電、不同USB孔,號碼都會不一樣 4. 用Terminal軟體打開([推薦Mobaxterm],設定如下(https://mobaxterm.mobatek.net/)) ![com port setting](https://i.imgur.com/2BqrgAO.png) 4. 剛連進去可能甚麼都沒有,鍵盤隨便敲幾個英文字後enter應該就會看到linux的文字介面了 note: 一次只能有一個軟體去開同個com port - **接上網際網路** 1. 先將板子與筆電用網路線對接,但是不要指定筆電乙太網路卡的IP,在IPv4中讓他自動取得IP位址 2. 到筆電上的網路介面卡選項,選擇網際網路來源(ex: wifi) 右鍵->內容->共用->允許...打勾->下拉選單選"乙太網路" 按下確定後會跳出一個視窗"當網際網路連線共用後blablabla",按是 ![](https://i.imgur.com/CSFWcCB.png) ![](https://i.imgur.com/akgffWT.png) 3. 稍待一兩分鐘後,用上述的**USB COM port**連接板子,檢查網際網路連線: `ping google.com -c 5` ![](https://i.imgur.com/zfa4lrc.png) 4. 如果要用jupyter開發的話,要在**USB COM port**查板子的IP位址 `ifconfig` 找到後在瀏覽器輸入IP位址即可進入jupyter介面 (也可以用[這個](https://blog.gtwang.org/linux/ping-and-arp-scan-ip-mac-address-script/)去掃區網的有哪些裝置) ![](https://i.imgur.com/PitZ1tR.png) - **Wifi** Ralink RT5370 recommended, it works without installing any extra driver. ```python= from pynq.lib import Wifi port = Wifi() ssid = input("Type in the SSID:") pwd = input("Type in the password:") port.connect(ssid=ssid, password=pwd, auto=True) ``` For `auto=True`, it sets up an service that connect to the wifi everytime reboot. To disconnect the wifi: ```python=7 port.reset() ``` ## Arduino IO The official [library](https://pynq.readthedocs.io/en/latest/pynq_package/pynq.lib/pynq.lib.arduino.html#pynq.lib.arduino.arduino_io.Arduino_IO) for accesing arduino IOs on the board is sucks. You can't use 1 pin for output and 1 pin for input at the same time. Here are some modified functions from the source code. ### Preset ```python= from pynq.lib.arduino import Arduino_DevMode from pynq.lib.arduino import ARDUINO_SWCFG_DIOALL from pynq.lib.arduino import ARDUINO_DIO_BASEADDR from pynq.lib.arduino import ARDUINO_DIO_TRI_OFFSET from pynq.lib.arduino import ARDUINO_DIO_DATA_OFFSET from pynq.lib.arduino import ARDUINO_CFG_DIO_ALLINPUT from pynq.lib.arduino import ARDUINO_CFG_DIO_ALLOUTPUT from pynq.lib.arduino import ARDUINO_NUM_ANALOG_PINS from pynq.lib.arduino import ARDUINO_NUM_DIGITAL_PINS from pynq.overlays.base import BaseOverlay from pynq.lib.arduino.arduino_io import Arduino_IO from pynq.lib.arduino.arduino_analog import Arduino_Analog import time base=BaseOverlay('base.bit') PT=Arduino_IO(base.ARDUINO,0,'in') # being careful, set all digital IO as input Arduino_IO.write_cmd(PT,ARDUINO_DIO_BASEADDR + ARDUINO_DIO_TRI_OFFSET, ARDUINO_CFG_DIO_ALLINPUT) """ parameters: pin: int, 0~13 corresponding pin AR0~AR13 on the board value: int/boolean, the output state return: None """ def io_write(pin, value): if pin in range(ARDUINO_NUM_ANALOG_PINS + ARDUINO_NUM_DIGITAL_PINS): if value: cur_val = Arduino_IO.read_cmd(PT, ARDUINO_DIO_BASEADDR + ARDUINO_DIO_DATA_OFFSET) new_val = cur_val | (0x1 << pin) Arduino_IO.write_cmd(PT, ARDUINO_DIO_BASEADDR + ARDUINO_DIO_DATA_OFFSET, new_val) else: cur_val = Arduino_IO.read_cmd(PT, ARDUINO_DIO_BASEADDR + ARDUINO_DIO_DATA_OFFSET) new_val = cur_val & (0xffffffff ^ (0x1 << pin)) Arduino_IO.write_cmd(PT, ARDUINO_DIO_BASEADDR + ARDUINO_DIO_DATA_OFFSET, new_val) """ parameters: pin: int, 0~13 corresponding pin AR0~AR13 on the board return: int/boolean, the state read from the pin """ def io_read(pin): if pin in range(ARDUINO_NUM_ANALOG_PINS + ARDUINO_NUM_DIGITAL_PINS): raw_value = Arduino_IO.read_cmd(PT, ARDUINO_DIO_BASEADDR + ARDUINO_DIO_DATA_OFFSET) return (raw_value >> pin) & 0x1 ``` ### Input/Output ```python=0 Arduino_IO.write_cmd(PT, ARDUINO_DIO_BASEADDR + ARDUINO_DIO_TRI_OFFSET, IO_GROUP_STATE) ``` The first 2 parameters are fixed. The third one `IO_GROUP_STATE` is 32bit unsigned int. If the n-th bit is **1** then then the n-th pin is configured as **input**. If the n-th bit is **0** then then the n-th pin is configured as **output**. Here are some examples. ```python= # set pin0(labeled AR0 on the board) as output and the rest as input Arduino_IO.write_cmd(PT,ARDUINO_DIO_BASEADDR + ARDUINO_DIO_TRI_OFFSET, 0b1111_1111_1111_1111_1111_1111_1111_1110) # set pin3(AR3) and pin6(AR6) as input and the rest as output Arduino_IO.write_cmd(PT,ARDUINO_DIO_BASEADDR + ARDUINO_DIO_TRI_OFFSET, 0b0000_0000_0000_0000_0000_0000_0100_1000) ``` ### Write value The snippet in **Preset** already define two functions `io_write()` and `io_read()`. You can write a simple program that blinks the AR1 onece AR0 is 0: ```python= Arduino_IO.write_cmd(PT,ARDUINO_DIO_BASEADDR + ARDUINO_DIO_TRI_OFFSET, 0b1111_1111_1111_1111_1111_1111_1111_1101) while io_read(0)==1: time.sleep(1) print("waiting...") print("Now blinking!") for i in range(5): # toggle five times time.sleep(1) io_write(1,1) time.sleep(1) io_write(1,0) ``` Since the library interacts with the entire IO set(from AR0~AR13) with `.write_cmd()`, so in a latency sensitive case you can write value into IOs with: ```python=0 Arduino_IO.write_cmd(PT, ARDUINO_DIO_BASEADDR + ARDUINO_DIO_DATA_OFFSET, IO_VAL) ``` where the first two parameters are fixed, and the third one `IO_VAL` is 32bit unsigned int. If the value of n-th bit is the the output state of n-th pin. ## On board LED, Button, Switch Import the library and assign the object. ```python= from pynq.overlays.base import BaseOverlay base = BaseOverlay("base.bit") ``` ### LED ```python= # you can access the API directly base.leds[0].on() base.leds[1].off() base.leds[2].toggle() # you can also assign it to a var led3=base.leds[3] led3.on() # since base.leds is iterable, you can also do this for led in base.leds: led.on() time.sleep(1) ``` ### Button and Switch ```python= print(base.buttons[0].read()) print(base.switched[0].read()) ``` ## HDMI out [Official github Ref](https://github.com/Xilinx/PYNQ/blob/master/boards/Pynq-Z1/base/notebooks/video/opencv_filters_webcam.ipynb) Displaying a cv2 image object. HDMI setupt: ```python= from pynq.overlays.base import BaseOverlay from pynq.lib.video import * base = BaseOverlay("base.bit") # monitor configuration: 1920*1080 @ (8 bits)*(BGR)=24, 60Hz Mode = VideoMode(width=1920,height=1080,bits_per_pixel=24,fps=60) hdmi_out = base.video.hdmi_out hdmi_out.stop() hdmi_out.close() hdmi_out.configure(Mode,PIXEL_BGR) # OpenCV default color space is BGR try: hdmi_out.start() except: print("[Error] HDMI Out failed to initialize.") hdmi_out.stop() hdmi_out.close() del hdmi_out else: print("[INFO] HDMI out initialized.") ``` Simple function to producce cv2 image object: ```python= import numpy as np import cv2 def mk_img(text): img = np.zeros((1080, 1920, 3), np.uint8) img.fill(170) # fill with gray cv2.line(img, (0, 0), (255, 255), (0, 0, 255), 5) # draw red line cv2.putText(img, text, (700, 700), cv2.FONT_HERSHEY_SIMPLEX, 10, (0, 255, 255), 1, cv2.LINE_AA) return img ``` Get a image object and output to HDMI out: ```python= img=mk_img('bla bla bla') print("[INFO] Image size:", end='') print(img.shape) outframe = hdmi_out.newframe() outframe[:] = img hdmi_out.writeframe(outframe) ``` It is **neccesarry** to clean and release the hardware HDMI out, otherwise bad things happen when using HDMI out next time. If, unfortunately, bad things happen when using HDMI out, then you might like to reboot the board. ```python= hdmi_out.stop() hdmi_out.close() del hdmi_out ```