しろあんのさかな

ふーちゃのエンジニアブログ

ハードウェア記述言語でPYNQボード上のLEDをPWM制御してみた

最近研究室に行ったら友人との話の流れでPYNQボードを貸してもらえることになったので、手始めにハードウェア記述言語であるVerilog-HDLと、統合開発環境であるVivadoを使って自作回路を作った話です。

※※注意※※ この記事は読んだ人が再現できるように細部の手順を細かく説明したものではないです。(もちろんコードは適切な手順を踏めば動きます。)初めてFPGAの記事を読む人にもやったことや背景がふんわりとでも伝わることを心がけて書きました。

f:id:taiyaki_future:20190513135209j:plain
PYNQボード

背景

Pythonで制御可能なFPGAボード

PYNQボードにあるZynqという部品にはPS(CPU)とPL(FPGA)が一つのボード上に搭載されています。配布されている専用のOSをmicroSDなどからブートすることでボード上でJupyterを動かすことができます。そのためPythonで書いたコードで簡単にボード上の部品の操作ができることで2年前くらいに話題になったFPGAのボードです。

発売当時、アメリカのDigilentという会社から学割で1万円しないくらいで手に入り、私の周りの友人たちは学生で欲しい人を集めてまとめて注文し、送料を割り勘する注文方法でお得に入手していたのを覚えています。

今回Pythonを使わない理由

単純に好みの問題です。 Pythonを使うためにはOSをブートしてCPUを動かす必要がありますが、CPUとFPGA上の自作回路を繋げるのは少し面倒なのでPythonは使いませんでした。 配布されているデモ用のパッケージはPythonでの記述に利用すると、FPGAはCPUから送られてくるbitファイルによって既製の回路に固定され、簡単に利用することができます。

せっかくPythonで制御ができるPYNQボードなのでCPUとFPGAを繋げてPython越しの実装もそのうちやってみる予定です。

私のスキル

学部2年から2年間Verilog-HDLを利用した回路記述を経験しました。ハードウェアで三角比の高速計算ができるCODICアルゴリズムとPWM(Pulse Width Modulation)制御を組み合わせて矩形波からSIN波を生成したり、ディスプレイに画像を表示させる回路を作成しAXIバス越しに同一ボード上のCPUからその回路を制御したりしました。

やったこと

PYNQボード上のLEDをPWM制御という方法を利用して4段階の明るさに点灯させます。

環境

  • PYNQ-Z1(Xilinx Zynq)
  • Vivado HL System Edition(研究室からのライセンスを持っているのでそれを利用しました。今回のような小規模回路ならば無償用(HL WebPACK Edition)でもできると思います。)

PWM制御とは

基本的にデジタル信号はHighかLowかしかありません。LEDだと、点灯している状態か、消灯している状態かの2つしかなく、アナログ回路のように電池を直列に繋いで電圧を高くしてLEDを眩しく点灯させるというようなことはできません。

そこで"ある区間"の平均値が明るさであるとして制御していく方法がPWMです。例えば下の例では、LED1は"ある区間"をCLK(クロック)周期5個分とすると、5回ともHigh(1)であるので、平均の明るさは1、LED4では平均の明るさは2/5となります。

f:id:taiyaki_future:20190513180709j:plain
PWMタイミングチャート例

ちなみにこの技術はLEDだけでなく、音声で音の大きさを変える(音色を変える)ことにも利用できます。

実行結果

写真ではわかりにくいですが、右のLEDになればなるほど弱く点灯しています。

f:id:taiyaki_future:20190513143633j:plain
実行結果

コード

module top (
    input wire sysclk,
    input wire [3:0] btn,
    output reg[3:0] led
);

wire RST = btn[0];
reg[2:0] count;

// 0~4を繰り返しカウントする
always @(posedge sysclk) begin
    if (RST) count <= 0;
    else if (count == 4) count <= 0;
    else count <= count + 1;
end

// カウント値に合わせて各LEDの値を変更する。
// ledレジスタの4桁それぞれが4つのLEDを
// 点灯させるかどうかを1/0で表している。
// PWM例: 各countの値で0桁目は一番1の数が少ないので弱い光になる。
always @(posedge sysclk) begin
    if (RST) led[3:0] <= 4'b0000;
    else if (count == 4) led[3:0] <= 4'b1110;
    else if (count == 3) led[3:0] <= 4'b1101;
    else if (count == 2) led[3:0] <= 4'b1010;
    else if (count == 1) led[3:0] <= 4'b1101;
    else led[3:0] <= 4'b1110;
end

endmodule

簡単な操作手順

  1. Vivadoのnew ProjectでボードPYNQ-Z1を指定
  2. Add Sourcesに.xdc,.vファイルを追加
  3. Run Synthesisボタンを押して論理合成
  4. Run Implementationボタンを押す
  5. Generate Bitstreamでbitファイルを生成
  6. ボードの電源を入れ、JTAGモードでFPGAに書込み
    • Open Hardware Manager -> Open Target -> (xc7z020_1を右クリック)Program Deviceで書込み

まとめ

PYNQボードのLEDをハードウェア記述言語で制御してみた話でした。Verilog-HDLは新しい研究室でこれからたくさん使うことになりそうなので、環境含め慣れていきたいです。