チート式GreenPAK(SLG46826)入門 その1 簡易ADC

概要

GreenPAK(SLG46826)を普通の使いかたでない方法でチートして、ちょっと便利に使ってみるシリーズです。今回はGreenPAK(SLG46826)では搭載されていないADCを、精度は粗いですがなんとか実装してみました。

SLG46826のアナログ回路

SLG46826には4つのコンパレータが搭載されていますが、ADCのようには使うことはできません。

コンパレータ自体は上記で復習をしてみてください。

簡易ADCの回路

こんな感じになります。A CMP0HにPORで有効化だけしただけの回路です。出力には何もつながっていません。

プロパティをみてみます。今回設定しているのがIN+gainとIN-sourceになります。ゲインはADCのアッテネータに相当します。コンパレータは0Vから2Vぐらいの電圧まで計測可能ですので0.5倍して、0Vから4Vぐらいまでの範囲に拡張しています。3.3Vまでの計測がこれで可能になりました。

IN-sourceは確認用なので、800mVに意味はありません。ゲインが0.5倍なので、判定が1600mVになっているのを確認するぐらいの用途になります。

x1.0x0.5x0.33x0.25
032mV64mV97mV128mV
164mV128mV194mV256mV
296mV192mV291mV384mV
3128mV256mV388mV512mV
4160mV320mV485mV640mV
5192mV384mV582mV768mV
6224mV448mV679mV896mV
7256mV512mV776mV1024mV
8288mV576mV873mV1152mV
9320mV640mV970mV1280mV
10352mV704mV1067mV1408mV
11384mV768mV1164mV1536mV
12416mV832mV1261mV1664mV
13448mV896mV1358mV1792mV
14480mV960mV1455mV1920mV
15512mV1024mV1552mV2048mV
16544mV1088mV1648mV2176mV
17576mV1152mV1745mV2304mV
18608mV1216mV1842mV2432mV
19640mV1280mV1939mV2560mV
20672mV1344mV2036mV2688mV
21704mV1408mV2133mV2816mV
22736mV1472mV2230mV2944mV
23768mV1536mV2327mV3072mV
24800mV1600mV2424mV3200mV
25832mV1664mV2521mV3328mV
26864mV1728mV2618mV3456mV
27896mV1792mV2715mV3584mV
28928mV1856mV2812mV3712mV
29960mV1920mV2909mV3840mV
30992mV1984mV3006mV3968mV
311024mV2048mV3103mV4096mV
321056mV2112mV3200mV4224mV
331088mV2176mV3297mV4352mV
341120mV2240mV3394mV4480mV
351152mV2304mV3491mV4608mV
361184mV2368mV3588mV4736mV
371216mV2432mV3685mV4864mV
381248mV2496mV3782mV4992mV
391280mV2560mV3879mV5120mV
401312mV2624mV3976mV5248mV
411344mV2688mV4073mV5376mV
421376mV2752mV4170mV
431408mV2816mV4267mV
441440mV2880mV4364mV
451472mV2944mV4461mV
461504mV3008mV4558mV
471536mV3072mV4655mV
481568mV3136mV4752mV
491600mV3200mV4848mV
501632mV3264mV4945mV
511664mV3328mV5042mV
521696mV3392mV5139mV
531728mV3456mV5236mV
541760mV3520mV5333mV
551792mV3584mV5430mV
561824mV3648mV
571856mV3712mV
581888mV3776mV
591920mV3840mV
601952mV3904mV
611984mV3968mV
622016mV4032mV

測定範囲が上記になります。5V以上は計測できないと思ったほうがいいです。

チート方法

コンパレータは基準電圧と、入力電圧を比べるセルになります。通常は基準電圧が固定されていて、バッテリー電圧を3段階のLEDで表示するなどの用途に利用されます。

チート式では、I2Cで回路の基準電圧を動的に変更してどの電圧で反応するのかを調べることで簡易ADC的に利用します。

回路データ

:1000000000000000000000000000000000000000F0
:1000100000000000000000000000000000000000E0
:100020000000000000000000000000000000E003ED
:1000300000000000000000000000000000000000C0
:1000400000000000000000000000000000000000B0
:1000500000000000000000000000000000000000A0
:100060000030300030303030000030303000303080
:1000700030303003000000000000000000000000ED
:1000800000000000001422300C610000000000009D
:100090000000000000000000000000000000000060
:1000A0000000002000010000000201000002000129
:1000B0000000020100000200010000020100000235
:1000C000000100000200010000000101000000002A
:1000D0000000000000000000000000000000000020
:1000E0000000000000000000000000000000000010
:1000F000000000000000000000000000000000A55B
:00000001FF

今回の回路データをHEX出力したものです。これをあらかじめSLG46826に焼き込んでおきます。

コード例

#include "I2C_SLG46826.h"

#define SLG46826_I2C_SDA 32
#define SLG46826_I2C_SCL 33

I2C_SLG46826 slg(Wire);

void setup() {
  Serial.begin(115200);
  delay(500);

  // Init I2C
  Wire.begin(SLG46826_I2C_SDA, SLG46826_I2C_SCL);
}

void loop() {
  for (int controlCode = 0; controlCode < 16; controlCode++) {
    if (slg.scanSlg(controlCode)) {
      // ADC
      uint8_t val89 = slg.readReg(controlCode * 8 + 1, 0x89);
      uint8_t div = val89 & 0x03;

      float div_val = 1.0;
      if (div == 0) {
        div_val = 1;
      } else if (div == 1) {
        div_val = 0.5;
      } else if (div == 2) {
        div_val = 0.33;
      } else if (div == 3) {
        div_val = 0.25;
      }

      uint16_t vol = 0;
      for (int i = 62; i >= 0; i--) {
        uint8_t val = (i << 2) + div;
        slg.writeReg(controlCode * 8 + 1, 0x89, val);
        uint8_t stat = slg.readReg(controlCode * 8 + 1, 0x7b) & 0x01;
        if (stat) {
          vol = (uint16_t)((i + 1) * 32 / div_val);
          break;
        }
      }

      Serial.printf("Vol = %4d\n", vol);
    }
  }

  delay(1000);
}

ざっくりとですが、基準電圧を変更しつつ、A CMP0Hの出力変化を確認しているだけのコードになります。

基準電圧

上記がデータシートです。0x89の下から2ビットがアッテネータ設定、残り6ビットが基準電圧になります。

uint8_t val = (i << 2) + div;

上記のコードで最高値の62からカウントダウンしつつ、基準電圧を下げていきます。

A CMP0H出力

上記より0x7Bの一番下のビットがA CMP0Hの出力になります。これが1の場合には基準電圧より入力電圧が高いことになります。

        uint8_t stat = slg.readReg(controlCode * 8 + 1, 0x7b) & 0x01;
        if (stat) {
          vol = (uint16_t)((i + 1) * 32 / div_val);
          break;
        }

上記コードで1になる基準電圧を発見したらループを終了しています。

実験

上記のUSBから任意電圧を出力できるデバイスを利用して、電圧を変えつつ出力を確認してみました。

Vol = 2624
Vol = 3008
Vol = 3520
Vol = 3520
Vol = 3136
Vol = 2624
Vol = 2240
Vol = 1664
Vol = 1152
Vol =  960
Vol =  960
Vol =  960
Vol =  960
Vol =  960

こんな感じの出力で、概ね設定している電圧に近い値が取得できました!

まとめ

I2Cで操作する前提の場合、8ポートのI/Oがありますが直接回路を書き換えることも可能です。ちょっとロジックICとしてのGreenPAKからは逸脱してしまいますが、便利なI2Cデバイスとしてはありだと思います。

欠点としては、精度が粗いです。4Vまで測定可能な0.5倍のアッテネータの場合64mV単位で、3.3Vまで使うと50段階ぐらいしか取得できません。概ね32段階ぐらいで十分な用途であれば個人的にはありだと思います。

本当は二分木とかで値を検索したほうが好ましいですが、実験コードとしては上から下げていくでいいのかな。。。前回の値から二分木とかとかいろいろやれることはあると思います。

コメント