前回WatchDogタイマを使ってみたのは、M5ATOMLite用の「環境測定&MQTT報告」スクリプトを長時間走らせているとハングする現象の対策のためでした。しかしWatchDogで復旧を試みるまえに原因に当たりをつけておきたいです。そこで「ダイイングメッセージ」が残るようにスクリプトを改変。
※「MicroPython的午睡」投稿順 Indexはこちら
M5ATOMLite用のスクリプトは、現状の設定で毎分ステータスや継続稼働時間(分)に相当する情報をMQTT経由でNode-REDダッシュボードへ送っています。「ハング」したことはブラウザでダッシュボード見ていれば、気づくことは気づきます。また逆に、Node-REDダッシュボードからATOMLiteにLEDの点灯指示を与えれば、毎秒LEDが点滅を繰り返すのですが、「ハング」するとこれが止まるので現物見ていても分かります。
WatchDogタイマでRESETをかけた場合、WatchDog発動時点でのスタックダンプはとれるようなのですが、MicroPythonをビルドしたときのリスティングかMAPファイルが無いと解析難しそうです。うーむ、ありもののバイナリを書き込んでいるのでスタックダンプもらっても困りそう。
とりあえず「特定の場所」でハングするのか否か、見れば分かるLOGを残せばいいんじゃね、と考えました。これまたMQTT経由で報告してもいいのですが、通信に問題起きていることもあり得るので、確実なローカル表示といたしました。
そこで「簡単に」LCDを取り付けるつもりでトラブりました。その顛末は以下記事に。
トホホな疑問(45) I2CでAQM1602通信失敗、Pull-up抵抗強すぎた。
今回、上記のトラブルを踏まえて、AQM1602用表示クラスをスクリプトに追加し、「ダイイングメッセージ」が残るようにスクリプトを改造してみました。
しかしその前にまたしても痛恨の失敗。
デバイス側のスクリプト、バックアップしとけよ、自分
今回一番時間がかかったのは、M5ATOMLite側のファイルシステムの /lib 配下にあるセンサや通信など制御用のモジュールの復旧でした。ぶっちゃけ、WatchDogタイマとか弄っていたときの余波で、M5ATOMLiteへMicroPythonインタプリタの再インストールをせざるを得ない状態になってました。
MicroPython再インストールするとローカルファイルシステムも失われます
つまり、計測用のスクリプト内で呼び出していた左の /lib 配下のモジュール群が失われてしまったのでございます。
しかし、PC側にも同じファイルがとってあるでしょ、と思いきや、愕然。
PC側にとってあった同名のファイルはちょっと古いものが混じってました。胸に手を当てて考えるに、ちょっとしたBUGフィックスのときにデバイス側のファイルシステム上で直接修正作業し、動作確認して、OKとしていたみたい。OKってなったところでPC側にも修正済コピーを置けばよかったのに、デバイス側で動作したことに喜んでそこを忘れていたと、多分。馬鹿だな自分。
ホスト機側でビルド作業をせざるを得ないC/C++等での開発であれば常にホスト側に最新ソースがある筈ですが、MicroPython、先っぽのデバイスの上でもちょろっと修正できちゃうんだ。便利といえば便利だけれども。
パソコン側でのソースの管理は、Gitにお任せすればOKな気がしますが、パソコンとデバイスの両方にまたがるとチト厄介です。何か良いツールでもないものかね。。。
気を取り直して復旧いたしましたです。
LCD表示用モジュールの追加
「トホホな問題」を踏まえて、今回はM5ATOMLiteのグローブコネクタに出力されている端子を使ってAQM1602LCDディスプレイを接続したので、表示そのものは直ぐに動きました。
なお、M5系のデバイスのグローブコネクタは電源5V(なのに信号線は3.3V)であることが多いので、グローブコネクタの電源を使うのは心配です(大き目のプルアップ抵抗で引っ張りあげてるだけ、であれば実力的には壊れもせず動いてるみたいです。でもスペック割れてるみたいで気持ち悪い。)よってLCDの電源端子には、別口で出ている3.3Vを与えています。
今回追加の LiteAQM1602.py モジュールが以下に。もともとラズパイPico用だったスクリプトをM5ATOMLiteモジュール化したもの。
import time from machine import Pin, I2C class LiteAQM1602: """AQM1602XA on I2C bus """ adr = 0x3E datA = 0x40 comA = 0x00 def __init__(self): self.i2c = I2C(0, scl=Pin(32), sda=Pin(26), freq=100000) self.adrAQM1602 = 0x3E self.datAQM1602 = 0x40 self.comAQM1602 = 0x00 def writeDatAQM1602(self, dat): self.i2c.writeto_mem(self.adrAQM1602, self.datAQM1602, bytes([dat & 0xFF]), addrsize=8) time.sleep_ms(1) def writeComAQM1602(self, com): self.i2c.writeto_mem(self.adrAQM1602, self.comAQM1602, bytes([com & 0xFF]), addrsize=8) time.sleep_ms(1) def initAQM1602(self): time.sleep_ms(100) self.writeComAQM1602(0x38) time.sleep_ms(20) self.writeComAQM1602(0x39) time.sleep_ms(20) self.writeComAQM1602(0x14) time.sleep_ms(20) self.writeComAQM1602(0x73) time.sleep_ms(20) self.writeComAQM1602(0x56) time.sleep_ms(20) self.writeComAQM1602(0x6C) time.sleep_ms(20) self.writeComAQM1602(0x38) time.sleep_ms(20) self.writeComAQM1602(0x01) time.sleep_ms(20) self.writeComAQM1602(0x0C) time.sleep_ms(20) def writeLineAQM1602(self, nL, lin): buf = bytearray(lin) if len(buf) <= 0: return False if len(buf) > 16: buf = buf[0, 16] if nL == 0: self.writeComAQM1602(0x80) else: self.writeComAQM1602(0xC0) for idx in range(0, len(buf)): self.writeDatAQM1602(buf[idx]) def main(): lcd = LiteAQM1602() lcd.initAQM1602() lcd.writeLineAQM1602(0, "Hello, World!") lcd.writeLineAQM1602(1, "1234567890ABCDEF") if __name__ == "__main__": main()
上記モジュールを使って、計測&MQTT報告スクリプトの各部に「いまxxしてます」メッセージをちりばめてみました。動作している様子が冒頭のアイキャッチ画像に。
しばらくしてハングすれば、どの辺で止まっているのか分かる筈。いつも同じところでハングするのであれば、疑い部分は絞り込めるとのトラタヌ。しかし毎回違うところだとどうだろ~。それどころか、見張っていると全然ハングしなかったりして。今のところ6時間ばかりまったく問題なく動いとります。元気。そんなもんかい。