NanoVNA は USB-CDC による通信をサポートしていますが、ここが無線化すると(特にアンテナ調整の場合は)便利なので、コンセプトを試してみました。無線化といってもいろいろやりようは考えられますが、今回はシリアル通信を BLE SPP にのせかえる方法としました。

シリアルポートをMCUから引き出す

USART1_TX USART1_RX を MCU (STM32F072CBT6) から引き出します。中華 NanoVNA では NC になっている、それぞれ PA9 (USART1_TX) PA10 (USART1_RX) です。LQFP48 なので PA9 は 30ピン、 PA10 は 31ピンになります。

かなり細かいので面倒ですが、このピッチならギリギリなんとかなります。あまり接続部に負担をかけたくないので、ポリイミドテープで一旦うけています。

これをそのまま BLE 変換器に繋いでもいいのですが、デバッグがしにくいので一旦安定したところに繋ぎます。JTAG のピンヘッダがある部分に曲げたピンヘッダを追加して置いて、固定しました。

シリアルポートの有効化

NanoVNA のコード側の対応も必要です。

このパッチによって有効化しています。USB を接続した状態で電源をONにした場合は USB-CDC のシェルを有効にし、そうではない場合はシリアル経由のシェルを有効にします。

BLE UART 変換

手元に ESP-WROOM-32 が余っていたので、これを利用してみました。一旦雑に配線して変換プログラムを書きこんで、不要な配線をとって実際に組みこみます。

コードはこんな感じです。あまり好ましいとは思いませんが、RF 回路の突発電流で brown out detection (低電圧検出) にひっかかることがあるので検知を切っています。

#include "BluetoothSerial.h"
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"

BluetoothSerial SerialBT;

void setup() {
	WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
	Serial.begin(115200);
	SerialBT.begin("NanoVNA");
}

void loop() {
	if (SerialBT.available()) {
		Serial.write(SerialBT.read());
	}
	if (Serial.available()) {
		SerialBT.write(Serial.read());
	}
}

デバッグの様子です。

組み込み

ピン名がわかりやすいからという理由で、ESP-WROOM-32 のシールド側を下にしています。シールドにはポリイミドテープを貼って念のため絶縁しています。これを無理矢理 STM32 の上に両面テープで貼りつけて固定し、配線しました。

一応これで納まりました。

懸念点

ESP-WROOM-32 の消費電力が非常に多いです。突発的に100mAぐらい平気で流れるので、本体の消費とあわせると 3.3V レギュレータの定格 (200mA) を若干オーバーしているかもしれません。

データが欠落します。BLE なのと、CTS/RTS を無視しているので仕方ないですが、データの欠落が結構起こります。

やっておいてなんですが、この方法は大変な割に微妙なので、ナシかなと思いました。古いスマフォでUSBを中継したほうが楽だし確実そうです。

9600bps ぐらいまでボーレートを落とせばデータ欠落はなくなるようです。が、本当に遅いのでやはり厳しいです。57600 だと少し欠落する。

BLE ではなく普通の Bluetooth SPP にすればいいんですが、普通の Bluetooth は Web Bluetooth API から呼べないのでやる気になっていません。

  1. トップ
  2. tech
  3. 中華 NanoVNA の Bluetooth シリアル化を試す
  1. トップ
  2. nanovna
  3. 中華 NanoVNA の Bluetooth シリアル化を試す

ヘタなの買うより安いですね。

Arduino をフレームワークにした場合これだけです。

// main.ino
#include "BluetoothSerial.h"

BluetoothSerial SerialBT;

void setup() {
	Serial.begin(115200);
	SerialBT.begin("ESP32");
}

void loop() {
	if (SerialBT.available()) {
		Serial.write(SerialBT.read());
	}
	if (Serial.available()) {
		SerialBT.write(Serial.read());
	}
}
  1. トップ
  2. tech
  3. ESP32 を BLE SPP / UART 変換器にする

NanoVNA の USB のコミュニケーション方法が USB-CDC で、プロトコル自体は簡単そうだ、というのを前に書きました。なぜそんなことを調べていたかといえばブラウザでUIを作りたかったからなので、作りました。

機能

  • デバイスの現在のデータの読みこみとグラフ化(スミスチャート・周波数応答)
  • 複数のトレースタイプ (clear write / freeze / minhold / maxhold / videoavg / poweravg)
    • freeze が値の比較に便利だと思う。これが欲しくてトレースタイプを実装してます。他のはオマケ
  • ウィザード形式のキャリブレーション
  • デバイス画面のキャプチャ
  • デバイスバージョンの表示 (比較的新しいファームでなければ version コマンドがありません)
  • TDR (Time Domain Reflectometry)
  • s1p s2p 出力。ただし s2p は S22 = S11, S12 = S21 として出力する。

実装

ほとんどの機能は JavaScript で直接実装しています。TypeScript も使っていません。USB Device との通信は WebUSB で、できるだけポーリングを正確にしたいため Worker 内で行っています。このあたりは HackRF One を WebUSB から操作してスペアナを作るのと同じような手順です。

グラフは chart.js をそのまま使っているので工夫したところはありません。

現状では TDR 測定のところでだけ Rust で書いた実装を wasm にしたものを呼んでいます (TDR は RL をただ ifft しているだけです)。パフォーマンスが必要なわけではないのですが、複素数の計算を JS でやるのがとにかく面倒かつ可読性を損うので、Rust 資産を流用しという魂胆です。

本当は、Rust での処理は生dump データから、デバイスでやっている計算すべてをホスト側でやるのも見越してやりはじめましたが、一通りスキャンするのにかえって時間がかかりそうなのでやるのをやめました。ヒルベルト変換は fft/ifft でできるし、すぐ実装はできそうではあります。

備考:WebUSB と USB-CDC の将来は不安

WebUSB はそもそも既存のよくあるUSBデバイスに対してアクセス権限を与えるようなコンセプトのものではなく、USB-CDC も同様にスコープに入っていません。本来はSerial APIという提案仕様があって、こちらでカバーされるはずです。だけれど現状では実装されているブラウザが存在しません。

ということでやはりWebUSB でやるしかないわけですが、OS間で取り扱いが違うので意外と面倒くさいことがわかりました。

  • Windows では CDC 用のドライバがインターフェイスを握ってしまう
    • ドライバを libusb 用のものに置き換えれば使える
  • Ubuntu では cdc_acm ドライバがインターフェイスを握ってしまう
    • udev ルールで bind 直後に即 unbind することができる。

ドライバを入れ替えると普通のシリアルポートとしてOSには(当然だけど)認識されなくなるので、必要に応じて再び入れ替えたりする必要があります。

ここで一つ問題があって、現行の NanoVNA は USB の vid/pid を STM32 の CDC デバイスのもの(?)を流用しているため、上記のようなドライバ置き換えが他の STM32 デバイスに影響を及ぼすことがあります。vid/pid の関するイシューはあるのでそのうちなんとかなるかもしれませんが現状ではこの通りです。

なお macOS は実際のデータ転送に使うインターフェイスは、実際にポートがopenされるまで排他的に確保しないようで、WebUSB からも自由にアクセスできます。逆に WebUSB で握っている間にシリアルポートを別途開こうとすると、そのタイミングで resource busy が出ます。

現行の Android では特に何もせず、OTG コネクタさえ使えば接続することができました。ただ、中華NanoVNAはコネクタにType-Cを採用はしているものの、CC に何も接続されていないため、Type-C - Type-C ケーブルを使うとデバイスを認識しません。Type-A OTG 変換ケーブルなどを経由する必要があります。

とりあえず何が言いたいかというと、今のところ WebUSB で USB-CDC デバイスをなんとか動かす方法は存在しているけど、今後はどうなるかわからないということです。WebUSB 自体も (使われなければ) 消滅する予感のする仕様と感じています。少なくとも今の仕様 (パーミッションダイアログが危険性の割に雑) のまま広く使われることもないだろうと思います。

  1. トップ
  2. tech
  3. NanoVNA を WebUSB を使ってブラウザから見る
  1. トップ
  2. nanovna
  3. NanoVNA を WebUSB を使ってブラウザから見る