2020-09-22
血圧計の解析(3)
続き。
手頃なので、家にあったM5StickCを繋いでみようと思った。
こいつは必要な機能は一通りあるし、 画面がついているからデバッグにも向いてるだろう。 CPUが240Mhzもあるから十分のはずだ。
WDTと戦わなかった。
昔、ESP8266で開発した経験だと、 このような作業をESPで行うと、 WDTがプログラムの暴走と判定し、 システムが再起動する。
調べた所、 esp_task_wdt_init関数でWDTの挙動を設定すると回避できるらしい。
で、試してみたんだけど、2分ぐらいのビジーループをまわしても、 WDTに怒られなかった。 M5StickCでは何か違うのか? Wifiに接続してないからか? SDKのバージョンが違うのか? とりあえずラッキー、という事にした。
M5StickCに接続
とりあえず、groveコネクタに付けようかとも思ったけど、 仮接続でいいだろう、という事で、 M5StickCの後ろ(どっち)のG26とG36というピンに、i2cのclockとdataの線をつなぎ、あとGNDを繋いだ。
前回までの調査で、通信レベルは3.3Vである事がわかってるので、 直結してもいいはずだ。
テストプログラム
やりたい事は、i2c通信を行う事ではなくて、 他のデバイスが行ってるi2c通信の内容を横から見る事なので、 既存のi2cハードウエアや、i2cライブラリを使う事はできない。
手で生のビット列を見て、デコードする必要がある。 前回までのPCとsigrokを使った計測の場合、 sigrokのpythonスクリプトが行っていた処理を、 マイコンでやるわけだ。
そこで、とりあえず↓のようなコードを書いてみた。
unsigned long start = millis();
unsigned long end = start + 100;
// wait start bit
while(true) {
if (digitalRead(scl) == LOW) continue;
if (digitalRead(sda) == LOW) continue;
while(digitalRead(sda) == HIGH); // wait sda down
if (digitalRead(scl) == LOW) continue;
break;
}
int k = 0;
int clk = 10000;
while(true) {
if (k == BUFSIZE) break;
// if (millis() > end) break;
//while(digitalRead(scl) == HIGH && millis() <= end); // wait scl down
//while(digitalRead(scl) == LOW && millis() <= end); // wait scl up
while(digitalRead(scl) == HIGH && clk-- > 0); // wait scl down
while(digitalRead(scl) == LOW); // wait scl up
buf[k] = digitalRead(sda);
k++;
clk=10000;
}
前半では、i2cのスタートマークがでるまで待ち、 後半では、クロックの立ち上がりエッジがくる度に、データ線の状態をバッファに書いている。
どうもこの血圧計は電源を入れた時に壊れたパケットを送るようなので、 タイムアウト処理も入れた。
ここで、問題が発生した。 たまにデータのとりこぼしが発生する。
まず、millis関数が思ったより時間がかかるようだった。 AVR版だと、レジスタ読み込みに落ちる操作だけど、 ESP版だともっと複雑な事をやってるようだ。
そこで、ループ回数ベースの物を導入したが、 それでも、30%ぐらいの確率でどこかをとりこぼす。
さて、どうしたものか。
AVR版やARM(STM)版のdigitalReadは、最適化すれば数百倍早くなるが、 調べた所、 ESP版のdigitalReadは最適化しても3倍ぐらいしか早くならないらしい。
配線を改良して、2つのdigitalReadを1つのアクセスで済むようにしたら更に倍速になるかもしれない。
しかし、そもそも、AVRの10倍以上早いチップを使っているのに、 とりこぼしが発生するのは、他の原因があるのかもしれない。 例えば、ESP32のFreeRTOSが何かをやってるのかもしれない。
最悪の場合、本体の通信には介入しないという方針をあきらめて、 すきをみてフラッシュメモリを直に読むという方法もある。 その場合は、計測が終わった頃合いをみて、ESP側につけたボタンをユーザー(俺)が押すと、 ESPがフラッシュを読み込んで、Wifiで送信するというシステムになると思う。 この場合、うっかり本体が読み書きしてるのとバッティングすると困った事になるが、 i2cだからハードウエア的には燃えたりはしないと思う。 ソフトウエア的に文鎮化したりするかもしれないから避けたいけど。