みつきんのメモ

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

Yocto BBC micro:bit V1向けのZephyrを試してみる

はじめに

YoctoでZephyrをビルドできるっぽいことは知っていたが、試したことがなかったのでやってみる。

使用するバージョンはhardknott

構築手順

ソース取得

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

$ mkdir -p mb-hardknott && cd mb-hardknott
$ git clone git://git.yoctoproject.org/poky.git -b hardknott

環境変数設定

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

自動的にビルドディレクトリに移動される。 これで、bitbake関連のツールが使用可能になる。

レイヤ追加

下記のコマンドでビルド対象にmeta-armmeta-zephyrを追加する。

$ bitbake-layers layerindex-fetch meta-arm meta-zephyr

複数のレイヤを一度に指定することもできる。

レイヤ 目的
meta-arm MACHINEでmicrobit-v1を使用するため
meta-zephyr Zephyrをビルドするため

local.confの修正

MACHINEをmicrobit-v1に設定する。

MACHINE = "microbit-v1"
DL_DIR ?= "${TOPDIR}/../downloads"

ビルド

hello worldをビルドしてみる。

$ bitbake zephyr-helloworld

build/tmp/deploy/images/microbit-v1以下にビルド結果のelfが配置される。

  • zephyr-helloworld-image-microbit-v1.elf
  • zephyr-helloworld-image-microbit-v1.qemuboot.conf
  • zephyr-helloworld-microbit-v1-20210826075435.qemuboot.conf
  • zephyr-helloworld.elf

プログラム本体はzephyr-helloworld.elf

Linuxをビルド

ためしにcore-image-baseをビルドしようとしてみる。

$ bitbake-layers show-layers 
NOTE: Starting bitbake server...
layer                 path                                      priority
==========================================================================
meta                  /home/mickey/work/yocto/x86-hardknott/mb-hardknott/poky/meta  5
meta-poky             /home/mickey/work/yocto/x86-hardknott/mb-hardknott/poky/meta-poky  5
meta-yocto-bsp        /home/mickey/work/yocto/x86-hardknott/mb-hardknott/poky/meta-yocto-bsp  5
meta-arm-toolchain    /home/mickey/work/yocto/x86-hardknott/mb-hardknott/poky/meta-arm/meta-arm-toolchain  5
meta-oe               /home/mickey/work/yocto/x86-hardknott/mb-hardknott/poky/meta-openembedded/meta-oe  6
meta-python           /home/mickey/work/yocto/x86-hardknott/mb-hardknott/poky/meta-openembedded/meta-python  7
meta-arm              /home/mickey/work/yocto/x86-hardknott/mb-hardknott/poky/meta-arm/meta-arm  5
meta-zephyr           /home/mickey/work/yocto/x86-hardknott/mb-hardknott/poky/meta-zephyr  6
mickey@yocto-build:~/work/yocto/x86-hardknott/mb-hardknott/build$ vim ./conf/local.conf 
mickey@yocto-build:~/work/yocto/x86-hardknott/mb-hardknott/build$ bitbake core-image-base
Loading cache: 100% |                                                                | ETA:  --:--:--
Loaded 0 entries from dependency cache.
Parsing recipes: 100% |###############################################################| Time: 0:00:34
Parsing of 2123 .bb files complete (0 cached, 2123 parsed). 3398 targets, 180 skipped, 0 masked, 0 errors.
NOTE: Resolving any missing task queue dependencies
ERROR: Nothing PROVIDES 'virtual/kernel'
linux-yocto PROVIDES virtual/kernel but was skipped: incompatible with machine microbit-v1 (not in COMPATIBLE_MACHINE)
linux-dummy PROVIDES virtual/kernel but was skipped: incompatible with host arm-poky-eabi (not in COMPATIBLE_HOST)
linux-yocto-rt PROVIDES virtual/kernel but was skipped: incompatible with machine microbit-v1 (not in COMPATIBLE_MACHINE)
linux-yocto-tiny PROVIDES virtual/kernel but was skipped: incompatible with machine microbit-v1 (not in COMPATIBLE_MACHINE)
linux-arm64-ack PROVIDES virtual/kernel but was skipped: incompatible with machine microbit-v1 (not in COMPATIBLE_MACHINE)
linux-yocto-dev PROVIDES virtual/kernel but was skipped: incompatible with machine microbit-v1 (not in COMPATIBLE_MACHINE)
linux-yocto PROVIDES virtual/kernel but was skipped: incompatible with machine microbit-v1 (not in COMPATIBLE_MACHINE)
linux-yocto-tiny PROVIDES virtual/kernel but was skipped: incompatible with machine microbit-v1 (not in COMPATIBLE_MACHINE)
linux-yocto-rt PROVIDES virtual/kernel but was skipped: incompatible with machine microbit-v1 (not in COMPATIBLE_MACHINE)
ERROR: Required build target 'core-image-base' has no buildable providers.
Missing or unbuildable dependency chain was: ['core-image-base', 'virtual/kernel']

Summary: There were 2 ERROR messages shown, returning a non-zero exit code.

非対応のマシンということでちゃんとエラーになった。

エミュレータ(qemu)で実行

下記のようにするとqemuでプログラムを実行することができる。

$ runqemu
(... snip ...)

*** Booting Zephyr OS build zephyr-v2.5.0  ***
Hello World! qemu_cortex_m0

ssh越しなどで、うまく文字列が表示されない場合は下記のようにオプションを渡して、シリアルの出力先を標準出力などに変えてやると、うまく行くことがある。

$ runqemu qemux86 qemuparams="-serial mon:stdio"

実機に書き込む

micro:bitの実機にプログラムを書き込む場合は、elfからbinary形式に変換する必要がある。

$ cd tmp/deploy/images/microbit-v1
$ arm-none-eabi-objcopy zephyr-helloworld.elf zephyr-helloworld.bin -O binary

micro:bitUbuntu 20.04のマシンににUSBで接続すると、/media/mickey/MICROBIT/として見えるようになる。

変換したbinary形式のファイルを下記のようにmicro:bitにコピーすると自動的リセットがかかり、新しいプログラムが読み込まれる。

cp ./zephyr-helloworld.bin /media/mickey/MICROBIT/

micro:bitのUSB-UARTは/dev/ttyACM0として見えているので、minicomなどで開く。

minicom -D /dev/ttyACM0

この状態でmicro:bitのリセットボタンを押すと下記のように出力される。

*�*** Booting Zephyr OS build zephyr-v2.5.0  ***
Hello World! qemu_cortex_m0

リセット直後の出力にゴミが入るが、プログラムは正しく動いているようだ。

バイナリファイルについて

実際のところ、bitbakeの結果としてzephyr.binも出来上がっている。 しかし、zephyr-hellworld.bbから読み込まれるzephyr-sample.incで定義されているdo_deployタスクが 下記のようにelfのみをコピーするようになっているので、binは放置されているようだ。

do_deploy () {
    install -D ${B}/zephyr/${ZEPHYR_MAKE_OUTPUT} ${DEPLOYDIR}/${PN}.elf
}

まとめ

Yocto Projectを使用してZephyrのmicro:bit向けバイナリをビルドすることができた。 生成されたバイナリはqemuでも実機でも動作することが確認できた。

実際Zephyrを直接ビルドするよりも、bitbakeのほうが時間かかる。 bitbakeでツールチェインやzephyrのカーネルなど、すべて構築されるのでそこはメリットと言えるかもしれない。

emacs markdown-modeで表を作成する

はじめに

筆者はemacsmarkdownを書く時にはmarkdown-modeのパッケージをインストールして、gfm-modeを使用する。

.emacs/init.elは多分こんな感じ。

;; Markdown mode
(use-package markdown-mode
  :ensure t
  :init
  (add-to-list 'auto-mode-alist '("\\.md$" . gfm-mode)))

表を作る基本

下記のような表を作りたいとする。

番号 項目
1 いちばん
2 にばん

markdownとしては下記のように記述する。

| 番号 | 項目     |
|------|----------|
| 1    | いちばん |
| 2    | にばん   |

これをいちいち手入力するのは結構面倒くさい。

下記のようなテキストを手入力して

|||
|-|

C-iすると表のように整形してくれることに気づいた

|   |   |
|---|---|

そして手入力で

| 番号  |   |
|---|---|

とやったあとでC-iすると、下記のように自動で整形してくれる。

| 番号 |   |
|------|---|

しばらくはこれで表を入力していた。

一括で値を設定したい

まとまったデータをコピペしてきて表にしたい場合、上記のやり方でも結構面倒くさい。

例えば下記のようなまとまったデータがある場合。CSVのデータとか。

番号,項目
1,いちばん
2,にばん
3,さんばん

これをset-markで選択状態にしてC-c C-c |と入力すると下記のようにしてくれる。

| 番号 | 項目     |
| 1    | いちばん |
| 2    | にばん   |
| 3    | さんばん |

その後に2行目に|-|を追加して

| 番号 | 項目     |
|-|
| 1    | いちばん |
| 2    | にばん   |
| 3    | さんばん |

C-iするとこのようになる。

| 番号 | 項目     |
|------|----------|
| 1    | いちばん |
| 2    | にばん   |
| 3    | さんばん |

つまり、markdown-modeで表を作る時はまずはコンマ区切りのデータを並べる。 C-c C-c |で表の形にして、ヘッダと値の分離は|-|+C-iで行う。

まとめ

この作り方を知らない頃はTables Generatorを使用していた。

ただ、これだとデータをオンラインでサーバに送るような気がしていて、仕事で使うのはちょっと心配だった。 ひょっとしたらJavaScriptでブラウザ上で完結していてサーバにデータを送るようなことはしないのかもしれないが。

まとまったデータをCSVにすること自体は割とどのようにでもできるので、 markdown-modeで表を作る時にこのやり方を知っているとかなり便利。

Yocto Project 3.3(Hardknott)で日本語入力

はじめに

Yocto Project 3.3(Hardknott)でラズベリーパイ4を動かすの環境をベースに、Hardknottで日本語入力環境を作成してみる。

かなり古いがyoctoで日本語入力も参考にする。

作業環境の準備

meta-oeをビルド環境に設定する。

$ cd rpi-hardknott
$ source poky/oe-init-build-env build
$ bitbake-layers layerindex-fetch meta-oe

local.confの修正

Yocto Project 3.3(Hardknott)でラズベリーパイ4を動かすで変更したconf/local.confの内容に下記を追加する。

IMAGE_INSTALL_append = " uim-xim uim-utils uim-common uim-gtk2.0 uim-gtk3 uim-anthy"
IMAGE_INSTALL_append = " ttf-vlgothic ttf-sazanami-gothic"
IMAGE_INSTALL_append = " setxkbmap"

IMAGE_LINGUAS = "ja-jp ja-jp.euc-jp"
GLIBC_GENERATE_LOCALES = "ja_JP.UTF-8 ja_JP.EUC-JP"

ビルド

下記のようにcore-image-satoをビルドする。

$ bitbake core-image-sato

ビルドには数時間かかる。

rootfs作成でエラー

最後の最後、core-image-satoのdo_rootfsの処理で下記のエラーが発生する。

Last metadata expiration check: 0:00:01 ago on Mon 05 Jul 2021 03:35:45 PM UTC.
No match for argument: uim-gtk2.0
No match for argument: uim-gtk3
No match for argument: uim-xim
Error: Unable to find a match: uim-gtk2.0 uim-gtk3 uim-xim

uimのレシピで作成されるはずの下記のパッケージが存在しないと言っている。

uimレシピのパッケージ生成状況の確認

まずは下記のコマンドを実行し、uimレシピのdevshellを起動する。

$ bitbake uim -c devshell

自動的にuimのソースディレクトリに移動されるので、次のようにしてパッケージがどのように生成されたかを確認する。

まずはuim-gtk2.0

# tree ../packages-split/uim-gtk2.0/
../packages-split/uim-gtk2.0/

0 directories, 0 files

続いてuim-gtk3

# tree ../packages-split/uim-gtk3/
../packages-split/uim-gtk3/

0 directories, 0 files

最後にgtk-xim

# tree ../packages-split/uim-xim/
../packages-split/uim-xim/

0 directories, 0 files

確かに全てのパッケージが空で生成されている。

config.logの確認

lessでconfig.logを開く。

# less ../build/config.log

gtkで検索してみる。

... (snip) ...
configure:30647: checking for gtk+-2.0 >= 2.2.0 gdk-x11-2.0
configure:30706: result: no
configure:30718: checking for gtk+-2.0 >= 2.4.0 gdk-x11-2.0
configure:30777: result: no
... (snip) ...
configure:30998: checking for gtk+-3.0
configure:31057: result: no

pkg-configでライブラリが見つかっていないように見える。

pkg-configの確認

devshell上でpkg-configを実行してみる。

gtk+-2.0

# pkg-config --libs gtk+-2.0
-lgtk-x11-2.0 -lgdk-x11-2.0 -lpangocairo-1.0 -latk-1.0 -lcairo -lgdk_pixbuf-2.0 -lgio-2.0 -lpangoft2-1.0 -lpango-1.0 -lgobject-2.0 -lglib-2.0 -lharfbuzz -lfontconfig -lfreetype

gtk+-3.0

# pkg-config --libs gtk+-3.0
-lgtk-3 -lgdk-3 -lpangocairo-1.0 -lpango-1.0 -lharfbuzz -latk-1.0 -lcairo-gobject -lcairo -lgdk_pixbuf-2.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0

どちらも見つかる。

本格的に何かがおかしい。

ログを強化する

devshellを抜けて、uimのレシピのdo_configureタスクを実行し直す。

$ bitbake uim -c configure -vvv -f

強化されたログを確認する

devshellに入り直し、log.do_configureを確認する。

# less ../temp/log.do_configure

../uim-1.8.8/configureで検索すると下記のようなログが見つかる。

+ CONFIG_SHELL=/bin/bash ../uim-1.8.8/configure --build=x86_64-linux --host=aarch64-poky-linux --target=aarch64-poky-linux --prefix=/usr --exec_prefix=/usr --bindir=/usr/bin --sbindir=/usr/sbin --libexecdir=/usr/libexec --datadir=/usr/share --sysconfdir=/etc --sharedstatedir=/com --localstatedir=/var --libdir=/usr/lib --includedir=/usr/include --oldincludedir=/usr/include --infodir=/usr/share/info --mandir=/usr/share/man --disable-dependency-tracking --with-libtool-sysroot=/home/mickey/work/yocto/rpi-hardknott/build/tmp/work/cortexa72-poky-linux/uim/1.8.8-r0/recipe-sysroot --disable-emacs --with-libedit=/home/mickey/work/yocto/rpi-hardknott/build/tmp/work/cortexa72-poky-linux/uim/1.8.8-r0/recipe-sysroot/usr --without-scim --without-m17nlib --without-prime --without-canna --without-mana --without-eb --disable-static --enable-nls

これが実際に実行されているconfigureのコマンドラインだと推測される。

情報を増やすためにdevshell上で下記のように実行してみる。ポイントはCONFIG_SHELLに設定するbashの引数に-xを設定することと、標準出力と標準エラー出力の内容をファイルに保存すること。

# cd ../build
# CONFIG_SHELL='/bin/bash -x' ../uim-1.8.8/configure --build=x86_64-linux --host=aarch64-poky-linux --target=aarch64-poky-linux --prefix=/usr --exec_prefix=/usr --bindir=/usr/bin --sbindir=/usr/sbin --libexecdir=/usr/libexec --datadir=/usr/share --sysconfdir=/etc --sharedstatedir=/com --localstatedir=/var --libdir=/usr/lib --includedir=/usr/include --oldincludedir=/usr/include --infodir=/usr/share/info --mandir=/usr/share/man --disable-dependency-tracking --with-libtool-sysroot=/home/mickey/work/yocto/rpi-hardknott/build/tmp/work/cortexa72-poky-linux/uim/1.8.8-r0/recipe-sysroot --disable-emacs --with-libedit=/home/mickey/work/yocto/rpi-hardknott/build/tmp/work/cortexa72-poky-linux/uim/1.8.8-r0/recipe-sysroot/usr --without-scim --without-m17nlib --without-prime --without-canna --without-mana --without-eb --disable-static --enable-nls > configure.txt 2>&1

いろいろ調べた結果下記のコマンドで得られた情報が有効だった。ログの感じからpkg-configコマンドでライブラリを調べているっぽい部分のtestによる比較が、空との比較になっているようだ。

# grep -i 'checking.*gtk' -A10 configure.txt
+ printf '%s\n' 'configure:30623: checking for gtk+-2.0 >= 2.2.0 gdk-x11-2.0'
+ printf %s 'checking for gtk+-2.0 >= 2.2.0 gdk-x11-2.0... '
checking for gtk+-2.0 >= 2.2.0 gdk-x11-2.0... + test -n ''
+ test -n ''
+ pkg_failed=untried
+ test -n ''
+ test -n ''
+ pkg_failed=untried
+ test untried = yes
+ test untried = untried
+ printf '%s\n' 'configure:30682: result: no'
+ printf '%s\n' no
no
... (snip) ...

configureスクリプトの30623行以降の判定分を確認してみる。

{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gtk+-2.0 >= 2.2.0 gdk-x11-2.0" >&5
printf %s "checking for gtk+-2.0 >= 2.2.0 gdk-x11-2.0... " >&6; }

if test -n "$GTK2_CFLAGS"; then
    pkg_cv_GTK2_CFLAGS="$GTK2_CFLAGS"
 elif test -n "$PKG_CONFIG"; then
    if test -n "$PKG_CONFIG" && \
    { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtk+-2.0 >= 2.2.0 gdk-x11-2.0\""; } >&5
  ($PKG_CONFIG --exists --print-errors "gtk+-2.0 >= 2.2.0 gdk-x11-2.0") 2>&5
  ac_status=$?
  printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }; then
  pkg_cv_GTK2_CFLAGS=`$PKG_CONFIG --cflags "gtk+-2.0 >= 2.2.0 gdk-x11-2.0" 2>/dev/null`
                      test "x$?" != "x0" && pkg_failed=yes
else
  pkg_failed=yes
fi
 else
    pkg_failed=untried
fi

下記の変数の内容が空になっていると思われる。

  • GTK2_CFLAGS
  • PKG_CONFIG

PKG_CONFIGはpkg-configコマンドのパスが格納されている必要があるので、これはおかしい。

念の為、devshellでpkg-configのパスを確認する。

# which pkg-config
/home/mickey/work/yocto/rpi-hardknott/build/tmp/work/cortexa72-poky-linux/uim/1.8.8-r0/recipe-sysroot-native/usr/bin/pkg-config

ちゃんとrecipes-sysroot-native以下のコマンドを呼び出している。

どうやら、configureスクリプトのpkg-config検出に問題があるっぽい。

PKG_CONFIGを設定してみる

PKG_CONFIGは環境変数によっても制御できるようなので、手動で設定してみる。

# export PKG_CONFIG=`which pkg-config`
# CONFIG_SHELL='/bin/bash -x' ../uim-1.8.8/configure --build=x86_64-linux --host=aarch64-poky-linux --target=aarch64-poky-linux --prefix=/usr --exec_prefix=/usr --bindir=/usr/bin --sbindir=/usr/sbin --libexecdir=/usr/libexec --datadir=/usr/share --sysconfdir=/etc --sharedstatedir=/com --localstatedir=/var --libdir=/usr/lib --includedir=/usr/include --oldincludedir=/usr/include --infodir=/usr/share/info --mandir=/usr/share/man --disable-dependency-tracking --with-libtool-sysroot=/home/mickey/work/yocto/rpi-hardknott/build/tmp/work/cortexa72-poky-linux/uim/1.8.8-r0/recipe-sysroot --disable-emacs --with-libedit=/home/mickey/work/yocto/rpi-hardknott/build/tmp/work/cortexa72-poky-linux/uim/1.8.8-r0/recipe-sysroot/usr --without-scim --without-m17nlib --without-prime --without-canna --without-mana --without-eb --disable-static --enable-nls > configure.txt 2>&1

実行結果を確認する。

+ printf '%s\n' 'configure:30623: checking for gtk+-2.0 >= 2.2.0 gdk-x11-2.0'
+ printf %s 'checking for gtk+-2.0 >= 2.2.0 gdk-x11-2.0... '
checking for gtk+-2.0 >= 2.2.0 gdk-x11-2.0... + test -n ''
+ test -n /home/mickey/work/yocto/rpi-hardknott/build/tmp/work/cortexa72-poky-linux/uim/1.8.8-r0/recipe-sysroot-native/usr/bin/pkg-config
+ test -n /home/mickey/work/yocto/rpi-hardknott/build/tmp/work/cortexa72-poky-linux/uim/1.8.8-r0/recipe-sysroot-native/usr/bin/pkg-config
+ printf '%s\n' 'configure:30630: $PKG_CONFIG --exists --print-errors "gtk+-2.0 >= 2.2.0 gdk-x11-2.0"'
+ ac_status=0
+ printf '%s\n' 'configure:30633: $? = 0'
+ test 0 = 0
++ /home/mickey/work/yocto/rpi-hardknott/build/tmp/work/cortexa72-poky-linux/uim/1.8.8-r0/recipe-sysroot-native/usr/bin/pkg-config --cflags 
'gtk+-2.0 >= 2.2.0 gdk-x11-2.0'
+ pkg_cv_GTK2_CFLAGS='-pthread -I/home/mickey/work/yocto/rpi-hardknott/build/tmp/work/cortexa72-poky-linux/uim/1.8.8-r0/recipe-sysroot/usr/i
nclude/gtk-2.0 -I/home/mickey/work/yocto/rpi-hardknott/build/tmp/work/cortexa72-poky-linux/uim/1.8.8-r0/recipe-sysroot/usr/include/atk-1.0 -
I/home/mickey/work/yocto/rpi-hardknott/build/tmp/work/cortexa72-poky-linux/uim/1.8.8-r0/recipe-sysroot/usr/include/gtk-2.0 -I/home/mickey/wo
rk/yocto/rpi-hardknott/build/tmp/work/cortexa72-poky-linux/uim/1.8.8-r0/recipe-sysroot/usr/lib/gtk-2.0/include -I/home/mickey/work/yocto/rpi
-hardknott/build/tmp/work/cortexa72-poky-linux/uim/1.8.8-r0/recipe-sysroot/usr/include/pango-1.0 -I/home/mickey/work/yocto/rpi-hardknott/bui
ld/tmp/work/cortexa72-poky-linux/uim/1.8.8-r0/recipe-sysroot/usr/include/harfbuzz -I/home/mickey/work/yocto/rpi-hardknott/build/tmp/work/cor
texa72-poky-linux/uim/1.8.8-r0/recipe-sysroot/usr/include/pango-1.0 -I/home/mickey/work/yocto/rpi-hardknott/build/tmp/work/cortexa72-poky-li
nux/uim/1.8.8-r0/recipe-sysroot/usr/include/fribidi -I/home/mickey/work/yocto/rpi-hardknott/build/tmp/work/cortexa72-poky-linux/uim/1.8.8-r0
/recipe-sysroot/usr/include/harfbuzz -I/home/mickey/work/yocto/rpi-hardknott/build/tmp/work/cortexa72-poky-linux/uim/1.8.8-r0/recipe-sysroot
/usr/include/cairo -I/home/mickey/work/yocto/rpi-hardknott/build/tmp/work/cortexa72-poky-linux/uim/1.8.8-r0/recipe-sysroot/usr/include/pixma
n-1 -I/home/mickey/work/yocto/rpi-hardknott/build/tmp/work/cortexa72-poky-linux/uim/1.8.8-r0/recipe-sysroot/usr/include/uuid -I/home/mickey/
work/yocto/rpi-hardknott/build/tmp/work/cortexa72-poky-linux/uim/1.8.8-r0/recipe-sysroot/usr/include/freetype2 -I/home/mickey/work/yocto/rpi
-hardknott/build/tmp/work/cortexa72-poky-linux/uim/1.8.8-r0/recipe-sysroot/usr/include/libdrm -I/home/mickey/work/yocto/rpi-hardknott/build/
tmp/work/cortexa72-poky-linux/uim/1.8.8-r0/recipe-sysroot/usr/include/libpng16 -I/home/mickey/work/yocto/rpi-hardknott/build/tmp/work/cortex
a72-poky-linux/uim/1.8.8-r0/recipe-sysroot/usr/include/gdk-pixbuf-2.0 -I/home/mickey/work/yocto/rpi-hardknott/build/tmp/work/cortexa72-poky-
linux/uim/1.8.8-r0/recipe-sysroot/usr/include/libmount -I/home/mickey/work/yocto/rpi-hardknott/build/tmp/work/cortexa72-poky-linux/uim/1.8.8
-r0/recipe-sysroot/usr/include/blkid -I/home/mickey/work/yocto/rpi-hardknott/build/tmp/work/cortexa72-poky-linux/uim/1.8.8-r0/recipe-sysroot
/usr/include/glib-2.0 -I/home/mickey/work/yocto/rpi-hardknott/build/tmp/work/cortexa72-poky-linux/uim/1.8.8-r0/recipe-sysroot/usr/lib/glib-2
.0/include'
+ test x0 '!=' x0
+ test -n ''

これまで空だった変数に値が設定され、pkg-configコマンドが実行されているように見える。

# tail config.log
#define GNOME3LOCALEDIR "/usr/share/locale"
#define XLIB_DIR "/usr/share"
#define UIM_PIXMAPSDIR "/usr/share/uim/pixmaps"
#define USE_GTK2 1
#define USE_GTK3 1
#define HAVE_FORKPTY 1
#define UIM_USE_NOTIFY_PLUGINS 1
#define UIM_USE_ERROR_GUARD 1

configure: exit 0

gtk2とgtk3は認識されたっぽい。

修正方法

bbappendを作成する

uimのdo_configureの時点でPKG_CONFIG環境変数が設定されるようにするためにbbappendを作成する。

$ bitbake-layers create-layer meta-local
$ mv ./meta-local ../poky/
$ bitbake-layers add-layer ../poky/meta-local/
$ recipetool newappend -e ../poky/meta-local uim

-eをつけてrecipetool newappendを実行すると、作成されたbbappendファイルがエディタで開かれた状態になるので、下記の内容を追加する。

do_configure_prepend() {
    export PKG_CONFIG="${RECIPE_SYSROOT_NATIVE}/usr/bin/pkg-config"
}

ビルド

$ bitbake uim -f 

パッケージ生成結果の確認

$ bitbake uim -c devshell

devshell上で下記のコマンドを実行する。

# tree uim-gtk* uim-xim
uim-gtk2.0
└── usr
    ├── bin
    │   ├── uim-im-switcher-gtk
    │   ├── uim-input-pad-ja
    │   ├── uim-pref-gtk
    │   ├── uim-toolbar-gtk
    │   └── uim-toolbar-gtk-systray
    └── lib
        └── gtk-2.0
            └── 2.10.0
                └── immodules
                    └── im-uim.so
uim-gtk2.0.shlibdeps [error opening dir]
uim-gtk3
└── usr
    ├── bin
    │   ├── uim-im-switcher-gtk3
    │   ├── uim-input-pad-ja-gtk3
    │   ├── uim-pref-gtk3
    │   ├── uim-toolbar-gtk3
    │   └── uim-toolbar-gtk3-systray
    └── lib
        └── gtk-3.0
            └── 3.0.0
                └── immodules
                    └── im-uim.so
uim-gtk3.shlibdeps [error opening dir]
uim-xim
└── usr
    ├── bin
    │   └── uim-xim
    ├── libexec
    │   ├── uim-candwin-gtk
    │   ├── uim-candwin-gtk3
    │   ├── uim-candwin-horizontal-gtk
    │   ├── uim-candwin-horizontal-gtk3
    │   ├── uim-candwin-tbl-gtk
    │   └── uim-candwin-tbl-gtk3
    └── share
        └── man
            └── man1
                └── uim-xim.1

18 directories, 20 files

必要なファイルが作成されていることがわかる。

日本語入力環境をビルド

core-image-satoをビルドしてみる。

$ bitbake core-image-sato

動作確認

ラズパイを起動し、rootでログインしたあと~/.profileを下記の内容で作成しrebootする。

export LC_ALL=ja_JP.UTF-8
export GTK_IM_MODULE="uim"
export XMODIFIERS="@im=uim-anthy"
uim-xim &
uim-toolbar-gtk-systray &
setxkbmap -layout jp

再起動後、キーボードも日本語配列になり、 「shift+スペース」で日本語入力ができるようになる。

f:id:mickey_happygolucky:20210706090553p:plain
日本語入力の例

まとめ

しばらく放置していたらuimのレシピがまた使えなくなっていた。

おそらくuimのバージョンが上がったことに原因がある。

本来はconfigureスクリプトがなぜpkg-configコマンドを検出しないかを調査し、修正する必要があるが、今回は環境変数PKG_CONFIGを設定することで対処した。

若干修正が必要だが、hardknottでも日本語入力環境を作成することができることがわかった。

Yocto Project 3.3(Hardknott)でラズベリーパイ4を動かす

はじめに

Yocto Project 3.3がリリースされていた。

リリースされた事自体は知っていたが、meta-raspberrypiをビルドする際に、bitbake-layers layerindex-fetchがうまく動かなかったので、しばらく様子を見ていた。

具体的には下記のようなこと。

  • OpenEmbedded Layer Indexとの接続に使用される証明書がエラーになった
  • OpenEmbedded Layer Indexのhardknottブランチにmeta-raspberrypiが登録されていなかった

5/26時点で、これらの問題が解消されたことを確認した。

構築手順

ソース取得

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

$ mkdir -p rpi-hardknott
$ cd rpi-hardknott
$ git clone git://git.yoctoproject.org/poky.git -b hardknott

環境変数設定

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

自動的にビルドディレクトリに移動される。 これで、bitbake関連のツールが使用可能になる。

レイヤ追加

下記のコマンドでビルド対象にmeta-raspberrypiを追加する。

$ bitbake-layers layerindex-fetch meta-raspberrypi

local.confの修正

MACHINEをraspberrypi4-64に設定し、UARTを有効化する。

MACHINE = "raspberrypi4-64"
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 = ""

# connman
IMAGE_INSTALL_append = " connman \
                 connman-client \
"

ビルド

core-image-baseをビルドする。

$ bitbake core-image-base

書き込み

bmaptoolで書き込む。

$ sudo bmaptool copy core-image-base-raspberrypi4.wic.bz2 /dev/sdX

/dev/sdXは環境に応じて適宜読み替える。

起動

OSを書き込んだマイクロSDカードをラズベリーパイ4に挿入し起動する。

rootでログインしたあと下記のコマンドで環境を確認する。

# cat /etc/os-release
ID=poky
NAME="Poky (Yocto Project Reference Distro)"
VERSION="3.3.1 (hardknott)"
VERSION_ID=3.3.1
PRETTY_NAME="Poky (Yocto Project Reference Distro) 3.3.1 (hardknott)"
# uname -a
Linux raspberrypi4-64 5.10.31-v8 #1 SMP PREEMPT Fri Apr 23 15:16:49 UTC 2021 aarch64 GNU/Linux

hardknottが起動したことが確認できた。

まとめ

3.3がリリースされていた。

リリース直後はbitbake-layers layerindex-fetchがうまく動作しないことがあるということがわかった。

ユーザーが使用する機能としては便利になった反面、正しく動作する環境を提供するコストは高くなったのかもしれない。

開発者の皆さんに感謝。

Yocto Chromiumをビルドする時に何回やってもリンカでSegmentation faultする時の対応

はじめに

YoctoでChromiumをビルドする時に下記のようにエラーで終了する。

... (snip) ...

nterface.o
| ninja: build stopped: subcommand failed.
| WARNING: exit code 1 from a shell command.
| 
ERROR: Task (/home/mickey/work/yocto/rpi-gatesgarth/poky/meta-browser/meta-chromium/recipes-browser/chromium/chromium-x11_89.0.4389.90.bb:do_compile) failed with exit code '1'
NOTE: Tasks Summary: Attempted 3513 tasks of which 3512 didn't need to be rerun and 1 failed.

Summary: 1 task failed:
  /home/mickey/work/yocto/rpi-gatesgarth/poky/meta-browser/meta-chromium/recipes-browser/chromium/chromium-x11_89.0.4389.90.bb:do_compile
Summary: There was 1 ERROR message shown, returning a non-zero exit code

試しにリトライしても、meta-clangのブランチを変えても、キャッシュを消しても同じところでエラーになる。

エラーの詳細を調べる

ログファイルの特定

こういうケースではどのログファイルを参照するかをまず、調べる必要がある。そのためにtmp/log/cooker/raspberrypi4-64/console-latest.logを参照する。

このファイルの末尾の方に下記のようにエラーが起きているタスクのログファイルのフルパスが表示されている。

ERROR: Logfile of failure stored in: /home/mickey/work/yocto/rpi-gatesgarth/build_kiosk/tmp/work/cortexa72-poky-linux/chromium-x11/89.0.4389.90-r0/temp/log.do_compile.3513135
NOTE: recipe chromium-x11-89.0.4389.90-r0: task do_compile: Failed
ERROR: Task (/home/mickey/work/yocto/rpi-gatesgarth/poky/meta-browser/meta-chromium/recipes-browser/chromium/chromium-x11_89.0.4389.90.bb:do_compile) failed with exit code '1'
NOTE: Tasks Summary: Attempted 3513 tasks of which 3512 didn't need to be rerun and 1 failed.

log.do_compile.3513135である。最後の数字は実行時のプロセスIDとなっている。

ログファイルの調査

errorの文字列でログファイルを検索していくと下記のようなエラーがメッセージが見つかる。

これはmeta-clangがgatesgarthブランチ時のログ

clang-11: error: unable to execute command: Segmentation fault (core dumped)
clang-11: error: linker command failed due to signal (use -v to see invocation)

つぎのmeta-clangがmasterブランチの時のログ。

clang-12: error: unable to execute command: Segmentation fault (core dumped)
clang-12: error: linker command failed due to signal (use -v to see invocation)

つまり同じところ、それもリンカ実行時にエラーが起きている。

リンカについての調査

リンカに問題がありそうということでコンパイル時にどのリンカが使用されているか、ログファイルを検索する。

python "../../build/toolchain/gcc_solink_wrapper.py" --readelf="aarch64-poky-linux-readelf" --nm="aarch64-poky-linux-llvm-nm"  --sofile="./libGLESv2.so" --tocfile="./libGLESv2.so.TOC" --output="./libGLESv2.so" -- aarch64-poky-linux-clang++ -target aarch64-poky-linux  -mcpu=cortex-a72 -march=armv8-a+crc+crypto   -mlittle-endian -Qunused-arguments -fstack-protector-strong  -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security --sysroot=/home/mickey/work/yocto/rpi-gatesgarth/build_kiosk/tmp/work/cortexa72-poky-linux/chromium-x11/89.0.4389.90-r0/recipe-sysroot -shared -Wl,-soname="libGLESv2.so" -Wl,--fatal-warnings -Wl,--build-id=sha1 -fPIC -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,-z,defs -Wl,--as-needed -fuse-ld=gold -Wl,--threads -Wl,--thread-count=4 -Wl,--icf=all -Wl,-O2 -Wl,--gc-sections -rdynamic -Wl,-O1 -Wl,--hash-style=gnu -Wl,--as-needed -Wl,-z,relro,-z,now -o "./libGLESv2.so" @"./libGLESv2.so.rsp"

-fuse-ld=goldということでgoldが使用されているようだ。

meta-chromiumgrepすると下記のような行が見つかる。

# by using the ld-is-lld distro feature otherwise use gold linker
GN_ARGS += "${@bb.utils.contains('DISTRO_FEATURES', 'ld-is-lld', 'use_lld=true use_gold=false', 'use_lld=false use_gold=true', d)}

これによるとDISTRO_FEATURESls-is-lldを追加する音でgoldの代わりにlldを使用するようになるらしい。

local.confの修正

conf/local.confに下記のように追加する。

IMAGE_INSTALL_append = " chromium-x11"
BBMASK += "meta-clang/recipes-core/busybox/busybox_1.33%.bbappend"
DISTRO_FEATURES_append = " ld-is-lld"

BBMASKはmeta-clangをmasterブランチで使用する時に発生するエラーを回避している。gatesgarthでは不要。

最終的に使用したレイヤの情報

こういう情報もcosole-latest.logに残っている。

Build Configuration:
BB_VERSION           = "1.48.0"
BUILD_SYS            = "x86_64-linux"
NATIVELSBSTRING      = "universal"
TARGET_SYS           = "aarch64-poky-linux"
MACHINE              = "raspberrypi4-64"
DISTRO               = "poky"
DISTRO_VERSION       = "3.2.2"
TUNE_FEATURES        = "aarch64 armv8a crc crypto cortexa72"
TARGET_FPU           = ""
meta                 
meta-poky            
meta-yocto-bsp       = "gatesgarth:6ed895d2b2d0dd5e5c85851c082954f5bb0294a0"
meta-oe              = "gatesgarth:945f062ff098dc9c8ba8d22c5eef88adec60730d"
meta-clang           = "master:404e8129c26ea5387a51248eebff1820db6f5015"
meta-python2         = "gatesgarth:56288c2599d7a6df6e34e8b07b7dc3d4d2d71e30"
meta-chromium        = "master:d6b1385daf2fd9178ba7bed5ba1eb909e47e8347"
meta-raspberrypi     = "gatesgarth:3ae135e590e375c8da26b003bda41c18fb977ae1"

おそらくmeta-clangはgatesgarthでも良い気がする。

meta-browserについて

もともとchromiumのレシピはmeta-browserのは以下にあったが、つい最近meta-firefoxとmeta-chromiumに分離されたようだ。 どちらも巨大だし依存関係も異なっているので、別々に管理するのは賛成。

その都合上2021/03/25前後ではbitbake-layers layerindex-fetchが使えない。

まとめ

Yoctoでchromiumをビルドする際にはDISTRO_FEATURES_append = " ld-is-lld"は必須。

最近meta-chromiumとmeta-firefoxに分離した。

chromiumのビルドだけで数時間はかかるのでエラーが出るとしんどい。

エラー時の解析にはconsole-latest.logを最初に参照すると便利。

Yocto リードオンリーなルートファイルシステムを構築する

はじめに

組み込みシステムの場合、製品として使用するようなケースではルートファイルシステムをリードオンリーとして、 本体が持つデータを書き換えられないようにすることがある。

Yoctoでは簡単に実現することができる。

実機でやったほうが楽しいのでラズベリーパイ4で試す。

使用するブランチはgatesgarth。

環境構築

下記のコマンドを実行し、環境を構築する。

ソース取得

$ mkdir rpi-gatesgarth && cd rpi-gatesgarth
$ git clone git://git.yoctoproject.org/poky.git -b gatesgarth
$ source layers/poky/oe-init-build-env build
$ bitbake-layers layerindex-fetch meta-raspberrypi

local.confの修正

conf/local.confに下記を追記する。

MACHINE = "raspberrypi4-64"
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 = ""

# connman
IMAGE_INSTALL_append = " connman \
                 connman-client \
"

EXTRA_IMAGE_FEATURES += "read-only-rootfs"

肝となるのはEXTRA_IMAGE_FEATURES += "read-only-rootfs"の部分。

ビルドおよび動作確認

下記のコマンドでビルドする。bitbakeは時間がかかる。

$ bitbake core-image-base

ビルドが完了したら、下記のコマンドでマイクロSDにイメージを書き込む。

$ cd tmp/deploy/images/raspberrypi4-64/
$ sudo bmaptool copy core-image-base-raspberrypi4-64.wic.bz2 /dev/sdX

/dev/sdXは環境に応じて適宜読み替える。

イメージを書き込んだマイクロSDでラズベリーパイ4を起動する。

試しに何かファイルを作成する。

root@raspberrypi4-64:~# echo hello > hello.txt
-sh: can't create hello.txt: Read-only file system

正しくエラーになる。これでルートファイルシステムがリードオンリーであることがわかる。

書き込み可能な領域

mega-manualを参照すると下記のようになっている。

With the "read-only-rootfs" feature enabled, any attempt by the target to write to the root filesystem at runtime fails. Consequently, you must make sure that you configure processes and applications that attempt these types of writes do so to directories with write access (e.g. /tmp or /var/run).

書き込みを伴うアプリケーションは/tmp/var/runのような書き込み可能な領域に配置する必要がある。

そのようなアプリケーションが/tmp/var/runでしか実行できないのは不便すぎる。

通常このような場合はoverlayfsやunionfsなどを使用して、書き込み可能な領域をオーバーレイすることによって問題を回避する。

オーバーレイする方法

単純に考えてオーバーレイする方法は下記のような感じになる。

  1. meta-readonly-rootfs-overlay
  2. aufs-utilやfuse-overlayfsを使って自前でなんとかする。

meta-readonly-rootfs-overlayは古すぎてメンテされいない。自前でなんとかするのは必要でなければできる限りやりたくない。

製品でYoctoを使用してリードオンリーなルートファイルシステムを使用したい場合、意外とこのへんで苦労すると思う。

VOLATILE_BINDSを使う

変更が揮発して良ければ、つまり、電源を切ったあとに保存される必要がなければVOLATILE_BINDSを使用して、書き込み不能ディレクトリに対して、書き込み可能な領域をバインドすることができる。

local.confに下記のように追加することで、任意のディレクトリを書き込み可能にすることができる。

VOLATILE_BINDS_append = " \
    /var/volatile/root /home/root\n\
"

ここではrootユーザーのホームディレクトリを書き込み可能にしている。

これは"read-only-rootfs"を有効化すると組み込まれるvolatile-bindsというレシピが提供している機能で、書き込み可能領域 バインド指定ディレクトリの順で記述すると、そのようにバインドしてくれる。

本来はリードオンリーである/home/rootを揮発するが書き込み可能である/var/volatile/rootでバインドすることにより、/home/rootを書き込み可能としている。

注意点としては、local.confでVOLATILE_BINDSを書き換えただけではvolatile-bindsパッケージは再ビルドされないので、下記のように明示的にビルドし直す必要がある。

$ bitbake volatile-binds -c clean
$ bitbake core-image-base

動作を確認する

先ほど書き込みできなかった/home/rootでファイルを作成してみる。

root@raspberrypi4-64:~# echo hello > hello.txt
root@raspberrypi4-64:~# cat hello.txt
hello

再起動したあとにlsを実行すると、ファイルが存在しないことがわかる。

まとめ

リードオンリーなルートファイルシステムIMAGE_FEATURES += "read-only-rootfs"で簡単に作れる。

任意のディレクトリを書き込み可能にしたい場合はvolatile-bindsVOLATILE_BINDS変数で可能。

電源を切ったあとも保存して置きたいデータは書き込み可能なパーティションを用意するか、USBメモリなどの外部メディアを用意する必要がある。

組み込み機器としてルートファイルシステムがリードオンリーであることの利点としては下記が考えられる。

  1. ファイル改ざんによる不具合の防止
  2. ストレージへの書き込み寿命による故障の防止
  3. セキュアアップデートなどでの環境の同一性の検証がしやすい

ファイルに書いたデータを保存するためには別途準備が必要となるが、リードオンリーなルートファイルシステムを持つ組み込み機器の用途を考えると、Yoctoが標準で用意する機能としては十分だと考える。

Raspberry Pi Pico タイマーでLチカ

はじめに

Raspberry Pi Pico(Pico)は4つの64ビットタイマーを持っている。それぞれ割り込みを発生させることができる。

ここまででSysTickやその割り込みを使ってLチカをしてきたが、すべてビジーループでタイミングを測っていた。

今回はWFIを使ってスリープしてみる。使用するタイマーはTIMER0。

タイマー

リセット

タイマーを使用するにはまず最初にタイマーをリセットする必要がある。リセットにはRESETSレジスタを使用する。RESETSレジスタは下記のようになっている。

f:id:mickey_happygolucky:20210311062823p:plain

f:id:mickey_happygolucky:20210311062848p:plain

割り込み

SysTickとは違いタイマーの割り込みはペリフェラルの割り込みとなる。

NVIC、IRQ

ペリフェラルの割り込みはNested Vectored Interrupt Controller(NVIC)に接続され、それぞれの機能がIRQ(Interrupt ReQuest)に割り当てられている。

f:id:mickey_happygolucky:20210311062900p:plain

TIMER0の割り込みはIRQ0に割り当てられていることがわかる。

IRQ0の割り込みが発生するとベクターテーブルのIRQ0に飛んでくる。

NVIC割り込みの操作には下記のレジスタを使用する。

f:id:mickey_happygolucky:20210311063033p:plain

タイマー割り込み

NVICは接続されているペリフェラルの割り込みを処理するだけのものなので、IRQ0を有効化するだけではタイマーの割り込みは発生しない。

タイマーの割り込みを発生させるには、ペリフェラル側でも下記のような操作が必要になる。

  1. 割り込みの有効化
  2. 割り込み条件の設定

タイマーのレジスタ構成は下記のようになっている。

f:id:mickey_happygolucky:20210311062912p:plain

f:id:mickey_happygolucky:20210311062931p:plain

割り込みの有効化

タイマーの割り込みを有効化するにはINTEレジスタをを使用する。INTEレジスタは下記のようになっている。

f:id:mickey_happygolucky:20210311063020p:plain

割り込み条件の設定

割り込み条件の設定にはALARM0〜3のレジスタを使用する。

ALARM0〜3に書き込まれた値がタイマーのカウンタであるTIMELRと一致すると4つのタイマーのうちの対応する割り込みが発生する。

タイマー0で使用するALARM0は下記のようになっている。

f:id:mickey_happygolucky:20210311062945p:plain

割り込みのクリア

割り込みが発生したら、割り込みハンドラの中でその割り込みをクリアする必要がある。割り込みをクリアするにはINTRレジスタの対応するビットをクリアする。

f:id:mickey_happygolucky:20210311062955p:plain

f:id:mickey_happygolucky:20210311063009p:plain

実装

main.cの中でそれぞれ実装する。

タイマーの初期化

タイマーの初期化処理では下記のことを行う。

  1. タイマーのリセット
  2. リセット完了待ち
  3. タイマー割り込みの有効化
  4. IRQ0の有効化

init_timer()として下記のように実装する。

void init_timer() {
        /* reset TIMER */
        write_reg_op(RESETS_RESET, (1<<21), OP_CLR);
        /* wait for reset TIMER to be done */
        while (!read_reg(RESETS_RESET_DONE)&(1<<21)) ;

        /* Enable timer interrupt */
        write_reg_op(TIMER_INTE, 1, OP_SET);

        /* Enable IRQ */
        irq_set_enabled(0, true); /* TIMER_IRQ_0=0 */
}

割り込み条件の設定

sleep_us()として下記のように実装する。

void sleep_us(uint32_t us) {
        uint32_t wakeup = read_reg(TIMER_TIMERRAWL);
        wakeup += us;
        write_reg(TIMER_ALARM0, wakeup);

        /* Wait For Interupt */
        __asm__ __volatile__("wfi");
}

sleep_usでは下記の処理を行っている。

  1. 現在のタイマーの値を取得
  2. 待ちたい時間を加算した値をALARM0に書き込む
  3. WFIを使って割り込み待ち状態(sleep)にする

WFIはWait For Interrupt命令のことで、割り込みが入るまでCPUがスリープ状態になる。 割り込み(この場合はタイマー割り込み)が発生すると、スリープが解除されCPUが復帰する。

割り込みハンドラ

isr_timer0()として下記のように実装する。

void isr_timer0() {
        /* Clear the timer0 irq */
        write_reg_op(TIMER_INTR, 1, OP_CLR);
}

isr_timer0start.Sの割り込みベクタの定義のIRQ0の位置に登録しておく。

/* vector table */
    .section .vectors, "ax"
    .align 2
    .global __vectors
__vectors:
.word 0x20001000
.word reset
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word isr_timer0

メイン処理

main関数は下記のようになっている。

int main(void) {

        /////////////////////
        // This initialise code is ported from https://github.com/dwelch67/raspberrypi-pico/blob/master/blinker00/notmain.c
        // release reset on IO_BANK0
        write_reg_op(RESETS_RESET, 1<<5, OP_CLR); //IO_BANK0
        //wait for reset to be done
        while(1) {
                if((read_reg(RESETS_RESET_DONE)&(1<<5))!=0) break;
        }
        write_reg_op(RESETS_RESET, (1<<8), OP_CLR); //PADS_BANK0
        while(1) {
                if((read_reg(RESETS_RESET_DONE)&(1<<8))!=0) break;
        }
        /////////////////////

        // GPIO init
        write_reg(SIO_GPIO_OE_CLR, (1ul<<25));
        write_reg(SIO_GPIO_OUT_CLR, (1ul<<25));
        uint32_t ra = read_reg(PADS_GPIO25);
        write_reg_op(PADS_GPIO25, (ra^0x40)&0xC0, OP_XOR);

        write_reg(IO_GPIO25_CTRL, 0x5);

        // Timer0 init
        init_timer();

        // Blink
        write_reg(SIO_GPIO_OE_SET, (1ul<<25));
        while (1) {
                sleep_us(100*1000); //100ms
                write_reg(SIO_GPIO_OUT_XOR, (1ul<<25));
        }
        return 0;
}

sleep_us関数を使って100msごとにLEDを点滅させている。

波形

問題なくPluseが100msとなっている。

f:id:mickey_happygolucky:20210311063044p:plain

まとめ

タイマーペリフェラルの割り込みでスリープを実装した。

  1. NVICで割り込みを有効化
  2. TIMERで割り込みを有効化
  3. TIMERで割り込みの発生条件を設定

これで使える。

ビルド可能なソースコード一式はここに置いてある。

参考