初めてのRaspberry Pi Pico ㉔ C言語 16ビットADC ADS1110


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

ADS1110のおもなスペック

  • ビット数 16
  • チャネル数 1
  • 基準電圧 2.048V ±0.05%、ドリフト5ppm/℃
  • 電源電圧 2.7~5.5V
  • 消費電流 240µA
  • 入力 差動、シングルエンド
  • 変換方式 ΔΣ型
  • データ・レート 15SPS(16ビット)
  • インターフェース I2C
  • I2C転送速度 最大3.4MHz
  • スレーブ・アドレス 発注時に指定できる。表面にED0の印字は0x48
  • プログラマブル・ゲイン・アンプ 1/2/4/8倍が設定できる

接続

 ボード化されたADS1110は、ebayで購入しました(購入時400円)。Digi-KeyでICは約500円です。

ADS1110ボードの端子 Picoの端子(GPIO) 名称
Vin+ - -
Vin- - -
Vcc 3.3V 3.3V
GND GND GND
SCL GP9 SCL
SDA GP8 SDA

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

プログラムads1110.c

 フォルダ名はads1110としました。CMakeLists.txtは省略します。17回以前を参考にしてください。

  ADS1110データシート

 設定用レジスタのアドレスはありません。

 ◆設定レジスタ デフォルト b10001100

b7 b6 b5 b4 b3 b2 b1 b0
ST/DRDY 0 0 SC DR1 DR0 PGA1 PGA0

SC=0は連続変換、'1'は1回のみの変換。
DR1,DR0はサンプリング・レート。デフォルト15SPSで16ビット。
PGA1,PGA0はアンプの増幅度。'00'=×1、'01'=×2、'10'=×4、'11'=×8。

 設定時に書き込むデータは、PGAによって変化します。PGAに倍率nを設定したら、読み取った電圧をnで割ります。
 x1の入力電圧はVrefなので約2.5V、x2のときはVrefの半分、x4のときはVrefの1/4、x8x4のときはVrefの1/8になります。増幅度を上げると分解能は向上しますが、許容入力電圧が下がります。

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

 内部の基準電源電圧は2.48Vですが、1.0000V入力に対して少し低めに出ていたので、2.028とわずかに変更しました。
 I2Cの転送速度はPicoの上限1MHzにしました。

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

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

#define I2C_PORT  i2c0
static int addr = 0x48;
static float Vref = 2.028;

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

float readADC(uint8_t PGAgain){
    printf(" SamplingRate is 15 <-16bit\n");
    uint8_t val = 0b10001100;
    switch (PGAgain) {
        case 1: val = val | 0x00; break;
        case 2: val = val | 0x01; break;
        case 4: val = val | 0x02; break;
        case 8: val = val | 0x03; break;
        default:
        printf("PGA 1 2 4 8");
    }
    i2c_write_blocking(I2C_PORT, addr, &val, 1, true);

    uint8_t buffer[2];
    i2c_read_blocking(I2C_PORT, addr, buffer, 2, false);
    uint16_t temp = (buffer[0]<<8) | buffer[1];
    int16_t tempSign = -(temp & 0b1000000000000000) | (temp & 0b0111111111111111);
    float V = Vref * tempSign / 32767;
    return V / PGAgain;
}

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

    printf("input: %.5fV\n", readADC(2));

    return 0;
}

 PGA=1のときの実行結果です。入力電圧=1.0000V、Reset、入力電圧=-1.0000V、Resetと4回実行しています。

 PGA=2のときの実行結果です。入力電圧=1.0000V、Reset、入力電圧=-1.0000V、Resetと4回実行しています。
 最初の実行時に1/2になりました。バグが残っているようです。