見出し画像

「IoTシステム設計」の授業内容と感想

入学してから今までの3年間でダントツでハードだったけどかなりためになったIoTシステム設計という授業について,何をする授業なのかをばーっと書いた.情報系以外の人にも雰囲気は伝わるはず(たぶん)
ちなみに受講生は院生 : 4年生 : 3年生 = 1 : 2 : 7くらい.

何をする授業なのか

一言で言うと,
ハードウェア記述言語を用いてFPGAをプログラムし,システムを設計する
ための方法とその周辺知識を得るための授業.

FPGAとかハードウェア記述言語って何?

FPGAを用いない論理回路実装の場合

まずはFPGAとかハードウェア記述言語とか関係ない普通の論理回路の話から.論理回路の例として,1ビットの2進数$${A, B}$$と下位桁からの繰り上がり$${C_i}$$を入力されて,$${A, B}$$の和$${S}$$と上位桁への繰り上がり$${C_o}$$を出力する全加算器の回路図を書いてみる.
この全加算器の回路図を書くためには

  1. 全ての入力に対して期待する出力を考えて真理値表を作成する

  2. 真理値表から出力$${S, C_o}$$それぞれの論理和標準形を求める

  3. クワイン・マクラスキー法やカルノー図を使って論理和標準形を一番シンプルな形(最簡形)に変形する

というステップを踏む必要がある.(めんどくさい)
完成した回路図はこんな感じ

1ビット全加算器

回路図が出来上がったので,次は実際に回路を作る.基板上に部品を配置することでANDゲートとかを実装して,それらを結線すると全加算器が完成する.

ただ,このアプローチには主に2つ問題があって,
1つ目は,回路図を書くために真理値表を書いて最簡形を求める過程がとても面倒なこと.1ビット全加算器ならまだ楽だけど複雑な回路ではこんなことやってられない.ソフトウェアみたいに$${A + B}$$って書くだけで,自動で回路図を書いてくれる仕組みが欲しい
2つ目は,実際に回路を作るときに使う部品を間違えたら(実質)直しようがないこと.回路中のANDゲートを1箇所ORゲートに間違えたら期待通りに動作しないし,これを後から修正するのは非常に大変あるいは無理.あとでやり直しの効く仕組みが欲しい

これらの要望を叶えるのがFPGA & ハードウェア記述言語!

FPGAとは

FPGAは,組み合わせ方を自由に調整できる小さな論理回路の集合体.例えば,今回使ったAltera製のFPGA "Cyclone V" は以下の図のような構造をしている.

https://www.intel.co.jp/content/www/jp/ja/products/details/fpga/cyclone/v/article.html より

上の図にある "ALM" というやつがいろいろな論理回路を実装するための最小単位のことで,膨大な数あるALMたちを適当に配線して組み合わせることで任意の論理回路を実現できる仕組みになっている.しかも,ALMの組み合わせ方は別の機器からFPGAに電気信号を入力することでいつでも好きなように変更することができる.だから,FPGAに電気信号を入れてALMを組み合わせた後に間違いに気づいたとしても,もう一度電気信号を入れて簡単に修正できる.

ハードウェア記述言語とは

FPGAを使えば後からやり直しが効くとはいえ,FPGAに入力する電気信号を生成するためには回路図を書く必要があるので,1つ目の問題であった「回路図を書くのが面倒」という問題は解決していない.そこでハードウェア記述言語が登場する.実は,上の全加算器はハードウェア記述言語(Verilog HDL)を使ってこのように書ける

module FullAdder(
    input wire A,
    input wire B,
    input wire Ci,
    output wire S,
    output wire Co
);
    assign {Co, S} = A + B + Ci;
endmodule

これで完成.見ての通りめちゃくちゃ楽!実際に論理回路(=ハードウェア)を作りたくなったら,専用のソフトウェアがこのコードからさっきの回路図を自動生成して(これを回路をコンパイルするという),さらにその回路図をFPGA上に実装する際に入力するための電気信号も自動で用意してくれる.

開発に使用した開発ボードとソフトウェア


DE10-Nano

https://www.terasic.com.tw/cgi-bin/page/archive.pl?Language=English&No=1046 より.

このボードにはFPGAだけでなくSoC(CPUやRAMがセットになったもの)やNIC,microUSB等が搭載されており,ボード上で組み込み用LinuxディストリビューションのAngstrom Linuxが動作する.ラズパイと同じくSDカードをストレージとして用いる.

Intel® Quartus® Prime Lite Edition & ModelSim 

ハードウェア記述言語で書いた回路を回路図に変換したり,それがきちんと動くかシミュレーションを行ったり,完成した回路をmicroUSBケーブル経由で開発ボードのFPGAに書き込んだりできる開発用ソフトウェア群.学生個人個人が所有するPCを開発PCとして,これらのソフトウェアをインストールして開発を行う.

各回の授業内容

第1回~第2回

最初の2回は工学院大学の先生や現場で実際に開発を行っているエンジニアの方が来て講義をしてくださった.ハードウェア何もわからん状態で聞いたので正直30%くらいしか理解できなかったけど,ハードウェア開発は実際の電気信号レベルで気にすることがいろいろありとても大変だということは分かった.

第3回

この日に初めてDE10-Nanoに触った.やっぱり最初はhello world,ということでC言語でhello worldを書いたのだが,プログラムを書くのに使う開発PCとDE10-NanoとではCPUのアーキテクチャが異なるため,開発PC上で普通にgccでコンパイルしたバイナリはDE10-Nano上では動作しない.よって,ソースコードをDE10-Nanoのアーキテクチャ用にコンパイルするための専用のコンパイラ(クロスコンパイラ)を用いてコンパイルする必要がある.出来上がったバイナリをDE10-NanoのSDカードにコピーし,DE10-Nano上で正しく動作することを確認した.

第4回

この回はFPGA開発の初回として,ひたすらスライドに載ってるコードを写す感じだった.作るのはクロックのライジングエッジごとに1ずつ加算する32ビットカウンタ回路で,このカウンタの出力の一部のビット列をDE10-Nano上の4つのLEDに表示する.
カウンタ部分のハードウェア記述はこんな感じになる.このハードウェア記述を元に,ライジングエッジを検出する機構やカウンタの値を保存するためのフリップフロップが必要な分だけ生成されて回路図が描かれる.

module simple_counter(
    input clock,
    output reg[31:0] counter_out
);
    always @ (posedge clock)
    begin
        counter_out <= counter_out + 1;
    end
endmodule

その後,入出力を設定してから回路をコンパイルし,それをボードに書き込んだ.回路が動き出し,LEDが正しくカウントアップした!

第5回

この回は論理回路のシミュレーション方法を学び,練習問題に取り組んだ.そもそもハードウェアはソフトウェアと違って動作時に中身がどう動いているかが見えないので,論理回路をFPGAに書き込む前にそれが想定通りに動作するか(入力に対する出力が期待通りになっているか)を開発PC上でテストして,問題ないことを確信してから書き込む必要がある.このためシミュレーションは必須であり,シミュレーションの方法を身につけることが後の自由開発で非常に大事だった.
練習問題はIntel公式のLab Exerciseをやった.ステートマシンの作成などの問題があるのだが,この時まではコードを写すのが中心だったためハードウェア記述言語を自力で書くことに慣れておらず,どう書けばいいのか全然分からなくて大変だった.

第6回

DE10-Nano上のCPUで動作するCプログラムから,同じくDE10-Nano上のFPGA上に実装したハードウェアにアクセスする方法を学んだ.やるべきことは大きく分けて3つで,

  • CPU側から値を受け取ってその値をLEDに出力するハードウェア(論理回路)をハードウェア記述言語で書いて,FPGA上に実装する

  • CPU側から上記のハードウェアにアクセスするために,ハードウェアをバスにスレーブとして接続する

  • CPU側から上記のハードウェアにアクセスする際に使用するハードウェアアドレスを求め,そのアドレスに値を書き込むCプログラムを作成する

となる.
ちなみにバスというのはCPUやRAM, SSDなどのI/O機器を接続するための経路のことで,バスに接続された被制御機器(スレーブ)たちはハードウェアアドレスによって区別される.また,複数の機器が同時にバスを使うことは出来ないので,複数のマスタが同時に信号を出すようなことがないように調停するためのバスプロトコルという規律があり,あらゆるハードウェアはこの規律に準拠するように実装されていなければならない.
今回作ったハードウェアは下の図で赤く示した部分で,このようなI/O機器をProgrammable I/O, 略してPIOと呼ぶらしい.

授業のレポート用に作った図

PIOをハードウェア記述言語で書き,これをバスに接続するためにPlatform Designerというソフトウェアを用いて様々な設定を行い,回路全体のコンパイルを行ってFPGAに書き込む.最後に,PIOのハードウェアアドレスを求めてそのアドレスに値を書き込むCプログラムを書き,これをDE10-Nano上で動作させるとDE10-Nano上のLEDが点灯した.

なるほど,これでCPU-FPGA間の連携方法が分かった!というようなことは全く無かった.
というのも,PIOのハードウェア記述はMoodleからダウンロードしたものをそのまま使用しており,Platform Designerによる設定方法もスライドの真似をしただけ,Cプログラムもスライド上のものを写しただけだった.何と言うか,開発をしているというよりも「よくわからないハードウェア記述をダウンロードしてきて,知らない用語であふれた設定画面をよく分からずにポチポチして,よくわからない関数まみれのCプログラムを写す」という感じで,内容はほぼ何も理解できていなかった.
このあたりから,K先生が初回で言っていた「ハードウェア記述言語の文法に関する説明や,細かい用語・ツールの使い方に関する説明はしません.自助努力で対処して下さい.」という言葉が重くのしかかるようになってきた…

第7回

この回では,CPUとI2Cで接続されたDE10-Nano上の加速度センサによって計測した値を元に,第6回で実装したハードウェアを用いてDE10-Nano上のLEDを光らせるプログラムを作成した.センサの値を読むのは難しそうだな〜と思ったものの,/dev 配下に用意されたデバイスファイルをreadシステムコールを使って読み,出てきた値を事前に定義された構造体に入れればいいだけだったので結構簡単だった.

第8回

なんもわからん,という言葉はIoTシステム設計第8回のためにあるんじゃないだろうか.
この回はDE10-Nano上のスイッチを操作したときに起こる割り込みを受け付けるデバイスドライバを開発するということだった.デバイスドライバというのはハードウェアとソフトウェアを繋いでくれるもので,もう少し言うとハードウェアの機能をOSからAPIとして利用できるようにするソフトウェア.
LinuxカーネルをMoodleからダウンロードしてきてカーネルをビルドするところから授業が始まった.その後,コンピュータに接続されたデバイスたちの構成を記述するDevice-treeというものを書いた.
次に割り込みを受け付けるデバイスドライバ本体を作った.ここについては今でも何も分かっていないので書くことがない.まあスライドを写してただけだしね.デバイスドライバをビルドするとカーネルモジュールというやつが出来た.
最後にFPGAに回路を書き込んでカーネルモジュールを読み込み,スイッチを動かすとカーネルに割り込みが通知された.全体を通してよくわからなかった.

第9回

さあ準備は整った!ハードウェア開発の海へ繰り出そう!って正気か?
ということで,ペアと一緒に第11~13回で開発するシステムを考えた.K先生の「ハードウェア・ソフトウェア両方にまたがるおもしろいシステムを作ってください」という注文に応えて,自分の班は画像に対してフィルタをかけるシステムを開発することにした.画像のエッジ抽出等のフィルタリング処理はハードウェアで行いやすいと聞いたことがあったし.
第10回は企画案を班ごとにみんなの前でプレゼンするとのことだったので,そのためのスライド資料を作成した.

第10回

それだとFPGA使わなくてもできちゃうよね?もうちょっと面白くしてほしいなあ.

K先生,52-201にて

班ごとに企画案を発表したのだが,先生の指摘が容赦なさすぎてすごかった.Linuxカーネル開発は当然やったことあるよねみたいなノリで話してくるので質疑応答が大変だった.自分の班もいろいろと指摘をされたが,フィルタシステムという構想自体は良いと思うと言って頂いたので安心して(技術的には不安要素しかなかったが)開発に取り掛かった.

第11回

自分たちは画像を扱うシステムを作る予定だったので,画像中の各画素をFPGAに送る際の転送速度を出来るだけ速くしたいという要求があった.第10回の発表時には第6回で扱ったPIOを使って画素を送りますと言ったのだが,この方式だとあまりにも遅すぎて話にならないらしく,DMAを使うと良いとの提案を頂いた.ちなみにDMAとは,CPUではなくDMAコントローラというデータコピー専用機器を使ってRAMからFPGAへ高速にデータを転送する方式である.
とは言うものの自分はDMAコントローラの制御方法を全く知らなかったので,まずDE10-Nanoに搭載されているDMAコントローラの公式仕様書を読み,コントローラのドライバを自力実装するのは大変そうだと分かると既存の資産が活用できないかとGitHubを探し回った.
いろいろ調べたところ,DE10-Nanoと同じDMAコントローラを搭載したDE0-SoCという別種のボード用のドライバが見つかった.このドライバのソースコードを情報理工学科のK君(フーリエ変換を高速に行うシステムを作成するために自分たちと同じくDMAを利用したいと思っていた)と一緒に改造し,DE10-Nano用に対応させて動作テストを成功させた.

第12回

今までの授業内容を理解できていないせいでさすがに苦しくなってきたので,大学の行き帰りの電車内等の空き時間を見つけてはいつでもどこでもIntelの公式ドキュメントを読んでいた.それに加えて先人たちの膨大な数のブログを見るうちにハードウェア記述言語の書き方とか動作タイミングの調整方法がだんだん分かってきて,第12回までに

  • 画像をグレースケールに変換するハードウェア

  • 画像に対してフィルタをかけた値を計算するハードウェア

の実装を完了でき,シミュレーションによる論理検証も完了した.

第13回

第6回の授業を参考にしながら,自作のハードウェアをバスに正しく接続する方法をひたすら調べた.Avalon® Memory-Mappedインターフェイスの仕様書は何回読んだか分からないくらい読んだ.(この頃にようやく今までの授業で何をやったのかを他人に説明できるようになった.)接続方法をおおよそ理解したあと,実際に自作のハードウェア群をバスにつなぎ,CPU側から書き込んだテスト入力が適切に計算されて返ってきた時は本当に本当に嬉しかった.
一方,ペアのH君はCプログラムを書いてくれた.Cプログラムの動作は,読み込んだ画像をFPGAにDMA転送してフィルタリング処理をさせ,FPGAの処理結果を新しい画像として保存するというもの.
いざ,これを実行してみると,左側の画像の入力に対して右側の画像が返ってきた!!嬉しすぎて深夜に自室で踊ってた.

左が入力画像で,右がハードウェアによるエッジ抽出フィルタを適用した後の画像

その後,DE10-Nanoにはディスプレイがないからこれだと出来上がった画像を見るためにいちいちscpで開発用PCに画像を送らなきゃいけなくて面倒だよね,ということでPythonとHTML, Javascriptを使って超シンプルなAPIサーバとAPIクライアントを作った.これは結構すぐ出来た.ハードウェアじゃないからね.

第14回~第15回

各班が最終成果物を発表した.このときに知ったことだが,企画案が完成しなかった場合は減点されていたらしい.恐ろしや…
自分たちの班の発表資料を載せておく.スピーカーノートに解説がある.
発表の感想は,本番でデモがちゃんと動いて安心した,ということに尽きる.一般にデモは発表本番だけ動かないので.

授業で出る課題

最初の招待講義では次の週までにリアクションペーパーを提出.実習が始まってからは毎週レポートを提出する(1~2ページで作業内容と考察を報告する)

授業を終えて

この授業は全体を通して
スライドを読んで真似しているだけでは細かいことは何も分からず,とにかく自分でたくさん調べて理解するしかない
という感じだった.というか先生は最初にそう断っていたので,本当に言われたとおりだった,という表現が正しいかもしれない.これに気づくまでにだいぶ時間がかかってしまった.
入学以来で間違いなく最も大変な授業だったが,先生は聞かれた質問には答えてくださったし,何よりハードウェア開発に関する知識が半年前の自分の何十倍にもなったので得たものは大きかった.ハードに興味あるけど手を出せてないなと思っていて,かつ分からないことは頑張って調べるぞという気概のある人にはとてもおすすめです.

この記事が気に入ったらサポートをしてみませんか?