みつきんのメモ

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

gitbook-templateを試す

はじめに

HeRoMo/gitbook-template: A gitbook project templateがよさそう。

Gitbook 環境 マイ・ベストを参考に作業する。

が。docker関連が一切入っていないのでそこから。

dockerのインストール

Ubuntuではsnapで入れる方法が簡単。ここが参考になる。

まず古いバージョンを削除。

$ sudo apt-get remove docker docker-engine docker.io containerd runc

次にdocker-ceをインストールする。

$ sudo snap install docker --stable

dockerのエラー

docker関連のコマンドを実行すると次のようなエラーが発生する。

Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post http://%2Fvar%2Frun%2Fdocker.sock/v1.38/images/create?fromImage=hero%2Fgitbook&tag=latest: dial unix /var/run/docker.sock: connect: permission denied

dockerグループをシステムに追加した後、ユーザーをdockerグループに追加する。

$ sudo addgroup --system docker
$ sudo adduser $USER docker
$ newgrp docker
$ sudo snap restart docker

これは普通に見落としがち。

gitbook-templateの導入

$ curl https://codeload.github.com/HeRoMo/gitbook-template/zip/master -O
$ unzip master
$ mv gitbook-template-master your-gitbook-name
$ cd your-gitbook-name

gitbookの初期化

$ docker-compose run --rm gitbook init

必要かわからないが、ファイルの所有権を変更しておく

$ sudo chown -R ${LOGNAME}:${LOGNAME} gitbook

ローカルサーバの操作

docker-compose.ymlがあるディレクトリで操作する。

起動

$ docker-compose up -d

停止

$ docker-compose stop

再起動

$ docker-compose restart

plantuml-cloudプラグインの修正

リンク元にあった謎のセミコロン問題を回避するために一度コンテナにログインする。

$ docker-compose exec gitbook bash

npmが更新されていないように見えるためgitbook/node_modules/gitbook-plugin-plantuml-cloud/index.jsを直接修正する。

# cd gitbook/node_modules/gitbook-plugin-plantuml-cloud
# cp index.js index.js.tmp
# sed -i 's|`!\[\](/${uml.svgPath});`|`!\[\](/${uml.svgPath})`;|g' index.js.tmp
# mv index.js.tmp index.js

ファイルを壊すとコンテナが起動しなくなるのでテンポラリファイルで作業する。 最後のmvの前にdiffなどで確認すると安心。

その後コンテナを再起動する。

$ docker-compose restart

PDF出力

$ docker-compose run --rm gitbook pdf

まとめ

gitbookの導入としては環境も汚れないため便利。

PDF出力時の日本語フォントなど、細かいところは調整が難しい感じ。 gitbookのプラグインはbook.jsonに記述すれば勝手にやってくれるっぽい?

NuttXアプリケーションの作成を補助するスクリプトを作った

はじめに

NuttXで小さい書捨てのアプリケーションをたくさん作る必要が出てきたので、 アプリケーションの雛形を出力するスクリプトを自分用に作成した。

せっかくなので(?)、githubに置いといた

スクリプトがやっていることの詳細はここを参照。

使い方

nuttx_gen_app.shをPATHの通ったディレクトリにコピーする。

環境変数NUTTX_APP_DIRappsディレクトリへのパスを設定する。

nuttx_gen_app.shを実行する。

アプリケーションの作成

次のように作成したいアプリケーション名を指定する。

$ nuttx_app_gen.sh hello

この時点でNuttXのmake menuconfigのメニューに追加されるようになる。 NuttXのmenuconfigに反映させるにはmake distcleanしてからtools/configure.shを実行し直す必要がある。

また、デフォルトのスタックサイズを指定することもできる。

$ nuttx_app_gen.sh hello 8192

アプリケーションの削除

次のようにすると、nuttx_gen_app.shで作成したアプリケーションを削除することができる。

$ nuttx_gen_app.sh hello -d

まとめ

自分用なので自分が必要な機能だけ。 そこまで細かいテストはしてないので、使用する場合はご注意を。

何かあればプルリクをくれると助かります。

Zephyrにアプリケーションを追加する

はじめに

Zephyrに自作のアプリケーションを追加したい。

ここの手順を参考にする。

環境変数の読み込み

とりあえず一番始めにsource zephyr-env.shを実行して環境変数を読み込む。 これを忘れるとwestがまともに動かない。

$ cd zephyr
$ source zephyr-env.sh

作成するファイル

次のような構成になるようにファイルを作成する。

app
├── CMakeLists.txt
├── prj.conf
└── src
    └── main.c

ディレクトリの名前はapp以外でも問題ない。 zephyrのソースツリー配下である必要もない。

今回は次のように作成する。

$ mkdir -p ~/zephyr_app/hello/src
$ cd ~/zephyr_app/hello

westでビルドする予定なので、あえて一段深い階層を作成する。

最終的には次のようになる。

~/zephyr_app
└── hello
    ├── CMakeLists.txt
    ├── prj.conf
    └── src
        └── main.c

CMakeLists.txt

CMakeLists.txtを次の内容で作成する、

cmake_minimum_required(VERSION 3.13.1)
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
project(my_zephyr_app)

target_sources(app PRIVATE src/main.c)

使用するボイラープレートの都合でCMakeLists.txtに記述するプロジェクト名はappとしなければならない。

prj.conf

プロジェクト固有のコンフィグ設定を記述する。何もない場合は内容は空でもよいがファイルは作成する。

$ echo '# nothing here' > prj.conf

src/main.c

プログラム本体。

#include <stdio.h>

int main(int argc, char *argv[])
{
    printf("My first Zephyr application. \n");
    return 0;
}

ビルド

westでビルドする。

$ cd ~/zephyr_app
$ west build -b qemu_x86 hello

アプリケーションと同じ階層にbuildが作成され、その中に成果物が出力される。

とりあえずqemu向けにビルドする。

実行

qemuなのでwestで実行できる。

$ west build -t run

次のように表示されればOK.

SeaBIOS (version rel-1.12.0-0-ga698c8995f-prebuilt.qemu.org)
Booting from ROM..***** Booting Zephyr OS zephyr-v1.14.0-1091-ge58df2c34eab *****
My first Zephyr application.

Ctrl+a,xで終了。

まとめ

source zephyr-env.sh環境変数を読み込んでしまえば、zephyrのソースツリー以外でもwestが使用できる。

アプリケーションを管理するためのディレクトリもzephyrのソースツリーの外に置くことができるので、管理がしやすい。

アプリケーションのビルドやデバッグにもwestが使用できるので便利。

Zephyrでデバッグ

はじめに

Zephyrのアプリケーションをデバッグする。ターゲットはSTM32F4Discoveryを使用する。

コンフィグレーション

westでmenuconfigを開くには次のようにする。

$ west build -t menuconfig

デバッグ用設定

次の設定を有効化する。

  • DEBUG
  • DEBUG_INFO
  • DEBUG_OPTIMIZATION

デバッグ開始

westでデバッグを開始できる。

$ west debug

gdbserverの起動、gdbの起動、ターゲットの接続まで自動でやってくれる。

gdbgui

コマンドラインgdbデバッグできないにわかなのでgdbguiを使用したい。

しかし、westもgdbgui同様gdbのフロントエンドなので、westからgdbguiを呼び出すようにするのは難しい。

このような場合は、次のようにwestでデバッグサーバーを開始してからgdbguiを実行する。

$ west debugserver

別のターミナルで先程のコマンドを実行する。

$ gdbgui -g ${ZEPHYR_SDK_INSTALL_DIR}/arm-zephyr-eabi/bin/arm-zephyr-eabi-gdb --gdb-args "-ex 'target remote :3333' -ex 'monitor halt' -ex 'monitor reset' -ex 'load'" build/zephyr/zephyr.elf

まとめ

gdbサーバの起動やgdbの起動までwestで一発でできるのでデバッグ開始までが簡単。

gdbguiも一応使用できることがわかった。

west debugserverではボードによって使用するgdbサーバが変わることがあるためgdbで接続するポートが異なったりするので注意が必要。

ZephyrをSTM32F4Discoveryで試す

はじめに

Zephyrの勉強のためにとりあえず動かしてみる。

準備

いろいろ事前にインストールが必要なのでやっておく。

west

直接gitでソースを取得するのではなくwestというツールを使用することが推奨されているようだ。

pip3が必要なのでインストールする。 OSの環境を汚したくないのでuserインストールする。

$ sudo apt install python3-pip
$ pip3 install --upgrade pip
$ sudo apt purge python3-pip

westのインストール。

$ pip3 install --user west

ninja

westは内部からninjaを叩くようなのでninjaをインストールする。

$ sudo apt install ninja-build

CMakeの更新

Ubuntu 18.04のcmakeでは古いため新しいcmakeをインストール

$ wget https://github.com/Kitware/CMake/releases/download/v3.14.4/cmake-3.14.4.tar.gz
$ tar xvf ./cmake-3.14.4.tar.gz 
$ cd cmake-3.14.4
$ ./configure
$ make -j $(nproc)
$ sudo make install

Zephyr SDK

SDKインストーラをダウンロードする。

$ cd /tmp
$ wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.10.0/zephyr-sdk-0.10.0-setup.run

インストーラを実行する。

$ sh zephyr-sdk-0.10.0-setup.run
Verifying archive integrity... All good.
Uncompressing SDK for Zephyr  100%  
Enter target directory for SDK (default: /opt/zephyr-sdk/): ~/bin/zephyr-sdk

デフォルトでは/opt/zephyr-sdk/にインストールされる。 インストール先はどこでも良いが、ここでは~/bin/zephyr-sdkにインストールした。

環境変数を設定する必要がある。

次の内容を~/.bashrcに追加する。

export ZEPHYR_TOOLCHAIN_VARIANT=zephyr
export ZEPHYR_SDK_INSTALL_DIR=${HOME}/bin/zephyr-sdk

.bashrcを読み込む。

$ source ~/.bashrc

Zephyrのソースを取得

westでソースを取得する。

$ west init zephyrproject
$ cd zephyrproject
$ west update

依存パッケージのインストール

依存するpythonパッケージをインストールする。

$ pip3 install --user -r zephyr/scripts/requirements.txt

westでビルドする

先程のzephyrprojectディレクトリに戻り次のコマンドを実行する。

$ cd zephyr
$ source zephyr-env.sh

対応ボードを調べる

次のコマンドでSTM32F4Discoveryを探す。

$ west boards | grep stm32f4
stm32f411e_disco
stm32f412g_disco
stm32f429i_disc1
stm32f469i_disco
stm32f4_disco

stm32f4_discoが見つかった。

Hello worldをビルドする

手始めに世界に挨拶してみる。

$ west build -b stm32f4_disco samples/hello_world

westで書き込む

次のコマンドで書き込みからボードのリセットまでやってくれる。

$ west flash

次のように接続し、minicomなどのターミナルを起動しておく

USB Cable STM32
TXD PA3
RXD PA2
GND GND

次のように表示されればOK

***** Booting Zephyr OS zephyr-v1.14.0-1091-ge58df2c34eab *****
Hello World! stm32f4_disco

まとめ

だいたい全部westで片付く。

platformioみたい。最近はこういうのが流行りなのか。

(おまけ)qemuで実行

実機なしで手軽に試すにはqemuを使用できる。

$ west build -b qemu_x86 samples/hello_world
$ west build -t run
...(snip)...
SeaBIOS (version rel-1.12.0-0-ga698c8995f-prebuilt.qemu.org)
Booting from ROM..***** Booting Zephyr OS zephyr-v1.14.0-1091-ge58df2c34eab *****
Hello World! qemu_x86

Ctrl+a, xで終了。

yoctoでもRust

はじめに

最近流行りのRust。meta-rustを使えばyocto環境でもRustアプリケーションを使えるようにできる。

meta-rustネタとしてはこちらに先を越されたが、試したブランチがsumo、rockoと古めなのと観点がRust開発者よりなので、本記事ではすこしyocto的に見てみる。

ちなみに筆者はRust初心者未満なのでRustの解説はリンク先の方を参照してください。

ターゲット環境はラズベリーパイ3。

環境構築

いつもの。

ソース取得

ラズベリーパイ環境のビルドのためのレイヤをダウンロードする。

$ mkdir -p rpi-thud/layers
$ cd rpi-thud/layers
$ git clone git://git.yoctoproject.org/poky.git -b thud
$ git clone git://git.yoctoproject.org/meta-raspberrypi -b thud
$ git clone git://git.openembedded.org/meta-openembedded -b thud

rustのパッケージを含んでいるmeta-rustはsumo(2.5)以降ブランチを切っていない。

masterブランチのLAYERSERIES_COMPATを確認すると次のようになっているので、thudwarriorを使用したい場合はmasterブランチを使用することになる。

LAYERSERIES_COMPAT_rust-layer = "rocko sumo thud warrior"

次のコマンドでソースを取得する。

$ git clone https://github.com/meta-rust/meta-rust.git
$ cd ../

環境変数の設定

環境変数の読み込みとビルドディレクトリを作成する。

$ source layers/poky/oe-init-build-env build_rust

コマンド実行後はビルドディレクトリに自動的に移動される。 ここではbuild_rustとしている。

レイヤの追加

ビルド対象にレイヤを追加する。 依存関係があるので追加する順番は変更しないこと。

$ bitbake-layers add-layer ../layers/meta-openembedded/meta-oe
$ bitbake-layers add-layer ../layers/meta-openembedded/meta-python
$ bitbake-layers add-layer ../layers/meta-openembedded/meta-networking
$ bitbake-layers add-layer ../layers/meta-raspberrypi
$ bitbake-layers add-layer ../layers/meta-rust

local.confの修正

MACHINEをラズベリーパイ3にする。

INITはsystemdで。あとは細かい設定。

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

# enable uart
ENABLE_UART = "1"

# systemd
DISTRO_FEATURES_append = " systemd pam"
VIRTUAL-RUNTIME_init_manager = "systemd"
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"
VIRTUAL-RUNTIME_initscripts = ""

IMAGE_INSTALL_append = " rust-hello-world"

ビルド

Linuxイメージを生成する。

$ bitbake core-image-base

Rustバージョンの確認

Rustのバージョンを確認。

$ find ./tmp/work -maxdepth 2 -and -type d -and -name 'rust*' | xargs ls
./tmp/work/cortexa7t2hf-neon-vfpv4-poky-linux-gnueabi/rust-hello-world:
git-r0

./tmp/work/x86_64-linux/rust-cross-arm:
1.33.0-r0

./tmp/work/x86_64-linux/rust-llvm-native:
1.33.0-r0

./tmp/work/x86_64-linux/rust-native:
1.33.0-r0

最新のstableが1.34.1みたいなので若干古い?。ここらへんは疎いので。

SDの作成

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

$ sudo dd if=tmp/deploy/images/raspberrypi3/core-image-base-raspberrypi3.rpi-sdimg of=/dev/sdX bs=100M

/dev/sdXはマイクロSDのデバイスなので適宜sdbsdcなどに書き換えること。

ddの代わりにEtcherを使用することもできる。

実行確認

作成したマイクロSDをラズベリーパイ3に挿入し電源をいれ、rust-hello-worldを実行してみる。

# rust-hello-world
Hello, world!

問題なく動作した。

開発環境の確認

yoctoではbitbakeで作成したLinuxイメージ上で動くプログラムを開発するためのクロスコンパイル環境を作成することができる。 これは、作成したLinux上にインストールされているライブラリを使用するために必要な情報が全て含まれている。

基本的にはGCCC/C++向け環境となっているので、Rustの開発環境はどのようになっているか確認する。

まず、次のコマンドでSDKを作成する。

$ bitbake core-image-base -c populate_sdk

tmp/deploy/sdkインストーラスクリプトが作成されるので、次のコマンドを実行しSDKをインストールする。

$ tmp/deploy/sdk/poky-glibc-x86_64-core-image-base-cortexa7t2hf-neon-vfpv4-toolchain-2.6.2.sh

インストール先は自由に設定できるが、デフォルトでは/opt/poky/2.6.2にインストールされる。

SDKを使用できるようにするために環境変数を読み込む。

$ source /opt/poky/2.6.2/environment-setup-cortexa7t2hf-neon-vfpv4-poky-linux-gnueabi

環境変数CCの値が次のようになっていればSDKが使用できる。

$ echo $CC
arm-poky-linux-gnueabi-gcc -march=armv7ve -mthumb -mfpu=neon-vfpv4 -mfloat-abi=hard -mcpu=cortex-a7 --sysroot=/opt/rust/2.6.2/sysroots/cortexa7t2hf-neon-vfpv4-poky-linux-gnueabi

最低でもrustcが入っていなければRust向けの開発環境とは言えないので探してみる。 SDKでインストールされたファイルは/opt/poky/2.6.2/sysroot以下にあるためそこの下をfindする。

$ cd /opt/poky/2.6.2/sysroot
$ sudo find -iname 'rustc'

見つからない。

*rust**cargo*などで検索してもRustの開発に必要なコマンドやファイルが見つからないことがわかる。

まとめ

低レイヤ強くなりたい組込み屋さんのブログで次のように言っている。

どうしてもYoctoでビルドしてdistributionとして配布したい、という状況でなければ、わざわざYoctoでビルドするうまみはなさそうです。

こちらは開発環境の古さなどの観点からの言葉なので若干言いたいポイントは異なるのだろうとも思うが、 Rustでの開発の観点で言えば全面的に同意できる。

ただ、SDKにRustの開発環境が含まれないことからmeta-rustではyoctoで作成したLinuxの上で開発・デバッグを行うことは目的に含まれていない。そのため「Yoctoでの配布目的以外ではうまみがない」のではなく「使えない」で良いと思う。

個人的にyoctoのうまみは一度作った設定済みのLinuxイメージを量産できるところにあると思っている。meta-rustもRustで書かれたアプリケーションをyoctoのイメージに取り込むのがこれを使用する目的であって、この観点ではmeta-rustのスタンスも間違ってはいないし存在意義もあると思っている。

yocto環境でのRustの開発環境を期待しているとハズレ感はあると思う。

異論は認める!

参考

tinygoでnRF52840-DK(PCA10056)を動かす

はじめに

nRF52840 Development Kitを入手したのでtinygoで動かしてみる。

tinygoのインストール

Ubuntu 18.04にtinygo-0.5.0をインストールするの手順でインストール済みであることを想定。

ツールのダウンロード

nrfjprogコマンドが必要なので、下記からコマンドラインツールをダウンロードする。

https://www.nordicsemi.com/Software-and-Tools/Development-Tools/nRF5-Command-Line-Tools/Download#infotabs

tarのアーカイブなので展開する。

$ tar xvf nRF-Command-Line-Tools_9_8_1_Linux-x86_64.tar
$ mv ./nrfjprog ~/bin/
$ mv ./mergehex ~/bin/
$ cat << 'EOF' >> ~/.bashrc
export PATH=$PATH:${HOME}/bin/nrfjprog:${HOME}/bin/mergehex
EOF
$ source ~/.bashrc

J-Link Softwareのインストール

当然のことながらnrfjprogはj-Linkのライブラリを必要とするので、インストールしていない場合はこれをインストールする。

SEGGERのダウンロードページからダウンロードする。

ダウンロードが完了したら次のコマンドでインストールする。

$ sudo gdebi JLink_Linux_V644g_x86_64.deb 

サンプルプログラムの書き込み

サンプルプログラムをビルドして書き込む。

バイスターゲットの生成

これは最初にやっておく必要がある。

$ cd $GOPATH/src/github.com/tinygo-org/tinygo
$ make gen-device

プログラムの書き込み

次のコマンドでビルドして書き込む。ここではexamples/Blinky1を書き込む。

ターゲット指定はpca10056

$ tinygo flash -target=pca10056 examples/blinky1

LED1がチカチカしたら成功。

まとめ

SEGGER J-LinkやnRF Command Line Toolは必要となるが、それを入れてしまえば問題なく動作する。

tinygoの手軽さは素敵。