あわせて読みたい


マイコン 目次
2022/10/23 EtherCATはここからジャンプできます。 マイコン記事の目次です。記事をお探しの場合は、この目次ページから目を通してみてください。 【RL78】 RL78の記事…
あわせて読みたい


NXPほか(EtherCATなど)
NXP(mbed)・EtherCATあなどのページです。 【微少電流計2(INA226版)】 微少電流計(RL78版) 改めてINA226で作ってみた。 ちょい仕事の方でバッテリー駆動の製品を…

興味があるところを読む
前振り
※2019/8にアップした記事を加筆・訂正しました。 こちらはINA226+LPC1114での記事です。 微少電流の変化を目で見る必要があるんで、微少電流計と言うか微少電流の変化を表示するものを作ってみた。 こちらを参考にさせて頂いて、CPUをPICからG10(R5F10Y47)に変更し、表示装置をLCDからPC(パソコン)に変更した。 つまりADC(MCP3901)の生値をSPIで取得してUARTでPCに送信し、生値の処理や表示は全部PC側で行う・・・G10はSPI-UARTゲートウエイみたいなもん。 電源は、ADCが5V、CPUもG10は5Vで使えるので、電源は5V一本でOK。 CPUのメインクロックは内蔵OSCを20MHzで使用。 UARTは2,000,000=2Mbps・・・こんな高速度でPCと通信できるのか分からなかったけど、やってみたら普通に通信できた。 SPIはポートをソフトでパタパタして実現した。速度は、6byte取得に56uS=9.3uS/byte → 107,143byte/秒 → 856Kbps。 200μS毎のインターバル割込みでサンプリングしてUARTで送信(5Ksps)。
SPI
このADCは24bitでSPIインターフェースだ。 CH0とCH1の2CH有り、各CHが24bitなので合計で48bit=6byteがSPIで出力される。 ↓LAP-Cで見るとこんな感じ。

読み出すときは_CSをLOWに固定したままで、_DR=0を確認しながら単純に連続で6バイト読み込めばOK。なのでADC初期化終了時に_CS=0にしてしまえば、後は_CSを動かす必要は無い=6byte毎に_CSを上下させる必要は無い(元記事では6byte毎に_CSを動かしてるけど、そうしなくても取得できます)。 PCとの通信にはUARTが必要なのだが、G10はSPIかUARTのどっちかしか使えないんで、SPIはポートを自分でパタパタすることにした。 G13だとSPIとUART両方を同時に使えるんで、G13で動作チェックして、大体OKになってからG10に移植した(G13はちょい大きいし勿体ないんで)。 SPI操作はアセンブラでやることにしました(先にCで書いておいて、動作確認後にアセンブラで書き直した)。 コードはこれで、アセンブラで書き直すとCの約二倍の速度になった。 // Cでの連続6バイト入力(検証済み) uint8_t* SPIRcv6(uint8_t rd[]) { int i, lp; uint8_t BitPos, data; for (lp=0; lp<6; ++lp) { data = 0; BitPos =0x80; // ビット位置リセット for(i=0; i<8; i++){ // 8ビット繰り返し SCK = 0; SCK = 0; SCK = 1; if (SDI) data |= BitPos;// ビット入力 BitPos = BitPos >> 1; // ビットシフト } rd[lp] = data; } SCK = 1; return(rd); // 受信データ*を戻す } ===================================================================== ; 自分用のアセンブラ関数用ファイル 2018/8/9 ;==================================================================== ; PUBLIC宣言はここ(TEXT内で宣言すると引数のアドレスが変になる) .PUBLIC _asmSPIRcv6 ; TEXT .SECTION .text,TEXT ;--------------------------------------------------------------------- ; void _asmSPIRcv6(uint8_t* data) ; AX=data pointer ; 6byte取得に56uS=9.3uS/byte → 107,143byte/秒 ;--------------------------------------------------------------------- _asmSPIRcv6: push hl ; HLは要保存 movw hl,ax ; 引数はAXで届くんで HL ← data ; for(X=0; X<6; ++X) clrb x ; X は6byteカウント用 .lp0: clrb b ; B は8bitカウント用 clrb c ; C はMISOを1byteに纏めたもの(それを[HL]に入れる) mov d,#0x80 ; D は bit7-6-5...0 とシフトしてる .lp1: ; 立ち上がりエッジをCLKに出力 mov a,p0 and a,#0xf7 ; CLK=0 P0.3=0 mov p0,a or a,#0x8 ; CLK=1 P0.3=1 mov p0,a ; MISO(P0.4)を読む mov a,p0 ; A=MISO and a,#0x10 ; check MISO bit bz $.lp2 ; if 0 skip ; MISO=HならCにDのbitをセット mov a,c or a,d ; D goes to 0x80-0x40-0x20...0x0 mov c,a ; set to C .lp2: mov a,d ; shr D shr a,1 mov d,a ; chek 8 bits loop inc b ; ++B mov a,b cmp a,#8 bnz $.lp1 ; set 8 bits to data[] mov a,c mov [hl],a incw hl ; chk 6 loop count inc x ; ++X mov a,x cmp a,#6 bnz $.lp0 ; end pop hl ret
RL78のアセンブラ
RL78アセンブラ言語仕様のリンク RL78ユーザーズ・マニュアル(S1コアの命令セットはP32~) RL78のアセンブラを良く知らないんで適当に書いてるけど、今のところは動いてる。 Cからの引数の受け渡しや戻り値などの決まりは、Cで書いてコンパイル・オプションでアセンブラソースを出してみたり、逆アセンブラでステップ実行すれば直ぐに分かります。 このRL78アセンブラ、雰囲気的にはZ80なんだけど、妙に書きにくい部分が多々ありで、μVisionのように自由自在ではない。 特にインライン・アセンブラがメチャクチャ不便で、殆どインラインでは書けないんで、別ファイルにしてASMソースとしてゼロから書いてる。つまりCで書いた関数内の一部だけを高速化するとかが出来ない・・・多分。 その他「20bitのCPUである」ってことがアセンブラレベルでは非情に使い難い。 20bitだから昔の8086みたいなセグメント・レジスタやら64k範囲内アクセス用のnearやらfarやらミラー領域やら、手間のかかることが大量に出てくる。んま、Cで書いてる際には気にならないから良いか。 それにしても「#0x80」って何?なんなのこの書き方は?「$.lp0」だって凄い変態だよね。 なんで「mov d,80h」や「JPNZ LP0」じゃダメなの?・・・んま文句を垂れたらキリが無いんで(^^; 取り敢えずレジスタだけを使って書いたけど、変数を使おうとすると更に変態になる必要があるんでパス。

PC側のアプリ
PC側はVisual Studio 2019でC#で作った。 単純にUARTから6byte受信して、どちらかのCHの3byteを補正してチャートに書いてるだけ。 通信のチェックとか何もしてない。落としたりズレたりすればチャートを見てれば分かるので、そう言うときは再起動して誤魔化す。

アプリはG10側に「サンプリングを開始せよ」を送信し、G10は200μS毎に6byteをPCに送信する。 アプリ側では受け取った6byteの半分(前半がCH0で後半がCH1)の3byeをInt32に変換してからADCのオフセットを加え、更にdoubleに変換してからてチャートに表示する。 オフセット量はADC入力をショート(電流ゼロ状態だから本当なら3byteのゼロが来るはず)したときの値から読み出した。 また1bitの大きさ(重み)は、適当な抵抗に決まった電圧をかけ、本来流れる電流を計算で出しておき、ADCから来た値と比べて出した。 もっとまともな計算方法があるはずだけど、ざっと合ってるから良しって事で。 <抵抗に3.0Vを通電してCH0を実測した> ショート時、ADCから 740C0 が来た。740C0・・・これをオフセットとして使う 116.6Kの抵抗に3Vをかければ26uA=260uV(CH0のシャント抵抗は10Ω)流れるはず。この時ADCからは 87FC0 が来た。 87FC0 - 740C0 = 13F00 (81664D) で 、1uA辺りの係数は 26uA ÷ 81664 ≒ 0.00032・・・これを1bitの値とする。 for (int i = 0; i < rcvbytes; i += 6) { int idx = (ch == 0) ? 0 : 3; // CH0は受信データの[0]から、CH1は[3]から Int32 temp = (rxbuf[i + idx] << 16) + (rxbuf[i + idx + 1] << 8) + rxbuf[i + idx + 2]; double ad = 0; if (ch == 0) { temp = (temp - 0x740C0); // CH0はPLUS側に多めに出るのでマイナスする if (temp < 0) temp = 0; ad = (double)temp * ((double)(26.0 / 81664.0)); // CH0 0.00032 } else { temp = (temp + 0x4300) & 0xffffff; // CH1はMINUS側に少な目に出るのでプラスする if (temp > 0x7fffff) temp = 0; ad = (double)temp * ((double)(30.430 / 1197446.0)); // CH1 0.000025 } // トリガチェック if (trgpos == 0 && checkBox_Trig.Checked == true) { double trigval = double.Parse(textBox_Trig.Text); if (ad >= trigval) trgpos = dcnt; } // チャート用に保存 df[dcnt++] = ad; total += ad; // for debug _totalH += temp; ++_lpH; }
反省
24bitのADCを使っても素人工作なのでノイズ成分が多い。 ってことなら16bitのADCで構わないわけで、それならここのINA226のシャント抵抗を取り替えて使う方が良さそう。 余計な工作も工夫もいらないし簡単だよね。 写真で見ると6432(2512inch)な薄膜チップ抵抗な感じなんで、これの1Ωと取り替えれば行けそうな予感だけど、サイズの合うのが見付からないかも。 ミスミの検索結果 (温度係数が±15ppm/℃で2500円だ!)。ちなみに巻き線抵抗で構わなければ1500円・・・やっぱ高いわ。
INA226PRCで試してみた

2019/12/7 INA226マニュアル Configレジスタ設定など 簡単な計算式 購入時点では25mΩ1W(MAX 3.2A)の薄膜シャント抵抗(誤差1%)が付いてるんだけど、これを外して手元にあった秋月の1Ω3W(誤差1%)を無理矢理くっつけて実験。本当はこの2500円のが良いんだろうけど高くて買えませんわ。チップ抵抗の型番とサイズ表 INA226の動作電圧範囲は0~36V、シャント抵抗は1Ω、8000~0x7FFFだから1bit辺り2.5μAかな?だとすれば電流の計測レンジはMAX±81.917mAなはず。 菊水の電圧発生器で10Vを出し、手元にあった誤差5%の抵抗を繋いで実測した。「」は計算値。 <10Vでシャント抵抗1Ω> 1M:27~30μA(0.03mA) ← 異常 「10μA」 470K:40~42μA(0.04mA) ← 異常「21.2μA」 100K:117~120μA(0.12mA) ← 怪しい「100μA」 47K:227~230μA(0.23mA) 20K:520~522μA(0.52mA) 10K:1,025~1,027μA(1mA) 2K:5,060~5,062μA(5mA) 1K:10,125~10,127μA(10mA) 470:21,515~21,517μA(21mA) 240:42,925~42,927μA(43mA) ショートすると81,917でOverFlow 抵抗値が大きいと誤差が大きく出るようなので、電圧を1Vにして計測してみた。 <1Vでシャント抵抗1Ω> 100K:10μA 47K:22.5μA 良いみたい。1bitの誤差は仕方ないんで結構正確。 ファームは元々INA260用に作ってあった「LPC1114+mbed」のを改造した。 INA260とINA226はソケットで取り替え可能にし、電源投入時にConfigRegを読み出して、0x6127ならINA260、0x4127ならINA226と判定してる。 I2Cで読み出してUARTでバラバラ連続送信してTeraTermで表示。 <シャント抵抗10Ωで実験> 手元にあった秋月の10Ω3W(誤差1%)をくっつけて実験した。 良い感じで10倍の精度で電流を測れた。 MAXは±8.1mAになるけど、0.25μA/bitで出てる感じで、これで行きますわ。 この後でこのINA226を使いLPC1114で第二弾を製作しました。

コメント