LoginSignup
6
4

More than 3 years have passed since last update.

第4回 PYNQのOVERLAYを使ってみた

Last updated at Posted at 2019-08-15

はじめに

こんどこそ、ハードウェアリソースへのアクセス。

第1回 Setup PYNQ-Z1
第2回 はじめてのJupyter
第3回 pythonとPYNQ PL資源へのアクセス
第4回 PYNQ OVERLAY
第5回 PYNQのOverlayを作ってみた
第6回 カスタムIPを作ってPYNQ overlayに組み込む
第7回 PYNQのHDMI出力overlayを作る
番外編 python ジャンプスタート

loading Overlay

こんどこそ。
overlayはbitstreamのことで、ブート時には"base"と呼ばれるオーバレイがPL(Programmable Logic)に読み込まれる。その後新しいオーバレイを読み込むこともできる。オーバーレイはFPGA回路データのbitstream,vivadoのTcl, Python APIを含む。
PYNQのOverlay classはbitstreamファイル名をつかってインスタンスをつくることできる。

from pynq import Overlay
overlay = Overlay("base.bit")

base overlay

boot時に読み込まれるオーバレイ。これがデフォルトね。

from pynq.overlays.base import BaseOverlay
base_overlay = BaseOverlay("base.bit")

読み込みが完了すればpythonからアクセス可能になる。4〜5秒かかる感じ。help(base_overlay)にて、各種機能のhelpが得られる。

こんな感じでhelpを読む
help(base_overlay.leds)
LEDへのアクセスはこんな感じ
base_overlay.leds[0].toggle()

partial reconfiguration

部分的な構成変更も可能。この場合ビットストリームとともに「.hwh」ファイルも必要とのこと。とりあえず後回しでいいかな。
partial reconfiguration

PYNQ-Z1のオーバーレイ

base overlay

サードパーティ製のオーバーレイもあるが、まずbaseをみる。

ハードウエア対応

  • HDMI (Input and Output) --> {Jupyter dashboard}/base/video
  • Microphone in --> {Jupyter dashboard}/base/audio
  • Audio out
  • User LEDs, Switches, Pushbuttons -->{Jupyter dashboard}/base/board/board_btns_leds.ipynb
  • 2x Pmod PYNQ MicroBlaze
  • Arduino PYNQ MicroBlaze
  • 3x Trace Analyzer (PMODA, PMODB, ARDUINO)

Audio/videoとLED,SWはサポートするクラスがある。PmodやArduinoインターフェースは、MicroBlase(softマクロ、マイコン)をプログラムしてコントローラにしてアクセスする構成か。

PYNQ-Z1のvideoのテスト

HDMI入力にMACのディスプレイ出力、出力にHDMIディスプレイをつないでデモをやってみる(http://{IP ADDRESS}:9090/notebooks/base/video/hdmi_introduction.ipynb)

bitストリームのダウンロードは、すこし時間がかかるがすんなり通過。

from pynq.overlays.base import BaseOverlay  # BaseOverlayをimport
from pynq.lib.video import *  # video関係もまとめて

base = BaseOverlay("base.bit")  # baseをロード
hdmi_in = base.video.hdmi_in    # hdmi入出力をcreate
hdmi_out = base.video.hdmi_out

パススルーテスト

hdmi_in.configure()  # Configure the pipeline to use the specified pixel format.

# configure(self, mode, pixelformat=None)
# Configure the pipeline to use the specified pixel format and size.
# mode : VideoMode
hdmi_out.configure(hdmi_in.mode)

hdmi_in.start()      # Start the pipeline
hdmi_out.start()
hdmi_in.tie(hdmi_out)  # Mirror the video input on to an output channel

ひと仕事おわったら、ちゃんとクローズするようにとのこと。context managerをつかえば、自動でおかたづけできるとのこと。(どうするのかは書いてない)

hdmi_out.close()
hdmi_in.close()

しかし、これをやったとしても、2例目以降を実行しようとするとJupyterに"kernel restarting"のダイアログがでる。なぜだろう。

映像のキャプチャ

オープンしてパススルー
hdmi_in.configure(PIXEL_RGB)  # RGBフォーマット
hdmi_out.configure(hdmi_in.mode, PIXEL_RGB)

hdmi_in.start()
hdmi_out.start()

hdmi_in.tie(hdmi_out)
キャプチャ
import PIL.Image  # Pillow : Python Imaging Library

frame = hdmi_in.readframe()  # Read a video frame; See AxiVDMA.S2MMChannel.readframe for details
image = PIL.Image.fromarray(frame)
image

Imaging Libraryね。PIL, Pillow, OpenCV, matplotlibの関係はどうなっているのかな。
nkmk(@nkmk_me twitter)さんのnote.nkmk.me Pythonで画像処理: Pillow, NumPy, OpenCVの違いと使い分けに回答があった。

  • Pillow(PIL): 画像処理ライブラリ
  • NumPy: 数値計算ライブラリ
  • OpenCV: コンピュータビジョンライブラリ

help(hdmi_in.readframe)するとAxiVDMA.S2MMChannel.readframe()を引けとでた。ヘルプはどこだろう。また見知らぬ略語だ。

  • AxiVDMA : AXI Video Direct Memory Access
  • S2MM : Stream to Memory Map

なるほど。まるで70年代のアセンブラのラベル。オートコンプリートつかってないのかなぁ。
みつけた pynq.lib.video Module

Audio

同様にサンプルをやってみる。マイクは内蔵なので、スピーカをつなぐ。ちゃんと音もでるし、録音したものをnotebookで再生できる。
レベルは調整したほうがいいかな。
MICはPulse Density Modulation(PDM)で符号化された出力なので、PDM->PCM変換が必要。ΔΣ変調がかかった状態なので、LPFをかければもとの信号を取り出せる。
なお、help(base.audio.record()によれば、ワードのサンプリングレートは192000Hz(192kHz)。1ワード16bitなので192x16ksample/sec(1bit)。

PDM MICについてはFreeplanetsPDMマイクからの信号よみとり(IP)の解説が詳しい

PDM->PCM
from pynq.overlays.base import BaseOverlay
base = BaseOverlay("base.bit")
pAudio = base.audio
pAudio.record(3)
#pAudio.load("Recording_1.pdm")

# ここから変換
import numpy as np

# まずバッファを32bitから16bitに変換(astype(np.int16))し
# 1bit x 16 sample を 8 bit x 16 sampleに変換
af_uint8 = np.unpackbits(pAudio.buffer.astype(np.int16)
                         .byteswap(True).view(np.uint8))

# PDM->PCM
from scipy import signal  # downsampleのためにscipyモジュールをインポート
# signal.decimateは8次チェビシェフ type I のIIRフィルタを用いる。
af_dec = signal.decimate(af_uint8,8,zero_phase=True)  # 1/8 
af_dec = signal.decimate(af_dec,6,zero_phase=True)  # 1/6 (1/48)
af_dec = signal.decimate(af_dec,2,zero_phase=True)  # 1/2 (1/96)
# 16 x 192000 [sample/sec] /96 -> 32 [ksample/sec]
af_dec = (af_dec[10:-10]-af_dec[10:-10].mean())  # DC offsetを削除する

del af_uint8

from IPython.display import Audio as IPAudio
IPAudio(af_dec, rate=32000)

LEDs, Switches, Pushbuttons

{Jupyter dashboard}/base/board/board_btns_leds.ipynb をやってみる。これは簡単。

from time import sleep
from pynq.overlays.base import BaseOverlay

base = BaseOverlay("base.bit")

for led in base.leds:
    led.off()
sleep(0.5)
base.leds[0].on()
while (base.buttons[3].read()==0):
    if (base.buttons[0].read()==1):
        base.leds[1].toggle();
        sleep(0.1);
for led in base.leds:
    led.off()    

せっかくなのでもう少し低いレベルまでほってみる。
PYNQ libraries AxiGPIO

ふむふむGPIOは、32pinを2チャンネルもてて、LED,Switch,Button,RGBLEDクラスはこれを拡張してカスタマイズしたもの[led|switch|button|rgbleds]_gpio

AxiGPIOの資料より
from pynq import Overlay
from pynq.lib import AxiGPIO
ol = Overlay("base.bit")

led_ip = ol.ip_dict['gpio_leds']
switches_ip = ol.ip_dict['gpio_switches']
leds = AxiGPIO(led_ip).channel1
switches = AxiGPIO(switches_ip).channel1

まとめ

手順は、baseをダウンロードし、しかるべきオブジェクトを介して操作する。

  • audioはPDMフォーマットであるから、PCMとの変換が必要
  • ledやSwitchは単純にread/writeするだけ
  • pmodやシールドはMicroBleaseで制御する
  • 割り込みもあるが、とりあえずおいておく
6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4