技術コラム
ModbusとELC
それはModbusで、リアルタイムに波形転送を行ないたい、という要求であった。
一般的にModbusのような半二重通信通信は、ビットレートから導かれる通信速度以上に無駄時間が大きく、通信量の多い高速通信には向かない。
100Hz(のちに256Hzも追加された)程度のサンプリングではあるが、3チャンネル32ビットのデータをリアルにパソコンに転送し、グラフ表示を行なうことを想定して、開発がスタートした。
CPUはルネサスのRX21Aが選ばれた。製品コストもあるのであまり高価なものは使えない。ΔΣADC内蔵は魅力的であった。
ビットレートに781,250bpsを選んだ。近年はCPUが高速になったとはいえ、割り込みによるプログラム転送では心配になってくる領域である。
DMAをはじめ、RXのペリフェラルを使い倒してやろうと思った。イベントリンクコントローラ(ELC)が使えるSCIチャンネルを選んだ。
Modbus RTUはちょっと変わったプロトコルを持っている。フレームの区切りを判断するのに、特定のデータコードを待つわけでもなく、バイト数を待つわけでもなく、一定時間データが途切れることで判断しなくてはならない。
DMAを仕掛けておいて、その終了を待つような手法は使えない。
そこで、DMAは仕掛けるのだけど、フレームの終了は一定周期のタイマー割り込みでポーリングすることを思いついた。
DMAは多めのバイト数を仕掛けておいて、DMAの終了は単にバッファーオーバーランとして機能させる。
さて、終了をどうやって検出するか?
フレームの終了を知るためには、フレームが始まったことを知らなくてはならない。
そして、フレームの途中で、ある一定時間データが来なかったら、終了と判断できる。
そのために、受信バイト数をカウントしようと思った。タイマー割り込みのポーリングで、カウントした受信バイト数を監視する。
カウントがゼロではなく、カウントの進みが止まったら、フレームの終了である。
しかし、せっかくDMAを使うのに、受信バイト数はどうやってカウントするのか?受信割り込みで処理したくない[*1]。DMAのカウンタは使い物にならなかった。
そこで、ELCを用いて受信割り込みを横取りし、別のタイマーカウンタでカウントさせた。
Modbusは例えば入力例レジスタを読み出すような概念である。ホストから読み出しに来てくれなければ、端末側から積極的にデータを送ることはできない。1回に読み出せるデータ量にも制限がある。リアルタイムデータを長々と読み出せるほどアドレス空間は広くない。
これらもまたリアルタイム転送を厄介にする。
転送トラフィックの不均衡に耐えるだけのFIFO的なバッファーは必須であるが、レジスタマッピングを適切に設計し、先頭アドレスからしか読み出せないような制約を与え、Modbusを土台としたある種の転送プロトコル的なものを設け、などなど、ようやく目的を果たすシステムが完成した。
[*1]のちのシステムで、ELCが使えないCPUにあたり、受信割り込みでバイト数はカウントするが、データ読み出しはDMAに頼る、という方式も行ったこともある。こちらのシステムは、そこまでパフォーマンスを上げなくても良かったが。