lp6m’s blog

いろいろかきます

FPGAデザインコンテスト@FPT2018 開発記

FPGAデザインコンテスト@FPT2018 開発記

はじめに

この記事はFPGA Advent Calendar 15日目の記事です。
先日FPT2018にて行われたFPGAデザインコンテストに参加しました。
FPGA搭載の自動運転ロボットが、決められたコースを走りながらいくつかの課題(障害物回避・信号検知・人間検知)をこなすといった内容のものでした。
FPGAボードに搭載されているハードマクロCPUの使用は認められています。外部との通信が完全に禁止されているのですべての判断・計算をロボットに搭載されたシステムで行う必要があり、効率的なシステムを構築する必要があります。
第8回 相磯秀夫杯 FPGAデザインコンテスト

大学院の同じ研究室の友人と2人で参加し、なんとか優勝することができました。
ここではその開発記・自分が担当した実装の内容について記録したいと思います。
友人とは完全に分業制で開発を行ったため、自動運転システムの進捗は全くわかりません。
まずは走行の様子の動画です。障害物の回避・信号の検知に成功しています。途中でコースアウトしてしまったのが残念・・

ZytleBot 本戦

時系列と、信号検出の詳細について紹介します。
だらだら書いてたらだいぶ長くなってしまいました・・ブログってもっと完結に書いたほうがいいのかな、
自分が作ったものはココにおいてます。全く整理していないので整理していきます・・
github.com

時系列

5月・6月

コンテストの存在を知る

7月

  • コンテストに参加したいと指導教員に伝えて、ZYBO + TurtleBot3を使用することを決めた

(研究室にTurtleBot3が存在したから選んだだけ)

  • ココの記事を参考にZYBOにUbuntu OSを搭載した

aster-ism.hatenablog.com

  • PetaLinuxのカーネル設定でWebカメラやTurtleBotに搭載されているOpenCRへの接続ができるようになった
  • ZYBOのUSB Host電源供給に苦しむ

( USBの端子が2つある8ポートハブの片方をZYBOに、もう片方をモバイルバッテリーに接続することで無理矢理電源を安定させている)
USB2.0ハブ 8ポートタイプ|株式会社バッファロー BUFFALO

8月

  • 那覇で行われたワークショップに参加:他のチームの進捗を見た
  • ZYBOにMIPI接続するPCam 5Cカメラの画像をUbuntuから取得するのに苦戦する→1ヶ月かけてなんとか成功

lp6m.hatenablog.com

 (デバイスドライバソースコードを読んだり、デバイスツリーについて勉強した)

  • 画像が取得できるようになり、自動運転SWの開発を完全にチームメイトに丸投げする

  大学の地下室のコース設置なども丸投げしてしまって申し訳なかった

 FPGA向けHalideコンパイラの開発に参加・多くのことを学んだ

9月

  • 慶応大学日吉キャンパスにて国内大会が開かれる。

  カメラ画像の取得以外は完全にSWで頑張っている状態で3位入賞。自分の貢献はほぼゼロ。
1位で優勝したチームが圧倒的強く、FPGAをうまく活用していることに憧れる、Twitterで交流する

10月

  • あと2ヶ月しかないという状況のなかFPTに向けて開発開始
  • PCamで取得した画像をFPGAで処理してからCPUに転送しようとしていろいろやってみる。
  • 結局1ヶ月かかって失敗(現在も未解決)

lp6m.hatenablog.com

10月末〜11月

あと1ヶ月で何ができるかを考えた
方針は、

  • むやみやたらに挑戦せず、頑張れば出来そうなラインをみつけて頑張る
  • 実装が公開されているものを探しまくってパクる・ひたすらググる
  • 必ず1ヶ月で完成させる、妥協するところは妥協する

信号検出ならなんとかなりそうということになり、信号の検出を目指すことに。
とりあえず3Dプリンタを購入してもらったので信号機を作った。


「ゼロから作るディープラーニング」を斜め読みして、「無理」となったので、ディープラーニング以外の機械学習アルゴリズムで、実装を完全に理解してフルスクラッチで実装できるアルゴリズムを探した。

以下の記事を参考にした。ありがとうございます。。
HOG特徴量とSVMを使った自動車の検出 - くーろんログ
画像からHOG特徴量の抽出 - Qiita
ランダムフォレストとSVMの使い分け - 静かなる名辞
ランダムフォレストのつくりかた(C++の実装例つき) - じじいのプログラミング

ZYBOにMIPI経由で接続されているPCamとは別にWebカメラを取り付けて、Webカメラから取得した画像から信号を検出する。
PCamは下向き、Webカメラは上向きに取り付けた。
f:id:lp6m:20181216185054j:plain:w500

次に実装が落ちているものを探した。以下のリポジトリにたどり着いた。
HOG+SVMによる人間検出 on Zedboard
GitHub - nikkatsa7/HOG_Zedboard: A real time Histogram of Oriented Gradients Implementation on FPGA
Real time HOG implementation on Zedboard - Xilinx XOHW18-222 - YouTube
 ・こちらはXilinxのコンペで優勝したらしい
 ・LinuxからAXI4/AXI-Lite経由でHLS IPを使う実装が公開されているので採用
 ・実はこのHOGのHLS実装が間違っていることに後々気づく
Python scikit-learnでRFによる車の検出
GitHub - t-lanigan/vehicle-detection-and-tracking: Detecting vehicles in a video stream using machine learning. Adds on to lane detection project.
 ・scikit-learnなんて使ったことないけどとりあえず実装が落ちていたので採用
この2つを参考に信号検出器を作成した。どうにか1ヶ月で完成させないといけなかったのでスケジュール管理したりしていた。
f:id:lp6m:20181216165203j:plain:w450

HOG特徴量とRFを使った信号検出器の作成

結局やったことは①と②の実装を組み合わせただけなんですが、、、まあ何をやったか書いていきます。

ランダムフォレスト・物体認識の仕組みの理解

まずは、②のソースコードやRFに関する記事を読んで、何をやっているのかを理解した。
(たぶん当たり前すぎて今更な内容なのでしょうが、恥ずかしながらそれすら知りませんでした。学部でこんな勉強したっけ・・?自分にとっては初めてだったので、まとめておきます。)

・学習
信号の画像(32x64)→特徴量の抽出(画素・ヒストグラムHOG) → RFの決定木を作成
f:id:lp6m:20181216173851p:plain:w700
・推論
カメラから取得した画像 → ウインドウをずらしながら画像を切り取り → 切り取った画像それぞれに対して → 特徴量の抽出(画素・ヒストグラムHOG) → RFによる認識
f:id:lp6m:20181216180447p:plain:w700
RFについての詳しい説明は省略しますが、いっぱい推論してくれる木が複数あって、
特徴量は1次元の配列に格納され、それぞれのif文の木をたどると(赤信号のサンプル数、赤信号以外のサンプル数)が得られます。

特徴量抽出・RF推論器のフルスクラッチ実装

②の実装において特徴量の抽出はscikit-learnとnumpyを使うことで数行で実現されている。
ライブラリのソースコードを読んでC++へ移植。scikit-learnのHOGC++でそのまま実装すると大変な行数になった。
https://gist.github.com/lp6m/349948c876bf1b80abe06bb9bfaed37a#file-hog-cpp

RF推論器のフルスクラッチ実装は簡単で、Scikit-learnで学習したモデルのを再帰的に辿ることで、if文の木を作成できる。というかほぼ答えみたいなのがあった
stackoverflow.com

フルスクラッチ実装ができたことで、Pythonとscikit-learnを用いて学習させ、学習モデルをC++コード化してC++から利用することができるようになった。

ちなみに、本来は抽出した特徴量に対する正規化を行ってから、RFに推論させるが、正規化処理はそれぞれの特徴量の配列要素に対して独立した計算なので、RFのif文の中のしきい値を逆正規化することで、推論時の正規化処理を省略している。

学習用画像作成ツール・学習済みモデルテスト用ツールの作成

・32x64の画像を学習用に大量に作成する必要があり、撮影した動画から生成した連番画像から信号の部分を手作業で切り抜く必要があった
・自分用にツールを作ったほうが早かったのでTkinterを使って作成
Python + Tkinterで連番画像ファイルを素早く切り抜くGUI画像トリミングツール - Qiita
・これを応用して、学習済みモデルを簡単に試すためのツールも後に作成した。(左下に赤信号である確率が表示される)
わりと外乱があっても精度がでていることがわかる。
f:id:lp6m:20181216174153g:plain:w500

ZYBO用にHOG計算の簡単実装・HLS実装

C++で実装したリアルタイム信号検出器をZYBOのCPUで動作させると1フレームにつき1.5secほどかかってしまった。主にHOG特徴量の抽出が非常に重たかった。(sqrtしたりatanしてるので当たり前)
そこで①の実装を参考にする。ユークリッド距離の計算・ヒストグラム正規化を簡略化したりatanのテーブルをLUTに持たせることで高速化していることを参考にする。
ただ、この実装をそのままパクって使うと、SWでの計算結果と実際にFPGAインプリメントした際のHWの計算結果が異なった。
理由はVivado HLSにおけるpragmaにあった。`#pragma HLS DEPENDENCE inter false`で配列インデックスへに対するループ依存がないことを高位合成ツールに伝えてパイプライン化を実現しているが、実際にはループ依存が存在する。
ただしこのpragmaを外すとレイテンシが大きいHWが生成されて頭を抱えた。

ふとインターンでやったラインバッファのことを思い出して、「HOG LineBuffer FPGA」で検索をかけたところ、以下の論文アーカイブ(?)に到達した。
(https://arxiv.org/ftp/arxiv/papers/1802/1802.02187.pdf)[A High-Performance HOG Extractor on FPGA]
各画素のgradientを計算する際に4近傍の画素の情報が必要になるが、ラインバッファで縦=3, 横=画像の幅=64の画素をもっておくことでループ内での画素読み込み(ブロックRAMからの読み込み)が1回で済む。
これを参考に、ラインバッファを使用したHOG特徴量抽出HLSコードを作成。レイテンシも短く、SWとHWで結果が一致するHLSコアが完成した!
■参考にしたリポジトリのHLSコード:ラインバッファなし
HOG_Zedboard/hog.cpp at master · nikkatsa7/HOG_Zedboard · GitHub
■実装したHLSコード:ラインバッファあり
ImageDetectionHW/main.cpp at master · lp6m/ImageDetectionHW · GitHub
比較すると、画素情報が格納されている`image_buffer`へのアクセス(=ブロックRAMへのアクセス)がループ内で1回で済んでいることがわかる。

↓これはなんかHLS実装してたときのメモ
f:id:lp6m:20181216181517p:plain:w500

FPGAへの実装・Linuxからの利用

作成したHLS IPコアは1枚の画像のHOG特徴量を計算してくれるコアなので、ウインドウが300個あるときは300回HLS IPコアを実行する必要がある。
Vivado上でHLS IPを4つならべて、4つの画像のHOG特徴量を同時に計算してくれるようにした。
f:id:lp6m:20181216182825p:plain:w500
LinuxからUIOを用いてHLS IPを利用するにあたっては①の実装を丸パクリさせていただいた。ありがとうございます。。。

結果的にSWで計算するよりも5,6倍高速になり、ZYBO上で12〜15fpsの信号検出を達成した。FPGAを活用したといえる(?)状態にはなった。

完成したものを友人に投げて、自動運転システムに組み込んでもらった。

おわりに

なんとか1ヶ月でFPGAを活用した信号検出プログラムを作成することができた。
画像認識や機械学習も初めてで、HLSツールもまともに使ったことがなかったのでなかなか頑張ったとは思っている。
開発中は、コースの整備やロボット本体の作成などに予想外に時間を取られた。
開発記には書いてないが、OpenCVを使ってカメラ画像を取得するとCPU使用率が非常に高くなったのでV4L2 APIをゴリゴリ叩いてカメラ画像を取得したりしている。
そういった絶妙なハマりポイントに陥りまくった。
手元のPCでは余裕で30fpsで信号を検出できるのにZYBOで実行したら1.5fpsとかになったりして、エッジデバイスの弱さを実感した。

通信プロトコルがAXI4/AXI4-LiteなのでCPUが通信を制御する必要があり、結局SW/HW間の通信がボトルネックになっているのが残念。
AXI-Streamプロトコルを使ってDMA転送することでもっとCPUの負荷を減らせるとは思う。DMAをLinuxから使えるようになりたい。
使えるようになったらブログにまとめたいと思う。

まだまだ課題もあるが、コンテストのおかげで色々と勉強することができた。
Twitter等で助言を頂いた方々、ありがとうございました。

Ubuntu on ZYBO Z7-20からFPGAで画像処理したPCam 5Cの映像をV4L2デバイスの映像として取得したい(失敗)

タイトルが随分ながくなってしまった。
前回Ubuntu on ZYBO Z7-20からPCam 5Cの映像を取得したい(成功) - lp6m’s blogでは、PCam 5CカメラをV4L2デバイスとして認識させ、画像を取得することができた。
せっかくMIPI経由でFPGA側に画像の信号があるので、HLSコアを用いて画像処理することはできないかと思った。
FPGAで画像処理しているカメラの画像がV4L2デバイスとしてOSに認識されて、簡単に画像取得できるとたぶんかなり嬉しい。
途中まで成功して、途中からは失敗したのでとりあえずログをまとめる。

やりたいこと

やりたいことの概略図は以下のようになる。
f:id:lp6m:20181022155350j:plain
元々のプロジェクトのFrame Buffer Write IPをVDMAに差し替えて、HLSコアを挿入するだけ。
元々のプロジェクトではYUYV形式でAXI4-StreamのDataWidthは16bit。
とりあえず情報を8bitに落とすHLSコアをつくって、1画素あたり8bitの情報を転送したい。

元のVivadoプロジェクトの確認

※元プロジェクトにはMIPI CSI2RX Subsystem IPが含まれており、LogiCore IPライセンスがないと合成やビットストリーム出力をすることができません。

1. DigilentgithubリポジトリGitHub - Digilent/Zybo-Z7-20-base-linuxからgit cloneする。

repo/vivado-libraryがgit submoduleになっている。回路で使用されているコアが別リポジトリに含まれており必要なので、以下コマンドでサブモジュールごとcloneする

git clone --recursive https://github.com/Digilent/Zybo-Z7-20-base-linux

Tools->Report->Report IP StatusからIP情報を更新、合成を行ってビットストリーム生成に成功することを確認。

Frame Buffer Write IPをVDMA IPに差し替え(ここまでは成功)

Vivado側の作業

元の回路にはFrame Buffer Write IPとよばれるIPが使われている。決まったビデオフォーマットにのSS2M(AXI4-Stream -> Memory Mapped)書き込みに特化したIPらしい。
Frame Buffer Write IPのフォーマットを変更してもDataWidthが8bitのフォーマットはなかったので、これをVDMAに差し替えて好きなデータ幅の転送ができるようにする。
とりあえずHLSコアを入れずに、VDMAに差し替えるだけを行う。
f:id:lp6m:20181022161304p:plain
axis_subset_converter_0とv_frmbuf_wr_0を削除して、VDMAを挿入
f:id:lp6m:20181022162054p:plain
この状態で合成・ビットストリーム生成を行う。
Export Hardwareを行い、Petalinuxプロジェクトにコピー。

Petalinuxプロジェクト側の作業

petalinux-config --get-hw-description <.hdfのあるディレクトリ>

HW情報をpetalinuxに読みこませる。
次にデバイスツリー(system_user.dtsi)を書き換える。FrameBuffer Write IPに対応する部分をコメントアウトして、amba_pl/video_capで指定しているDMAをFrameBuffer Write IPからVDMA IPに変更。
オリジナルとのdiffを載せておく。

10c10
< 		bootargs = "console=ttyPS0,115200 earlyprintk uio_pdrv_genirq.of_id=generic-uio root=/dev/mmcblk0p2 rw rootwait";
---
> 		bootargs = "console=ttyPS0,115200 earlyprintk uio_pdrv_genirq.of_id=generic-uio";
264c264
< /*&v_frmbuf_wr_0 {
---
> &v_frmbuf_wr_0 {
273c273
< };*/
---
> };
278c278
< 		dmas = <&axi_vdma_2 0>;
---
> 		dmas = <&v_frmbuf_wr_0 0>;
335,336d334
< 
<

これでPetalinuxのプロジェクトをビルドする。

petalinux-build

ここまでやってpetalinux-buildすると以前作成したカメラ画像取得プログラムが正常に動作した。

HLSコアの作成

YUYV16bitでは、1画素の情報は「YとU」あるいは「YとV」である(UとVは2画素に1つしか情報がなく、軽量)。いずれの場合もはじめの8bitを取り出す、すなわちYの値だけをとりだすコアを作成する。
Vivado HLSで1画素ずつの処理を行うサンプルが以下で公開されているので、それを参考にさせていただく。
github.com
yuyvyというモジュールを作成した。また、axiliteプロトコルしきい値を設定するといったことも将来的に行いたいので、char型のしきい値を入力として受けるようにした。
作成したコアのコードは以下リンク。
Extract Y 8bit data from YUYV 16bit data. · GitHub
実際に計算を行っているのは59行目の以下の部分だけ。YUYVからYの値を取り出して、valとのmaxを結果とする。特に意味はない。
コードの大部分はTLASTやTUSERなどの信号を扱うためのコード。解説されると簡単だけと自分で書くのは難しい・・

axis_writer.data = std::max((int)((axis_reader.data & 0xFF00) >> 8), (int)val);

高位合成の結果は以下の通りになった。まだ未熟で見方がわかってないが、特に問題はないらしい。。?
f:id:lp6m:20181022164438p:plain
Export RTLでIPとしてエクスポートを行った。

HLSコアを回路に挿入

Vivadoプロジェクトに戻り、IP CatalogにエクスポートしたHLS IPコアを追加する。
回路にHLS IPコアを挿入。
f:id:lp6m:20181022165240p:plain
HLSコアはs_axiliteプロトコルの入力があるので、メモリマップする必要がある。Address Editorでアドレスを割り当てる。
とりあえず、0x43c80000から64K割り当てた。
f:id:lp6m:20181022174510p:plain
この状態で合成・ビットストリーム生成を行う。
Export Hardwareを行い、Petalinuxプロジェクトにコピー。

Petalinuxプロジェクトの編集

先ほどと同様にpetalinux-config --get-hw-description <ディレクトリ>で新しい回路情報をプロジェクトにロードする。
ここから、Petalinuxプロジェクト側でデバイスツリーを書き換える。

Digilent Linux Kernelの話

注意しなければならないことが1つある。PetalinuxではLinuxカーネルの参照をgitリポジトリにすることができるのだが、
元のPetalinuxプロジェクトはDigilent Linux Kernelリポジトリの最新版ではなく、途中のコミットのものを参照している。
これを最新のものを参照するようにpetalinux-configで書き換えてしまうと動かなかった。
例えばMIPI CSI2RX Subsystemのデバドラは最新版使用しているPetalinuxが参照しているバージョンを見比べてみる。 旧版ではデバイスツリーのreset-gpioプロパティで指定したピンのリセットをxcsi2rxss_start_stream関数で行うが、最新版では行わない。
サンプルプロジェクトではMIPI CSI2RXSSのvideo_aresetnピンはGPIOに接続されており、これがリセットされないことでMIPI CSI2RXSSのSoft Resetがタイムアウトしてしまう。
(最新版のデバドラを使う場合は他の方法でvideo_aresetnをリセットしないといけなくなった)

まあ要は元々のままにしておけばいいのだけど、自分でカーネルをフォークする場合などは要注意。これで3日溶かした。

V4L2デバイスの話

HLSコアをV4L2のサブデバイスとして登録してくれるデバイスドライバxilinx-hls.cがDigilent Linux Kernelには存在する。
ソースコード
linux-digilent/xilinx-hls.c at 1496c680c6df2e3911feed13aa9663a851bf30e9 · Digilent/linux-digilent · GitHub
ドキュメント:
linux-digilent/xlnx,v-hls.txt at 1496c680c6df2e3911feed13aa9663a851bf30e9 · Digilent/linux-digilent · GitHub
これらを参考にして、デバイスツリーを編集する。

はじめの「やりたいこと」でも表している図の説明になるが、カメラ+画像処理がV4L2デバイス/dev/video0として認識されるのは、大体以下のような仕組み(のはずと理解したつもり・・・)

  • video_capが「xlnx,video」ドライバによって/dev/video0として認識される
  • xlnx,videoドライバはデバイスツリーで指定されている「エンドポイント」を辿って、サブデバイスを探す
  • PCam 5C、HLS IP、MIPI CSI2RX IPは各デバイスドライバによってV4L2サブデバイスとして登録される

 (各デバイスドライバは必要に応じてIPコアのリセットなどを適切に行ってくれる。ユーザアプリケーションはioctl()サービスコールを用いてドライバを呼び出すことができる)

バイスツリーの編集

バイスツリーの編集
そのまえに、Petalinuxで自動的に生成されるデバイスツリーをみる。(これはおそらくXilinx SDKで自動生成できるものと同じ)
petalinux-config --get-hw-descriptionでは回路に対応するデバイスツリーはなぜか生成されない。
とりあえずエラーがでてもいいので、petalinux-buildコマンドを叩くと回路に対応するデバイスツリーが更新される。
生成されるデバイスツリーは/components/plnx_workspace/device-tree/device-tree-generation/にある。pl.dtsiが回路に対応するデバイスツリー。
自動生成されたpl.dtsiを参考程度に貼っておく。
Dropbox - pl.dtsi
ユーザが記述するデバイスツリーsystem_user.dtsiはこの自動生成されたデバイスツリーに情報を付加・補完する形になっている。
それぞれのサブデバイスの接続情報がデバイスツリーにかかれているので、これらを編集する。
編集したデバイスツリーは以下。
Dropbox - system-user.dtsi
オリジナルのデバイスツリーとのdiffは以下の通り。

245c245
< 				remote-endpoint = <&hls0_in>;
---
> 				remote-endpoint = <&vcap_in>;
264c264
< /*&v_frmbuf_wr_0 {
---
> &v_frmbuf_wr_0 {
273c273
< };*/
---
> };
278c278
< 		dmas = <&axi_vdma_2 0>;
---
> 		dmas = <&v_frmbuf_wr_0 0>;
289,311d288
< 					remote-endpoint = <&hls0_out>;
< 				};
< 			};
< 		};
< 	};
< };
< 
< yuyvy_0: yuyvy@43c80000 {
< 		compatible = "xlnx,v-hls";
< 		reg = <0x43c80000 0x0024>, <0x43c80024 0xFFDC>;
< 		clocks = <&clkc 15>;
< 
< 		ports {
< 			#address-cells = <1>;
< 			#size-cells = <0>;
< 
< 			port@0 {
< 				reg = <0>;
< 
< 				xlnx,video-format = <XVIP_VF_YUV_422>;
< 				xlnx,video-width = <8>;
< 
< 				hls0_in: endpoint {
315,324d291
< 			port@1 {
< 				reg = <1>;
< 
< 				xlnx,video-format = <XVIP_VF_MONO_SENSOR>;
< 				xlnx,video-width = <8>;
< 
< 				hls0_out: endpoint {
< 					remote-endpoint = <&vcap_in>;
< 				};
< 			};
325a293
> 	};
367,368d334
< 
< 

HLS IPが1画素8bitのデータを出力する。これに相当するvideo-formatの値はXVIP_VF_MONO_SENSORのようだ。(UG934, 9ページ参照)

yuyvy_0: yuyvy@43c80000内のreg = <0x43c80000 0x0024>, <0x43c80024 0xFFDC>の意味がわからない。
ドキュメントによると

  • reg: Physical base address and length of the registers sets for the device.

The HLS core has two registers sets, the first one contains the core
standard registers and the second one contains the custom user registers.

らしいけど、standard registerとcustom user registerってなんのことだろう・・?とりあえずデフォルトの0x0024の範囲をstandard registerにしたけど。
HLS IPには64K割り当てたのでとりあえず合計0x100000になるようにした。

カーネルコンフィグの変更

元々のpetalinuxプロジェクトではHLS IPに対応するデバイスドライバが有効になっていない。

petalinux-config -c kernel

カーネルコンフィグを表示して、xlnx,hlsを有効(Build-In)にする。
f:id:lp6m:20181022175621p:plain

これでPetalinux側の作業も終わり。プロジェクトのビルドおよびFSBLとU-BOOTのビルドを行う。

petalinux-build 
petalinux-build -c fsbl
petalinux-build -c u-boot

BOOT.BINの作成

以下コマンドでBOOT.BINを作成する。

petalinux-package --boot --fsbl images/linux/zynq_fsbl.elf --fpga <bitファイルのパス> --u-boot --force

起動およびデバイス認識の確認

これまでどおりSDカードのFATでフォーマットした第1パーティションにimage.ubとBOOT.BINを,第2パーティションUbuntuのrootfsを入れる。
PCam 5Cを接続し、/dev/media0と/dev/video0が見えていればとりあえずデバイスドライバが正常にデバイスを登録できていることが確認できる。。

Ubuntuにはsudo apt-get install v4l-utilsでV4L-Utilsをインストールしておく。
ログイン後、sudo su -コマンドでスーパユーザに切り替えてから、V4L2サブデバイスのフォーマットの設定を行う。(本家と同じコマンド)

root@arm:~#
width=1920
height=1080
rate=15
media-ctl -d /dev/media0 -V '"ov5640 2-003c":0 [fmt:UYVY/'"$width"x"$height"'@1/'"$rate"' field:none]'
media-ctl -d /dev/media0 -V '"43c60000.mipi_csi2_rx_subsystem":0 [fmt:UYVY/'"$width"x"$height"' field:none]'

このコマンドで、デバイスツリーでフォーマットを指定していていなかった情報をセットしている。
V4L2デバイスが正しく認識、かつ正しくパラメータがセットされていることを以下のコマンドで確認する。

root@arm:~# media-ctl -p /dev/video0
Media controller API version 4.9.0

Media device information
------------------------
driver          xilinx-video
model           Xilinx Video Composite Device
serial          
bus info        
hw revision     0x0
driver version  4.9.0

Device topology
- entity 1: video_cap output 0 (1 pad, 1 link)
            type Node subtype V4L flags 0
            device node name /dev/video0
	pad0: Sink
		<- "43c80000.yuyvy":1 [ENABLED]

- entity 5: ov5640 2-003c (1 pad, 1 link)
            type V4L2 subdev subtype Sensor flags 0
            device node name /dev/v4l-subdev0
	pad0: Source
		[fmt:UYVY/1920x1080 field:none]
		-> "43c60000.mipi_csi2_rx_subsystem":1 [ENABLED]

- entity 7: 43c80000.yuyvy (2 pads, 2 links)
            type V4L2 subdev subtype Unknown flags 0
            device node name /dev/v4l-subdev1
	pad0: Sink
		[fmt:UYVY/1920x1080 field:none]
		<- "43c60000.mipi_csi2_rx_subsystem":0 [ENABLED]
	pad1: Source
		[fmt:Y8/1920x1080 field:none]
		-> "video_cap output 0":0 [ENABLED]

- entity 10: 43c60000.mipi_csi2_rx_subsystem (2 pads, 2 links)
             type V4L2 subdev subtype Unknown flags 0
             device node name /dev/v4l-subdev2
	pad0: Source
		[fmt:UYVY/1920x1080 field:none]
		-> "43c80000.yuyvy":0 [ENABLED]
	pad1: Sink
		[fmt:UYVY/1920x1080 field:none]
		<- "ov5640 2-003c":0 [ENABLED]

登録は成功しているようだ。特にHLS IPである43c80000.yuyvyのSourceのフォーマットは[fmt:Y8]となっており、1画素のデータが8bitのデータが出力されるということが登録されている。

カメラ撮影プログラムの修正

カメラ撮影プログラムは以前作成したプログラムを元に作成する。
HLSコアにはs_axilite経由の入力値があるので、これをセットする必要がある。HLSコアは先ほどのコマンドで/dev/v4l-subdev1に認識されていることが確認できた。
VIvadoHLSでExport RTLを行うと、IPコアのためのドライバが出力される。(/solution1/impl/ip/drivers/yuyv_v1_0/src)
この中にあるxyuyv_hw.hは以下の通り。

// CONTROL_BUS
// 0x00 : reserved
// 0x04 : reserved
// 0x08 : reserved
// 0x0c : reserved
// 0x10 : Data signal of val_r
//        bit 7~0 - val_r[7:0] (Read/Write)
//        others  - reserved
// 0x14 : reserved
// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)

#define XYUYVY_CONTROL_BUS_ADDR_VAL_R_DATA 0x10
#define XYUYVY_CONTROL_BUS_BITS_VAL_R_DATA 8

ここから、物理アドレスの0x43c80000+オフセット0x10の位置に値を書き込めば、HLSコアの入力値valを設定できるということがわかる。
嬉しいことに、HLS IPのデバドラにはs_axilite経由の値をサービスコールを用いて書き込む機能がある。
xilinx-hls-common.hやxilinx-vip.hを含めてデバイスドライバソースコードを読んだところ。

struct buffer_addr_struct{
  void *start[FMT_NUM_PLANES];
  size_t length[FMT_NUM_PLANES];
} *buffers;


struct xilinx_axi_hls_register {
  __u32 offset;
  __u32 value;
};

struct xilinx_axi_hls_registers {
  __u32 num_regs;
  struct xilinx_axi_hls_register *regs;
};

#define XILINX_AXI_HLS_READ _IOWR('V', BASE_VIDIOC_PRIVATE+0, struct xilinx_axi_hls_registers)
#define XILINX_AXI_HLS_WRITE _IOW('V', BASE_VIDIOC_PRIVATE+1, struct xilinx_axi_hls_registers)

を記述しておき、

xilinx_axi_hls_register reg[1];
reg[0].offset = 0x10;
reg[0].value = 255;
xilinx_axi_hls_registers regs;
regs.num_regs = 1;
regs.regs = reg;
int fd2;
fd2 = open("/dev/v4l-subdev1", O_RDWR, 0);
if (fd2 == -1){
  std::cout << "Failed to open subvideo device." << std::endl;
  return 1;
}
if (-1 == xioctl(fd2, XILINX_AXI_HLS_WRITE, &regs)){
  std::cout << "Failed to set param via s_axilite" << std::endl;
  return 1;
}

を実行すれば値を書き込めそうだということがわかった。reg[0].offset = 0x10;の値は先程のxyuyv_hw.hを参考に設定した。

また、/dev/video0に設定するフォーマットは1画素8bitのフォーマットなので、

fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_GREY;

に変更する。

最終的に完成したプログラムのコードを以下に示す。
Dropbox - cam2.cc

実行・・失敗

実行してみたが、途中で止まってしまった。実行ログは以下の通り。

root@arm:/home/ubuntu# ./a.out
waiting in xioctl() 
waiting in xioctl() 
bus_info	: platform:video_cap:0
card		: video_cap output 0
driver	: xilinx-vipp
version	: 264448
waiting in xioctl() 
waiting in xioctl() 
reqbuf.count : 3
waiting in xioctl() 
buf.length : 1
buf.m.offset : 3196044192
buf.m.planes[j].length : 2073600
buffers[i].start[j] : 0xb6a9a000
waiting in xioctl() 
buf.length : 1
buf.m.offset : 3196044192
buf.m.planes[j].length : 2073600
buffers[i].start[j] : 0xb689f000
waiting in xioctl() 
buf.length : 1
buf.m.offset : 3196044192
buf.m.planes[j].length : 2073600
buffers[i].start[j] : 0xb66a4000
waiting in xioctl() 
waiting in xioctl()

具体的にはxioctl(fd, VIDIOC_STREAMON, &buf.type))を実行してカメラのキャプチャをスタートしようとすると、サービスコール呼び出しの実行がおわらず、待機状態になる。
バッファの確保はできているようだ。

わからないこと

  • なぜ取得できなかったのか・・

 いろいろ理由を考えているけど、わからない。

  • 前述のyuyvy_0: yuyvy@43c80000内のreg = <0x43c80000 0x0024>, <0x43c80024 0xFFDC>はどのように設定するのが正しいのか

この設定とカメラ取得プログラムのreg[0].offset = 0x10;は関係ありそう。デバイスドライバをもう少しきちんと読もう。

  • HLSコアはap_ctrl_noneになっているが、axilite経由の入力の値がセットされていない場合はどのように動作するのか?

デフォルト値(intなら0とか)が使用されるのかなと思っている。入力の値がセットされていないから計算が実行されない、なんていうことは多分ないと思っている。
(もしそうなら、カメラ取得プログラムで正しく入力値valが設定されていないせいでHLSの出力がでていない、というのも原因として考えられる。)
そうでないなら、axilite経由の値をうまくセットできていなかったとしても何らかの出力は出るのではないか・・?

  • Vivado上で配線にMark as Debugを設定し、ILAコアをいれた場合Linuxを動作したままHardware Manager上でILAデバッグができるのか?

これに関してはTwitter上でできるという話を聞いたが、やってみたが上手くいかない・・

  • タイミングの問題が原因?

これは見方をまだ理解していない。赤字なので何かヤバそう・間に合っていないとは思う。ただ、回路を変更する前から赤字はあった。値の変化はまだ確認していない。
f:id:lp6m:20181022215459p:plain


ブログが非常に長くなってしまった。何か原因として考えられることがあればご教示願います・・・

Ubuntu on ZYBO Z7-20からPCam 5Cの映像を取得したい(成功)

前回Ubuntu on ZYBO Z7-20からPCam 5Cの映像を取得したい(失敗) - lp6m’s blogの続き。成功したのでまとめておく。

やったこと

前回なぜかyavtaコマンドで画像の取得ができなかった。
Xilinx Forumに質問した。
Solved: Re: can't get image from PCam 5C on Ubuntu running... - Community Forums

どうやら以下のコマンドでは画像の取得ができた。なぜyavtaだとダメなのかは不明。

v4l2-ctl -d /dev/video0 --set-fmt-video=width=1920,height=1080,pixelformat=YUYV --stream-mmap --stream-count=1 --stream-to=test.raw

とりあえずこれで取得できるので、v4l2-ctlコマンドの実装を参考にC++コードを記述する。
コードは以下。
Get image from PCam 5C on Ubuntu running on ZYBO-Z7-20 · GitHub

Ubuntu on ZYBOでapt-get upgrade, apt-get update, apt-get install g++ gccしておく。
特に外部ライブラリを使用しないのでg++ cam.ccでビルドできる。PcamはUbuntu起動前に接続しておく。

以下のおまじないコマンドを叩く

sudo media-ctl -d /dev/media0 -V '"ov5640 2-003c":0 [fmt:UYVY/'1920x1080'@1/'15' field:none]'
sudo media-ctl -d /dev/media0 -V '"43c60000.mipi_csi2_rx_subsystem":0 [fmt:UYVY/'1920x1080' field:none]'
$ ./a.out
bus_info	: platform:video_cap:0
card		: video_cap output 0
driver	: xilinx-vipp
version	: 264448
reqbuf.count : 3
buf.length : 1
buf.m.offset : 3195409312
buf.m.planes[j].length : 4147200
buffers[i].start[j] : 0xb687e000
buf.length : 1
buf.m.offset : 3195409312
buf.m.planes[j].length : 4147200
buffers[i].start[j] : 0xb6489000
buf.length : 1
buf.m.offset : 3195409312
buf.m.planes[j].length : 4147200
buffers[i].start[j] : 0xb6094000
r : 0
store image in array....
write data...

画像が取得できた!
得られたYUYV形式のcamdata.datファイルは以下のPythonコードでpng画像に変換できる。
Convert Raw YUYV image from PCam 5C to png · GitHub

python test.py camdata.dat out.png

Pythonコード内のRGBへの変換が間違っているらしく、緑っぽい画像が出力されるかも・・)

勉強したこと

  • 上に書いたおまじないコマンドは何なのか

これは、V4L2 SubDeviceそれぞれに使用するフォーマットを教えている。SubDeviceに設定されたフォーマットは以下のコマンドで確認できる。

$media-ctl /dev/video0 -p
Media controller API version 4.9.0

Media device information
------------------------
driver          xilinx-video
model           Xilinx Video Composite Device
serial          
bus info        
hw revision     0x0
driver version  4.9.0

Device topology
- entity 1: video_cap output 0 (1 pad, 1 link)
            type Node subtype V4L flags 0
            device node name /dev/video0
	pad0: Sink
		<- "43c60000.mipi_csi2_rx_subsystem":0 [ENABLED]

- entity 5: ov5640 2-003c (1 pad, 1 link)
            type V4L2 subdev subtype Sensor flags 0
            device node name /dev/v4l-subdev0
	pad0: Source
		[fmt:UYVY/1920x1080 field:none]
		-> "43c60000.mipi_csi2_rx_subsystem":1 [ENABLED]

- entity 7: 43c60000.mipi_csi2_rx_subsystem (2 pads, 2 links)
            type V4L2 subdev subtype Unknown flags 0
            device node name /dev/v4l-subdev1
	pad0: Source
		[fmt:UYVY/1920x1080 field:none]
		-> "video_cap output 0":0 [ENABLED]
	pad1: Sink
		[fmt:UYVY/1920x1080 field:none]
		<- "ov5640 2-003c":0 [ENABLED]

V4L2 SubDevice参考:4.15. Sub-device Interface — Linux Media Subsystem Documentation documentation
きちんとPCam(OV5640) -> MIPI_CSI2_RX_SubSystem -> video_capにデータが流れるようになっていることがわかる。
この接続はPetaLinuxプロジェクトのデバイスツリー(project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi)内でremote-endpointで指定されている。
以下、system-user.dtsi一部抜粋

&axi_iic_0 {
	...
	ov5640: camera@3c {
		compatible = "ovti,ov5640";
		...
		port {
			ov5640_to_mipi_csi2: endpoint {
				remote-endpoint = <&mipi_csi2_from_ov5640>;
				...
			};
		};
	};
};

&amba_pl {
	video_cap {
		compatible = "xlnx,video";
		dmas = <&v_frmbuf_wr_0 0>;
		...
		ports {
			...
			port@0 {
				...
				vcap_in: endpoint {
					remote-endpoint = <&mipi_csi2_out>;
				};
			};
		};
	};
};


&mipi_csi2_rx_subsystem_0 {
	compatible = "xlnx,mipi-csi2-rx-subsystem-2.0";
	...
	ports {
		...

		port@0 {
			reg = <0>;
			xlnx,video-format = <XVIP_VF_YUV_422>;
			xlnx,video-width = <8>;
			mipi_csi2_out: endpoint {
				remote-endpoint = <&vcap_in>;
			};
		};
		port@1 {
			reg = <1>;
			xlnx,video-format = <XVIP_VF_YUV_422>;
			xlnx,video-width = <8>;
			mipi_csi2_from_ov5640: endpoint {
				...
				remote-endpoint = <&ov5640_to_mipi_csi2>;
			};

		};

	};
};	

これができたのが8月末。
第8回 相磯秀夫杯 FPGAデザインコンテストではこれを使用した。
FPGAでは何の画像処理も行っていない状態で、ソフトウェアに頑張らせた。

次はFrame Buffer Write IPをVDMAに置き換えて、HLSコアを挿入する。
VDMAに置き換えるところまでは昨日できた。
ブログが書くのが下手で、わかってる人しかわからない記事になってしまった気がするけど。。

Ubuntu on ZYBO Z7-20からPCam 5Cの映像を取得したい(失敗)

Digilent社製ZYBO Z7-20でUbuntuを動作させ、PCamの映像を取得したい。
store.digilentinc.com
store.digilentinc.com

git cloneしてサンプルを試す:成功

Petalinuxツールを使用してZYBO上で動作するLinuxカーネル・rootfsを作成することができる。
Digilentgithubにサンプルがあるのでこれをcloneする。
github.com

デフォルトではRAMにrootfsを展開する設定(initramfs)になっているので、githubのREADMEのBoot the newly built files from SDに書いてあるとおりに、SD Bootに変更・system-user.dtsi のbootargsを変更した。

第一パーティションカーネルとイメージ(BOOT.BIN・image.ub)をコピー
第二パーティションにROOTFSをコピー(images/linus/rootfs.tar.gzを展開)

起動確認、githubのREADMEに書いてあるとおりのコマンドでPCamからの映像を取得成功

width=1920
height=1080
rate=15
media-ctl -d /dev/media0 -V '"ov5640 2-003c":0 [fmt:UYVY/'"$width"x"$height"'@1/'"$rate"' field:none]'
media-ctl -d /dev/media0 -V '"43c60000.mipi_csi2_rx_subsystem":0 [fmt:UYVY/'"$width"x"$height"' field:none]'
v4l2-ctl -d /dev/video0 --set-fmt-video=width="$width",height="$height",pixelformat='YUYV'
yavta -c14 -f YUYV -s "$width"x"$height" -F /dev/video0

rootfsをUbuntuに変更

Petalinuxでビルドしたrootfsではapt-getなどのパッケージ管理システムを使用することができない。
ARM用にビルドされたUbuntuのrootfsをダウンロードしてarmhf-rootfs-ubuntu-xenial.tar を第二パーティションに展開
参考;ZYBO-Z7を用いたLチカ(Ubuntu16.04編) - aster_ismの工作室

wget https://rcn-ee.com/rootfs/eewiki/minfs/ubuntu-16.04.3-minimal-armhf-2017-10-07.tar.xz

Ubuntuの起動確認・必要なソフトウェアのインストール

Ubuntuの起動を確認。

v4l-utilsをインストール

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install v4l-utils

※電源が不安定になりapt-get upgrade中にボードが再起動することがあるので、補助電源をボードに接続する・電流が大きいものを使用するなどして対処

yavtaのインストール・yavtaはapt-getでは入らない

sudo apt-get install build-essential
git clone https://github.com/fastr/yavta
cd yavta
make

*画像取得(失敗)
sudoをつけた以下のコマンドを実行

width=1920
height=1080
rate=15
sudo media-ctl -d /dev/media0 -V '"ov5640 2-003c":0 [fmt:UYVY/'"$width"x"$height"'@1/'"$rate"' field:none]'
sudo media-ctl -d /dev/media0 -V '"43c60000.mipi_csi2_rx_subsystem":0 [fmt:UYVY/'"$width"x"$height"' field:none]'
v4l2-ctl -d /dev/video0 --set-fmt-video=width="$width",height="$height",pixelformat='YUYV'
./yavta/yavta -c14 -f YUYV -s "$width"x"$height" -F /dev/video0

yavtaを実行するとエラーが起きる。

Error opening device /dev/video0: neither video capture nor video output supported.

yavtaの実装を見て調べたところ、 yavta.cの121行目でioctl()を使ってデバイスの属性を取得した際にカメラの属性が取得できていない

原因究明

必要なドライバがロードされていないのでは?と思いdmesgやls /sys/moduleの結果を比較したが特に理由は見つからない・・・

また、petalinux-config -c kernelによるカーネルの設定でXilinx Video IPのドライバを、カーネルにビルトインする設定からモジュールに変更してみた。
ビルドしたpetalinuxのrootfsの/libフォルダ内に読み込むべきドライバが生成されるので、それらをubuntuの/libにコピーしてみた。しかし、同様にエラーでカメラの映像を取得することができない・・・

dmesgおよびls /sys/moduleの結果をpetalinuxのときとUbuntuのとき両方を貼っておく。

  • 成功したほうのdmesg

petalinux_dmesg.log · GitHub

  • 失敗したほうのdmesg

ubuntu_dmesg.log · GitHub

  • 成功したほうのls /sys/module

petalinux_sys_module.log · GitHub

  • 失敗したほうのls /sys/module

ubuntu_sys_module.log · GitHub

AR# 50826 『ブロックRAM から OCM へのキャッシュ コヒーレントの CDMA 転送 』を試した

HW関連の研究室でZynq All Programmable SoCを触っています。
正直Xilinxのマニュアルは難しすぎてよくわからない・・・体系的に学べるといいのだけれど。

オンチップメモリ(OCM)への書き込みをテストするために調べていたら、以下のページが見つかった。
japan.xilinx.com


今回はこれを試してみた。自分なりの解釈とかのメモを残す。

このアプリケーションは何か

このアプリケーションはBRAMの64箇所に0x01から0x40の値を、OCMの64箇所に0xCDの値をセットした後、CDMA(Central Direct Memory Access)を使用してBRAMからOCMへデータを送信する。送信後OCMの64箇所の値が0x01から0x40になっていれば成功。

CDMA

メモリマップされたアドレス間でデータの送受信を行うコントローラ。プロトコルはAXI4/AXI4-Liteが使用できる。

BRAM

FPGA上に配置することができるRAM。BRAM Generator IPがBRAM本体で、データの送受信はBRAM Controllerで動作させる。

OCM

256KBのオンチップメモリがPS上のAPU内に存在する。ACPポートは直接ここにつながっている?(よくわかっていない)

手順(いつものやつ。この本とかに詳しく書いています。)

1. プロジェクトをダウンロードしてVivadoで開いてビットストリーム生成
2. Export HardwareしてSDK(SDSoC)起動
3. File -> New -> Application Projectを選択、Hello Worldプロジェクトを作成し、添付されているhello_axi_cdma.cの内容をhelloworld.cにコピペ
4. Xilinx Toolsを開いてProgrammable FPGAを選択してビットストリーム書き込み
5. Build Allして実行用のelfファイル作成。右クリックしてRun As -> Launch On Hardware (System Debugger)を選択。
6. TeraTermなどから出力を確認(ポートレート115200に設定)

これで動けばよかったのだけど動かなかった。OCMの値全てが0xCDのままになっていた。

修正箇所

結論から言えば、サンプルソースの53行目を

Xil_SetTlbAttributes(0xFFF00000,0x14c0e);

から

Xil_SetTlbAttributes(0xFFF00000,0x14de2);

に修正。
 あるいは、Xil_SetTlbAttributes(0xFFF00000,0x14c0e);をコメントアウトし、
CDMAによる転送が終了した後の121行目などに、

Xil_DCacheInvalidateRange(dstCPU, 64*8);

を挿入。

Xil_SetTlbAttributesとは何か

色々調べてみると、TRM(テクニカルリファレンスマニュアル)UG585の73ページ図3-5にページエントリのフォーマットが書いてある。
またココによると図のSectionの欄が空欄になっているけどSuperSectionと同じらしい。
TEX[2:0], C, Bなどのビットが大切らしい。DomainとかXNとかnGは謎パラメタ・・・

Xil_SetTlbAttributesはキャッシュのポリシーなどを変更するための関数であるということがわかった。
0x14c0eは2進表記で0001_0100_1100_0000_1110 C=1 B=1 キャッシュ属性は「ライトバック、書き込み割り当てなし」
これだとキャッシュが有効になっているのでCDMAが成功していてもアプリケーションは古い値を参照してしまう。
0x14de2は2進表記で0001_0100_1101_1110_0010 C=0 B=0 キャッシュ属性は「キャッシュ不可」
キャッシュを切ることによってアプリケーションは正しい値を参照することができる。

CDMAやDMAを使用したとき、古い値を参照しないように気を付ける必要があるらしい。
DMAを使用したときは Xil_SetTlbAttributesなんて使っていなかったなと思って、Xil_DCacheInvalidateRangeを試したところ、これでもOKだった。
この関数だと、指定したアドレス範囲のデータに関してのみキャッシュが無効化され、新しい値が参照されるようになる。

その他

DMAを使用したときはVivadoでビットストリームを生成したときに出力されるドライバファイルxaxidma.h内で宣言される関数XAxiDma_SimpleTransferを使用してデータ送受信を行っていた。このサンプルアプリケーションにはそのような関数が含まれておらず、最初は意味がわからなかった。
CDMAのリファレンスを読んでみたところ解決した。
CDMAの制御レジスタを直接変更することでエラー割り込み、終了割り込みの有効化・送受信先アドレスの設定・データ転送開始を制御している。

また、ダウンロードしたサンプルのデザインを実行しても動かなかったので、手作業で回路を作り直した。
Vivado内でBRAMを配置した際にBRAMのサイズが変更できずに困っていたところ、以下のようなリンクを発見した。
Solved: how to edit bram controller+bram memory size? - Community Forums
BRAM GeneratorのWidthとDepthの欄はマスター側によって自動的に決まると書いてあった。
BRAMコントローラでBRAMのサイズを変更できないな~と思っていたら、Address EditorでBRAMコントローラに与えるアドレス範囲を変更することでBRAMのサイズが変更できる。

コード

Xilinxのサンプルコードを修正・コメント文を追加したものをおいておきます。
gist.github.com

分からないことも多いまま試行錯誤しているので、間違っているところなどあれば教えてください。

ICPC2017国内予選に参加しました

久々にブログを書いた
1年前:
lp6m.hatenablog.com

2年前:
lp6m.hatenablog.com

去年と同じメンバーで出た。チーム名はfoldLeft.
特に練習もしていないので自分は簡単な問題を解こうとおもっていた。
自分はABを通してチームメイトがCDを解いた。D解けるのすごい。
46位/368チームでした 2桁になれたのはチームメイトのおかげ。

勉強しないとな~

UbuntuやElementary OSでスリープ後に画面の明るさが変更できないのを解消できた

先日気が狂ってmacOSを消した.
UbuntuベースのElementary OSというOSをインストールした.
なんかスリープ後に画面の明るさが調節できなくてつらかったのでググりまくった.
いろんな情報がでてきたけどどれもダメでつらいなあとおもっていたら,今日はやっとみつけることができた.

まずココに同じ問題が書かれてる.
MacBookAir6-2/Trusty - Community Help Wiki

Mac用にドライバを書いてくれた人がいるみたい.インストールしようとした.READMEにしたがってすすめていく.
make installで以下のようなエラーがでて失敗する.

- SSL error:02001002:system library:fopen:No such file or directory: bss_file.c:175
- SSL error:2006D080:BIO routines:BIO_new_file:no such file: bss_file.c:178
sign-file: certs/signing_key.pem: No such file or directory

つらいと思ってしらべたら、同じのがあった.
github.com
make installできないときは,checkinstallってのを使えばいいらしい.
sudo apt install checkinstall
mba6x_blのディレクトリ内でcheckinstallのコマンドを叩く. なんかパッケージの説明をかけとか言われるので「Macのがめんの明るさ設定する」って書いた.
そしたらディレクトリ内にdebが作成された.checkinstallってのはdebを生成するコマンドらしい?
最後にsudo -i dpkg ~.debでインストール.
READMEに書いてる最後の手順のsudo modprobe mba6x_bl をしたらちゃんと反映された.

たぶんいまのところ動いてるっぽいのでよかった.インターネットすばらしいしMacのドライバかけるのすごい.

おわり.