概要
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.0 | x0.5 | x0.33 | x0.25 |
0 | 32mV | 64mV | 97mV | 128mV |
1 | 64mV | 128mV | 194mV | 256mV |
2 | 96mV | 192mV | 291mV | 384mV |
3 | 128mV | 256mV | 388mV | 512mV |
4 | 160mV | 320mV | 485mV | 640mV |
5 | 192mV | 384mV | 582mV | 768mV |
6 | 224mV | 448mV | 679mV | 896mV |
7 | 256mV | 512mV | 776mV | 1024mV |
8 | 288mV | 576mV | 873mV | 1152mV |
9 | 320mV | 640mV | 970mV | 1280mV |
10 | 352mV | 704mV | 1067mV | 1408mV |
11 | 384mV | 768mV | 1164mV | 1536mV |
12 | 416mV | 832mV | 1261mV | 1664mV |
13 | 448mV | 896mV | 1358mV | 1792mV |
14 | 480mV | 960mV | 1455mV | 1920mV |
15 | 512mV | 1024mV | 1552mV | 2048mV |
16 | 544mV | 1088mV | 1648mV | 2176mV |
17 | 576mV | 1152mV | 1745mV | 2304mV |
18 | 608mV | 1216mV | 1842mV | 2432mV |
19 | 640mV | 1280mV | 1939mV | 2560mV |
20 | 672mV | 1344mV | 2036mV | 2688mV |
21 | 704mV | 1408mV | 2133mV | 2816mV |
22 | 736mV | 1472mV | 2230mV | 2944mV |
23 | 768mV | 1536mV | 2327mV | 3072mV |
24 | 800mV | 1600mV | 2424mV | 3200mV |
25 | 832mV | 1664mV | 2521mV | 3328mV |
26 | 864mV | 1728mV | 2618mV | 3456mV |
27 | 896mV | 1792mV | 2715mV | 3584mV |
28 | 928mV | 1856mV | 2812mV | 3712mV |
29 | 960mV | 1920mV | 2909mV | 3840mV |
30 | 992mV | 1984mV | 3006mV | 3968mV |
31 | 1024mV | 2048mV | 3103mV | 4096mV |
32 | 1056mV | 2112mV | 3200mV | 4224mV |
33 | 1088mV | 2176mV | 3297mV | 4352mV |
34 | 1120mV | 2240mV | 3394mV | 4480mV |
35 | 1152mV | 2304mV | 3491mV | 4608mV |
36 | 1184mV | 2368mV | 3588mV | 4736mV |
37 | 1216mV | 2432mV | 3685mV | 4864mV |
38 | 1248mV | 2496mV | 3782mV | 4992mV |
39 | 1280mV | 2560mV | 3879mV | 5120mV |
40 | 1312mV | 2624mV | 3976mV | 5248mV |
41 | 1344mV | 2688mV | 4073mV | 5376mV |
42 | 1376mV | 2752mV | 4170mV | |
43 | 1408mV | 2816mV | 4267mV | |
44 | 1440mV | 2880mV | 4364mV | |
45 | 1472mV | 2944mV | 4461mV | |
46 | 1504mV | 3008mV | 4558mV | |
47 | 1536mV | 3072mV | 4655mV | |
48 | 1568mV | 3136mV | 4752mV | |
49 | 1600mV | 3200mV | 4848mV | |
50 | 1632mV | 3264mV | 4945mV | |
51 | 1664mV | 3328mV | 5042mV | |
52 | 1696mV | 3392mV | 5139mV | |
53 | 1728mV | 3456mV | 5236mV | |
54 | 1760mV | 3520mV | 5333mV | |
55 | 1792mV | 3584mV | 5430mV | |
56 | 1824mV | 3648mV | ||
57 | 1856mV | 3712mV | ||
58 | 1888mV | 3776mV | ||
59 | 1920mV | 3840mV | ||
60 | 1952mV | 3904mV | ||
61 | 1984mV | 3968mV | ||
62 | 2016mV | 4032mV |
測定範囲が上記になります。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段階ぐらいで十分な用途であれば個人的にはありだと思います。
本当は二分木とかで値を検索したほうが好ましいですが、実験コードとしては上から下げていくでいいのかな。。。前回の値から二分木とかとかいろいろやれることはあると思います。
コメント