初めてのRaspberry Pi Pico ㉕ C言語 16ビットADC ADS1115

　Picoには12ビット4チャネルのA-Dコンバータが内蔵されています。ENOB（effective number of bits：有効ビット数）が9.5なので、もう少し高いビット数がほしいという想定で外部にICを追加します。


###ADS1115のおもなスペック

- ビット数　16
- チャネル数　4（シングルエンド）、2（差動）
- 基準電圧　内蔵
- 電源電圧　2.7～5.5V
- 入力　差動（A0-A1、A0-A3、A1-A3、A2-A3）、シングル（A0、A1、A2、A3とGND）
- 変換方式　ΔΣ型
- データ・レート　128SPS以下で16ビット
- インターフェース　I2C
- I2C転送速度　最大3.4MHz
- スレーブ・アドレス　デフォルトは0x48
- プログラマブル・ゲイン・アンプ　フルスケール；±6.144V、±4.096V、±2.048V、±1.024V、±0.512V、±0.256V

###接続

　ボード化されたADS1115は、[Adafruit製の旧製品](https://www.adafruit.com/product/1085)で、スイッチサイエンスで購入しました。


<img width="270" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/1c94f2a2-2ffc-1d1e-a679-62c37f430299.png">



|ADS1115ボードの端子|	Picoの端子(GPIO)	|名称|
|------------|------------|:-------------:|:------|
|Vcc|	3.3V|	3.3V|
|GND|	GND|GND|
|SCL|	GP9|	SCL|
|SDA|	GP8|	SDA|
|A0|	-|	-|
|A1|	-|	-|
|A2|	-|	-|
|A3|	-|	-|

　プルアップ抵抗10kΩがSDA/SCLに入っていましたが取りました。
　ADS1115の入力には、直流標準電圧電流発生器TR6142で電圧を入力しています。1.0000だと小数点第4位まで正確です。

###プログラム
　フォルダ名はads1115としました。cmake makeの手順は省略します。17回以前を参考にしてください。プログラムは、ads1115.hとads1115.cに分けました。

 　　[ADS1115データシート](https://www.tij.co.jp/jp/lit/ds/symlink/ads1115.pdf?ts=1614002338660&ref_url=https%253A%252F%252Fwww.tij.co.jp%252Fproduct%252Fjp%252FADS1115)

```shell:CMakeLists.txt
add_executable(ads1115
        ads1115.c
        )

# Pull in our (to be renamed) simple get you started dependencies
target_link_libraries(ads1115 pico_stdlib hardware_i2c)

# create map/bin/hex file etc.
pico_add_extra_outputs(ads1115)
```

###設定レジスタ　デフォルト b10001100
　設定用ポインタ・レジスタのアドレスは0x01です。ads1115.hに記述しました。

- bit1　OS。'1'で変換開始。デフォルト1
- bit14、bi13、bit12　チャネル・セレクト。
- - 000 : AINP = AIN0 and AINN = AIN1 (デフォルト)
- - 001 : AINP = AIN0 and AINN = AIN3
- - 010 : AINP = AIN1 and AINN = AIN3
- - 011 : AINP = AIN2 and AINN = AIN3
- - 100 : AINP = AIN0 and AINN = GND
- - 101 : AINP = AIN1 and AINN = GND
- - 110 : AINP = AIN2 and AINN = GND
- - 111 : AINP = AIN3 and AINN = GND
- bit11、bit10、bit9　PGA。
- - 000 : FSR = ±6.144 V
- - 001 : FSR = ±4.096 V
- - 010 : FSR = ±2.048 V (デフォルト)
- - 011 : FSR = ±1.024 V
- - 100 : FSR = ±0.512 V
- - 101 : FSR = ±0.256 V
- - 110 : FSR = ±0.256 V
- - 111 : FSR = ±0.256 V
- bit8　MODE。1；連続、0；ワンショット（デフォルト）
- bit7、bit6、bit5　サンプル・レート。
- - 000 : 8 SPS
- - 001 : 16 SPS
- - 010 : 32 SPS
- - 011 : 64 SPS
- - 100 : 128 SPS (デフォルト)
- - 101 : 250 SPS
- - 110 : 475 SPS
- - 111 : 860 SPS
- bit4　COMP_MODE；コンパレータ。省略
- bit3　COMP_POL ；コンパレータ。省略
- bit2　COMP_LAT ；コンパレータ。省略
- bit1、bit0　COMP_QUE[1:0] 　；コンパレータ。省略（デフォルト3h　ディセーブル）

``例；電源を入れた直後のデフォルト設定値。　変換スタート、差動A0-A1チャネル、フルスケール±2.048V、ワンショット、128SPS、コンパレータは無効；1000010110000011h``

```cpp:ads1115.h
//ads1115 Config Register reset = 8583h

/// input
#define D1 0x0000 // Differential  : AINP = AIN0 and AINN = AIN1 (default)
// #define MUX001 0x1000 // not use  : AINP = AIN0 and AINN = AIN3
// #define MUX010 0x2000 // not use  : AINP = AIN1 and AINN = AIN3
#define D2 0x3000 // Differential  : AINP = AIN2 and AINN = AIN3
#define S1 0x4000 // Single-ended: AINP = AIN0 and AINN = GND
#define S2 0x5000 // Single-ended: AINP = AIN1 and AINN = GND
#define S3 0x6000 // Single-ended: AINP = AIN2 and AINN = GND
#define S4 0x7000 // Single-ended: AINP = AIN3 and AINN = GND

/// Gain
#define Gain0 0x0000   // 000 : FSR = ±6.144 V
#define Gain1 0x0200   // 001 : FSR = ±4.096 V
#define Gain2 0x0400   // 010 : FSR = ±2.048 V (default)
#define Gain4 0x0600   // 011 : FSR = ±1.024 V
#define Gain8 0x0800   // 100 : FSR = ±0.512 V
#define Gain16 0x0a00  // 101 110 111: FSR = ±0.256 V

/// Data Rate
#define DR8 0x0000   // 000 : 8 SPS
#define DR16 0x0020  // 001 : 16 SPS
#define DR32 0x0040  // 010 : 32 SPS
#define DR64 0x0060  // 011 : 64 SPS
#define DR128 0x0080 // 100 : 128 SPS (default)
#define DR250 0x00a0 // 101 : 250 SPS
#define DR475 0x00c0 // 110 : 475 SPS
#define DR860 0x00e0 // 111 : 860 SPS
```

###プログラムads1115.c


　読み出すポインタ・レジスタのアドレスは0x00です。
　読み出したデータは2バイトで、0から32767までのデータです。2の補数形式で、D15は符号を表します。
　　``D15 D14 D13 D12 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0``

　I2Cの転送速度は100kHzにしました。


```c:ads1115.c
/**
 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/i2c.h"
#include "ads1115.h"

#define I2C_PORT  i2c0
static int addr = 0x48;
static uint16_t config = 0x8583;
#define configPointer 0x01
#define conversionPointer 0x00
#define READ_BIT 0x80

void setup_I2C(){
    // This example will use I2C0 on GPIO8 (SDA) and GPIO9 (SCL) running at 100kHz.
    i2c_init(I2C_PORT, 100 * 1000);
    gpio_set_function(8, GPIO_FUNC_I2C);
    gpio_set_function(9, GPIO_FUNC_I2C);
    gpio_pull_up(8);
    gpio_pull_up(9);
}

static void I2C_read_registers(uint8_t reg, uint8_t *buf, uint16_t len) {
    // For this particular device, we send the device the register we want to read
    // first, then subsequently read from the device. The register is auto incrementing
    // so we don't need to keep sending the register we want, just the first.
    reg = reg | READ_BIT;
    i2c_write_blocking(I2C_PORT, addr, &reg, 1, true); 
    i2c_read_blocking(I2C_PORT, addr, buf, len, false);
}

static void I2C_write_register16(uint8_t reg, uint16_t data) {
    uint8_t buf[3];
    buf[0] = reg;
    buf[1] = (uint8_t)(data >> 8);
    buf[2] = (uint8_t)(data & 0xff);
    i2c_write_blocking(I2C_PORT, addr, buf, 3, true);
}

float readADC(uint16_t channel, uint16_t PGAgain, uint16_t DataRate){
    config = config | channel | PGAgain | DataRate;
    I2C_write_register16(configPointer, config);

    uint8_t buffer[2];
    I2C_read_registers(conversionPointer, buffer, 2);
    uint16_t temp = (buffer[0]<<8) | buffer[1];
    int16_t tempSign = -(temp & 0b1000000000000000) | (temp & 0b0111111111111111);
    float V = tempSign / 32767.f;

    return V;
}

int main() {
    stdio_init_all();
    printf("\nstart ADS1115\n");
    setup_I2C();

    printf("\n==S1=0x0200=DR8 input: %.5fV\n", readADC(S4, Gain1, DR8));
    printf("\n==S1=0x0200=DR8 input: %.5fV\n", readADC(S4, Gain2, DR8));
    printf("\n==S1=0x0200=DR8 input: %.5fV\n", readADC(S4, Gain4, DR8));
    printf("\n==S1=0x0200=DR8 input: %.5fV\n", readADC(S4, Gain2, DR128));
    printf("\n==S1=0x0200=DR8 input: %.5fV\n", readADC(S4, Gain4, DR128));
/*
    printf("\n==G1=0x0200=DR8 input: %.5fV\n", readADC(D1, Gain1, DR8));

    printf("-G1-DR16-- input: %.5fV\n", readADC(D1, Gain1, DR16));
    printf("-G1-DR32-- input: %.5fV\n", readADC(D1, Gain1, DR32));
    printf("i-G1-DR64--input: %.5fV\n", readADC(D1, Gain1, DR64));
    printf("-G1-DR128--input: %.5fV\n", readADC(D1, Gain1, DR128));
    printf("-G1-DR250--input: %.5fV\n", readADC(D1, Gain1, DR250));
    printf("-G1-DR475--input: %.5fV\n", readADC(D1, Gain1, DR475));
    printf("-G1-DR860--input: %.5fV\n", readADC(D1, Gain1, DR860));

    printf("==G2=0x0400=DR8 input: %.5fV\n", readADC(D1, Gain2, DR8));
    printf("-G2-DR16-- input: %.5fV\n", readADC(D1, Gain2, DR16));
    printf("-G2-DR32-- input: %.5fV\n", readADC(D1, Gain2, DR32));
    printf("-G2-DR64-- input: %.5fV\n", readADC(D1, Gain2, DR64));
    printf("-G2-DR128--input: %.5fV\n", readADC(D1, Gain2, DR128));
    printf("-G2-DR250--input: %.5fV\n", readADC(D1, Gain2, DR250));
    printf("-G2-DR475--input: %.5fV\n", readADC(D1, Gain2, DR475));
    printf("-G2-DR860--input: %.5fV\n", readADC(D1, Gain2, DR860));

    printf("==G4=0x0600=DR8 input: %.5fV\n", readADC(D1, Gain4, DR8));
    printf("-G4-DR16-- input: %.5fV\n", readADC(D1, Gain4, DR16));
    printf("-G4-DR32-- input: %.5fV\n", readADC(D1, Gain4, DR32));
    printf("-G4-DR64-- input: %.5fV\n", readADC(D1, Gain4, DR64));
    printf("-G4-DR128--input: %.5fV\n", readADC(D1, Gain4, DR128));
    printf("-G4-DR250--input: %.5fV\n", readADC(D1, Gain4, DR250));
    printf("-G4-DR475--input: %.5fV\n", readADC(D1, Gain4, DR475));
    printf("-G4-DR860--input: %.5fV\n", readADC(D1, Gain4, DR860));
*/

    return 0;
}

```
　mainのprinf文はテスト時の残骸です。
　フルスケール±6.144Vと±4.096Vのレンジは電源電圧3.3Vを超えて入力できません。16ビットの確度は、多くがDR128以下のデータレートで得られます。