みつきんのメモ

組み込みエンジニアです。Interface誌で「Yocto Projectではじめる 組み込みLinux開発入門」連載中

raspberrypi3 yoctoでSSD1306 OLEDディスプレイを動かす

アマゾンで安価に入手できるOLEDディスプレイを購入した。

I2Cで、VCC、GND、SCL、SDAの4本のみの結線で使用できる。 制御用のICはSSD1306とのこと。

このデバイスはArduinoなどの電子工作用となっているが、意外とラズベリーパイでの動作報告が見当たらない。 そこでこれを動かしてやろうと考えた。

Linuxにはssd1307fb.cというドライバがあり、これがSSD1306にも対応している。

しかし、実際に動かそうとすると意外と問題があり、カーネル4.4ではLEDが光らなかったり、表示位置がずれていたりしたので、それらは力技で直した。

yoctoの基本環境およびmeta-raspberrypi

基本環境のダウンロード

$ mkdir ~/rpi3
$ cd ~/rpi3
$ git clone git://git.yoctoproject.org/poky.git
$ cd ~/rpi3/poky
$ git clone git://git.yoctoproject.org/meta-raspberrypi

meta-rpi-ssd1306

meta-rpi-ssd1306をダウンロード。

$ cd ~/rpi3/poky
$ git clone https://github.com/mickey-happygolucky/meta-rpi-ssd1306.git

環境変数を設定

下記を実行してbitbakeの実行に必要な環境変数を設定する。

$ cd ~/rpi3
$ source poky/oe-init-build-env build

ビルド対象に追加

bitbake-layerでビルド対象に追加。

$ bitbake-layers add-layer ../poky/meta-raspberrypi
$ bitbake-layers add-layer ../poky/meta-rpi-ssd1306

local.conf

今回は、SSD1306のディスプレイをコンソールとして使用するために次の行を追加する。

MACHINE ?= "raspberrypi3"

ENABLE_I2C = "1"
KERNEL_DEVICETREE_append = " overlays/ssd1306fb.dtbo"

OLED_CONSOLE = "1"

bitbake実行

$ bitbake rpi-basic-image

イメージの書き込み

meta-raspberrypiではrpi-sdimgとしてSDカードのイメージが生成されるので、これをddコマンドで書き込む。

$ sudo dd if=./tmp/deploy/images/raspberrypi3-64/rpi-basic-image-raspberrypi3-64.rpi-sdimg of=/dev/sdb bs=40M

/dev/sdbは環境によってはsdbだったりsdcだったりするので適宜変更する。 内蔵HDDの追加など行ってなければ大抵はsdbとなる。

動作確認

f:id:mickey_happygolucky:20161007024414j:plain

OLEDにコンソールが表示されている。

raspberrypi3 yoctoでkernel4.8を試す

インターフェース11月号の記事で、linuxカーネルのバージョン4.8からラズベリーパイ3の64ビットが対応されるという情報があった。 筆者が紹介したカーネルは、Electron752さんが4.5および4.6のカーネルに64ビット対応したものだったので、今回はもともと64ビット対応されているというカーネル4.8を試してみようと思う。

ただし、バニラカーネルだと自前でコンフィグレーションなどが必要になるので、ラズベリーパイのカーネルrpi-4.8.yブランチを使用する。

使用するブランチ

meta-raspberrpyはkrogothブランチを持っていないため、pokyのmasterブランチを追従している。 masterブランチはバージョンの移り変わりが激しく、時間が経つと再現性が乏しくなるという欠点がある。 そのため、なるべくその時点の最新のリリースバージョンのブランチ(今はkrogoth)を使用するのだが、最近masterブランチが破壊的な修正が入ってしまった。その影響で現時点(10/3)ではkrogothのpoky(oe-core)とmasterのmeta-raspberrypiの組み合わせではビルドできなくなっている。 これは非常に残念なので、meta-raspberrypiにはkrogothブランチを切って欲しいと思う。 特定のコミットでcheckoutするという回避策もあるにはあるのだが。

今回は、このような事情からpoky(oe-core)もraspberrypiもmasterブランチで作業する。

環境のダウンロード

poky

次のコマンドを実行し、pokyの環境をダウンロードする。作業は~/rpi3で行う。

$ mkdir ~/rpi3
$ cd ~/rpi3
$ git clone git://git.yoctoproject.org/poky.git

先述の通りmasterブランチで作業する。

meta-raspberrypi

meta-raspberrypiをダウンロードする。

$ cd ~/rpi3/poky
$ git clone git://git.yoctoproject.org/meta-raspberrypi

こちらもmasterブランチで作業する。

meta-rpi3-aarch64

インターフェース2016年11月号でも紹介させてもらった64ビット環境を作成するためのレイヤをダウンロードする。 ここでは、カーネル4.8に対応したrpi-4.8.yブランチを取得する。

$ git clone https://github.com/mickey-happygolucky/meta-rpi3-aarch64.git -b rpi-4.8.y

ビルド環境の設定

同じみのoe-init-build-envを読み込み、bitbakeに必要な環境変数などの設定を行う。 meta-rpi3-aarch64はコンフィグレーションファイルのテンプレートを提供しているので、次のようにする。

$ TEMPLATECONF=meta-rpi3-aarch64/conf/template source poky/oe-init-build-env build64

これで、local.confbblayers.confが設定済みの状態で作成される。

自動的にbuild64ディレクトリに移動される。

bitbakeの実行

bitbakeを実行しイメージを作成する。

$ bitbake rpi-basic-image

SDカードの作成

ddコマンドでSDカードにイメージを書き込む。

$ sudo dd if=./tmp/deploy/images/raspberrypi3-64/rpi-basic-image-raspberrypi3-64.rpi-sdimg of=/dev/sdb bs=100M

/dev/sdbはSDカードのデバイス。各自環境によって変化する可能性があるので注意。

実行

f:id:mickey_happygolucky:20161003235046j:plain

カーネルが4.8でaarch64になっている。

インターフェース 2016年11月号 特集記事の中の「マニアの挑戦!ラズパイ3×64ビットLinux初体験」とmeta-rpi3-aarch64についてのフォロー

今回、ありがたいことに、この記事を書かせていただきました。 しかし、ちょっと手違いとか不運なことが重なってしまったので、すこしフォローをしたいと思います。主には次の2点。

  1. P19の図3について
  2. P29〜P31で解説しているmeta-rpi3-aarch64の内容について

P19の図3について

こちらについては単純に誤植なのですが、掲載されている手順を実行しても64ビット版Linuxが作成されません。

$ cd rpi3
$ TEMPLATECONF=meta-rpi3-bt-support/conf/template source poky/oe-init-build-env build_bt
$ bitbake core-image-sato
$ sudo dd if=./tmp/deploy/images/raspberrypi3/core-image-sato-raspberrypi3.rpi-sdimg of=/dev/sdb bs=100M

正しくはこちらになります。

$ cd rpi3
$ TEMPLATECONF=meta-rpi3-aarch64/conf/template source poky/oe-init-build-env build64
$ bitbake rpi-basic-image
$ sudo dd if=./tmp/deploy/images/raspberrypi3-64/rpi-basic-image-raspberrypi3-64.rpi-sdimg of=/dev/sdb bs=100M

YoctoProjectを使用して64ビットLinuxを体験しましょうという記事なのに肝心の手順が間違っていたので、フォローさせていただきました。

P29〜P31で解説しているmeta-rpi3-aarch64の内容について

これは、Electron752さんがGithubで公開していたファームウェアと64ビット版カーネルをYoctoProjectのレイヤとして作成するという内容でした。

こちらは不運というか、執筆時点と現在でElectron752さんのGithubリポジトリの構成が大きく違ってしまったため、この記事の内容を実践してもビルドエラー(実際にはfetchエラー)になってしまいます。

meta-rpi3-aarch64の内容については私が公開しているものが、9/24時点のElectron752さんのリポジトリの構成に対応したものになっているため、こちらを参考にしていただければと思います。

執筆時点のものと現在のものについての差分はこちらになります。

raspberrypi3 yocto PiTFT3.5を赤く染める(SDKの作成)

先日の記事の最後で、「前回の記事で作成したfirst_window.cのコンパイル結果を実行すると、PiTFT35が赤く染まる」と書いたが、具体的な手順について解説する。

まずはじめに環境を整える必要がある。

  1. PiTFT35の手順でmeta-pitft35-rpiのビルド環境を作成
  2. rpi-fbcpの手順でmeta-rpi-fbcpの環境を作成

次にrpi-fbcpの環境をベースにSDKを作成する。

SDKの作成

bitbakeではLinuxイメージを作成するためにクロスコンパイルを行っているが、それとは別に作成されたLinuxの上で動作するアプリケーションを作成するためのクロスコンパイラ(ツールチェイン)を作成することができる。

次の手順で作成する。

$ cd ~/rpi3
$ source poky/oe-init-build-env build_pitft35
$ bitbake core-image-sato -c populate_sdk

SDKインストーラpoky-glibc-x86_64-core-image-sato-cortexa7hf-neon-vfpv4-toolchain-2.1.1.shbuild_pitft35/tmp/deploy/sdkにできあがる。

これを実行し、インストールする。

$ cd tmp/deploy/sdk
$ ./poky-glibc-x86_64-core-image-sato-cortexa7hf-neon-vfpv4-toolchain-2.1.1.sh
Poky (Yocto Project Reference Distro) SDK installer version 2.1.1
=================================================================
Enter target directory for SDK (default: /opt/poky/2.1.1): 
You are about to install the SDK to "/opt/poky/2.1.1". Proceed[Y/n]? 

デフォルトの設定では/opt/poky/2.1.1SDKがインストールされる。

SDKの使用

bitbake実行したシェルとは別のシェルを開いて、次のコマンドを実行する。

$ source /opt/poky/2.1.1/environment-setup-cortexa7hf-neon-vfpv4-poky-linux-gnueabi

これでクロスコンパイルのために必要な設定が環境変数に設定される。たとえば、次のようにしてみると、クロスコンパイル用のコンパイラおよびビルドオプションが確認できる。

$ echo $CC
arm-poky-linux-gnueabi-gcc -march=armv7ve -marm -mfpu=neon-vfpv4 -mfloat-abi=hard -mcpu=cortex-a7 --sysroot=/opt/poky/2.1.1/sysroots/cortexa7hf-neon-vfpv4-poky-linux-gnueabi

上記はC言語のためのコマンドで、C++の場合は次のようにする。

$ echo $CXX
arm-poky-linux-gnueabi-g++ -march=armv7ve -marm -mfpu=neon-vfpv4 -mfloat-abi=hard -mcpu=cortex-a7 --sysroot=/opt/poky/2.1.1/sysroots/cortexa7hf-neon-vfpv4-poky-linux-gnueabi

sourceコマンドによる環境変数の読み込みは、すでに読み込まれているシェルの上で実行するとエラーになる。

hello world

例えば、hello worldのプログラムを作成し、コンパイルを実行してみる。

#include <stdio.h>

int main(int argc, char *argv[])
{
    printf("hello world\n");
    return 0;
}
$ $CC ./hello.c -ohello

$CC環境変数が展開されarm-poky-linux-gnueabi-gccコマンドによりコンパイルが実行され、helloというファイルがされる。

次のようにして、生成されたファイルを確認する。

$ file ./hello
./hello: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 2.6.32, BuildID[sha1]=add3753e8732c8cec29a4b0203819bdc78aed85c, not stripped

ARMのバイナリが生成されていることがわかる。

このhelloファイルをラズベリーパイ上で実行すると、hello worldと文字が出力される。

コンパイル済みバイナリをラズベリーパイへコピー

方法はいくつかあるが、筆者がよく行うのは次の2つのうちどちらか。

  1. SDカードをPCにマウントし、/home/rootなどの適当な場所へコピーする。
  2. LAN環境へ接続し、scpコマンドで転送する。

環境が出来上がってしまえばscpのほうが手軽だと思う。

PiTFT3.5を赤く染める

PiTFTを赤く染める手順をSDKがインストールされた後の手順から示す。

ソースのダウンロード

先日のOpenGLESソースコードをダウンロードする。

作業は~/fisrt_windowで行う。

$ mkdir ~/first_window
$ cd ~/first_window
$ git clone https://gist.github.com/1650444ca53d819474c9c69ed2604abb.git

ビルド

sourceでSDK環境変数を読み込み、ビルドを実行する。

$ cd 1650444ca53d819474c9c69ed2604abb
$ source /opt/poky/2.1.1/environment-setup-cortexa7hf-neon-vfpv4-poky-linux-gnueabi
$ cmake .
$ make

出来上がったfirst_windowファイルをfbcpのLinuxイメージを書き込んだラズベリーパイの上で実行すると、PiTFT3.5が赤く染まる。

f:id:mickey_happygolucky:20160919153814j:plain

raspberrypi3 yoctoでfbcp

PiTFTなどSPI接続のLCDではGPUを使用した描画処理は行えない。 そのためOpenGLESなどのアプリケーションはPiTFTでは使用できない。

しかし、fbcpを使用するとこの問題が解決できる。

fbcpは「Framebuffer Copy」のことで、GPUに描画されているデータをSPI側のフレームバッファにコピーするというアプリケーション。

実装を見ると、dispmanxでLCDバイス(HDMIへの出力)を開いて、必要に応じて縮小し/dev/fb1に転送している。 このアプリケーションは、実はすでに有名なようでちょっと筆者としては出遅れた感がある。

以前、PiTFT3.5でQML(Quick2)アプリケーションが実行できない理由の時に「2.2インチや2.8インチのPiTFTではGPUを使用せずにOpenGLを描画することができる」というところでリンクを紹介したがこの内容も実はfbcpを使用することだった。 リンク先で「The 3.5" PiTFT (480x320) is NOT recommended for this project 」とされていたので深追いしなかったが、実は意外と使えるということが今回の実験でわかった。

とりあえず、yoctoprojectで使用できるようにmeta-rpi-fbcpを作成した。

環境の作成

raspberrypi3 yoctoでPiTFT35の環境をベースに作業を行う。

meta-rpi-fbcpのダウンロード

gitでmeta-rpi-fbcpを取得する。

$ cd ~/rpi3/poky
$ git clone https://github.com/mickey-happygolucky/meta-rpi-fbcp.git

ビルド環境の設定

oe-init-build-envを読み込む。

$ cd ~/rpi3
$ source poky/oe-init-build-env build_pitft35

自動的にbuild_fbcpに移動される。

レイヤの設定

ビルド対象にはすでに、meta-raspberrypimeta-pitft35-rpiは追加されているので、次のコマンドでmeta-rpi-fbcpを追加する。

$ bitbake-layers add-layer ../poky/meta-rpi-fbcp

conf/local.conf

local.confからRPI_PITFT35 = "1"の行を削除し、RPI_PITFT35_FBCP = "1"を追加する。

カーネル4.1の場合だと次のようになる。

MACHINE ?= "raspberrypi3"
DL_DIR ?= "${TOPDIR}/../downloads"

KERNEL_DEVICETREE_append = " overlays/pitft35-resistive-overlay.dtb"
RPI_PITFT35_FBCP = "1"

設定が衝突するため、RPI_PITFT35 = "1"RPI_PITFT35_FBCP = "1"は同時に指定できない。

動作確認

この環境では、PiTFT35のタッチパネルは無効化される。 今回は、X11環境で動作を確認する。

ビルド

$ bitbake core-image-sato

SDカードへ書き込み

$ sudo dd if=./tmp/deploy/images/raspberrypi3/core-image-sato-raspberrypi3.rpi-sdimg of=/dev/sdb bs=40M

/dev/sdbのSDカードデバイスは環境によって変化することがあるのでfdisk -lなどで確認すること。

このままではただsatoのGUI環境が表示されるだけなので、fbcpなしの環境と比較するとタッチパネルが無効化されただけのように見えるが、

前回の記事で作成したfirst_window.cコンパイル結果を実行すると、PiTFT35が赤く染まるようになっている。

raspberrypiでOpenGLESプログラミング

ラズベリーパイOpenGLのプログラミングをはじめようと思ったが、ラズベリーパイではOpenGLESでプログラムする必要がある。 PCなどではOpenGLプログラミングというとglutやglfwなどが主流のようで、なかなかそのまま動くコードが見つからない。

また、OpenGLESで調べようとするとAndroidiOSの情報ばかりでこれもハードルが高い。 いろいろ調べていくと、OpenGLESの世界では、OpenGL ES 3.0 Programming GuideOpenGL ES 2.0 Programming Guideバイブルとなっているらしく、これらのコードを元にしたサンプルがあちこちで見かけられる。ここが大本か。

ただ、これは純粋にOpenGLESプログラミングの説明に集中するため、Windowsを表示するための最低限の仕組みはesUtil.cというフレームワークの中に隠蔽されており、ラズベリーパイでこれらのコードを動かすにはどうすればよいかがわかりづらい。

中には移植してGitHubにあげている人もいるが、「ラズベリーパイでOpenGLESプログラミングの第一歩」を踏み出すためは最低限何をすればよいかがなかなかわからない。

さらに調べた先にここを見つけた。 ここのrectangle.cがかなり求めていたものに近い。 余談だが、冒頭のコメントの「code stolen from」は面白い表現だと思った。

ただ、rectangle.cではOpenGLESの初期化コードとラズベリーパイのネイティブウィンドウシステムであるdispmanxの初期化コードがごっちゃに書かれているため、整理したものを作成した。

ラズベリーパイでOpenGLESプログラミングを行うにはまず次のキーワードを理解する必要がある。

  • dispmanx
  • EGL

dispmanxはラズベリーパイGPUを操作するためのAPIでローレベルのウィンドウシステムを提供するAPI

EGLはOpenGL(本来はKhronos rendering APIs)の描画周りの抽象化層で、実際に描画を行うネイティブウィンドウシステムとOpenGLとの橋渡しを行う。

そのため、ラズベリーパイではdispmanxとEGLを関連付ける必要がある。

大まかな手順としては次のようになる。

  1. dispmanxの初期化
  2. EGLの初期化
  3. EGLの描画コンテキストを作成
  4. dispmanxでウィンドウを作成
  5. EGLの描画コンテキストにdispmanxのウィンドウを関連付け

first_window.cではcreate_native_windowでdispmanxのウィンドウを作成、 init_oglでEGLの描画コンテキストの作成create_native_windowの呼び出し、 eglCreateWindowSurface関数により描画コンテキストとウィンドウを関連付けしている。

このプログラムを実行すると、画面が真っ赤に塗りつぶされる。

rectangle.cのサイトを作成したJan Newmarchさんがこのような本を書いているので参考になると思う。 OpenGLESのあたりから急にOpenGLES-bookのコードが手元にあることを前提に話が始まるので、それを頭に入れていないと混乱するかもしれない。

raspberrypi3 yoctoでPiTFT35

以前PiTFT35をyoctoで動作させるためにmeta-pitft35-rpiを作成した^1が、 最近のmeta-raspberrypiでは動作しなくなっていた。

一度、リポジトリの方に問い合わせが来たが、その人がうちのパッチをまとめて(勝手に)meta-raspberrypiにPRを送っていた。 meta-raspberrypiに取り込まれるならもうmeta-pitft35-rpiも用済みかと思ってしばらく放置していたのだが、そのパッチ取り込まれるようすがなく、送ったPRの内容を確認すると結構いい加減な対応だったので、 とりあえずmeta-pitft35-rpiをRPi3(というかカーネル4.1、4.4)に対応させることにした。

ついでにcore-image-satoではキャリブレーションデータが固定だったので、イメージを書き込んで初回など、キャリブレーションデータが存在しない場合、OS起動時にキャリブレーションが実行されるように修正した。

使用方法は変更なし。

環境の作成

作業は~/rpi3で行う。

pokyとmeta-raspberrypiのダウンロード

pokyのブランチはkrogothを使用する。 meta-raspberrypiはkrogothブランチがないので、masterブランチを使用する。

$ mkdir ~/rpi3
$ cd ~/rpi3
$ git clone git://git.yoctoproject.org/poky.git -b krogoth
$ cd ~/rpi3/poky
$ git clone git://git.yoctoproject.org/meta-raspberrypi

meta-pitft35-rpiのダウンロード

meta-pitft35-rpiをダウンロードする。

$ git clone https://github.com/mickey-happygolucky/meta-pitft35-rpi.git

ビルド環境の設定

次のコマンドでoe-init-build-envを読み込む。

$ cd ~/rpi3
$ source poky/oe-init-build-env build_pitft35

自動的ににbuild_pitft35に移動される。

レイヤの設定

bitbake-layersコマンドでビルド対象にmeta-raspberrypimeta-pitft35-rpiを追加。

$ bitbake-layers add-layer ../poky/meta-raspberrypi
$ bitbake-layers add-layer ../poky/meta-pitft35-rpi

conf/local.conf

エディタでconf/local.confを修正する。 カーネル4.1と4.4で若干異なる。

カーネル4.1

バージョン4.1のカーネルを使用する場合はlocal.confに次を追加する。

MACHINE ?= "raspberrypi3"
DL_DIR ?= "${TOPDIR}/../downloads"

KERNEL_DEVICETREE_append = " overlays/pitft35-resistive-overlay.dtb"
RPI_PITFT35 = "1"

PiTFT35のための設定はKERNEL_DEVICETREE_appendRPI_PITFT35MACHINEでRPi3向けのイメージを指定。 DL_DIRはbitbake時にダウンロードされるデータを格納するディレクトリの指定。 デフォルトではビルドディレクトリごとにダウンロードされるが、階層をひとつ上げることで他のビルドディレクトリと共用している。

カーネル4.4

バージョン4.4のカーネルを使用する場合はlocal.confに次を追加する。

MACHINE ?= "raspberrypi3"
DL_DIR ?= "${TOPDIR}/../downloads"

PREFERRED_VERSION_linux-raspberrypi = "4.4.%"

KERNEL_DEVICETREE_append = " overlays/pitft35-resistive-overlay.dtb"
RPI_PITFT35 = "1"

PREFERRED_VERSION_linux-raspberrypiカーネルバージョンを指定している。 それ以外は4.1と同じ。

動作確認

コンソール環境とX11環境を作成

コンソール環境

次でビルド。

$ bitbake rpi-basic-image

次でSDカードに書き込み

$ sudo dd if=./tmp/deploy/images/raspberrypi3/rpi-basic-image-raspberrypi3.rpi-sdimg of=/dev/sdb bs=40M

/dev/sdbはSDカードデバイスの指定で環境によっては/dev/sdcとかになるのでfdisk -lなどで確認する必要がある。

X11環境

ビルド。

$ bitbake core-image-sato

SDカードに書き込み

$ sudo dd if=./tmp/deploy/images/raspberrypi3/core-image-sato-raspberrypi3.rpi-sdimg of=/dev/sdb bs=40M