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

## はじめに

「**お手軽ARMコンピュータ ラズベリー・パイでI/O**」（インターフェース増刊 2013 CQ出版社）の「第4章 コマンド入力で外付け回路を動かしてみる」の桑野氏の記事の内容を、2020年秋になって`Ubuntu 18.04`で動作確認しました[^1]。記事の内容はとても理解しやすく説明も丁寧でわかりやすいのですが、2013年当時の記事で`raspbian`の利用が前提なので、`Ubuntu`上で動かすにはGPIO上のSPI設定を無効にする作業や、紹介されている回路設計にも一部変更の必要があり、その作業内容や変更点のメモを自分の理解の整理を兼ねて記事にします。
[^1]: 私個人が将来的に`ROS`の学習を予定しているので、`ROS`のインストールが楽な`ubuntu`をOSとして選んだ結果として発生した作業なので、もちろん、`raspbian`なら最新バージョンでも`raspi-config`は初期設定に入っているので利用するのに必要な作業はありません。

##実験環境

- Raspberry Pi 3B+
- Ubuntu 18.04 LTS

##GPIOテスト用の回路
以下に参考の回路図[^2]へのリンクと実際に作ったデバイスの写真[^3]を示します。
- ONE SEGMENT 7-DIGIT LED TEST BOARDの[「回路図」](https://www.schematics.com/project/one-segment-7-digit-led-driver-174059/)
![実際に作ったもの](https://photohito.k-img.com/uploads/photo151/user150694/9/2/92023b7c8eaaa7fa2c73dedc84324127/92023b7c8eaaa7fa2c73dedc84324127_l.jpg)
[^2]: 実際に作ったデバイスの回路は、「[Raspberry Piで学ぶ ARM デバイスドライバー プログラミング](https://www.socym.co.jp/support/s-940 "米田聡著 2014 ソシム")」（米田聡著 2014 ソシム）P.47の７セグLEDと74HC4511を使った設計を少しだけ修正したものです。修正点は、DP端子用を抵抗（510Ω）を介してGPIO11に直接接続してコントロールしている点と、「ラズベリーパイでI/O」の回路のとおり、10kオームのプルアップ抵抗を使用したプッシュスイッチ2個を追加している点だけです。スイッチのコントロールのためのGPIOへの接続は、`J8 GPIO`の`GPIO2`と`GPIO3`を使用しています。
[^3]: ICとユニバーサル基板以外は、ほとんど自宅にあった廃材を再利用しているのと、配線を間違えて配線を何度もつけたり外したりしたので配線も作りも雑ですが、とりあえずは指示通りに動いてくれています。

##確認作業
まず、`/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
```

デフォルトで`GPIO7`と`GPIO8`のピンが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
```

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

##raspi-config のインストール
GPIOの機能設定には、raspi-configを使用しました。raspbian専用の設定変更ツールなのですが、ubuntuでも以下のURLで動作することが紹介されていたので、その紹介されている手順どおりに作業しました。
- [Trading on Raspberry Pi with Ubuntu 18.04](https://trenki2.github.io/blog/2019/05/14/trading-with-raspberry-pi/)

```
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番号を「`0`と`1`」の組み合わせから「`2`と`3`」の組み合わせにプログラム上で変更しています。


```shell: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デバイス・ドライバでの使い方と、レジスタを直接たたく方法を実験したいと思います。