Chapter 05
UART とシリアルコンソール — 機器が漏らす一番のヒント
この章のゴール.
UART の物理(ボーレート・フレーム)を理解し、未知のシリアル線を見つけて速度を割り出し、 ログ・コマンドコンソールを観測・自動化してテストのオラクルとフックにできるようになること。
この章で使う既出の用語(定義は各リンク先). USB(01 章 2 節)、オラクル(01 章 8 節)、不変条件(01 章 3 節)、刺激(02 章 1 節)、状態遷移(02 章 1 節)、電源(02 章 2 節)、オシロ(04 章 8 節)、トリガ(04 章 3 節)、ロジックアナライザ(04 章 1 節)
1. UART は最初に探すべき窓
UART(Universal Asynchronous Receiver/Transmitter、調歩同期式シリアル)は、2 本(TX/RX)+ GND で 1 バイトずつ送る最も基本的な通信である。 多くの組み込み機器は、開発時のデバッグのために UART にブートログ・状態表示・コマンドコンソールを出している。製品版でも残っていることが多く、中身を知る最短の窓になる。
- ブートローダ・OS(Linux なら U-Boot、カーネルログ、シェル)
- ファームの
printfデバッグ出力、状態遷移、エラー - AT コマンド(無線モジュール)、独自コマンドコンソール
2. UART のフレーム構造
1 バイトは、アイドル(High)から スタートビット(Low)→ データ 8 ビット(LSB 先)→ (パリティ)→ ストップビット(High) で送られる。
- ボーレート(baud rate): 1 秒あたりのビット数。9600、115200 が定番。送受で一致していないと文字化け
- 設定は「8N1」(8 ビット・パリティなし・ストップ 1)が最多
- 非同期なのでクロック線がない。だから受信側はボーレートを知っている必要がある
3. 未知のシリアル線を見つける
基板に「これが UART」と書いていない。探す手順:
- 候補ピンを探す: 4 つ並んだテストポイント(GND/VCC/TX/RX が典型)、シルクの
TX/RX/DBG、未実装のピンヘッダ - GND を特定: テスターの導通で、金属シェルや大きなベタと導通するピン
- TX を特定: 起動時に周期的に動くピンをロジックアナライザ/オシロで探す。TX はアイドル High で、データ送出時に忙しく動く。VCC(常時 High)や GND(常時 Low)と区別
- ボーレートを割り出す: TX の最短パルス幅を測る。それが 1 ビットの時間。ボーレート = 1 / パルス幅。例: 最短 8.68 µs → 約 115200。
sigrokの「baudrate 自動検出」や、いくつかの定番速度を総当たりする手も
# 最短パルス幅からボーレートを推定
import numpy as np
edges = load_edges("tx.csv") # エッジ時刻[秒]
widths = np.diff(edges)
bit = widths.min() # 最短 = 1 ビット時間
print("推定ボーレート:", round(1/bit)) # 115200 付近に丸める4. 観測 — ログをオラクルにする
TX を USB-シリアル変換(3.3V ロジックのものを。5V を当てて壊さない)で受けて、ログを取る。
# ログを取りながらタイムスタンプを付ける
picocom -b 115200 /dev/ttyUSB0 | ts '[%H:%M:%.S]'
# Python なら pyserial
python3 -c "import serial; s=serial.Serial('/dev/ttyUSB0',115200);
[print(s.readline().decode(errors='replace').rstrip()) for _ in iter(int,1)]"ログをオラクルに使う型:
- 状態の確認: 「起動後 2 秒以内に
WiFi connectedが出る」——刺激(電源投入)に対する観測 - エラーの不在: テスト中に
ERROR/assert/WDT reset/stack overflowが出ないこと(不変条件) - タイミング: ログのタイムスタンプ差で処理時間を測る(粗いが手軽、14 章)
- リセットの検出: ブートバナーが再び出たら、それは意図しない再起動
AI 生成コードでは、ログと実際の動作が食い違うことがある(Sending... と出すが実際は送っていない、04 章・09 章の観測と突き合わせる)。ログを鵜呑みにせず、他の観測点と照合する。
5. 能動 — コマンドコンソールを叩く
コンソールがあれば、UART は観測だけでなく刺激の入口になる。
- ヘルプ(
help、?)でコマンド一覧を引く - 状態取得コマンドを叩いて内部値を読む(テストの観測点として)
- 設定・トリガコマンドで機器を望む状態に置く(テストの前提づくり)
- AT コマンド(無線モジュール)で接続・送信を直接指示し、その結果を無線側で観測(09 章〜12 章と連携)
def cmd(ser, line, timeout=1.0):
ser.reset_input_buffer(); ser.write((line+"\r\n").encode())
import time; end=time.time()+timeout; out=b""
while time.time()<end: out+=ser.read(ser.in_waiting or 1)
return out.decode(errors="replace")
assert "OK" in cmd(ser, "AT+STATUS"), "状態取得に失敗"6. 落とし穴
- RX を駆動するときのレベル: 機器の RX に PC 側 TX をつなぐとき、3.3V/5V を合わせる。逆結線(TX-TX)だと通信できない
- フロー制御: RTS/CTS を使う機器で無視すると取りこぼす
- ログで負荷が変わる: デバッグ出力自体が時間を食い、タイミングが変わる(観測が対象を乱す。14 章)
- セキュアな製品はコンソールを閉じている: 出ていない・パスワードがかかる・製品版で無効。それ自体が「正しくロックされているか」のテスト項目(17 章)
7. 手を動かす
シリアル線を見つけて速度を割り出す
この章のポイント
- UART は中身を知る最短の窓。ブートログ・状態・コマンドコンソールが出ていることが多い
- フレームは スタート + 8 データ + ストップ、クロックなし。ボーレート一致が命
- 未知の線は GND → TX(周期的に動く)→ 最短パルス幅からボーレートの順で特定
- ログはオラクル(状態・エラー不在・タイミング・リセット検出)。ただしログと実動作の食い違いを他観測と照合
- コンソールは刺激の入口にもなる(AT コマンド等)