Elixir Circuits I2Cでアナログ入力 （Grove Base Hat for Raspberry Pi）

#1.はじめに

Elixirを使って、RaspberryPiのハードウェア制御の練習をしてみました。
今回は、[Elixir Circuits.I2C](https://github.com/elixir-circuits/circuits_i2c)から、[Grove Base Hat for Raspberry Pi](https://wiki.seeedstudio.com/jp/Grove_Base_Hat_for_Raspberry_Pi/)に搭載されているADコンバータを制御してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145581/8b091c12-bb47-a090-0eeb-6d28cd8767f5.png)

#2.ハードウェア

Seeed社の[GROVE規格](https://jp.seeedstudio.com/category/Grove-c-1003.html)[^grove1]の機器を、RaspberryPiに接続するインターフェース・ボードです。GPIO、I2C、UART、そしてアナログタイプの入力用として12bitのADコンバータも搭載しています。

 - [Grove Base Hat for Raspberry Pi](https://wiki.seeedstudio.com/jp/Grove_Base_Hat_for_Raspberry_Pi/)
   - RaspberryPi用
     - [スイッチサイエンス](https://www.switch-science.com/catalog/5336/)、[マルツエレック](https://www.marutsu.co.jp/pc/i/1558555/)、他
   - RaspberryPi Zero用（小型版）
     - [秋月電子通商](https://akizukidenshi.com/catalog/g/gM-13879/)、[共立電子産業](https://eleshop.jp/shop/g/gK51122/)、他

[^grove1]: https://wiki.seeedstudio.com/Grove_System/

 
###I2C通信仕様

- Grove Base HATのアドレス：`0x04`

```bash:コマンドライン
 $ i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- 04 -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --                         
```

|I2C Registers|値|
|:--|:--|
|0x10 ~ 0x17|ADC raw data|
|0x20 ~ 0x27|input voltage|
|0x29|output voltage (Grove power supply voltage)|
|0x30 ~ 0x37|input voltage / output voltage|

I2Cコマンドの処理の流れ

```elixir
# I2Cアドレス
@address 0x04

#コマンド送信
I2C.write(ref, @address, <<I2C Registers>>)
Process.sleep(1)

#結果受信、2バイト読み込み
I2C.read(ref, @address, 2)
{:ok, <<ret0, ret1>>} = I2C.read(ref, @address, 2)

#2バイト分を連結
ret0 ||| ret1 <<< 8
```

#3.ソフトウェア

##(1)下準備

プロジェクトを作ります。

```bash:コマンドライン
$ cd gitwork
$ mix new i2chatad
$ cd i2chatad
```

##(2)コード

```elixir:i2chatadc.ex
defmodule I2chatad do
  @moduledoc """
  Documentation for `I2chatad`.

  https://github.com/elixir-circuits/circuits_i2c
  https://github.com/Seeed-Studio/grove.py/blob/master/grove/adc.py
  """

  alias Circuits.I2C
  require Logger
  use Bitwise

  # I2Cアドレス
  @address 0x04

  @doc """
  データ取得
  ## Examples
      iex> I2chatad.get()
  """
  def get() do
    # I2Cを開く
    {:ok, ref} = I2C.open("i2c-1")

    Logger.info("      RAW  VOLT    RATE")

    # AD0～3読み込み
    Enum.each([0, 1, 2, 3], fn ch ->
      # RAWデータ
      raw = read_raw(ref, ch)
      # mVデータ
      vol = read_voltage(ref, ch)

      # RATEの表記(xx.x %)のうち、整数部だけ残す
      rat =
        read(ref, ch)
        |> div(10)

      #測定結果を表示
      Logger.info(" ch#{ch}: #{raw}  #{vol} mV  #{rat} %")
    end)
  end

  @doc """
  12bitアナログ入力のRAWデータを読み込み
  ## Parameter
    - channel (int): 0 - 7, specify the channel to read
  ## Return:
    - (int): the adc result, in [0 - 4095]
  """
  def read_raw(ref, channel) do
    regaddr = 0x10 + channel
    read_register2(ref, regaddr)
  end

  @doc """
  電圧(mV)変換した値を返す
  ## Parameter
    - channel (int): 0 - 7, specify the channel to read
  ## Return:
    - (int): the voltage result, in mV
  """
  def read_voltage(ref, channel) do
    regaddr = 0x20 + channel
    read_register2(ref, regaddr)
  end

  @doc """
  入力電圧を、0～3.3Vのスケールでパーセント変換した値を返す
  ## Parameter
    - ref : i2c id
    - channel (int): 0 - 7, specify the channel to read
  ## Return:
    - (int): the ratio, in 0.1%
  """
  def read(ref, channel) do
    regaddr = 0x30 + channel
    read_register2(ref, regaddr)
  end

  @doc """
  I2Cレジスタの読み出し(8bit)
  ## Parameter
    - ref : i2c id
    - n (int): I2C Resister Addr
  ## Return:
  """
  def read_register(ref, n) do
    I2C.write(ref, @address, <<n>>)
    Process.sleep(1)
    {:ok, <<ret>>} = I2C.read(ref, @address, 1)
    ret
  end

  @doc """
  I2Cレジスタの読み出し(12bit)
  ## Parameter
    - ref : i2c id
    - n (int): I2C Resister Addr
  ## Return:
  """
  def read_register2(ref, n) do
    I2C.write(ref, @address, <<n>>)
    Process.sleep(1)
    I2C.read(ref, @address, 2)
    {:ok, <<ret0, ret1>>} = I2C.read(ref, @address, 2)
    #2バイト分の値をビットシフトして連結
    ret0 ||| ret1 <<< 8
  end
end
```

##(3)実行結果

iexのプロンプトから、`I2chatad.get`を実行するたびに、ch0～4までの値を取得します。

ここでは、各ADxのコネクタに、以下のセンサを繋いでいます。

|Grove AD|センサ|
|:--|:--|
|AD0|[Grove Light Sensor](https://jp.seeedstudio.com/Grove-Light-Sensor-v1-2-LS06-S-phototransistor.html)|
|AD2|[Grove Button](https://wiki.seeedstudio.com/Grove-Button/)|

```bash
$ iex -S mix
Erlang/OTP 22 [erts-10.5.4] [source] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe]

Compiling 1 file (.ex)
Remember to keep good posture and stay hydrated!
Interactive Elixir (1.10.3) - press Ctrl+C to exit (type h() ENTER for help)

iex(1)> I2chatad.get
12:34:45.246 [info]        RAW   VOLT     RATE
12:34:45.253 [info]   ch0: 2502  2010 mV  60 %   ### ←　Light 明るい
12:34:45.260 [info]   ch1: 2374  1796 mV  52 %
12:34:45.267 [info]   ch2: 0  0 mV  0 %          ### ←　Button 離した
12:34:45.274 [info]   ch3: 2504  2010 mV  61 %
:ok  

iex(2)> I2chatad.get
12:34:48.758 [info]        RAW   VOLT     RATE
12:34:48.767 [info]   ch0: 1225  1126 mV  32 %   ### ←　Light 暗い
12:34:48.776 [info]   ch1: 2131  1889 mV  54 %
12:34:48.785 [info]   ch2: 4095  3283 mV  99 %   ### ←　Button 押した
12:34:48.794 [info]   ch3: 2944  2396 mV  70 %
:ok: 
```

#4.おわりに

Elixir Circuits.I2Cから、Grove Base Hat for Raspberry PiのADコンバータを操作する例を紹介しました。もう少し使いやすくするため、ライブラリにしてみます。（作成中）

#参考資料

 - [grove.py](https://github.com/Seeed-Studio/grove.py)
   - [ADコンバータの制御プログラム](https://github.com/Seeed-Studio/grove.py/blob/master/grove/adc.py)