びぼうろく

北海道の人。適当にもっさりまったり書きます。さくら荘のましろが好きです。アニメとかパソコンとか

Raspberry Pi Zero向けのデバイスドライバを作る(本編)

デバイスドライバ作成

はじめに

この記事は前回の続きになります。
gari30.hatenablog.com

仕事が忙しく、あまり作業時間が取れない状況でしたが、
やっとこさ出来上がったので、ここにまとめておきます。

ターゲットデバイスRaspberry Pi Zero WHになります。

参考にさせていただいたサイト様

(前回同様)RaspberryPi2上でデバイスドライバを作成する記事です。
リンクのページから連載されています。
組み込みLinuxデバイスドライバの作り方 (1) - Qiita

(前回同様)RaspbianとRaspbian Kernelについて説明がある記事です。
大変参考になりました。
Raspberry Pi でドライバ開発したい(基礎編) | なたで日記


出来たもの

github.com

詰まったところメモ

1. 環境変数設定スクリプト

参考にさせていただいたサイト様に記載のこちらのサイト を参考に、
ロスコンパイル環境の環境変数設定シェルスクリプトを作成しました。
deviceDriver/env.sh at master · Kyokko-OB-Team/deviceDriver · GitHub

. ./env.sh

のように、ドット(.)コマンドを使うと、

source ./env.sh

と同じ効果があるとのことを初めて知りました。
ドットコマンドを使うと、現在のコマンド実行環境で実行してくれるようです。

2. printk

躓いた、というか寝ぼけて間違えただけですが、念の為書いておきます。

kernel moduleではprintfは使えないです。
代わりにprintkが使えます。

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だったので完璧!
以上