通信のフロー制御と受信処理設計
シリアル通信で受信データを取りこぼす障害は、多くの場合、フロー制御や受信処理設計の不足が原因です。対策の柱は4つあります。
- RTS/CTSによるハードウェアフロー制御
- XON/XOFFによるソフトウェアフロー制御
- 上位プロトコルによる送信制御(ウィンドウ制御など)
- マイコン側のリングバッファやDMA受信
これらを組み合わせれば、装置間の処理速度差や一時的な負荷集中があっても、受信パスでの取りこぼしリスクを下げられます。
この記事では次の4つの観点で、設計における勘所を整理します。取り上げるのは、フロー制御自体の必要性と、RTS/CTSによるハードウェアフロー制御です。さらに、XON/XOFFやウィンドウ制御といったソフトウェアフロー制御、リングバッファとDMA受信による実装を扱います。
シリアル通信におけるフロー制御の必要性
シリアル通信では送信側と受信側の処理タイミングが一致するとは限らないため、一時的に受信処理が追いつかず、受信バッファがあふれる場合があります。フロー制御は「送信停止/送信許可」の意思疎通をおこなう仕組みです。未設計の場合、データ欠落や通信異常が再現性の低い問題として残ります。
バッファオーバーランで起きる症状
UART受信データを読み出す前に次のデータが到着すると、多くのUARTではオーバーラン(Overrun Error)を示すフラグが立ちます。フラグの名称には例としてORE、OERなどがあります。名称も置かれるレジスタもデバイスの系列により異なるため、リファレンスマニュアルで確認してください。
このオーバーランが発生すると、受信データの一部が失われます。アプリケーション層から見ればコマンドが届かない、応答が途切れる、受信文字列の一部が抜けるといった症状となります。低速通信では顕在化しにくく、高速通信時や受信処理に遅延が生じた場合にのみ発生するという特性が、原因解析を難しくします。
各フロー制御の役割分担
フロー制御には、RTS/CTSによるハードウェアフロー制御と、XON/XOFFによるソフトウェアフロー制御があります。このほかTCPなどの通信プロトコルでは、受信ウィンドウを用いたフロー制御もおこなわれます。ハードウェアフロー制御はRTS/CTSなどの制御信号線を必要とします。ソフトウェアフロー制御は、通信データ内に制御文字を組み込みます。通信プロトコルによるフロー制御では、ウィンドウサイズに代表される制御情報を参照します。
これらを適切に使い分けると、受信側の処理能力を超えるデータの到着を抑制できます。その結果、バッファオーバーランの発生リスクを低減しつつ、通信効率の低下も防止できます。
ハードウェアフロー制御(RTS/CTS)
RTSはRequest to Send、CTSはClear to Sendの略です。この2本の信号を使う方式が、UARTベースのシリアル通信で広く使われるハードウェアフロー制御にあたります。RS-232通信などが代表例です。データ線とは別に専用の制御信号線を用意して送受信を制御し、受信側の処理能力に応じてデータ転送を調整します。
RTS/CTSの基本動作とアサート方向
RS-232の標準定義では、RTSはDTEからDCEへの送信要求、CTSはDCEからDTEへの送信許可です。DTE(Data Terminal Equipment)はデータ端末装置、DCE(Data Circuit-terminating Equipment)はデータ回線終端装置を指します。
一方、実務のUARTハードウェアフロー制御では、受信側がRTS端子をアサートして「データ受信可能状態」を通知します。RTS端子を受信準備通知として扱うのは実装上の慣行であるため、装置仕様書でRTS端子の意味と極性を必ず確認してください。送信側はCTS入力の状態を確認し、送信許可状態であればデータを送信します。受信バッファの使用量が、設定したしきい値に近づくと、受信側はRTSを無効レベル(アクティブLow構成ではHigh)に戻して送信停止を通知します。送信側はこれを受けて送信を一時停止します。
なお有効レベルと無効レベルがどの電圧に対応するかは、UARTペリフェラルの極性設定(対応している場合)と、物理層トランシーバの論理反転仕様に依存します。信号線は、一方のRTSが他方のCTSにクロス接続される構成が一般的です。
RS-232とTIA/EIA-232-E(対称型)の解釈差と配線ミスの典型
オリジナルRS-232のRTS/CTSは非対称型で、DTEからDCE方向のみのハンドシェイクでした。1991年のTIA/EIA-232-E改訂ではRTR(後述)の考え方が追加され、受信準備通知を利用した対称型フロー制御に対応しました。ここでいう対称型とは、送信側と受信側の双方が同じ手順で相手に受信可否を伝える形を指します。
同改訂ではRTR(Ready to Receive:受信準備完了)が導入されました。RTRはITU-T V.24の回路133に相当します。実装によっては、既存のRTS信号線(端子)を受信準備通知として利用する方式も採用されています。
古い装置と新しい装置を組み合わせて使用する場合、RTS信号を送信要求として扱う側と、受信可能通知として扱う側で解釈が異なるおそれがあります。その結果、通信停止や送信制御の不一致を招きます。装置仕様書での意味確認とアサート極性の合わせ込みが必須です。
マイコンUARTでのRTS/CTS実装
多くのマイコンのUARTペリフェラルには、RTS/CTSによるハードウェアフロー制御をおこなう機能があります。有効化に使うレジスタとビットの名称はデバイスにより異なるため、リファレンスマニュアルを参照してください。RTS/CTS信号をペリフェラル側で制御できるため、CPUによるGPIO制御や割り込み処理が削減され、CPU負荷の低減につながります。
マイコンのなかには、ペリフェラルにRTS/CTS機能がないものもあります。その場合はGPIOと割り込みを利用し、ソフトウェアでRTS/CTSと同等の動作を実装します。
ソフトウェアフロー制御と上位プロトコル設計
ハードウェアフロー制御を使えない3線結線環境や、上位プロトコルレイヤで流量を制御したい場合は、ソフトウェアフロー制御を採用します。制御方式によっては通信データや制御情報を利用するため、応答遅延や通信オーバーヘッドが生じる点に注意が必要です。
XON/XOFFの動作と適用範囲
受信側はバッファ高水位のしきい値(実装例として75%)に達すると、XOFF(Transmission Off:送信停止)を送信します。XOFFはDC3、0x13にあたり、送信側へ送信停止を要求します。バッファ低水位のしきい値(実装例として25%)まで下がると、XON(Transmission On:送信再開)を送信します。XONはDC1、0x11にあたり、送信再開を促します。
バイナリデータの送受信では、XON/XOFFと同じバイト値がデータ中に出現する可能性があります。この場合は透過モードやエスケープ処理(バイトスタッフィングなど)を採用するか、ハードウェアフロー制御へ切り換えます。
ウィンドウサイズとACK/NACKによる通信制御
RS-485上で動作する独自プロトコルの一部では、上位レイヤでウィンドウ制御を実装する例があります。「送信側が未ACKの送信済みフレーム数を最大N個に制限する」といった形です。なお、Modbus TCPのようにTCP上で動作するプロトコルは、TCP自身が持つウィンドウ制御機構に依存します。そのため上位レイヤで別途実装する必要はありません。
また、通信エラーへの対策としてARQ(Automatic Repeat Request:自動再送要求)方式を採用するプロトコルもあります。受信側が異常を検知した際にNACKを返し、送信側へ再送を要求する仕組みです。このARQ方式により、ノイズ環境下でも信頼性の高い通信を実現します。
取りこぼさない受信処理の実装
受信パスの実装では、ペリフェラルから受け取ったデータを効率よく蓄積し、メインタスクから安全に処理する仕組みが重要です。リングバッファとDMA受信を組み合わせるのが現代の定番です。
リングバッファとDMA受信の併用
受信割り込みハンドラでは、UARTのデータレジスタからリングバッファに1 バイト書き込むだけにとどめ、解析処理はメインタスクへ委譲します。
ISR(Interrupt Service Routine:割り込みハンドラ)内でおこなってもよい処理と、避けるべき処理があります。その設計指針は同カテゴリ「組み込みOSと並行処理」の「割り込み処理とデバッグの基礎」で扱っています。実装時にはあわせて参照してください。
DMA受信を使えば、CPUによる転送処理を介さずに、UART受信データをDMA受信バッファなどのメモリ領域へ格納できます。その後、リングバッファへ受信データを取り込む方法や、DMA受信バッファを直接参照してメインタスクで順次処理する方法が一般的です。
可変長フレームには、循環(サーキュラ)DMAモードとアイドル割り込みの併用が有効です。ただしアイドル割り込みだけに頼ると、転送と読み出しの競合で取りこぼす場合があります。DMAの半転送割り込みと転送完了割り込みも併用し、読み出し位置を管理してください。
DMA受信バッファのサイズは、一例として想定フレーム長の2倍以上を確保すると、上位タスクの取り出し遅延に対する余裕が生まれやすくなります。ただし実際には、最悪ケースの取り出し遅延とビットレートから必要量を見積もってください。
タイムアウト・再送との連携
受信側でフレーム境界やフレーム途中の通信異常を判定するには、タイムアウト判定が必要です。Modbus RTUでは、1.5文字時間を超える無通信がフレーム途中に入った場合、受信側は不完全フレームとして破棄します。また3.5文字時間以上の無通信区間は、フレーム境界(次フレーム開始の区切り)として扱います。
フロー制御においては次の4つの観点を意識することが重要です。
- フロー制御自体の必要性
- RTS/CTSのハードウェアフロー制御
- XON/XOFFやウィンドウ制御といったソフトウェアフロー制御
- リングバッファとDMA受信による実装
4つの観点を設計段階から織り込めば、受信パスでの取りこぼしを構造的に防げます。
なお、タイムアウト後の再送要求や指数バックオフの設計は別記事で扱っています。同カテゴリ「プログラミング言語と設計技法」の「通信におけるI/Oの堅牢化とタイムアウト設計」です。この記事と組み合わせて読むと、受信パスから再送までの一連の処理が見通せるでしょう。


