SPI /IIOサブシステムを用いたラズベリーパイ用高精度A/D変換モジュール「ADPi Pro」による計測方法

Raspberry Pi 3を使って、アナログ信号をデジタル信号に変換するプログラムを作成します。A/D変換には、メカトラックス社の[ラズベリーパイ用高精度A/D変換モジュール「ADPi Pro」](https://mechatrax.com/products/adpi/)を使用します。ADPi Proは、24bit分解能のAnalog Devices社「AD7794」を使用し、温度特性に配慮した外部基準電圧発生ICの搭載し、出荷時校正データを格納した「EEPROM」により、A/D変換したデータを補正します。
ADPi Proは、SPIインタフェースとIIOサブシステムにより接続可能で、SPIインタフェースを使用するときは[SPIを用いたラズベリーパイ用高精度A/D変換モジュール「ADPi Pro」のセットアップ](https://qiita.com/TomoSoft/items/8aee48e685db8ffab3ca)、IIOサブシステムを使用するときは[IIOサブシステムを用いたラズベリーパイ用高精度A/D変換モジュール「ADPi Pro」のセットアップ](https://qiita.com/TomoSoft/items/7eea3e7483ff8b0df82d)に従って、それぞれセットアップします。
実際にADPi Proに分圧した1Vのアナログ電圧を入力して、Raspberry Pi 3でA/D変換値を取得する動作環境の様子を次に示します。なお、ADPi Pro の資料は、[ADPi Pro（ラズベリーパイ用高精度 A/D 変換モジュール）](https://github.com/mechatrax/adpipro?_ga=2.190419565.739881186.1531101539-1744061270.1449811405)に公開されています。

![adpi01.jpg](https://qiita-image-store.s3.amazonaws.com/0/124811/68b655af-6f81-3778-c67c-ed2726eae64e.jpeg)

作成したプログラムを確認するための1Vのアナログ電圧は、ADPi Proのターミナルブロック4個の差動電圧入力「Vin+」「Vin-」のそれぞれに、5Vを5個の抵抗で分圧した「1V」を次ように接続します。

<div align="center" "><img src="https://qiita-image-store.s3.amazonaws.com/0/124811/90f309ed-1b45-fe3f-4359-2f742d7b4883.jpeg"></div>


#_SPIを用いたADPi Proによる計測_
ADPi ProをSPIデバイスとして動作させ、ADPi Proのターミナルブロックに接続されたアナログ電圧値をA/D変換して入力するpythonスクリプトを作成します。なお、SPIを用いたADPi Proのセットアップについては、[ADPi Proのセットアップ（SPI）](https://qiita.com/TomoSoft/items/8aee48e685db8ffab3ca#adpi-pro%E3%81%AE%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97)に示します。

##_SPIを用いたADPi ProのPythonスクリプトの作成_
ADPi Proに接続されたアナログ電圧を、SPIインタフェースを使ってA/D変換値を入力し、変換した値に対して補正を行うPythonスクリプトを作成します。

- Python3 により SPI 通信でADPi ProのA/D変換器「AD7794」をアクセスするために、spidevパッケージを使用します。
- Python3 により I<sup>2</sup>C通信でADPi Proの出荷時校正データ「EEPROM」をアクセスするために、smbusパッケージを使用します。
- adpiパッケージは、ADPi Proを構成する24bit分解能のA/D変換器「AD7794」、出荷時校正データを格納する「EEPROM」、GPIO エキスパンダ「MCP23008」を制御するPythonスクリプトクラスで、Pythonスクリプトのコードを[python-adpi](https://github.com/mechatrax/python-adpi/tree/master/adpi)に示します。
- get_voltage関数は、adpiクラスのインスタンスとA/D変換するチャンネル番号をパラメータにし、チャンネル番号に対応するターミナルブロックに接続されたアナログ電圧値を、single_conversion関数を用いて取得し、取得したデータから対応するチャンネルの入力電圧を計算して、その計算結果を文字列変換して関数の戻り値とします。
- single_conversion関数は、入力電圧のスケール値とその生の電圧値を取得します。

```Python:adpispisample.py
#!/usr/bin/python3

import spidev
import smbus
import adpi
import sys
from time import sleep

RAW_OFFSET = (1 << 23)
RAW_SCALE = (
    0.000596040,
    0.000298020,
    0.000149010,
    0.000074500,
    0.000037250,
    0.000018620,
    0.000009310,
    0.000004650,
)
TEMP_VREF = 1.17


def v2k(rate, val):
    for k, v in rate.items():
        if v == val:
            return k


def single_conversion(dev, ch):
    c = dev.adc.channel[ch]
    g, _ = dev.read_configuration()
    dev.write_configuration(g, c)
    _, r = dev.read_mode()
    dev.write_mode(dev.adc.mode['single'], r)
    rate = v2k(dev.adc.rate, r)

    while True:
        sleep(2 * 1.0 / float(rate))
        if not dev.read_status() & 0x80:
            break

    raw = dev.read_data()
    return raw, g


def get_voltage(dev, ch):
    raw, g = single_conversion(dev, ch)
    vol = RAW_SCALE[g] * (raw - RAW_OFFSET)
    return "Ch {} : {:.9f}".format(ch,vol)


if __name__ == "__main__":
    spibus = 0
    spics = 0
    eeprombus = 1
    eepromaddr = 0x57
    gpiobus = 1
    gpioaddr = 0x27
    spi = spidev.SpiDev()
    i2c = smbus.SMBus(eeprombus)
    try:
        spi.open(spibus, spics)
        spi.mode = 0b11
        spi.max_speed_hz = 1000000
        ad = adpi.ADPiPro(spi, i2c, eepromaddr, gpioaddr)
        print(get_voltage(ad, "1"))
        print(get_voltage(ad, "2"))
        print(get_voltage(ad, "3"))
        print(get_voltage(ad, "4"))

    except (IndexError, ValueError):
        sys.exit(2)
    finally:
        spi.close()

```

##_作成したPythonスクリプトの実行_
作成したPythonスクリプトを次のコマンドで実行すると、4チャンネル分のA/D変換値が表示されます。

```
$ python3 adpispisample.py
Ch 1 : 1005.942668400
Ch 2 : 1005.440802720
Ch 3 : 1006.350359760
Ch 4 : 1005.499810680
```
#_IIOサブシステムを用いたADPi Proによる計測_
ADPi ProをIIO サブシステムとして動作させ、ADPi Proのターミナルブロックに接続されたアナログ電圧値をA/D変換して入力するシェルスクリプトを作成します。なお、IIOサブシステムを用いたADPi Proのセットアップについては、[ADPi Proのセットアップ（IIOサブシステム）](https://qiita.com/TomoSoft/items/7eea3e7483ff8b0df82d#adpi-pro%E3%81%AE%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97)に示します。

##_IIOサブシステムを用いたADPi Proのシェルスクリプトの作成_
ADPi Proに接続されたアナログ電圧を、IIOサブシステムを使ってA/D変換値を入力し、変換した値に対して補正を行うシェルスクリプトを作成します。シェルスクリプトは、[IIO サブシステム](https://github.com/mechatrax/adpipro/wiki/IIO-%E3%82%B5%E3%83%96%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0#%E9%9B%BB%E5%9C%A7%E5%80%A4%E3%81%AE%E6%B8%AC%E5%AE%9A%E4%BE%8B)に示すIIO サブシステムを用いて、ADPi Pro に搭載された ADC へアクセスします。


- 「`cat ${IIO_PATH}/in_voltage${idx}-voltage${idx}_offset` 」により、チャンネルに対応したオフセット値を取得します。
- 「`cat ${IIO_PATH}/in_voltage-voltage_scale` 」により、入力電圧のスケール値を取得します。
- 「`cat ${IIO_PATH}/in_voltage${idx}-voltage${idx}_raw` 」により、チャンネルに対応した生の電圧値を取得します。
- get_voltage関数は、A/D変換するチャンネル番号をパラメータにし、チャンネル番号に対応するターミナルブロックに接続されたアナログ電圧をデジタル変換し、取得した入力電圧のスケール値、オフセット値、生の電圧値からチャンネルごとの入力電圧を計算して表示します。

```Bash:adpiiiosample.sh
#!/bin/bash

set -e

LIB_PATH=/usr/lib/adpi-utils-backend-iio/
IIO_PATH=/sys/bus/spi/devices/spi0.0/iio:device0

INDEX_OFFSET=-1

#
# Usage: get_voltage <N>
#
get_voltage () 
{
  local idx
  local ofs
  local scl
  local raw
  
  idx=$(($1 + $INDEX_OFFSET))
  ofs=$(cat ${IIO_PATH}/in_voltage${idx}-voltage${idx}_offset)
  scl=$(cat ${IIO_PATH}/in_voltage-voltage_scale)
  raw=$(cat ${IIO_PATH}/in_voltage${idx}-voltage${idx}_raw)
  
  printf "Ch %d : " $(echo $1)
  printf "%.9f\n" $(echo "($raw + $ofs) * $scl" | bc -l)
}

#
# execute command
#
status=2
get_voltage 1
get_voltage 2
get_voltage 3
get_voltage 4
status=$?

exit $status
```

##_作成したシェルスクリプトの実行_
作成したシェルスクリプトを次のコマンドで実行すると、4チャンネル分のA/D変換値が表示されます。

```
$ ./adpiiiosample.sh
Ch 1 : 1005.272123400
Ch 2 : 1005.208347120
Ch 3 : 1006.048167480
Ch 4 : 1005.173776800
```

#_ADPi Proに関連する記事_
1.　[SPIを用いたラズベリーパイ用高精度A/D変換モジュール「ADPi Pro」のセットアップ](https://qiita.com/TomoSoft/items/8aee48e685db8ffab3ca)
ADPi ProをSPIデバイスとして動作させ、Python言語で作成されたサンプルスクリプトを実行して、ADPi Proに接続したアナログ電圧のA/D変換値を確認します。
2.　[IIOサブシステムを用いたラズベリーパイ用高精度A/D変換モジュール「ADPi Pro」のセットアップ](https://qiita.com/TomoSoft/items/7eea3e7483ff8b0df82d)
ADPi ProをIIOサブシステムとして動作させ、作成されたサンプルシェルスクリプトを実行して、ADPi Proに接続したアナログ電圧のA/D変換値を確認します。