実機での追加検証

Copy Markdown View Source

このページは、最初の通信確認を終えた開発者向けです。配線・書き込みの基本手順は 実機チュートリアル を参照してください。

以下は記録した XIAO ESP32-C5 / HW-519 の検証方法です。別の機器で同じ結果になるとは限りません。

ここから先は、最初の通信確認には不要です。baud rate、障害復旧、memory、長時間運転、resource limit を 再検証するときに使用します。

RS485 baud rate の実機検証

2 台の XIAO ESP32-C5 と 2 台の HW-519 を使い、8N1、unit ID 1、function 0x03、holding register address 0 / quantity 1、5 秒間隔の条件で次の baud rate を確認しています。client console で 少なくとも 3 回連続して modbus: registers [0] を受信することを合格条件としました。

Baud rate結果
9,600成功
19,200成功
38,400成功
115,200成功

baud rate は compile-time configuration のため、server と client をそれぞれ clean build して flash します。 次は 19,200 baud の例です。

mix clean
MODBUS_ROLE=server ATOMVM_UART_SPEED=19200 \
mix atomvm.esp32.flash --port /dev/ttyACM_SERVER

mix clean
ATOMVM_UART_SPEED=19200 \
mix atomvm.esp32.flash --port /dev/ttyACM_CLIENT

mix atomvm.esp32.monitor --port /dev/ttyACM_CLIENT

/dev/ttyACM* の番号は再接続時に変わることがあるため、flash 前に USB serial number で board の role を確認します。この検証は request / response の成立を確認するもので、echo、turnaround、frame gap の 個別計測を完了したものではありません。

RS485 cable の切断と再接続

9,600 baud で client が 5 秒間隔の polling を継続している間に、2 台の HW-519 間の A conductor を 実際に切断しました。client console で modbus: request failed :timeout を確認してから同じ conductor を 再接続し、board、application、managed client のいずれも再起動せず、4 回連続して modbus: registers [0] に復帰することを確認しています。

この試験は RS485 line loss に対する request-level recovery の確認です。UART peripheral 自体は open のまま なので、UART driver が :closed を返した場合の managed reopen / backoff の実機確認とは区別します。

Modbus ASCII

client / server とも MODBUS_MODE=ascii を指定します。一般的な 7E1 設定の例:

MODBUS_MODE=ascii \
ATOMVM_UART_DATA_BITS=7 \
ATOMVM_UART_PARITY=even \
mix atomvm.packbeam

Modbus TCP

TCP server を起動する場合は MODBUS_MODE=tcp MODBUS_ROLE=server を指定します。実際に LAN から接続するには application 側で AtomVM network interface も設定してください。

MODBUS_ROLE=server MODBUS_MODE=tcp MODBUS_TCP_PORT=502 mix atomvm.packbeam

TCP client では MODBUS_TCP_HOST と MODBUS_TCP_PORT も指定します。

Artifact size の上限

production artifact を build して size regression budget を確認します。

MIX_ENV=prod mix atomvm.size

baseline と budget の更新方針は リソース計測 を参照してください。

設定

環境変数既定値説明
MODBUS_ROLEclientclient / server
MODBUS_MODErturtu / ascii / tcp
MODBUS_TCP_HOST127.0.0.1TCP server host
MODBUS_TCP_PORT502TCP listen / destination port
MODBUS_UNIT_ID1unit id
MODBUS_START_ADDRESS0client が読む Holding Register の開始 address
MODBUS_QUANTITY1client が読む register 数
MODBUS_RESPONSE_TIMEOUT_MS1000client startup の default response timeout
MODBUS_REQUEST_INTERVAL_MS5000polling interval
MODBUS_HEALTH_INTERVAL_MS0device health snapshot の間隔。0 以下で無効
MODBUS_MEASURE_MEMORYfalsestartup 前後の ESP32 heap と client / server process memory を出力するか
MODBUS_RESOURCE_PROBEfalseTCP loopback の bounded resource recovery probe を起動するか
MODBUS_RESOURCE_PROBE_CYCLES3resource probe の反復回数
MODBUS_RESOURCE_PROBE_CONNECTIONS4cycle ごとの loopback client / server connection 数。安全確認済み範囲は 1..4
MODBUS_WORKFLOW_PROBEfalsereal RS485 representative workflow probe を起動するか
MODBUS_WORKFLOW_PROBE_CYCLES3workflow probe の反復回数
MODBUS_WORKFLOW_GAP_MS20workflow probe の送信前 gap。0 は baud rate から算出
ATOMVM_UART_PERIPHERALUART1UART peripheral
ATOMVM_UART_SPEED9600baud rate
ATOMVM_UART_TX_PIN23TX GPIO (XIAO ESP32-C5 D4)
ATOMVM_UART_RX_PIN24RX GPIO (XIAO ESP32-C5 D5)
ATOMVM_UART_DATA_BITS8data bits
ATOMVM_UART_PARITYnonenone / even / odd
ATOMVM_UART_STOP_BITS1stop bits
ATOMVM_UART_RX_IDLE_TIMEOUT_MS20AtomVM UART の隣接 chunk をまとめる idle timeout
MODBUS_ECHOfalseadapter echo を除去するか
MODBUS_RTU_GAP_MS0通常 RTU client / server の送信前 gap。0 は baud rate から算出
MODBUS_SILENCE_MS20unknown-length frame の silent interval
MODBUS_BROADCAST_TURNAROUND_MS100broadcast write 後の待ち時間
MODBUS_HANDLER_TIMEOUT_MS10000server handler timeout
MODBUS_RECONNECT_MIN_MS100UART reopen の最初の delay
MODBUS_RECONNECT_MAX_MS5000UART reopen delay の上限

これらは compile-time configuration として使われるため、設定を変えた場合は必要に応じて mix clean してから build してください。

Memory 使用量の測定

AtomVM / ESP32 上で role startup 前後の heap と process memory を計測します。

MODBUS_MEASURE_MEMORY=true MIX_ENV=prod mix atomvm.packbeam
MODBUS_MEASURE_MEMORY=true MIX_ENV=prod mix atomvm.esp32.flash --port /dev/ttyACM0
mix atomvm.esp32.monitor --port /dev/ttyACM0

server を計測する場合は clean 後、build と flash の両方で MODBUS_ROLE=server も指定します。出力される modbus_memory line は free heap delta、largest / minimum free heap、binary memory、process count、 各 managed process の推定 byte 数を含みます。

実機 soak test の状態出力

長時間の実機検証では MODBUS_HEALTH_INTERVAL_MS を正の値にして build / flash します。 client / server の connection state、uptime、ESP32 free heap、minimum free heap、binary memory、 process count、managed process ごとの memory と mailbox length を modbus_health line として定期出力します。

MIX_ENV=prod mix clean

MODBUS_ROLE=server \
MODBUS_HEALTH_INTERVAL_MS=60000 \
MIX_ENV=prod \
mix atomvm.packbeam

MODBUS_ROLE=server \
MODBUS_HEALTH_INTERVAL_MS=60000 \
MIX_ENV=prod \
mix atomvm.esp32.flash --port /dev/ttyACM0

mix atomvm.esp32.monitor --port /dev/ttyACM0

この telemetry は観測機能であり、それ自体を external Modbus peer との interoperability 成功とは扱いません。 実 RS485 traffic を使った計測条件と結果は Memory 使用量の実 RS485 基準値 に 記録しています。

実機の resource recovery probe

TCP server の connection cap、client の pending / wait queue、slow handler process を同時に動かし、 :queue_full、正常 response、socket / process cleanup、free-heap recovery を loopback 上で反復確認できます。 通常 application には含めない compile-time diagnostic mode です。

MIX_ENV=prod mix clean

MODBUS_RESOURCE_PROBE=true \
MIX_ENV=prod \
mix atomvm.packbeam

MODBUS_RESOURCE_PROBE=true \
MIX_ENV=prod \
mix atomvm.esp32.flash --port /dev/ttyACM0

mix atomvm.esp32.monitor --port /dev/ttyACM0

最初の warm-up で AtomVM / ESP-IDF network stack の one-time allocation を完了してから、各 measured cycle は before / connected idle / active snapshot / after cleanup の process count、free heap、largest free block を出力します。 loopback Client と Server connection の両方を含む deployed probe 全体の値であり、Server connection 単体の heap cost ではありません。active snapshot は request 投入直後の一点計測で、連続観測した最大値ではありません。 MODBUS_RESOURCE_PROBE_CONNECTIONS=1..4 を同じ firmware / configuration で比較し、確認済み範囲内の増分を評価できます。 全 request result、5 秒以内の process cleanup、steady-state baseline から 32 KiB 以内の free-heap recovery が成功した場合だけ最終的に modbus_resource_probe result=ok を出力します。

retained probe はこの board / firmware で回復を確認した 1..4 connections だけを受け付けます。 0 以下は invalid configuration、5 以上は unsafe_connection_count として socket を開く前に停止します。 hard-limit 調査では production example の guard を緩めず、symbol 付き runtime と一時 diagnostic build を使用してください。

AtomVM 0.7.0-beta.0+git.8d3e051 では複数の loopback socket をまとめて閉じた際、ESP32 socket driver が event_queue への enqueue failure を出力する場合があります。これは bounded FreeRTOS queue の platform warning です。probe の最終結果が ok で、各 cycle の process count と free heap が回復していれば、 AVModbus の resource leak を示すものではありません。hard-limit 付近の挙動とは区別してください。

実 RS485 workflow probe

通常の RTU または ASCII server image を一方の board に flash した後、もう一方に同じ mode の compile-time workflow probe を flash すると、実 RS485 bus 上で registers、coils、mask write、 read/write multiple、file record、FIFO、diagnostics、device identification、broadcast と exception response を連続確認できます。

# Server board
MIX_ENV=prod mix clean
MODBUS_ROLE=server MIX_ENV=prod mix atomvm.packbeam
MODBUS_ROLE=server MIX_ENV=prod \
  mix atomvm.esp32.flash --port /dev/ttyACM_SERVER

# Client/probe board
MIX_ENV=prod mix clean
MODBUS_WORKFLOW_PROBE=true MIX_ENV=prod mix atomvm.packbeam
MODBUS_WORKFLOW_PROBE=true MIX_ENV=prod \
  mix atomvm.esp32.flash --port /dev/ttyACM_CLIENT
mix atomvm.esp32.monitor --port /dev/ttyACM_CLIENT

Modbus ASCII 7E1 では、Server と Client/probe の build / flash command すべてに次の環境変数を追加します。

MODBUS_MODE=ascii ATOMVM_UART_DATA_BITS=7 ATOMVM_UART_PARITY=even

XIAO ESP32-C5 と HW-519 の組み合わせでは、RTU 8N1 に加えて ASCII 7E1 でもこの workflow を実機確認済みです。

probe は最初に write-single response が request と同一 frame になる性質を使い、echo: true で local adapter echo の有無を分類します。その後は echo: false で 20-step workflow を 3 cycle 実行します。transport wrapper が response read と次の UART write の時刻を記録し、configured serial gap 以上であることを確認します。broadcast write の所要時間も configured turnaround 以上で、その直後の read が更新値を返す場合だけ成功です。最後の modbus_workflow result=ok line に request 数と timing summary を出力します。

ASCII 7E1、9,600 baud、20 ms gap では 3 cycle / 60 request を 2 回連続で完走し、最小の response-to-next-write は 36 ms、100 ms broadcast turnaround の実測値は 130 ms でした。

この計測は AtomVM UART API 境界の millisecond timestamp であり、RS485 waveform の oscilloscope / logic analyzer 計測を置き換えるものではありません。MODBUS_RESOURCE_PROBE と同時には有効にしないでください。 MODBUS_WORKFLOW_GAP_MS=0 で protocol から算出した gap を使い、正の値で hardware margin を比較できます。

検証した XIAO ESP32-C5 / HW-519 pair の 9,600 baud run では local echo はありませんでした。protocol から 算出した 5 ms では第 2 cycle、10 ms では第 3 cycle に request timeout が再現し、20 ms では 3 cycle / 60 request がすべて成功しました。20 ms run の UART API 境界で観測した最小 response-to-next-write interval は 37 ms、100 ms に設定した broadcast turnaround の request elapsed は 130 ms でした。このため workflow probe の既定値は、この hardware profile で安定した 20 ms としています。

同じ margin を通常 application に適用する場合は、client / server image の build と flash の両方で MODBUS_RTU_GAP_MS=20 を指定します。この値は RTU request / response の送信前 delay の下限となり、 unknown-length frame を確定する MODBUS_SILENCE_MS には影響しません。個別の injected transport 利用時は 従来どおり managed client / server の gap: option で上書きできます。

ATOMVM_UART_RX_IDLE_TIMEOUT_MS は、AtomVM UART の read 呼び出し間で byte を失わないために隣接 chunk を drain する UART 固有の時間です。既定 20 ms はこの ESP32-C5 / AtomVM 0.7 構成で検証済みです。 Modbus の gap / silence とは別の設定であり、短縮する場合は長い request と fragmented response を含む workflow probe を再実行してください。

2026-10-13 に RTU 8N1、20 ms transmit gap、3 cycle / 60 request で比較した結果です。所要時間は Client API の end-to-end 値であり、RX idle timeout だけの microbenchmark ではありません。

Baud rateRX idle結果Request min / avg / max
9,60020 ms60 / 60 成功136 / 179 / 233 ms
9,60010 ms5 request 目で timeout途中終了
115,20020 ms60 / 60 成功134 / 144 / 164 ms

10 ms では長い write_multiple_registers request への response が得られませんでした。このため、現在は 低遅延化より frame の完全性を優先して 20 ms を既定値とします。workflow の最終行は speed、 rx_idle_timeout_ms、request の min / average / max を出力するため、別の board / UART driver でも同じ 判定基準で比較できます。console の記録には tio --baudrate 115200 /dev/ttyACM_CLIENT も使用できます。

Firmware download のトラブルシューティング

OTP 28 で firmware download 時に :ssl.versions/0 の load error が出る場合は、SSL application を起動した mix run 経由で image を download できます。

mix run -e 'Mix.Tasks.Atomvm.Esp32.Install.run(["--version", "v0.7.0-beta.0", "--download-only", "--chip", "esp32c5"])'
mix atomvm.esp32.install --image firmware_images/AtomVM-esp32c5-elixir-v0.7.0-beta.0.img