tshell_blog

ソフトウェアと車輪がついた乗り物のはなし

yoctoでNano Pi NEO 2用イメージをビルドする

tshell.hatenablog.com

公式イメージもいいですが,meta-allwinner-hxレイヤーというものがあるのでyoctoでNano Pi NEO 2用イメージをビルドすることができます。

環境

以下の環境を使いました。

  • ホストPC:ubuntu 18.04 LTS
  • poky warrior 2.7.1
  • meta-allwinner-hx (warrior)
  • meta-openembedded(warrior)

ビルド環境のセットアップ

meta-allwinner-hxのREADMEを見ながら ホームディレクトリの下に以下のような構成のbuild_nanopiディレクトリを作っていきます。(名前は何でもいいです)

build_nanopi/
├── flash_sd.sh
├── setup-environment.sh
└── sources
    ├── meta-allwinner-hx 
    ├── meta-openembedded
    └── poky

yocto環境は通常~/poky-warriorなどに作成されているかと思います。上記のようなフォルダ構成を実現するためにまた同じものをダウンロードしてくるのも無駄なので,sourcesディレクトリ以下はシンボリックリンクを作成します。

以下コマンドを実行していきます。

$ mkdir ~/build_nanopi
$ cd ~/build_nanopi
$ mkdir sources
$ cd sources
$ ln -s ~/poky-warrior/meta-allwinner-hx meta-allwinner-hx
$ ln -s ~/poky-warrior poky
$ ln -s ~/poky-warrior/meta-openembedded meta-openembedded

セットアップスクリプトをコピーします。

$ cd ~build_nanopi
$ cp sources/meta-allwinner-hx/scripts/setup-environment.sh .
$ cp sources/meta-allwinner-hx/scripts/flash_sd.sh .

環境変数MACHINEにnanopi-neo2を設定します。

$ export MACHINE=nanopi-neo2

setup-environment.shを実行します。

$ source ./setup-environment.sh build

以下のようにsetup-environment-append.shが見つからないというメッセージが表示されますが,buildディレクトリは正常に生成されます。

Configuring for nanopi-neo2
Searching for append setup scripts...

ls: '/home/***/build_nanopi/sources/*/setup-environment-append.sh' にアクセスできません: そのようなファイルやディレクトリはありません
These are the default supported images:
    allwinner-image

You can now build your image. To build the allwinner-image then run this:
$ bitbake allwinner-image

buildディレクトリが生成され,confディレクトリ内にlocal.confとbblayers.confが自動生成されます。
私の環境ではbitbakeのdo_fetchでダウンロードするファイルが~/poky-warrior/downloadsに入っているのでlocal.confのDL_DIRは以下のように変更しました。

DL_DIR = "${HOME}/poky-warrior/downloads"

local.confを設定したら以下のコマンドを実行するとNano Pi NEO 2用のイメージを作成できます。(bitbakeへのパスが通っている必要があります)

$ bitbake allwinner-image

microSDカードへの書き込み

イメージが作成できたらmicroSDカードへ書き込みます。
~/build_nanopiにあるflash_sd.shを使用します。flasah_sd.shからbmaptoolが呼ばれるので,まずは必要なパッケージをインストールします。

$ sudo apt-get install bmap-tools

MACHINEと書き込み先を指定して./flash_sd.shを実行します。
デフォルトでは13.8GBのイメージを書き込むようになっているため,16GB以上のmicroSDカードを用意する必要があります。

$ sudo MACHINE=nanopi-neo2 ./flash_sd.sh /dev/sdb

meta-allwinner-hxのREADMEには「デフォルトだと13.8GBのイメージを作るが,本当に必要なのは60MB弱だから中身スカスカで,bmaptoolを使えば14GBを数秒で書き込めるんだ」みたいなことが書いてありますが,ならばもっと低容量のSDに入るようにしたいですね。

作成されるイメージを小さくするにはmeta-allwinner-hx/classes/allwinner-wks-defs.incを編集し,ROOT_EXTRA_SPACEを変更してルートディレクトリの領域を小さくします。デフォルトでは10240となっていますが,1024に変更すると1.2GBくらいのイメージが作成されます。

meta-allwinner-hx/classes/allwinner-wks-defs.incのROOT_EXTRA_SPACEを以下のように変更します。

ROOT_EXTRA_SPACE ?= "1024"

起動確認

イメージを書き込んだmicroSDをNano Pi NEO 2に挿入し,LANケーブルも接続して電源を入れます。
シリアルコンソールを繋いでいない場合,Nano Pi NEO 2のIPアドレスを知るにはNmapを使ってスキャンする必要があります。
IPアドレスがわかったらSSHで接続します。

$ sudo nmap -sP 192.168.0.*
・・・
Nmap scan report for nanopi-neo2 (192.168.0.32)
・・・

$ ssh root@192.168.0.32

なんとパスワード無しでログインできました。
早めにパスワードを変えておきましょう。

Raspberry Piに増設したSDカードの速度を測る 1bitモードと4bitモードの比較

Raspberry Piに増設したSDカードのパフォーマンスをfioで測ってみました。
増設方法は以下で紹介しています。 tshell.hatenablog.com

実は前の記事のようにdtboファイルを作らなくても以下の設定を/boot/config.txtに追記するだけで使えました。

dtoverlay=sdio,poll_once=off,sdio_overclock=50

前回はbus_width=1を指定して動作させ,とりあえず動いて喜んでいましたがこれを指定すると1bitモードで動作するようです。せっかくDAT0〜3まで結線しているのにDAT0しか使っていません。
今回はbus_width=1の指定を外してデフォルトの4bitモードで動作させ,どれくらい速度が違うのか測ってみます。

環境

以下のものを使用しました。

測り方

SDカードをマウントしたあと,fioを使用してSDカードへの書き込み速度を測ってみます。
以下のコマンドを実行します。

$ sudo mount -t ext4 /dev/mmcblk1 /mnt/sdcard
$ fio -filename=/mnt/sdcard/test1g -direct=1 -rw=write -bs=4k -size=1G -name=file1

/mnt/sdcardに1GBのファイルをブロックサイズ4kBで書き込んでアクセス速度を測ります。

1bitモード

まずは/boot/config.txtへの追記内容を以下のようにしたときの速度を測ってみます。

dtoverlay=sdio,poll_once=off,bus_width=1,sdio_overclock=50

結果は以下のようになりました。

file1: (g=0): rw=write, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=psync, iodepth=1
fio-3.12
Starting 1 process
file1: Laying out IO file (1 file / 1024MiB)
Jobs: 1 (f=1): [W(1)][100.0%][w=1628KiB/s][w=407 IOPS][eta 00m:00s]
file1: (groupid=0, jobs=1): err= 0: pid=667: Mon Dec  2 04:37:06 2019
  write: IOPS=406, BW=1626KiB/s (1665kB/s)(1024MiB/644787msec); 0 zone resets
    clat (usec): min=1602, max=20014, avg=2442.16, stdev=763.70
     lat (usec): min=1603, max=20019, avg=2444.70, stdev=763.72
    clat percentiles (usec):
     |  1.00th=[ 1926],  5.00th=[ 1975], 10.00th=[ 2040], 20.00th=[ 2073],
     | 30.00th=[ 2089], 40.00th=[ 2114], 50.00th=[ 2147], 60.00th=[ 2311],
     | 70.00th=[ 2507], 80.00th=[ 2900], 90.00th=[ 3064], 95.00th=[ 3294],
     | 99.00th=[ 3851], 99.50th=[ 9110], 99.90th=[10814], 99.95th=[11338],
     | 99.99th=[13042]
   bw (  KiB/s): min= 1552, max= 1736, per=100.00%, avg=1626.02, stdev=20.09, samples=1289
   iops        : min=  388, max=  434, avg=406.50, stdev= 5.02, samples=1289
  lat (msec)   : 2=8.00%, 4=91.17%, 10=0.61%, 20=0.22%, 50=0.01%
  cpu          : usr=0.59%, sys=7.93%, ctx=265811, majf=0, minf=23
  IO depths    : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     issued rwts: total=0,262144,0,0 short=0,0,0,0 dropped=0,0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=1

Run status group 0 (all jobs):
  WRITE: bw=1626KiB/s (1665kB/s), 1626KiB/s-1626KiB/s (1665kB/s-1665kB/s), io=1024MiB (1074MB), run=644787-644787msec

Disk stats (read/write):
  mmcblk1: ios=0/262310, merge=0/279, ticks=0/592877, in_queue=592690, util=91.91%

IOPS(1秒あたりのIO数)が406,アクセス速度は1665kB/sでした。

4bitモード

次に/boot/config.txtの追記内容を以下のようにして4bitモードでの速度を測ってみます。

dtoverlay=sdio,poll_once=off,sdio_overclock=50

結果は以下のようになりました。

file1: (g=0): rw=write, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=psync, iodepth=1
fio-3.12
Starting 1 process
Jobs: 1 (f=1): [W(1)][100.0%][w=2312KiB/s][w=578 IOPS][eta 00m:00s]
file1: (groupid=0, jobs=1): err= 0: pid=530: Mon Dec  2 04:47:50 2019
  write: IOPS=577, BW=2310KiB/s (2366kB/s)(1024MiB/453837msec); 0 zone resets
    clat (usec): min=921, max=21609, avg=1715.19, stdev=743.28
     lat (usec): min=922, max=21611, avg=1717.64, stdev=743.29
    clat percentiles (usec):
     |  1.00th=[ 1205],  5.00th=[ 1254], 10.00th=[ 1319], 20.00th=[ 1352],
     | 30.00th=[ 1369], 40.00th=[ 1385], 50.00th=[ 1418], 60.00th=[ 1582],
     | 70.00th=[ 1795], 80.00th=[ 2114], 90.00th=[ 2311], 95.00th=[ 2376],
     | 99.00th=[ 3228], 99.50th=[ 8029], 99.90th=[ 9503], 99.95th=[10159],
     | 99.99th=[11207]
   bw (  KiB/s): min= 2160, max= 2504, per=100.00%, avg=2310.03, stdev=34.79, samples=907
   iops        : min=  540, max=  626, avg=577.46, stdev= 8.71, samples=907
  lat (usec)   : 1000=0.01%
  lat (msec)   : 2=75.77%, 4=23.49%, 10=0.68%, 20=0.06%, 50=0.01%
  cpu          : usr=0.77%, sys=3.67%, ctx=263680, majf=0, minf=26
  IO depths    : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     issued rwts: total=0,262144,0,0 short=0,0,0,0 dropped=0,0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=1

Run status group 0 (all jobs):
  WRITE: bw=2310KiB/s (2366kB/s), 2310KiB/s-2310KiB/s (2366kB/s-2366kB/s), io=1024MiB (1074MB), run=453837-453837msec

Disk stats (read/write):
  mmcblk1: ios=1/262264, merge=0/91, ticks=1/435935, in_queue=435340, util=95.99%

IOPSは577,アクセス速度は2366kB/sです。

まとめ

アクセス速度を比較すると1bitモードのとき1665kB/s,4bitモードのとき2366kB/sで,4bitモードにすると1.4倍ほど速くなります。
データシートにはシーケンシャル書き込みは最大50MB/sと書いてありますが,ブロックサイズを大きくすればこれくらい出るということかもしれません。

Fuegoにテストを追加する(スクリプト編)

前回はホストPCにFuegoをインストールし,サンプルを実行しました。 tshell.hatenablog.com

今回はシェルスクリプトとして記述したテストを追加する方法です。

環境

前回と同様以下の環境を使用しました。

  • ホストPC : ubuntu 18.04 LTS
  • ターゲット : Raspberry Pi 3(Raspbian Buster Lite)
  • fuego (Commit eeb3c08c...)

作業手順

以下の作業を行ってテストを追加します。

  1. テストディレクトリの作成
  2. テストスクリプトの作成
  3. spec.jsonの作成
  4. fuego_test.shの作成
  5. テストの登録

今回はmytestという名前のテストを作成します。

ディレクトリ作成

Fuegoのインストールディレクトリにテストを作成します。Fuegoは/home/ユーザー名/fuegoにインストールされているとします。
ホストPCのターミナルで以下のコマンドを実行します。

cd /home/ユーザー名/fuego/fuego-core/tests
mkdir Functional.mytest
cd Functional.mytest

テストスクリプトの作成

作成したFunctional.mytestディレクトリの中にmytest-target.shを以下の内容で作成します。
与えられた引数をそのまま表示するスクリプトです。

#!/bin/bash

echo $1

spec.jsonの作成

以下の内容でテストスペックを設定するファイルspec.jsonを作成します。このファイルは必ずspec.jsonという名称で作成する必要があります。

{
        "testName": "Functional.mytest",
        "specs":{
                "fail":{
                        "ARG":"FAIL"
                },
                "success":{
                        "ARG":"SUCCESS"
                },
                "default":{
                        "ARG":"SUCCESS"
                }
        }
}

ここで設定したARGはあとで述べるfuego_test.shの中でFUNCTIONAL_MYTEST_ARGとして使用できます。spec.jsonの中でARGとだけ記述したものに自動的にテスト名が付加されます。

fuego_test.shの作成

以下の内容でfuego_test.shを作成します。このファイルもfuego_test.shという名前で作成する必要があります。

function test_deploy {
        put $TEST_HOME/mytest-target.sh $BOARD_TESTDIR/fuego.$TESTDIR/
}

function test_run {
        report "cd $BOARD_TESTDIR/fuego.$TESTDIR; \
                ./mytest-target.sh $FUNCTIONAL_MYTEST_ARG"
}

function test_processing {
        log_compare "$TESTDIR" "1" "SUCCESS" "p"
}

function test_deployではテスト実行前にターゲットに対して何を転送するか記述しています。

function test_runではテストを実行する際に何をするか記述しています。 Fuegoのreportコマンドは引数で指定されたコマンドを実行して結果をファイルに保存するコマンドです。

Fuego wiki - function report

test_runの中で,spec.jsonで設定したARGを$FUNCTIONAL_MYTEST_ARGとして使っています。

function test_processingはテスト結果を判定する設定です。log_compareコマンドで結果を判定します。

Fuego wiki - function log_compare

各引数の意味は以下のようになっています。

$1 = reflog_prefix = prefix of reference parsed log filename
$2 = match_count = number of matching results
$3 = results_expression
$4 = results_category (either 'p', 'n', or something else)

log_compare "$TESTDIR" "1" "SUCCESS" "p"と記述した場合は,$TESTDIRからログを読み取ってSUCCESSが含まれれば成功とする,という意味になります。

テストの登録

前回のサンプルと同様にFuegoコンテナのコンソールで以下のコマンドを実行して,作成したテストを登録します。

ftc add-jobs -b myboard -t Functional.mytest

上記のコマンドで登録するとspec.jsonのdefaultに記述した内容が有効になります。別のspecを指定したい場合は以下のようにコマンドを実行します。

ftc add-jobs -b mytest -t Functional.mytest -s fail

以上のようにしてシェルスクリプトで作成したテストをFuegoで実行することができます。

FuegoでRaspberry Piをテストする

Fuegoとは

Fuegoとは組み込みLinux用テストフレームワークです。ターゲットにSSH接続してターゲット上でテストを実行し,Jenkinsでテストを管理することができます。
ターゲット上で動作するソフトの単体テストを実行するものではなく,組み込みシステムとしてのテストを実行するものです。
スペイン語で炎という意味です。(炎上しそうですね)

Fuego wikiArchitectureのページに詳しく載っていますが,

Fuego = (Jenkins + abstraction scripts + pre-packed tests) inside a container

ということでJenkinsとテスト実行のためのスクリプト群,よく使いそうなテストの記述がDockerコンテナとして提供されています。

今回はFuegoのインストールとサンプルのテストの実行までやってみます。

構成

f:id:tshell:20191201091340p:plain

Fuegoの構成は上のような感じになっています。ホストPCからターゲット(ここではRaspberry Pi)に対してSSH接続できるようになっている必要があります。
ホストPCではJenkinsとFuegoのスクリプトが含まれるDockerコンテナが起動し,Jenkinsからテストを実行できます。

テストプログラムはホストPC上でクロスコンパイルされ,Raspberry Piに転送されます。Raspberry Pi上で実行されたテストが標準出力上に結果を返し,この結果によってテストの成功・失敗を判定します。なにをもって成功とするかはテストの設定ファイルに記述します。

テストの設定ファイルはFuegoのインストールディレクトリ内に含まれ,Fuegoのコンテナが起動するときにReadOnlyでコンテナにマウントされます。

開発時には以下のものを操作しながら作業することになります。

  • JenkinsのWebUI操作
  • Fuegoコンテナのコンソール操作
  • Fuegoインストールディレクトリ内のファイル編集

参考情報

公式のWikiを読むとだいたい使えるようになります。

環境

以下の環境を使いました。

  • ホストPC : ubuntu 18.04 LTS
  • ターゲット : Raspberry Pi 3 (Raspbian Buster Lite)
  • Fuego (Commit eeb3c08c...)

Fuegoのインストールとテスト実行

Quick Start Guideに記載されているコマンドを実行していきます。

大まかに以下のような流れです。

  1. ホストPCにFuegoをインストールする
  2. Raspberry Piの設定をする
  3. ホストPCでJenkinsにジョブを登録する

Fuegoのインストール

ホストPC上で以下のコマンドを実行し,必要なパッケージをインストールする。

sudo apt-get update
sudo apt-get install git docker.io

ホストPCで以下のコマンドを実行し,Fuegoのリポジトリをクローンする。

git clone https://bitbucket.org/fuegotest/fuego.git

fuegoディレクトリに移動し,インストール用スクリプトを実行する。
(数十分かかります)

cd fuego
./install.sh

インストールが終了したら以下のコマンドを実行する。

./start.sh

start.shを実行すると以下のように,Fuegoコンテナのコンソールにアタッチされる。

f:id:tshell:20191201093726p:plain

http://localhost:8090/fuegoを開き,以下のような画面が表示されればOK

f:id:tshell:20191201093828p:plain

Raspberry Pi側の準備

既存のユーザー(piなど)でテストを実行しても良いと思いますが,ここでは以下のコマンドを実行し,ユーザーfuegoを作成します。

sudo su
mkdir /home/fuego
adduser fuego
(fuegoのパスワード等設定)

rootでの接続が必要な場合

テストによってはrootでの実行が必要かもしれません。
rootでのSSH接続が必要な場合は/etc/ssh/sshd_configのPermitRootLoginをyesに変更し,SSHサーバーを再起動します。

sudo vi /etc/ssh/sshd_config
(PermitRootLogin をyesに変更)
sudo systemctl restart sshd

ボードファイルの作成

テストの実行対象を設定するボードファイルを作成します。 fuego/fuego-ro/boards内にraspberrypi3.boardがすでにあるので,これをmyboard.boardにコピーして編集します。

cd fuego/fuego-ro/boards
cp raspberrypi3.board myboard.board

myboard.boardは以下のように修正しました。(修正箇所のみ載せています)
IPADDRはRaspberry PiIPアドレスSRV_IPはホストPCのIPアドレスを設定します。また,PASSWORDはRaspberry Piに作成したユーザーfuegoのパスワードを指定します。

IPADDR="192.168.0.10
SSH_PORT="22"
SRV_IP="192.168.0.11"
LOGIN="fuego"
BOARD_TESTDIR="/home/fuego/"
PASSWORD="****"
TOOLCHAIN="debian-armhf"

#TARGET_SETUP_LINK="fuego-lava-target-setup"
#TARGET_TEARDOWN_LINK="fuego-lava-target-teardown"

クロス開発用ツールチェインのインストール

Fuegoコンテナのコンソールで以下のコマンドを実行します。

cd /fuego-ro/toolchains
./install_cross_toolchain.sh

Jenkinsにジョブを登録

Fuegoコンテナのコンソールで以下のコマンドを実行し,Jenkinsにノードを登録します。上で作成したmyboard.boardの内容が登録されます。

ftc add-nodes -b myboard

Fuegoコンテナのコンソールで以下のコマンドを実行し,ジョブを登録します。

ftc add-jobs -b myboard -t Functional.hello_world

テストの実行

Jenkinsでビルドの実行をクリックするとテストがビルドされ,Raspberry Piに転送されたあと実行されます。
Functional.hello_worldはデフォルトでは常に成功します。

f:id:tshell:20191201095833p:plain

FuegoからRaspberry Pi上でテストを実行させることができました。次回はテストの記述方法です。

tshell.hatenablog.com

Raspbian buster-liteでCM3+のeMMCをROM化

前回はRaspberry Pi Compute Module 3+(CM3+)にSDカードを増設しました。 tshell.hatenablog.com

産業用途で使う場合であってもなくても,予期しない電源断によってファイルシステムが飛んで二度と起動しなくなるというのは避けたいところです。
CM3+はeMMCからOSが起動するようになっていますが,今回はeMMCをリードオンリーに設定してみます。

環境

  • Raspberry Pi Compute Module 3+
  • Compute Module IO Board v3.0
  • Raspbian Buster-lite

スワップ領域をSDカードに変更する

メモリが1GBもあるのでスワップなしでもよさそうですが一応スワップありの構成で進めます。以降の作業でeMMCへの書き込みがRAMに保持されるようになるのでスワップファイルがデフォルトの/var/swapのままではスワップの意味をなさなくなります。
前回の記事で増設したSDカード上にスワップファイルを作成し,こちらを使用するようにします。

まずはSDカードをフォーマットして,起動時に/mnt/sdcardにマウントされるようにします。

フォーマット

sudo mkfs -t ext4 /dev/mmcblk1

マウントポイントを作成する

sudo mkdir /mnt/sdcard

UUIDを含む行をfstabに追加しておく

sudo bash
lsblk -f | grep mmcblk1 >> /etc/fstab

fstabを編集する

sudo vi /etc/fstab

以下の行を追加する。(あらかじめUUIDを含む行を追加しているのでそのまま利用する。)

UUID=...    /mnt/sdcard ext4    defaults    0   2

再起動して/mnt/sdcardにlost+foundがあることを確認します。

スワップファイルの作成とdphys-swapfileの設定

SDカード上に256MBのスワップファイルを作成します。

sudo dd if=/dev/zero of=/mnt/sdcard/swap/swap bs=1M count=256
sudo chmod 600 /mnt/sdcard/swap/swap
sudo mkswap /mnt/sdcard/swap/swap

作成したスワップファイルが使えるかテストする

sudo swapoff --all
sudo swapon /mnt/sdcard/swap/swap

free -hを実行してswapのサイズが256MBになっていることを確認します。

/etc/dphys-swapfileを以下のようにコメントアウトを解除して編集します。

CONF_SWAPFILE=/mnt/sdcard/swap/swap
CONF_SWAPSIZE=256

再起動後にfree -hを実行し,swapのサイズが256MBであることを確認します。

以上でスワップファイルを増設したSDカードに移すことができました。

fsprotectをインストールする

続いてeMMCをリードオンリー化していきます。
まずはfsprotectをインストールします。

sudo apt-get install fsprotect

aufs-dkmsのセットアップでエラーが出た場合は,以下のようにpsotinstとpreermを削除してから再度セットアップします。

sudo rm /var/lib/dpkg/info/aufs-dkms.postinst
sudo rm /var/lib/dpkg/info/aufs-dkms.prerm
sudo apt-get install fsprotect

initramfsイメージの作成

以降のステップで編集するhook-functionsなどのファイルを生成するため,update-initramfsを実行します。

sudo update-initramfs -c -k `uname -r`

上記を実行すると/usr/share/initramfs-tools/hooks/fsprotectの処理でコケます。
/usr/bin/touchを読みに行くところで失敗しており,/usr/bin/touchは/bin/touchへのシンボリックリンクなので,/usr/share/initramfs-tools/hooks/fsprotectの最終行を以下のように変更します。

copy_exec /bin/touch "/bin"

再度update-initramfsを実行します。

sudo update-initramfs -c -k `uname -r`

hook-functionsの修正

以下のページを参考に,hook-functionsを修正します。
https://www.raspberrypi.org/forums/viewtopic.php?t=161416

/usr/share/initramfs-tools/hook-functionsの524行目付近を以下のように編集します。
(modulesの最後にoverlayを追加する)

for arg in "$@" ; do
        case "$arg" in
        base)
            modules="$modules btrfs ext2 ext3 ext4 ext4dev overlay"

新しいbootスクリプトを作成する

既存のスクリプトをコピーしてoverlayファイルシステムを使用するように変更します。

cd /usr/share/initramfs-tools/scripts
sudo cp local overlay
sudo cp -rp local-premount overlay-premount
sudo cp -rp local-bottom overlay-bottom

/usr/share/initramfs-tools/scripts/overlayのlocal_mount_root()の中を以下のように修正します。
ここに示した行でlocal_mount_root()が終わるようにします。

#   if [ "${readonly}" = "y" ]; then
        roflag=-r
#   else
#       roflag=-w
#   fi

    # FIXME This has no error checking
    modprobe ${FSTYPE}

    checkfs ${ROOT} root

    # FIXME This has no error checking
    # Mount root
    mkdir /upper /lower
    if [ "${FSTYPE}" != "unknown" ]; then
        mount ${roflag} -t ${FSTYPE} ${ROOTFLAGS} ${ROOT} /lower
    else
        mount ${roflag} ${ROOTFLAGS} ${ROOT} /lower
    fi
    modprobe overlay
    mount -t tmpfs tmpfs /upper
    mkdir /upper/data /upper/work
    mount -t overlay \
        -olowerdir=/lower,upperdir=/upper/data,workdir=/upper/work \
        overlay ${rootmnt}

initramfsの作成

以下のコマンドを実行し,initramfsを作成してリネームします。

sudo update-initramfs -c -k `uname -r`
sudo mv /boot/initrd.img-4.19.66-v7+ /boot/initrd7.img

/boot/config.txt,/boot/cmdline.txtの編集

/boot/config.txtに以下を追記します。

kernel=kernel7.img
initramfs initrd7.img

/boot/cmdline.txtの先頭にboot=overlayを追加して再起動します。

動作確認

再起動後,mountを実行し,overlay on / type overlayのような行があればルートファイルシステムがoverlay fs でマウントされています。
適当なファイルを作成して,再起動すると消えることを見てみましょう。

参考にしたページはRaspbian Pixelを使っていましたが,Raspbian busterでも以前と同様にして実現できるようです。

Raspberry Pi にSDカードスロットを増設する

f:id:tshell:20190904194539j:plain

Raspberry Pi Compute Module 3+(CM3+)にSDカードスロットを増設しました。

CM3+の開発ボード,Compute Module IOにはMicroSDカードスロットが実装されていますが,付近にSD CARD ONLY FOR MODULES WITHOUT ON-BOARD FLASHと書いてあり,eMMCが搭載されているCM3+ではこのスロットが使えません。
CM3+を使うにあたってOSの起動はeMMCから,データの記録はSDカードへ,ということがしたい場合にはGPIOにSDカードを接続して使うことができます。
CM3+と開発ボードを使いましたが,ほかのRaspberry Piでも可能だと思います。

環境

以下のものを使いました。

  • Raspberry Pi Compute Module 3+
  • Compute Module IO rev 3
  • Raspbian Buster-lite

配線

Raspberry PiではGPIO22-27またはGPIO34-39にSDカードを接続するとセカンダリSDとして使用することができます。今回はGPIO22-27に接続しました。

SDカードのピンアサインは以下のようになっています。

f:id:tshell:20190904195247p:plain

CM3+のGPIO22-27には後述する設定により,以下機能を割り当てることができるので,SDカードのピンの対応するものを接続します。
なお,VCCには3.3Vを,VSSはGNDに接続します。

GPIO 機能 SD
22 SD1_CLK CLK
23 SD1_CMD CMD
24 SD1_DAT0 DAT0
25 SD1_DAT1 DAT1
26 SD1_DAT2 DAT2
27 SD1_DAT3 DAT3

設定

ここのソースをダウンロードします。sdio22-overlay.dtsに名前を変えて,以下のコマンドを実行します。

sudo dtc -@ -I dts -O dtb -o sdio22.dtbo sdio22-overlay.dts

作成されたsdio22.dtboを/boot/overlaysに移動します。

sudo mv sdio22.dtbo /boot/overlays/

/boot/config.txtに以下を追記して再起動します。

dtoverlay=sdio22,poll_once=off,bus_width=1,sdio_overclock=50

接続確認

dmesg | grep mmcを実行し,以下のような表示があれば増設したSDがmmc1として認識されています。mmc0はCM3+に実装されているeMMCです。

[    2.554010] mmc1: host does not support reading read-only switch, assuming write-enable
[    2.573205] mmc1: new high speed SDHC card at address aaaa
[    2.616025] mmcblk1: mmc1:aaaa SA08G 7.40 GiB
[    2.705981]  mmcblk1: p1

Raspberry PiにSDカードを増設したかったらUSBに接続してしまうのが手っ取り早いと思いますが,CM3+を使って自分で基板を起こすとかRaspberry Pi Zeroを使うという場合には以上のような方法が使えると思います。

Nano Pi NEO 2のセットアップ

Frendly ArmのNano Pi NEO 2 WikiのInstall OSの項を参照
nanopi-neo2_sd_friendlycore-xenial_4.14_arm64_20190430.img.zipをダウンロード

Nano Pi NEOでは書き込むイメージが違うので注意
Frendly ArmのNano Pi NEO Wiki

Win32DiskImagerで書き込む。
イメージを指定して,下部のWriteボタンを押す。
f:id:tshell:20190612203256p:plain

確認ダイアログが表示されるので,Yesを選択する。
f:id:tshell:20190612203403p:plain

書き込み中
f:id:tshell:20190612203437p:plain

終了するとダイアログが出る。
f:id:tshell:20190612203507p:plain

書き込み済みのマイクロSDをマウントしようとするが,Windowsが対応していないファイルシステムのため,フォーマットするか聞かれる。キャンセルを選択して,マイクロSDをPCから取り出す。
f:id:tshell:20190612203532p:plain

マイクロSDカードを本体に挿入して起動する。
IPアドレスDHCPで設定されるが,何に設定されたかわからない場合はシリアルコンソールで接続して調査する。
シリアルコンソール用のピンはUSB端子の近く,2.54mmピンヘッダ,外側からGND,5V,RX, TX(RX,TXはNano Pi NEO 2側,シリアルケーブルはクロスになるようにつなぐ) ボーレートは115200bps

ifconfigでipアドレスを調べる。
f:id:tshell:20190612203609p:plain

ssh接続する。ユーザー名,パスワードともにpi
f:id:tshell:20190612203637p:plain

ログインすると以下のような画面が表示される。
f:id:tshell:20190612203704p:plain

固定IPの設定

公式Wikiの以下ページを参考に固定IPの設定を行う。
Use NetworkManager to configure network settings

NetworkManagerで設定する。
nmcli connection showで現在の設定を見る。
f:id:tshell:20190612203823p:plain

nmcli connection modifyで設定し,再起動する。
f:id:tshell:20190612203902p:plain

あとは自由に使えます。