Raspberry Pi ZeroにWatchdogを設定する
はじめに
自宅の室温監視用のラズパイが、気がつくと死んでいることが何度かありました。
原因を調べてもよくわからず、とりあえず電源OFF→ONで復帰するので、
それならwatchdogでもつければいいのでは?と思い立ったので、作業のメモ。
Watchdog基板つけなくてもSoCにWatchdog付いてるじゃん
外部watchdogを考えていましたが、RaspberryPi ZeroのSoC(BCM2835)には内蔵watchdog付いてるんですね。
しかし公式なドキュメントが全く出てこない・・・。
$ ls -al /dev/watchdog* crw------- 1 root root 10, 130 5月 28 12:17 /dev/watchdog crw------- 1 root root 250, 0 5月 28 12:17 /dev/watchdog0
/devにwatchdogという名前のなにかがいるのでwatchdogと呼ばれているなにかがありそうだけど。。
公式ドキュメントでwatchdogについて言及されているところとか知っている人いたら教えてください。
とりあえず他の人に前ならえする
絶対良くないんだけど、やるだけやってみることにする
参考にしたのは以下のサイト様たち
RaspberryPi 1BでBCM2835内蔵のウォッチドッグを有効にした - 悪霊にさいなまれる世界 -The Demon-Haunted World
Raspberry PiにハードウェアWatchdogを設定してみましょう | CANDY LINE Blog
手順
1. watchdogを有効化
/boot/config.txt
を開いて以下の1行を追加する
dtparam=watchdog=on
2. watchdogのタイムアウト時間を設定
/etc/modprobe.d/bcm2835-wdt.conf
を開く(ない場合は新規で作成)
以下の1行を追加する。
これでどうやら15秒間ハートビートを待つ(15秒間に1度もハートビートが無いとwatchdogが発火する)らしい。
options bcm2835_wdt heartbeat=15 nowayout=0
3. ハートビート送信間隔の設定
/etc/systemd/system.conf
を開いて以下を探してコメントアウトを解除し、設定値を変更する。
これでsystemdがハートビートを5秒以内に1度送信してくれるらしい。
正常時はwatchdogのタイムアウトまで2回は通知されるようにしたいので、
ワーストケースを考えて5秒にした。
//↓これを探す #RuntimeWatchdogSec=0 //↓これを追加 RuntimeWatchdogSec=5
4. 再起動で設定が反映される
再起動後、fork爆弾を使ってwatchdogのテストをしてみる。
$ :(){ :|:& };:
実行後すぐterminalの応答が返ってこなくなり、数分後に自動的に再起動することが確認できる。
最後に
公式のwatchdogについて書かれているドキュメントをご存じの方、教えてください。
Raspberry Pi Zero向けのデバイスドライバを作る(本編)
デバイスドライバ作成
はじめに
この記事は前回の続きになります。
gari30.hatenablog.com
仕事が忙しく、あまり作業時間が取れない状況でしたが、
やっとこさ出来上がったので、ここにまとめておきます。
ターゲットデバイスはRaspberry Pi Zero WHになります。
参考にさせていただいたサイト様
(前回同様)RaspberryPi2上でデバイスドライバを作成する記事です。
リンクのページから連載されています。
組み込みLinuxデバイスドライバの作り方 (1) - Qiita
(前回同様)RaspbianとRaspbian Kernelについて説明がある記事です。
大変参考になりました。
Raspberry Pi でドライバ開発したい(基礎編) | なたで日記
出来たもの
詰まったところメモ
1. 環境変数設定スクリプト
参考にさせていただいたサイト様に記載のこちらのサイト を参考に、
クロスコンパイル環境の環境変数設定シェルスクリプトを作成しました。
deviceDriver/env.sh at master · Kyokko-OB-Team/deviceDriver · GitHub
. ./env.sh
のように、ドット(.)コマンドを使うと、
source ./env.sh
と同じ効果があるとのことを初めて知りました。
ドットコマンドを使うと、現在のコマンド実行環境で実行してくれるようです。
3. __aeabi_uldivmod 未定義エラー
ERROR: "__aeabi_uldivmod" [/home/xxxx/deviceDriver/hc-sr04/hc-sr04.ko] undefined!
kernel module内で浮動小数点を使用するとこのエラーが出るらしい。
distance = ((falling_timestamp - rising_timestamp) / 58) * 1000;
Cキャストをするようにした。
distance = ((unsigned int)(falling_timestamp - rising_timestamp) / 58) * 1000;
4. 認識されないコマンドラインオプション '-fstack-protector-strong'
arm-linux-gnueabihf-gcc: エラー: unrecognized command line option ‘-fstack-protector-strong’
raspberry pi toolchainのgccのバージョンが古いことで発生するらしい。
使用しているコンパイラのバージョンはこれ。
$ /mnt/4tb/raspberrypi_kernel/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf-gcc -v 組み込み spec を使用しています。 COLLECT_GCC=/mnt/4tb/raspberrypi_kernel/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf-gcc COLLECT_LTO_WRAPPER=/mnt/4tb/raspberrypi_kernel/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/../libexec/gcc/arm-linux-gnueabihf/4.8.3/lto-wrapper ターゲット: arm-linux-gnueabihf configure 設定: /home/zhehe01/work/bzr/pi-build/builds/arm-linux-gnueabihf-raspbian-linux/.build/src/gcc-linaro-4.8-2014.03/configure --build=x86_64-build_unknown-linux-gnu --host=x86_64-build_unknown-linux-gnu --target=arm-linux-gnueabihf --prefix=/home/zhehe01/work/bzr/pi-build/builds/arm-linux-gnueabihf-raspbian-linux/install --with-sysroot=/home/zhehe01/work/bzr/pi-build/builds/arm-linux-gnueabihf-raspbian-linux/install/arm-linux-gnueabihf/libc --enable-languages=c,c++,fortran --disable-multilib --enable-multiarch --with-arch=armv6 --with-tune=arm1176jz-s --with-fpu=vfp --with-float=hard --with-pkgversion='crosstool-NG linaro-1.13.1+bzr2650 - Linaro GCC 2014.03' --with-bugurl=https://bugs.launchpad.net/gcc-linaro --enable-__cxa_atexit --enable-libmudflap --enable-libgomp --enable-libssp --with-gmp=/home/zhehe01/work/bzr/pi-build/builds/arm-linux-gnueabihf-raspbian-linux/.build/arm-linux-gnueabihf/build/static --with-mpfr=/home/zhehe01/work/bzr/pi-build/builds/arm-linux-gnueabihf-raspbian-linux/.build/arm-linux-gnueabihf/build/static --with-mpc=/home/zhehe01/work/bzr/pi-build/builds/arm-linux-gnueabihf-raspbian-linux/.build/arm-linux-gnueabihf/build/static --with-isl=/home/zhehe01/work/bzr/pi-build/builds/arm-linux-gnueabihf-raspbian-linux/.build/arm-linux-gnueabihf/build/static --with-cloog=/home/zhehe01/work/bzr/pi-build/builds/arm-linux-gnueabihf-raspbian-linux/.build/arm-linux-gnueabihf/build/static --with-libelf=/home/zhehe01/work/bzr/pi-build/builds/arm-linux-gnueabihf-raspbian-linux/.build/arm-linux-gnueabihf/build/static --enable-threads=posix --disable-libstdcxx-pch --enable-linker-build-id --enable-plugin --enable-gold --with-local-prefix=/home/zhehe01/work/bzr/pi-build/builds/arm-linux-gnueabihf-raspbian-linux/install/arm-linux-gnueabihf/libc --enable-c99 --enable-long-long --with-float=hard スレッドモデル: posix gcc バージョン 4.8.3 20140303 (prerelease) (crosstool-NG linaro-1.13.1+bzr2650 - Linaro GCC 2014.03)
回避策をggるとgccをアップデートしろ、と言われるが
raspberry pi用のクロスコンパイラはこれが最新版なのでアップデートできない。
csdnのこのページを参考に、kernelのMakefileを変更してエラーがでなくなった。
動作確認
カーネルモジュールをロードして、
テストアプリを実行して、
カーネルモールをアンロードして、
dmesg
でログを確認
$ sudo insmod ./hc-sr04/hc-sr04.ko $ sudo ./test_hc-sr04/test_hc-sr04 ./test_hc-sr04/test_hc-sr04 ver.0.1 exec measure distance. exec get distance. distance: 6310000mm $ dmesg (省略) [ 223.047133] hc_sr04: loading out-of-tree module taints kernel. [ 223.058371] hc_sr04 init. ver.0.1. [ 418.259926] hc_sr04 module exit.
特にエラーが出ないのでOK
デバイスドライバの動作環境をまとめる
デバイスドライバを動作させるカーネルセットも保存しておきたいので、
動作環境をまとめておきます。
// kernelディレクトリに移動 $ cd linux/ // 一時コピー先ディレクトリ作成 $ mkdir -p device_tree/overlays // デバイスツリーファイル群をコピー $ cp ./arch/arm/boot/dts/*.dtb ./device_tree/. $ cp ./arch/arm/boot/dts/overlays/*.dtb* ./device_tree/overlays/. // デバイスツリーファイル群をアーカイブにする $ cd device_tree/ $ tar -cvzf ../dtb.tar.gz * // モジュールファイルをビルド $ sudo make ARCH=arm INSTALL_MOD_PATH=./modules/ modules_install // モジュールファイル群をアーカイブにする $ cd modules/ $ tar -cvjf ../modules.tar.bz2 *
Raspberry Piで展開
まとめた動作環境ファイルをRaspberry Pi上にコピーしてから以下の様に
ファイルを展開する。
// カーネルイメージのバックアップ $ sudo cp /boot/kernel.img /boot/kernel-bk.img // カーネルイメージを更新 $ sudo cp ./kernel.img /boot/. // デバイスツリーファイルを展開 // 所有者を変更できません。とエラーが出るので、--no-same-ownerオプションをつける $ sudo tar --no-same-owner -xzvf ./dtb.tar.gz -C /boot/ // モジュールファイルを展開 $ sudo tar -xvjf ./modules.tar.bz2 -C / // 再起動して起動確認 $ sync $ sudo shutdown -r now
起動確認
まとめたデバイスドライバの動作環境をRaspberry Pi上で展開して
作成したカーネルモジュールとテストアプリでの動作確認をした。
OKだったので完璧!
以上
デキる人は知っているgnuplotの使い方
gnuplotを初めて使ったのでそのログ
はじめに
最近、おすすめの記事とかに「ショートカットを使いこなして仕事爆速!」とか
「デキる人は使ってる仕事術!」みたいなのがあって
記事を呼んでみると
Windowsはショートカットキーを使って時短!
とか
Excel、wordでおすすめのショートカットはこちら!ctrl+v!!
みたいなのばっかりで面白いので
似たタイトルにしてみた。
仕事だとデータ解析とかその結果はExcelが好まれるので
仕事で使う機会はあまりなかったけど
使えるようになりたいので勉強してみた。
やりたいこと
温度と湿度のデータがあるので、それを1つのグラフにしたい。
データはここに無限に上がってくるこれを使う。
1. 入力データの整理
入力データの形式はJSONもどきで、文字列が含まれるため
このままプロットできない。
ワンライナーを書いた。
cat ./202105_Temp_Humidi_Sensor_Data.json | sed -e 's/: /,/g' | sed -e 's/ /,/g' | sed -e 's/[\{\|\}\|"\]//g' | awk -F "," ' $2 == "2021/05/28" { print $3","$5","$6 }' > temp.log
ワンライナーでやってること
sed -e 's/: /,/g'
keyとvalueの区切りが:
になっているので,
にする。
sed -e 's/ /,/g'
日時データの日付と時間の間のスペースを,
にする。
sed -e 's/[\{\|\}\|"\]//g'
行の両端の{}
を消す。
awk -F "," ' $2 == "2021/05/28" { print $3","$5","$6 }'
区切り記号を,
として、
日付を指定して時刻、温度、湿度のデータだけ抽出する。
2. gnuplotでグラフ作成
gnuplotがなければインストールする。
$ sudo apt install gnuplot
gnuplotで設定して、グラフを作る。
$ gnuplot gnuplot> set timefmt "%H:%M:%S" // 入力データの時間のフォーマット設定 gnuplot> set datafile separator "," // 入力データの区切り記号を設定 gnuplot> set title "2021/05/29" // グラフのタイトル設定 gnuplot> set xdata time // x軸を時間に設定 gnuplot> set format x "%H" // x軸のフォーマット設定 gnuplot> set xlabel "time" // x軸のラベル設定 gnuplot> set yrange [0:40] // y軸のレンジ設定(0~40) gnuplot> set ylabel "temp" // y軸のラベル設定 gnuplot> set ytics nomirror // y軸のメモリを片側表示に設定 gnuplot> set y2label "humidi" // y2軸のラベル設定 gnuplot> set y2range [0:100] // y2軸のレンジ設定(0~100) gnuplot> set y2tics nomirror // y2軸のメモリを片側表示に設定 gnuplot> set my2tics 10 // y2軸のメモリの数を設定(10) gnuplot> set terminal png // グラフの出力設定(png) // 出力ファイルの名前設定 gnuplot> set output "20210528_plot.png" // グラフの作成(グラフ1の指定、グラフ2の指定) // グラフ1: 入力ファイル、使うデータ、出力グラフ、グラフのプロット方法 // グラフ2: 入力ファイル、使うデータ、出力グラフ、グラフのプロット方法 gnuplot> plot "./temp.log" using 1:2 axis x1y1 with line title "temp", "./temp.log" using 1:3 axis x1y2 with line title "humidi"
これで出力したファイルがこれ
3. シェル化
作った。
measurementData/graph-make.sh at master · Kyokko-OB-Team/measurementData · GitHub
使い方
./graph-make.sh <任意の日付>_Temp_Humidi_Sensor_Data.json YYYY/MM/DD
Raspberry Pi Zero向けのデバイスドライバを作る(環境構築)
ラズパイゼロのデバイスドライバ開発環境構築
はじめに
Raspberry Pi ZeroでHC-SR04を使いやすくするために、
デバイスドライバを作成するので、
やったことをメモしておく。
とりあえず環境構築まで<2021/08/16修正>
再度環境構築し直したときに、記載ミスに気付いたのでコマンドを修正しました。
HC-SR04について
超音波をつかった距離センサです。
超音波パルスを送出して、
反射した超音波を受信するまでの時間で距離を求める仕組みです。
2cm~400cmまで、0.3cmの分解能で距離を測定できる仕様となっています。
お勉強がてらこいつのデバイスドライバを作ります。
参考にさせていただいたサイト
RaspberryPi2上でデバイスドライバを作成する記事です。
組み込みLinuxデバイスドライバの作り方 (1) - Qiita
今回の私と同じく、RaspberryPiZeroのデバイスドライバを別のLinuxPCで作成する記事です。
Raspberry Pi でドライバ開発したい(基礎編) | なたで日記
RaspbianとRaspbian Kernelについて説明がある記事です。
Raspberry Pi でカーネルモジュールビルドの準備 - Qiita
開発環境作成
1. 必要なものを集める
必要なパッケージをインストール
$ sudo apt install git bc bison flex libssl-dev make
$ git clone https://github.com/raspberrypi/linux $ git clone https://github.com/raspberrypi/tools
2. ラズパイのカーネルバージョンのソースにする
カーネルモジュール(*.ko)を作成する場合、
ターゲット環境のカーネルバージョンを合わせておくと面倒が無い。
ターゲットのカーネルバージョンの確認する。
今回は 5.4.51+
だった。
$ uname -r 5.4.51+
同じバージョン番号のコミットをここから探す。
Commits · Hexxeh/rpi-firmware · GitHub
今回はこのコミットだった。
同じバージョン番号のコミットのハッシュ値をコピーする。
今回は、8382ece2b30be0beb87cac7f3b36824f194d01e9
だった。
コミットのハッシュ値をgithubに投げるとカーネルのリビジョンが取得できる。
(仕組みはわからん)
今回は、ff68b68ffe3e8f1759fd17532b6fe8dc4e211a2d
だった。
$ export FIRM_REV=8382ece2b30be0beb87cac7f3b36824f194d01e9 $ curl -L https://github.com/Hexxeh/rpi-firmware/raw/${FIRM_REV}/git_hash
これで、現在ターゲットのRaspbianのカーネルのリビジョンがわかったので、
先程クローンしたカーネルを、先程取得したカーネルのリビジョンでチェックアウトする。
今回はこんな感じでブランチを切った。
$ git checkout -b raspbian-5.4.51_kernel ff68b68ffe3e8f1759fd17532b6fe8dc4e211a2d
3. カーネルのビルド
ターゲットによってビルド時に設定する環境変数が異なる。
今回は、Raspberry Pi Zeroなので以下のようにビルドする。
$ export ARCH=arm $ export KERNEL=kernel $ make bcmrpi_defconfig # # configuration written to .config # $ export CROSS_COMPILE=/mnt/4tb/raspberrypi_kernel/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf- $ make zImage modules dtbs
4. カーネルの書き込み
事前にRaspbianをmicroSDに焼いておく。
microSDをPCに接続して、ビルドしたカーネルを更新する。
今回は以下のようにした。
// マウント先ディレクトリの作成 $ sudo mkdir raspbian-boot $ sudo mkdir raspbian // マウント $ sudo mount /dev/sdc1 /mnt/raspbian-boot $ sudo mount /dev/sdc2 /mnt/raspbian // カーネルモジュールの書き込み $ sudo make ARCH=arm INSTALL_MOD_PATH=/mnt/raspbian/ modules_install // カーネルのバックアップ $ sudo cp /mnt/raspbian-boot/kernel.img /mnt/raspbian-boot/kernel_bk.img // カーネルのコピー $ sudo cp ./arch/arm/boot/zImage /mnt/raspbian-boot/kernel.img // デバイスツリーのコピー $ sudo cp ./arch/arm/boot/dts/*.dtb /mnt/raspbian-boot/. $ sudo cp ./arch/arm/boot/dts/overlays/*.dtb* /mnt/raspbian-boot/overlays/. // マウント解除 $ sudo umount /mnt/raspbian* // マウント先ディレクトリの削除 $ sudo rm -rf ./raspbian*
5. 起動確認
ラズパイにmicroSDを戻して、通常通り起動するか確認する。
今回はコードに変更を加えなかったので、起動したらOKということにする。
続き
この後の作業も記録しました。
gari30.hatenablog.com
組み込みLinuxでスクリーンショットを撮影する
組み込みでスクリーンショット
はじめに
組み込みLinuxはデスクトップ環境が無いので
スクリーンショットを取るアプリも無い。
でも操作画面(LCD)はあるからドキュメントを作るのにスクリーンショットが欲しい!
という上司からの要望があった。
半日でスクリーンショット撮影するツールを作らされたのでここにメモっておく。
こちらのサイトを参考にさせていただきました。
非常に助かりました。ありがとうございます。
ラズパイでフレームバッファ(/dev/fb0)を使用して、直接ディスプレイ画像を入出力する - Qiita
Bitmapファイルフォーマット
内容
結論までの経緯とやったことを書いておく。
フレームバッファとは
Linuxはフレームバッファにデータを書き込むとカーネルがいい感じに勝手に描画してくれる。
つまりディスプレイの情報はフレームバッファに入っている。
カーネルが書き込んだフレームバッファをどう処理しているのかはわからない(そのうち理解したい)。
手元のUbuntuマシンでは/dev/fb0
があった。
フレームバッファの情報は以下のコマンドで確認できるらしい。
$ cat /sys/class/graphics/fb0/bits_per_pixel 32 $ cat /sys/class/graphics/fb0/virtual_size 1920,1080
フレームバッファを取得して見てみる
以下のコマンドでフレームバッファを取得する。
$ cat /dev/fb0 > temp.raw
IrfanViewでrawファイルを開く。
ソフトを起動して、ドラッグ&ドロップでrawファイルをぶち込むとrawファイルを開く設定ができる。
今回は以下の設定でrawファイルを正常に表示できた。
- Image width:1920
- Image heigh:1080
- BitsPerPixel:32 BPP[4 byte per pixel]
- Options for 24 and 32 BPP:Color order BGR(32bit BGRA)
rawファイルは扱いにくい
rawファイルでスクリーンショットを撮影することはできた。
でもrawファイルは一般的な画像ビューアで表示できないし、ドキュメントに貼り付けることもできない。
...と参ってたら、チームのすごい人から
「昔、bitmapでスクリーンショット撮るツールあった気がする。ツール見つけられないけど確かbitmapヘッダをくっつけてただけだった気がする。」
と、神の導きを頂いたので、とりあえずbitmapヘッダを作ってみることにした。
bitmapヘッダを作る
bitmapのヘッダは、ファイルヘッダ(14byte)と情報ヘッダ(40byte)の54byteでできているらしい。
とりあえず空のバイナリファイルを作る。
dd if=/dev/zero of=bmp_head.bin bs=54 count=1
vscodeの拡張機能「vscode-hexdump」でヘッダにデータを入れていく。
ファイルタイプ以外はすべてリトルエンディアンでデータを入れる。
以下は実際に入れたデータ
種類 | オフセット | サイズ | 値 | メモ |
ファイルタイプ | 0 | 2byte | 0x42、0x4D | 固定値 |
ファイルサイズ(byte) | 2 | 4byte | 0x00 1F A4 36 | ヘッダサイズ(54byte)+1920*1080 |
予約領域1 | 6 | 2byte | 0x00 | 固定値 |
予約領域2 | 8 | 2byte | 0x00 | 固定値 |
ヘッダサイズ | 10 | 4byte | 0x00 00 00 36 | 固定値 |
情報ヘッダサイズ | 14 | 4byte | 0x00 00 00 28 | 固定値 |
画像の横幅(ピクセル) | 18 | 4byte | 0x00 00 07 80 | 1920 |
画像の縦幅(ピクセル) | 22 | 4byte | 0x FF FF FB C8 | -1080(縦幅の2の補数) |
プレーン数 | 26 | 2byte | 0x00 01 | 固定値(プレーンとは?) |
1画素の色数 | 28 | 2byte | 0x00 20 | bits_per_pixelの値 |
圧縮形式 | 30 | 4byte | 0x00 00 00 00 | rawファイルなので0固定 |
画像サイズ | 34 | 4byte | 0x00 1F A4 00 | 1920*1080 |
水平解像度(ppm) | 38 | 4byte | 0x00 00 00 00 | 固定値 |
垂直解像度(ppm) | 42 | 4byte | 0x00 00 00 00 | 固定値 |
色数 | 46 | 4byte | 0x00 00 00 00 | 固定値 |
重要色数 | 50 | 4byte | 0x00 00 00 00 | 固定値 |
rawファイルにbitmapヘッダをくっつける
必死こいてポチポチ計算してヘッダファイル作ったらあとは、rawファイルにくっつけるだけ。
cat bmp_head.bin temp.raw > test.bmp
何故かできた
これで何故かbitmapファイルでスクリーンショットが作れてしまった。