Nerves Livebook をカスタマイズし、 Pigpiox を追加する

## はじめに

Rspberry Pi 4 で PWM を実行するため、 Nerves Livebook に Pigpiox を追加します

https://github.com/nerves-livebook/nerves_livebook

カスタマイズ手順は README にも書いてあります

https://github.com/nerves-livebook/nerves_livebook?tab=readme-ov-file#going-further

:::note info
PWM の利用頻度が高いため、様々な記事から参照しやすいよう、「[Nerves Livebook でパッシブブザーを演奏しドレミの歌を奏でる](https://qiita.com/RyoWakabayashi/items/c203e40bd2004cb95aae)」の記事から独立させました
:::

## PWM とは

Pulse Width Modulation = パルス幅変調

電力の ON と OFF を交互に繰り返し、 ON になっている期間と OFF になっている期間の割合を調整することで、出力される電力を制御します

[@mnishiguchi](https://qiita.com/mnishiguchi) さんの記事で分かりやすく解説しています

https://qiita.com/mnishiguchi/items/4bdf88acf0ab0e8e2c7e

以下の記事で PWM を使用しています

https://qiita.com/RyoWakabayashi/items/c203e40bd2004cb95aae

https://qiita.com/RyoWakabayashi/private/ea1a620c3114b064dc2c

https://qiita.com/RyoWakabayashi/private/d6948b9f7df2ead8d9e4

## 背景

Pigpiox があれば簡単に PWM を実行できます

https://github.com/tokafish/pigpiox

サンプルコードも公開されています

https://github.com/nerves-livebook/nerves_livebook/blob/main/priv/samples/basics/pwm.livemd

しかし、デフォルトの Raspberry Pi 4 用 Nerves Livebook ファームウェアには Pigpiox が含まれていません

### Nerves Livebook にインストールされているモジュール

Raspberry Pi 0 〜 3 の場合は Nerves Livebook のファームウェアが Pigpiox インストール済のものになっています

しかし、 Raspberry Pi 4 では Pigpiox がインストールされていません

以下の箇所を参照することで、どのファームウェアに何がインストールされているか確認できます

https://github.com/nerves-livebook/nerves_livebook/blob/main/mix.exs

```elixir
...
  @rpi_targets [:rpi, :rpi0, :rpi2, :rpi3, :rpi3a, :rpi4, :rpi0_2, :rpi5]
  @all_targets @rpi_targets ++
                 [:bbb, :osd32mp1, :x86_64, :npi_imx6ull, :grisp2, :mangopi_mq_pro]

  # Libraries that use MMAL on the Raspberry Pi won't work with the Raspberry
  # Pi 4. The Raspberry Pi 4 uses DRM and libcamera.
  @rpi_mmal_targets [:rpi, :rpi0, :rpi2, :rpi3, :rpi3a]
...
      {:pigpiox, "~> 0.1", targets: @rpi_mmal_targets},
...
```

`targets` が `@rpi_mmal_targets` となっており、 `@rpi_mmal_targets` には `:rpi4` が含まれていません

### PWM 対応ピン

Raspberry Pi 4 であっても GPIO12 と GPIO13 は PWM に対応しています

https://pongsuke.hatenablog.com/entry/2019/12/03/101747

そのため、 Pigpiox をインストールした上で GPIO12 または GPIO13 を指定すれば PWM が実行できます

それ以外のピンを指定した場合は以下のエラーが返ってきます

```elixir
{:error, :not_hpwm_gpio}
```

### Nerves Livebook の Mix.install 未サポート

Nerves Livebook は `Mix.install` をサポートしていないため、 **必要なモジュールはファームウェアに書き込む時点でインストール済にしておく必要があります**

Nerves Livebook 上で `Mix.install` を実行すると以下のようなエラーが出ます

```
** (RuntimeError) Mix.install/2 is not supported on Nerves Livebook (yet!).

All is not lost, but you will have to rebuild the Nerves Livebook firmware.
Go to https://github.com/nerves-livebook/nerves_livebook and clone the repository.
Add :pigpiox to the dependencies listed in the `mix.exs` file, build,
and then try again.
```

## Nerves Livebook のカスタマイズ手順

### Nerves Livebook のクローン

GitHub からソースコードを取得します

```shell
git clone https://github.com/nerves-livebook/nerves_livebook.git
cd nerves_livebook
```

### ビルド環境の構築

ルートディレクトリーにある `.tool-versions` で Erlang と Elixir のバージョンを指定しています

```
erlang 26.2.5
elixir 1.16.3-otp-26
```

asdf を使用している場合、以下のコマンドを実行すれば簡単にインストール可能です

```shell
asdf install
```

[Nerves.Bootstrap](https://github.com/nerves-project/nerves_bootstrap) も必要になるのでインストールしておきます

```shell
mix archive.install hex nerves_bootstrap
```

SquashFS も `mix burn` で要求されるためインストールします

```shell
brew install squashfs
```

### 依存モジュールの編集

`mix.exs` の以下の箇所を編集します

```diff_elixir
-     {:pigpiox, "~> 0.1", targets: @rpi_mmal_targets},
+     {:pigpiox, "~> 0.1", targets: @all_targets},
```

### ファームウェアのビルド

デバイスと環境を指定します

```shell
export MIX_TARGET=rpi4
export MIX_ENV=prod
```

依存モジュールを取得します

```shell
mix deps.get
```

ファームウェアをビルドします

```shell
mix firmware
```

### SD カードへのファームウェア書込み

WiFi の接続情報を指定して SD カードにファームウェアを書き込みます

```shell
NERVES_WIFI_SSID='<WiFi の SSID>' NERVES_WIFI_PASSPHRASE='<WiFi の パスワード>' mix burn
```

## まとめ

これで Pigpiox 入りの Nerves Livebook が出来ました

あとはこれまでと同じく、 SD カードを Raspberry Pi に差し込んで起動し、ブラウザから nerves.local にアクセスするだけです