【M5】M5Atomと2CHひずみゲージアンプADS122U04基板作った<小さな2CHひずみアンプ>

電子工作向きの高性能ひずみゲージアンプADS122U04をM5Atomに接続しました。
今までは、mbed LPC1768に接続していたのですが、ADSのメリットである小型化を生かすためにM5Atomと組み合わせました。

●ADS122U04についての紹介記事はこちら
シンプルで安くて小さくて精度と速度が速いというパフォーマンス抜群のアンプです。
TIの製品サイト https://www.tij.co.jp/product/jp/ADS122U04#top

【ひずみゲージアンプ】ADS122U04の動作その1<UARTで楽ちん動作>

【ひずみゲージアンプ】ADS122U04の動作その2<2CHで370Hz出る>

 

●用意するものとADS122U04の半田付けは、紹介記事に書いてあります
●M5Atom用配線図

注意1)RESETを3.3Vにプルアップしておくこと
注意2)信号線に抵抗47Ωをいれておくこと
ひずみゲージブリッジの接点との接続は、汎用なので覚えておく必要があります。
決まり1:1番ゲージー2番ゲージ-3番ゲージー4番ゲージ-1番ゲージと時計回りに周回接続します。
決まり2:接点①=1番ゲージと4番ゲージ、接点②=1番ゲージと2番ゲージ、接点③=2番ゲージと3番ゲージ
  接点④=3番ゲージと4番ゲージ
決まり3:接点①=電源+(3.3v)、接点②=AINpピン、接点③=GND、接点④=AINnピン
(ロードセルの線色:接点①赤、接点②緑、接点③黒、接点④白 が多いですが、例外もあります)
決まり4:4ゲージブリッジが基本です、1ゲージとか2ゲージは温度ドリフトが大きすぎて難しい。
決まり5:得られる電圧値∝(R1+R3)-(R2+R4)となるので、ゲージの伸び縮みを組み合わせて所望の分力を得る
(ゲージが伸びると抵抗は増える、ゲージが縮むと抵抗は減る)

決まり6:私の場合ターミナルブロックの結線順は、左から接点①赤、接点③黒、接点④白、接点②緑としてます。

●ピッチ変換基板
秋月に0.65mmピッチの16ピンがなかったので、SSOP20ピン基板を使ってます。

丸ピンIC用連結ソケット両端連結ピン
ロジアナ オシロで観察するには両端ピンが便利です。

●065mmピッチTSSOPチップの半田付け方法
半田の濡れ促進のためフラックスを用意しないとできません、アマゾンで売ってます。
やり方は、こちらの動画がわかりやすいです。私の場合は、半田がブリッジになってショートしてしまうので
最後に半田吸い取り線で半田を除去しながらショートを回避してます。

【MFT2019】TSSOPの半田付け練習<何とかできそう>

●基板実装
小型のターミナルブロックを2CH分使って基板を小型化しました。
このターミナルブロックは、アマゾンで売ってます。

●デバッグ用に中国製格安ロジアナがあったほうがいいです。
 プログラムとADS122U04が正常に動作しているかチェックするために、ロジアナを常用してます。ロジアナがないとプログラムのdelayタイミングの最適化ができません。紹介記事
レジスタの設定が良いかどうかも最終的にロジアナで確認します。
中国製ロジアナ千円程度ですが結構使えるので電子工作必携品です。
実行コードとデータ内容とタイミングが目視で確認できます。

ADS122U04のピンを上下に長い丸ピンで制作しておけば、ロジアナやオシロでチェックしやすいです。

●ADS122U04の基本動作
仕様書37ページの表15が基本となります。
rrrは、レジスタ番号ですが、最下位ビットのxは使ってないダミーですが
その分ビットシフトしますので、レジスタ番号がビットシフトします。
レジスタ00=0x00,レジスタ01=0x02,レジスタ02=0x04,レジスタ03=0x06
レジスタ04=0x08となるので注意です。

 モードがたくさんあって混乱するのですが、ここで使っているのをご説明します。
★動作概要
マニュアルモード=AUTOでなく、プログラムからSTART/SYNC命令をいれて、DRDYタイミング信号を開始します。タイミングは指定周波数で発生します。
データを取得する命令は、RDATAです。RDATAの直後にSerial2.read()を3回繰り返して3byteのデータを読み込みます。
・Manualモード:プログラムでSTART/SYNC RDATAを命令してからデータを取得します。

・Contiuousモード:START/SYNC命令を一回いれると以降連続してDRDYタイミングが発生します。ですので、RDATAをいれてデータを3バイトよむ動作を繰り返してデータを取得します。
対のSingleShotモードだと毎回START/SYNC命令をいれてからRDATAするので周期はプログラム次第で決まりますので、サンプリングレートの定義通りにはなりません。

・Normalモード:サンプリングレートのクロックが普通、倍速はULTRAモードです。

・割り込み:M5ATOMのGPIO23ピンにDRDY線が接続して、FALLで割り込み関数へ飛びます。
・割り込み関数:flip()は、毎回CH定義を交代させてます。偶数回ではAIN0p-AIN1nで1CH測定
奇数回では、AIN2p-AIN3nで2CH測定します。
レジスタ設定例(設定しているコードにコメントが入ってます。)
①レジスタ0:CHとピン番号の定義とゲインを定義するレジスタ
割込関数flip()内のCH切り替えで使います。
偶数回:0000でAIN0p-AIN1nを1CHに定義します。
奇数回:0110でAIN2p-AIN3nを2CHに定義すます。
ゲインは128です。
②レジスタ1:DataRate定義とNormalモード、Contiunuousモード、電圧ref定義
レジスタ1は、モードだらけで混乱しやすいのですが、Normal,Continuous,refは、11とします。
③レジスタ2:DRDYとDCNT、INVERT,BCS 、IDAC定義
ここはdefaultとBCS onで0x08とします。
④レジスタ3:切り替え機能IMUXの定義 マニュアルモード指定
defaultで0x00でいいです。
⑤レジスタ4:GPIOの方向と機能選定してDRDY信号の定義します。
GPIO2にDRDY信号出力を定義します。
GPIO2DIRは、OUTPUTになります。
GPIOSELは、DRDYとなります。
0100 1000=0x08となります。

●M5Atom用サンプルプログラム
https://gist.github.com/dj1711572002/d4802b5b6e1aedf3719584c40d725f61
配線図通りに配線すれば、あとはGISTにあるコードをM5Atomにコンパイルすれば動作します。
私がミスったのは、RESETピンを3.3Vにプルアップしてなかった点とRREGのレジスタアドレスを間違っていた点
で数時間トラブりました。
おかしかったら上記ロジアナでデバッグしてみてください。
概要1:2CH用プログラムです。

概要2:レジスタ設定は、600spsです。M5Atomの場合115200bpsでしかUSBシリアルが動作しないので1000SPSだと送信タイミングで遅延してしまうので速度があがりません。
=>USBシリアルでなくESP-NOWで無線送信すれば高速なので、遅延がないので後日改良します。

概要3:原理は、DRDY線をM5Atomのピン23に接続して、ピン割り込みをかけてます。
pinMode(DRDY, INPUT_PULLUP);
attachInterrupt(DRDY, flip,FALLING);//DRDY 下がりエッジで割り込み関数flipへ飛ぶ

概要4:割り込み関数flip()は、偶数回目でCH1奇数回目でCH2を切り替え測定していて、CH間遅延が2msecほど発生してます。2CHの周期は、4msec丁度です。
遅延と周期はプログラム速度で決まりますので、最終的に測定してきまります。

●TeraTermでのログ例
[1Ch電圧,2Ch電圧,1CH時刻msec,2CH時刻msec] を2CHが終了した時点Serial.println出力してます。

#include <M5Atom.h>

//—————-Texsus ADS122U04————————–
int DRDY = 23; //DataRdy Pin 23
double ft1, ft2;
int RREGwait;
int flipN;
uint8_t RR0, RR1, RR2, RR3, RR4;
uint8_t d0, d1, d2, d3, d4, d5, d6;
double data1ch, data2ch;
int DRDYflag = 0;
void setup() {
// シリアル設定
M5.begin();
Serial.begin(115200);
Serial2.begin(115200, SERIAL_8N1, 33, 22); //M5Atom-ADS122 GPIO33:RX ,GPIO22:TX
//ピン割り込み設定
pinMode(DRDY, INPUT_PULLUP);
//attachInterrupt(digitalPinToInterrupt(2),呼び出される関数,FALLING);
attachInterrupt(DRDY, flip,FALLING);//DRDY 下がりエッジで割り込み関数flipへ飛ぶ
//=============ADS122U04レジスタ初期設定==========================================
//ADS122U04 RESET
Serial2.write(0x55);
Serial2.write(0x06);
delayMicroseconds(3000);
//================Register Setting=============================================================================
RREGwait = 600; //RREG wait time usec 2*Tbaud(10usec)

//—–Register00[7:4(MUX)3:1(GAIN)0(PGA_BYPASS)]————————————————————–
Serial2.write(0x55);//Synchronization word 0x55
Serial2.write(0x40);//WriteREGister 0x04 0x00(0000register00 Selected)
Serial2.write(0x0E);//7:0(0000 1110=0x0E)[7:4(0000)MUX AINp=AIN0,AINn=AIN1 3:1(111)GAIN128, 0:0(0)PGA enabled]
delayMicroseconds(1000);
Serial2.write(0x55);//Synchronization word 0x55
Serial2.write(0x20);//Synchronization word 0x55 Read REGister00=0010 0000=0x20
delayMicroseconds(RREGwait);
if (Serial2.available()==1)
{
RR0 = Serial2.read();
delayMicroseconds(RREGwait);
Serial.println();
Serial.print(“Register00=0x0E:”);
Serial.println(RR0,HEX);
delayMicroseconds(RREGwait);
}

//—–Register01[7:5(DataRate)4:(OperationMode)3:(ConversionMode)2:1(VREF)0:(TemperatureSensor mode)]———
Serial2.write(0x55);//Synchronization word 0x55
Serial2.write(0x42);// WriteREGister 0x04 0x02(0010register01 Selected)
Serial2.write(0xAE);//7:0(1010 1110=0xAE)[7:5(101)DataRate600sps,4:(0)Normal Mode, 3:(1)Continuous conversion mode,2:1(11)VDD-VSS VRef,0:(0)Temp disabled]
delayMicroseconds(1000);
Serial2.write(0x55);//Synchronization word 0x55
Serial2.write(0x22);//Synchronization word 0x55 Read REGister01=0010 0010=0x22
delayMicroseconds(RREGwait);
if (Serial2.available()==1)
{
RR1 = Serial2.read();
delayMicroseconds(RREGwait);
Serial.print(“Register01=0xAE:”);
Serial.println(RR1,HEX);
delayMicroseconds(RREGwait);

}

//—–Register02[7:DRDY)6:(DCNT)5:4(CRC)3:(BCS)2:0(IDAC)]—————————————————–
Serial2.write(0x55);//Synchronization word 0x55
Serial2.write(0x44);// WriteREGister 0x04 0x04(0100register02 Selected)
Serial2.write(0x08);//7:0(0000 1000=0x08)[7:(0)DRDY,6:(0)DCNT disable, 5:4(00)) inverte,3:(1)BCS On,2:0(0)IDAC off]
delayMicroseconds(1000);
Serial2.write(0x55);//Synchronization word 0x55
Serial2.write(0x24);//Synchronization word 0x55 Read REGister02=0010 0100=0x24
delayMicroseconds(RREGwait);
if (Serial2.available()==1)
{
RR2 = Serial2.read();
delayMicroseconds(RREGwait);
Serial.print(“Register02=0x08:”);
Serial.println(RR2,HEX);
delayMicroseconds(RREGwait);
}

//—-Register03[7:5(I1MUX)4:2(I2MUX)1(RSERVED)0(AUTO)]—————————————————-
Serial2.write(0x55);//Synchronization word 0x55
Serial2.write(0x46);// WriteREGister 0x04 0x06(0110register03 Selected)
Serial2.write(0x00);//7:0(00000000=0x00)[7:5(000)default,4:2(000)default, 1:(0)Reserved,0:(0)Manual Read
delayMicroseconds(1000);
Serial2.write(0x55);//Synchronization word 0x55
Serial2.write(0x26);//Synchronization word 0x55 Read REGister03=0010 0110=0x26
delayMicroseconds(RREGwait);
if (Serial2.available()==1)
{
RR3 = Serial2.read();
delayMicroseconds(1000);
Serial.print(“Register03=0x00:”);
Serial.println(RR3,HEX);
delayMicroseconds(RREGwait);
}

delayMicroseconds(1000);
//—-Register04[7:(Reserved)6:(GPIO2DIR)5:(GPIO1DIR)4:(GPIO0DIR)3:(GPIO2SEL)2:(GPIO2DAT)1:(GPIO1DAT)0:(GPIODAT0)]—————————————————-
Serial2.write(0x55);//Synchronization word 0x55
Serial2.write(0x48);// WriteREGister 0x04 0x08(1000register04 Selected)
Serial2.write(0x48);//7:0(0100 1000=0x08)[6:(1)GPIO2output,5:(0)GPIO1Input, 4:(0)GPIO0Input,3:(1)GPIO2SEL DRDY,2:(0)GPIO2DAT Low,1:(0)GPIO1DAT Low,0:(0)GPIO0DAT Low
delayMicroseconds(1000);
Serial2.write(0x55);//Synchronization word 0x55
Serial2.write(0x28);//Synchronization word 0x55 Read REGister04=0010 1000=0x28
delayMicroseconds(RREGwait);
if (Serial2.available()==1)
{
RR4 = Serial2.read();
delayMicroseconds(RREGwait);
Serial.print(“Register04=0x48:”);
Serial.println(RR4,HEX);
delayMicroseconds(RREGwait);
}

//Serial.println(“====Start/Sync Go=============”);
//Start/Sync
Serial2.write(0x55);
Serial2.write(0x08);
delayMicroseconds(100);//************************このWAIT重要************************************

}

void loop() {
// put your main code here, to run repeatedly:
delayMicroseconds(500);//5msec Period
}

//==================InterruptIn DRDY====================
void flip() {
flipN++;
if (flipN % 2 == 0)
{
//1CH—–Register00[7:4(MUX)3:1(GAIN)0(PGA_BYPASS)]————————————————————–
Serial2.write(0x55);//Synchronization word 0x55
Serial2.write(0x40);//WriteREGister 0x04 0x00(0000register00 Selected)
Serial2.write(0x0E);//7:0(0000 1110=0x0E)[7:4(0000)MUX AINp=AIN0,AINn=AIN1 3:1(111)GAIN128, 0:0(0)PGA enabled]
delayMicroseconds(50);

Serial2.write(0x55);
Serial2.write(0x10);
delayMicroseconds(10);
d0 = Serial2.read();
delayMicroseconds(10);
d1 = Serial2.read();
delayMicroseconds(10);
d2 = Serial2.read();
delayMicroseconds(10);
data1ch = (d0 + d1 * 256 + d2 * 65536) * 0.000393391;
ft1 = (double)micros() / 1000;
// Serial.print(“%d,%8.3f\n\r”,data1ch,ft);
}
else
{
//2CH—–Register00[7:4(MUX)3:1(GAIN)0(PGA_BYPASS)]————————————————————–
delayMicroseconds(50);
Serial2.write(0x55);//Synchronization word 0x55
Serial2.write(0x40);//WriteREGister 0x04 0x00(0000register00 Selected)
Serial2.write(0x6E);//7:0(0110 1110=0x6E)[7:4(0110)MUX AINp=AIN2,AINn=AIN3 3:1(111)GAIN128, 0:0(0)PGA enabled]
delayMicroseconds(50);

Serial2.write(0x55);
Serial2.write(0x10);
delayMicroseconds(10);
d3 = Serial2.read();
delayMicroseconds(10);
d4 = Serial2.read();
delayMicroseconds(10);
d5 = Serial2.read();
delayMicroseconds(10);
data2ch = (d3 + d4 * 256 + d5 * 65536) * 0.000393391;

//Serial.print(“d0=%x,d1=%x,d2=%x,data=%d\n\r”,d0,d1,d2,data);
ft2 = (double)micros() / 1000;
//Serial.print(“%d:CH2=%d,%8.3f\n\r”,flipN,data2ch,ft);
Serial.print(data1ch);
Serial.print(“,”);
Serial.print(data2ch);
Serial.print(“,”);
Serial.print(ft1);
Serial.print(“,”);
Serial.println(ft2);

//myled = !myled;
//Serial.print(“————-DRDY Falled—————-\n\r”);
}
}

●動作確認
3軸のロードセルユニットのFzとFxを接続して動作確認しました。

この2CH小型アンプユニットをスキーの曲率センサ用に使います。

 

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です