ubuntu 18.04 にraspi-configをインストールしてGPIOの初期設定を変更した話


はじめに

お手軽ARMコンピュータ ラズベリー・パイでI/O」(インターフェース増刊 2013 CQ出版社)の「第4章 コマンド入力で外付け回路を動かしてみる」の桑野氏の記事の内容を、2020年秋になってUbuntu 18.04で動作確認しました1。記事の内容はとても理解しやすく説明も丁寧でわかりやすいのですが、2013年当時の記事でraspbianの利用が前提なので、Ubuntu上で動かすにはGPIO上のSPI設定を無効にする作業や、紹介されている回路設計にも一部変更の必要があり、その作業内容や変更点のメモを自分の理解の整理を兼ねて記事にします。

実験環境

  • Raspberry Pi 3B+
  • Ubuntu 18.04 LTS

GPIOテスト用の回路

以下に参考の回路図2へのリンクと実際に作ったデバイスの写真3を示します。
- ONE SEGMENT 7-DIGIT LED TEST BOARDの「回路図」

確認作業

まず、/sysディレクトリのGPIOインターフェースは、初期設定のままで既に存在します。

~$ ls -l /sys/class/gpio/
total 0
--w------- 1 root root 4096 Jan  1  1970 export
lrwxrwxrwx 1 root root    0 Jan  1  1970 gpiochip0 ->
../../devices/platform/soc/3f200000.gpio/gpio/gpiochip0
lrwxrwxrwx 1 root root    0 Jan  1  1970 gpiochip504 -> ../../devices/platform/soc/soc:firmware/soc:firmware:expgpio/gpio/gpiochip504
--w------- 1 root root 4096 Jan  1  1970 unexport

でも、GPIO7のピンのシンボリックリンクを作成しようとすると、「デバイスかリソースがビジーで、echoでの書き込みエラー」と叱られます。

~$ sudo -s
~# echo 7 >/sys/class/gpio/export
bash: echo: write error: Device or resource busy

デフォルトでGPIO7GPIO8のピンがSPI用に設定されていました4

~# cat /sys/kernel/debug/gpio
gpiochip0: GPIOs 0-53, parent: platform/3f200000.gpio, pinctrl-bcm2835:
gpio-7   (                    |spi0 CS1            ) out hi ACTIVE LOW
gpio-8   (                    |spi0 CS0            ) out hi ACTIVE LOW
gpio-29  (                    |led0                ) out lo 
~# exit

raspi-config のインストール

GPIOの機能設定には、raspi-configを使用しました。raspbian専用の設定変更ツールなのですが、ubuntuでも以下のURLで動作することが紹介されていたので、その紹介されている手順どおりに作業しました。
- Trading on Raspberry Pi with Ubuntu 18.04

sudo echo "deb http://archive.raspberrypi.org/debian/ jessie main" >> /etc/apt/sources.list
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 7FA3303E
sudo apt-get update
sudo apt-get install raspi-config
sudo mount /dev/mmcblk0p1 /boot

これで、普通にraspi-configのGUIのメニュー画面を立ち上げることができます。

~$ sudo rapsi-config

rapsi-configのトップメニュー画面から「5 Interfacing Options Configure connections to peripherals」>「P4 SPI Enable/Disable automatic loading of SPI kernel module」を選択します。あとは、「Would you like the SPI interface to be enabled?」で「No」を選択すると「The SPI interface is disabled」のメッセージで「Ok」を押すとトップ画面に戻りますので、最後に「Finish」で変更を保存するだけです。

~$ sudo reboot -h now

設定変更を読み込むためにリブートしたら、もう一度GPIOの設定状況を確認します。

~# cat /sys/kernel/debug/gpio
gpiochip0: GPIOs 0-53, parent: platform/3f200000.gpio, pinctrl-bcm2835:
gpio-29  (                    |led0                ) out lo
gpiochip1: GPIOs 504-511, parent: platform/soc:firmware:expgpio, raspberrypi-exp-gpio, can sleep:
gpio-506 (                    |led1                ) out lo ACTIVE LOW 

GPIO7と8がリストから消えていたら成功です。ここでうまくいかなかった場合、raspi-configの変更設定が保存されていないことが考えられます。

参考

今回の作業の目的は、自作のGPIOデバイスドライバ学習用デバイスの回路テストの実行環境の構築です。つまり、実際に以下のシェルスクリプトのコードを動かして回路上の配線ミスがないかなどを最終チェックすることでした。

コマンドラインでエラーも出ず、実機テストでも、スクリプトの仕様通り、ドットが2回点滅した後に7セグLEDに0から9までの数字が表示されて再度ドットが2回点滅した後に終了しました。

プッシュボタンを開放した状態ではコンソール画面に1が表示され、ボタンを押すと0が表示されます。

なお、「ラズベリーパイでI/O」当時から、GPIO番号の配置が少し変更になっています。今回の実験用回路では、プッシュスイッチの物理的なピン位置を従来のまま3番と5番を使っているので、GPIO番号を「01」の組み合わせから「23」の組み合わせにプログラム上で変更しています。

gpio_sh
echo gpio export pin seting ...
echo 2 > /sys/class/gpio/export
echo 3 > /sys/class/gpio/export
echo 7 > /sys/class/gpio/export
echo 8 > /sys/class/gpio/export
echo 9 > /sys/class/gpio/export
echo 10 > /sys/class/gpio/export
echo 11 > /sys/class/gpio/export
echo gpio pin direction seting ...
echo in > /sys/class/gpio/gpio2/direction
echo in > /sys/class/gpio/gpio3/direction
echo out > /sys/class/gpio/gpio7/direction
echo out > /sys/class/gpio/gpio8/direction
echo out > /sys/class/gpio/gpio9/direction
echo out > /sys/class/gpio/gpio10/direction
echo out > /sys/class/gpio/gpio11/direction
echo gpio test start...
echo 1 > /sys/class/gpio/gpio7/value
echo 1 > /sys/class/gpio/gpio8/value
echo 0 > /sys/class/gpio/gpio9/value
echo 1 > /sys/class/gpio/gpio10/value
echo 1 > /sys/class/gpio/gpio11/value
echo 1 > /sys/class/gpio/gpio11/value
sleep 1
echo 0 > /sys/class/gpio/gpio11/value
sleep 1
echo 1 > /sys/class/gpio/gpio11/value
sleep 1
echo 0 > /sys/class/gpio/gpio11/value
sleep 1
echo 0 > /sys/class/gpio/gpio7/value
echo 0 > /sys/class/gpio/gpio8/value
echo 0 > /sys/class/gpio/gpio9/value
echo 0 > /sys/class/gpio/gpio10/value
echo 0
sleep 1
echo 1 > /sys/class/gpio/gpio7/value
echo 0 > /sys/class/gpio/gpio8/value
echo 0 > /sys/class/gpio/gpio9/value
echo 0 > /sys/class/gpio/gpio10/value
echo 1
sleep 1
echo 0 > /sys/class/gpio/gpio7/value
echo 1 > /sys/class/gpio/gpio8/value
echo 0 > /sys/class/gpio/gpio9/value
echo 0 > /sys/class/gpio/gpio10/value
echo 2
sleep 1
echo 1 > /sys/class/gpio/gpio7/value
echo 1 > /sys/class/gpio/gpio8/value
echo 0 > /sys/class/gpio/gpio9/value
echo 0 > /sys/class/gpio/gpio10/value
echo 3
sleep 1
echo 0 > /sys/class/gpio/gpio7/value
echo 0 > /sys/class/gpio/gpio8/value
echo 1 > /sys/class/gpio/gpio9/value
echo 0 > /sys/class/gpio/gpio10/value
echo 4
sleep 1
echo 1 > /sys/class/gpio/gpio7/value
echo 0 > /sys/class/gpio/gpio8/value
echo 1 > /sys/class/gpio/gpio9/value
echo 0 > /sys/class/gpio/gpio10/value
echo 5
sleep 1
echo 0 > /sys/class/gpio/gpio7/value
echo 1 > /sys/class/gpio/gpio8/value
echo 1 > /sys/class/gpio/gpio9/value
echo 0 > /sys/class/gpio/gpio10/value
echo 6
sleep 1
echo 1 > /sys/class/gpio/gpio7/value
echo 1 > /sys/class/gpio/gpio8/value
echo 1 > /sys/class/gpio/gpio9/value
echo 0 > /sys/class/gpio/gpio10/value
echo 7
sleep 1
echo 0 > /sys/class/gpio/gpio7/value
echo 0 > /sys/class/gpio/gpio8/value
echo 0 > /sys/class/gpio/gpio9/value
echo 1 > /sys/class/gpio/gpio10/value
echo 8
sleep 1
echo 1 > /sys/class/gpio/gpio7/value
echo 0 > /sys/class/gpio/gpio8/value
echo 0 > /sys/class/gpio/gpio9/value
echo 1 > /sys/class/gpio/gpio10/value
echo 9
sleep 1
echo 0 > /sys/class/gpio/gpio7/value
echo 1 > /sys/class/gpio/gpio8/value
echo 0 > /sys/class/gpio/gpio9/value
echo 1 > /sys/class/gpio/gpio10/value
echo 1 > /sys/class/gpio/gpio11/value
echo dot
sleep 1
echo 0 > /sys/class/gpio/gpio11/value
sleep 1
echo 1 > /sys/class/gpio/gpio11/value
sleep 1
echo 0 > /sys/class/gpio/gpio11/value
sleep 1
echo 1 > /sys/class/gpio/gpio11/value
cat /sys/class/gpio/gpio2/value
cat /sys/class/gpio/gpio3/value
echo test exiting...
echo 2 > /sys/class/gpio/unexport
echo 3 > /sys/class/gpio/unexport
echo 7 > /sys/class/gpio/unexport
echo 8 > /sys/class/gpio/unexport
echo 9 > /sys/class/gpio/unexport
echo 10 > /sys/class/gpio/unexport
echo 11 > /sys/class/gpio/unexport
echo end

おわりに

デバイスドライバの作成の実験のための準備で、できるだけ単純な動作確認のためraspi-configの導入を行いました。/sys/kernel/debug/gpioファイルの中に、gpiochip0: GPIOs 0-53, parent: platform/3f200000.gpio, pinctrl-bcm2835と表記されており、SOCのGPIOアドレスが3f200000からであることがこんなところにも記載されていることを知り、単純な実験ですがLinuxがまた更に身近に感じられるようになりました。

次は、C言語でGPIOデバイス・ドライバでの使い方と、レジスタを直接たたく方法を実験したいと思います。


  1. 私個人が将来的にROSの学習を予定しているので、ROSのインストールが楽なubuntuをOSとして選んだ結果として発生した作業なので、もちろん、raspbianなら最新バージョンでもraspi-configは初期設定に入っているので利用するのに必要な作業はありません。 

  2. 実際に作ったデバイスの回路は、「Raspberry Piで学ぶ ARM デバイスドライバー プログラミング」(米田聡著 2014 ソシム)P.47の7セグLEDと74HC4511を使った設計を少しだけ修正したものです。修正点は、DP端子用を抵抗(510Ω)を介してGPIO11に直接接続してコントロールしている点と、「ラズベリーパイでI/O」の回路のとおり、10kオームのプルアップ抵抗を使用したプッシュスイッチ2個を追加している点だけです。スイッチのコントロールのためのGPIOへの接続は、J8 GPIOGPIO2GPIO3を使用しています。 

  3. ICとユニバーサル基板以外は、ほとんど自宅にあった廃材を再利用しているのと、配線を間違えて配線を何度もつけたり外したりしたので配線も作りも雑ですが、とりあえずは指示通りに動いてくれています。 

  4. 上のデバイスの写真にあるとおり、電源を入れると自動的に数字の3が表示されます。74HC34113が表示されるのは、回路図からGPIO7GPIO8Hになっているからなので、GPIOに回路をつなげた段階でSPIが初期設定で使えるようになっていることの想像はできますが、コマンドでも調べられると大変便利です。