Network Stomper開発 Project 基板設計記[第4回(全5回)]

2019年11月14日 木曜日


【この記事を書いた人】
末永 洋樹

2003年の入社以来SEILシリーズのファームウェア開発に取り組んでいましたが、最近は子会社のIIJ-IIでエッジコンピューティングを中心として次世代技術の動きを追っています。

「Network Stomper開発 Project 基板設計記[第4回(全5回)]」のイメージ

IIJは今年8月3日、4日に開催されたDIYのイベントMaker Faire Tokyo 2019に出展しました。展示テーマの一つ「音楽×IoT」の作品として、IPネットワーク経由でギターのエフェクタを操作する「Network Stomper(ネットワークストンパー)」を制作し、会場でギターの実演を行いました。

エフェクターを遠隔操作「ネットワーク・ストンパー」(Maker Faire Tokyo 2019)

このNetwork Stomperのコアになるハードウェア(制御ボード)は、IIJのエンジニアが一から開発しています。ハードウェアの開発は電源やノイズなど、ソフトウェアやネットワークの開発と異なるポイントに気をつけなければなりません。
実際に開発を担当したIIJ技術研究所の末永が、ハードウェア設計についてのレポートをまとめましたので、5回に分けて掲載します。

(編集部)

USBシリアル回路

概要

USB端子はプログラムの書き換え、デバッグ出力、電源供給など幅広く使える端子です。
プログラムの書き換えやデバッグ出力については、Wi-Fiを使うこともできますし、ESP-WROOM-02のUART出力を取り出して外付けの3.3V対応USBシリアル変換器を使うこともできます。基板上にレベルコンバータを設置することで汎用のRS-232C(EIA-232)接続ポートを使えるようにするという選択肢もあります。昨今はRS-232C搭載のコンピュータは少なくなってきたので汎用とは言い難い状況ですが・・・。
電源供給については、もともと9V電池を使える設計ですので、代わりに9V出力のAC/DCアダプタを接続することも可能です。
色々と選択肢はあるのですが、USBにまとめてしまったほうが開発の効率は確実に良くなりますのでUSBシリアル接続対応とすることにしています。

自動リセット機構

普通にUART出力がやりとりできて、電源を供給できれば最低限の機能は果たすのですが、Arduino IDEによるプログラムの自動更新ができると開発効率が飛躍的に向上します。
ESP-WROOM-02のプログラムを更新する手順は、以下の通りです。

  1. IO0をLOWレベルに落とす
  2. リセットをかけてUART起動の処理を開始させる
  3. IO0をHIGHレベルに戻す
  4. プログラムを送信してSPIフラッシュに書き込みさせる
  5. リセットをかけて書き込んだプログラムを起動する

簡易開発キットなどはディップスイッチやタクトスイッチとしてIO0とRSTを操作できるように作られています。これだと毎回手作業が必要になり不便です。ESP-WROOM-02のコミュニティでは、この作業を自動化するためにRS-232Cの制御線を利用した様々な黒魔術的技法が開発されています。RS-232Cは古来より様々な黒魔術の舞台となってきた通信ポートで、古い技術者にとってはちょっと懐かしい話だと思います。
まず、本来の非同期通信ポートとしてのRS-232Cの構成をおさらいしておきます。

RS-232Cは通信網に接続するためのポートで、非対称な制御信号を持っています。例えば、DTEはRTSでDCEに対してデータ送信の許可を求め、DCEは自身の受信バッファの空きや通信網側の輻輳状態などを確かめてからCTSによりDTEに対してデータ送信の許可を与えますが、逆はできません。DTE側の処理が溢れていたとしても、網側からは容赦無くデータが届けられます。したがってDTE側では受信バッファ(FIFO)の管理を手厚くしてバッファリングでがんばるのが基本です。網からの呼び出し(着呼)を通知するRIも同様に非対称です。DTEはRIを検知すると着呼処理を実行します。要はベルがなったら受話器を取れ、という話です。対となる発呼の処理は専用線接続でない限りは一本の制御信号でできることはあまりありません。特に制御信号は使わず、最初からATコマンドで発呼処理を実行します。

ESP-WROOM-02は購入時点ではATコマンドで制御するモデムとして動くようにプログラムされています。この場合、ESP-WROOM-02は(配線は異なるのですが)DCEに近い動作をしているとみなすことができます。通信網とはWi-Fiのセグメントであり、キャリア検出とはアクセスポイントとステーション間の接続状態の検出であると言えるでしょう。・・・と言ってもESP-WROOM-02のUARTはRXD,TXD,RTS,CTSの4本しかありませんし、ATコマンドファームウェアは制御線の扱いはあまり気にしていないようです。

プログラムを書き換える際には、ESP-WROOM-02は通信網に接続するためのDCEではなく、データを処理するDTEとして動作します。この時点でRS-232C本来の使い方ではなくなり、標準規格からは外れます。制御線の意味も読み換えることになるのですが、標準は存在しません。代表的な読み替え方法にしたがって通信路を作ると以下のようになります。いわゆるRS-232Cクロスケーブルという結線の一つです。

RXDとTXDはそれぞれのDTEにとっての受信と送信を意味します。したがって配線はクロスします。DTRとDSRお互いの通信準備を確認できれば良いので、ここもクロスにします。通信網は存在しないのでDCDの定義は曖昧ですが、DSRと同じ意味とすることが多いようです。他にもDTEの電源状態を反映すると考えることもできますし、(検知できるのであれば)ケーブルの接続状態を反映すると考えることもできますね。RTSは自身の受信バッファに空きがあることを対向機器に示し、CTSは対向機器の受信バッファに空きがあることを検出します。このRTSの読み換えは危うく、かつてはケーブルごと、ソフトウェアごとに考え方が違っていて動くかどうかは運次第でした。別の流儀としてバッファの空きを通知するためにDTRとDSRを利用することもあります。現在では端末ソフトでハードウェアフロー制御OFFを指定してDTRやRTSの動作は気にしないという使い方が普通だと思います。
RIにはあまり使い道がありませんが、FTDIの場合はUSBデバイスからスリープ状態のPCを復帰させるための信号線として利用できます。また、GPS受信機やJJY受信機で時刻を送信する際に、TXDで「ただいまより、何時何分をお知らせします」という情報を流してから、実際にその時刻になったタイミングでRIやDCDを操作して割り込みをかけることで高精度に時刻を知らせるという使い方をされることもあります。このような用途ではGPIOと接続しておく必要があるかもしれません。
さて、ESP-WROOM-02のIO0とRSTの自動制御方法を考えていたハッカーたちは、どうせ使わないであろうDTR/RTS/CTSに着目し、これらの信号線を駆使する様々な手段を編み出していきます。GitHubで公開されているesptool-ckというプログラム書き込みツールで主要なアイデアが実装されています。

  1. ck … RTSを RESET端子に接続し、DTRをIO0端子に接続する
  2. wifio …DTRをRESET端子に接続し、TXDの電圧をIO端子にも反映させる
  3. nodemcu … RTSとDTRのxorをとって、RESET端子とIO0端子を駆動する

もっともシンプルな案はck方式です。

DTRをHIGHにするとIO0がLOWになり、この状態でRTSをHIGHにすればRESETがLOWになってリセットがかかり、RTSをLOWに戻すとESP-WROOM-02はUARTモードで起動します。FTDIだともともとDTRピンもRTSピンも負論理なので、接続は大変簡単です。問題は端末制御プログラムによっては起動時にDTRとRTSをHIGHに初期化することがあり(気持ちはよくわかります)、実際に意図せずリセット状態に移行してしまう事故が起こりがちだという報告がありました。なによりArduino IDEのシリアルモニタでこれが発生するという話があり、問題は大きかったようです。

そこで考案されたのがwifio方式です。

TXDをbreak状態(LOWで固定)にしておくとPNPトランジスタのベースからR2を経由してTXDへ電流が流れ込みます。これによりトランジスタはONとなり、R3には電流が流れ電圧降下が生じます。この結果、IO0はGNDD近くまで電圧が下がりLOWになります。厳密にはトランジスタのVceによりますが、LOWの範囲内でしょう。

DTRをHIGH(3.3V)にしておくと、コンデンサの両端が3.3Vとなりますから、コンデンサは充電されません。への入力も3.3Vとなりますからリセットは解除状態となります。ここで、DTRをLOWに落とすと、コンデンサはR1を通じて充電されます。この充電電流によりR1は電圧降下をおこし、充電完了までの間はがLOWレベルとなります。このパルスによりリセットがかかります。コンデンサの充電が完了すればはHIGHレベルに戻ります。DTRをせわしなく上げ下げする必要はありません。リセットがかかるのは、レベルが変動するタイミングだけなので、ck方式のようにリセット状態が維持されてしまうこともありません。この回路は一般的にはCR微分回路と呼ばれています。CR微分回路は本家Arduinoのリセットでも使われているようですね。

PNPトランジスタ1個、コンデンサ1個、抵抗3個で回路が構成できるというシンプルさと、CR微分回路を利用してパルスを作るというアイデアが光るかっこいい回路です。break信号を使ってTXDのレベルを固定するというRS-232Cをよく知らなければ出てこない発想もかなりイカしています。DTRをLOWからHIGHに戻すと充電されたコンデンサが電圧を過剰に持ち上げてしまい、過電圧パルスが生じそうなところは気になるのですが・・・この回路はとても好きです。

下図にwifio回路のリセット波形を示します。定数としてR1に10kΩ、C1に10uFを入れてLTspiceでシミュレーションした結果です。DTRを1秒間LOWレベルに下げる制御をしています。RSTの電圧が一瞬だけ低下してすぐに元に戻ること、DTRがHIGHに戻るタイミングで過電圧パルスが生じることがわかります。過電圧パルスを軽減する方法として、放電用のダイオードを入れる方法などが考えられます。

最後がnodemcu方式です。この方式では、RTSとDTRのどちらか片方だけがHIGHになるケースは稀だ、という仮定を置いています。特にDTRがLOWであるにもかかわらず、RTSがHIGHになるという状況には無理があります。DTE-DCE間の接続で通信準備ができていないのに送信要求を出してくるのは不条理ですし、DTE-DTE接続で通信準備ができていないのにデータの受け入れが可能なわけがありません。そこでnodemcu方式では、DTRがLOWかつRTSがHIGHのときRESETピンをLOWにしてリセットをかけることにしています。これでリセットの誤作動の可能性はかなり減少します。逆にDTRがHIGHかつRTSがLOWのきにはIO0をLOWにします。この条件は、DTE-DCE間接続を前提にした制御が有効になっていたり、DTE-DTE間でハードウェアフロー制御が有効になっていたりすると普通に起こり得ます。とはいえ、昨今ではあまり見かけない条件ではありますし、IO0のレベルが変わるだけであればリセットよりは実害は少ないと言えます。問題点としては厳密にはIO0をLOWにしつつリセットをかけるという動作ができないので、確実にUARTモードで起動するとは言えません。esptool-ckではリセットをかけた直後にIO0をLOWにするという手順を踏んでいます。ESP-WROOM-02の初期化が終わるより早くこの手順を実行できればUARTモードで起動するだろうということですが、実環境では問題なく動作するようです。今回はこの方式を採用していますので回路は後ほど紹介します。

Arduino IDEには他にnone(制御線には触らない)とdtrset(DTRをHIGHにする)という選択肢があります。dtrset用の回路は探し出せなかったのですが、wifio方式のリセット部分だけ作っておいて、リセットを自動でかけられるだけでも多少楽になるという意味合いかもしれません。他のAruduinoボードはリセットのみの自動化でなんとかなるものも多いです。ESP-WROOM-02もブートローダの作り方次第ではIO0を使わなくても、起動時に特定のメッセージを送ることで書き込みモードに切り替える処理は可能だと思います。

チップ選定

USBシリアル変換ICの供給元は、FTDI、SILICON LABS、WCHといったメーカがメジャーです。EspressifはかつてFTDIのFT232を推奨しており (ESP8266 System Description v1.4, 2016, p. 25)、実績としてもFTDI製品は信用がおけますので今回はFTDIのUSBシリアル変換ICを選択しました。
FTDIといっても幅広い品種がありますが、半田付けの手間を考えると可能な限りピン数が少ないほうがブリッジなどのトラブルが少なく、自動リセット機構の利用を考えるとDTRとRTSを扱える必要があります。ピン数からするとFT230/FT234系統は魅力ですが、DTRの制御ができません。FT231であればDTRの制御ができつつ、ピン数も抑えられます。FT232は高機能ですが、28ピンとピン数が多く、今回の用途にはオーバースペックでしょう。ということで、秋月電子で売っているFT231XSの20ピンSSOPパッケージを利用することとしました。

回路図

下図にFT231XS周辺の回路の拡大を示します。

電源としては3.3Vを利用しています。この場合、主電源であるVCCとI/O電源のVCCIOに3.3Vを供給するのに加え、内蔵LDOの出力である3V3OUTにも3.3Vを供給する必要があります。この3つが電源ピンです。リセット端子は利用しないので3.3Vに固定しています。データシートのリファレンス回路ではVCCIO、3V3OUT、RESETの各ピンにはC15(積層セラミックコンデンサ, 0.1uF)のパスコンを入れているのでそれに従っています。VCCについては電源回路側にコンデンサを並べてあるのでよしとしています。本来は0.1uFと4.7uFをFT231XSの近くに配置しておくべきだったかもしれません。

TXDとRXDは方向がややこしいですが、FT231XSからみたTXDとRXDとなりますので、FT231XSのTXDとESP-WROOM-02のRXDを接続し、FT231XSのRXDとESP-WROOM-02のTXDを接続することになります。

ESP-WROOM-02とFT231XSの間にはR34、R35の2本の470Ωの保護抵抗を入れています。保護抵抗はなくても、FT231XSとESP-WROOM-02が入力対出力の関係を保っている限りさほどの問題はおこらないと思います。ただし、FT231XSのTXDとESP-WROOM-02のRXDの関係は崩れる可能性があります。ESP-WROOM-02のRXDはGPIOとしても制御でき、OUTPUT指定ができてしまいます。この指定をされてしまうと出力同士が衝突します。FT231XSが3.3V出力、ESP-WROOM-02が0V出力、あるいはその逆になると、電圧を上げようとする動きと下げようとする動きが衝突して際限なく電流が流れてしまい過電流による誤動作か破壊が生じるでしょう。470Ωの抵抗が入っている場合、抵抗による電圧降下が生じますので、7mAの電流が流れた時点でHIGH側が3.3V、LOW側が0Vで安定します。ESP-WROOM-02は12mA、FT231XSは22mAが出力電流に関する絶対最大定格です。保護抵抗が入っていれば、誤動作は誤動作ですがプログラミングエラーでハードウェアにダメージがいくことがなくなります。抵抗を大きくすると電流を抑えることも可能ですが、ノイズの混入による電圧の上下が大きくなってしまいますのであまり大きな値にはできません。他の設計を眺めると470Ωを選択していることが多いようですので、素直に実績のある値を採用しています。FT231XSのRXDに関しては出力に設定することはできませんので保護抵抗は必ずしも必要ありませんが、ノイズを減衰させられるかも?という程度の意味合いで同じ抵抗を入れています。

ノイズの話はデータシートに由来するもので、ESP8266EXではESP8266EXからみたTXD (FT231XSのRXD)に499Ωの抵抗を挿入するように指定されています (ESP8266 Hardware Degisn Guidelines v2.4, 2018, p. 10)。80MHzの高調波を抑制するため、と書かれていますがいまいちよくわかりません。CPUクロックが40MHzだと80MHzの高調波ノイズは発生するだろうとは思いますが、なぜUARTのTXDでそれをことさら気にする必要があり、なぜ499Ωが適しているのか。事情があるのだと思うのですが、調べきれませんでした。499Ωは特殊な値なので470Ωでも概ね問題ないだろうと都合よく考えていますが、どうなのでしょうね?470Ωで良いなら最初から470Ωを指定するところだろうという気もします。

RTSとCTSは基板上でつなげています。USBホストがRTSを出力すると、FT231XSは即座にCTSを出力する仕組みです。これによりハードウェアフロー制御は事実上無効となります。ハードウェアフロー制御は役に立つことよりトラブルを招くことのほうが多い気がするのでこのような仕組みにしています。DTRとDSRの関係も同様です。真面目な端末ソフトはDSRを検出するまでは通信を開始しませんが、デバッグ目的ではそんなことは無視してTXD/RXDに流れている情報をみたいことのほうが多いので制御を無効化しています。

RTSとDTRはR21、R23の10kΩでpull downしています。これにより、FT231XSの起動が完了するまではLOWレベルに固定されます。これはFT231XSの起動中に後述するリセット回路を安定させておくための措置です。

RIはUSBホストにスリープからの復帰を要求するために利用できますが、このためにGPIOを一つ使うのもなんなのでR32でpull upしてHIGHに固定しています。PCの周辺機器として利用するのであればGPIOに接続しておくのも一案です。

CBUSはFTDIのICでは定番のピンで、ユーザが用途を設定できるピンとなっています。設定はFT_PROGというソフトウェアを利用してUSB経由でおこないます。今回はTXとRXに反応するLEDと、USBの電源状態を監視するVBUS_SENSEを利用しています。LEDはESP-WROOM-02からみたTXとRXを表示します。USBシリアルケーブルとは逆の動作です。VBUS_SENSEを利用するとUSBケーブルが抜けている際にスリープ状態に入って消費電力を削減できます。

LED1(赤色LED, SML-E12V8WT86)は電圧効果が2.2Vから2.7V程度のLEDとなります。電源電圧が3.3Vですから、差し引き0.6Vから1.1VがR30,R31の100Ωでの電圧降下分となり電流値は6mAから11mAという計算になります。20mAで最大の輝度を発揮する品種ですが、6mAで40%程度、11mAで60%程度の輝度を発揮できますので動作の目視確認には十分な明るさです。

下図にEMI対策関連の回路を示します。

USB+(USBDP)とUSB-(USBDM)は差動信号の配線です。今回の基板では最も高速・高周波の信号が流れますので配線長は可能な限り短くする必要があります。リファレンス回路では、ノイズ減衰と過電流保護用と思われる27Ωの抵抗を入れています。これは特殊な抵抗値ですし、効果のほどもよくわからないなぁ、と思いつつ秋月電子の開発ボードやスイッチサイエンスの開発ボードの回路図を眺めてみると、秋月電子は村田製作所のコモンモードノイズフィルタとESDフィルタを組み合わせたような素子を使っています。スイッチサイエンスは何も入れていません。ここは秋月電子に従って、FL1(コモンモードESDフィルタ, LXES11DAA2)だけを入れておくことにしました。LXES11は特性インピーダンス60Ωです。USBの特性インピーダンスは90Ωですので、90Ωに対応するLXES21を使う必要がありそうなところなのですが、売ってなさそうなのでLXES11を利用しています。正直、あってもなくても良いような部品ではありますが、手に入るのであれば入れておこうかという程度の選択です。この部品があるからといって、基板の動作に大きな改善はないでしょう。どちらかというと、自作のいい加減な基板がUSBホストとなるPCに悪さをするのを少しでも軽減するという意味のほうが強い部品です。EMI/ESD対策部品は基本的に自分を守るというよりも、対向機器に迷惑をかけないという紳士の部品です。

電源ラインに入っているFB2(フェライトビーズ、BLM18PG471SN1D)も同じようにEMI対策の部品です。損失の多いコイルを使って電源ライン上に流れる交流成分の出入りを制限します。C17(積層セラミックコンデンサ、0.1uF)はFB2とは逆に交流成分を積極的にグランドに流して電源ラインから排除しようという部品です。これもUSBホストに迷惑をかけないという意味合いのほうが強い部品です。

R3の4.7kΩとR25の10kΩはUSBの電源電圧を分圧してFT231XSのVBUS_SENSEに入力します。これはリファレンス回路の値をそのまま採用しています。FT231XSはこの電圧が低いとUSBケーブルがつながっていないと判断して省電力動作に移行します。

Nodemcuリセット回路

下図にnodemcu互換のリセット回路を示します。

Q1(Nch MOSFET, IRLML6344TRPBF)とQ2(同)はスイッチとして働きます。ポイントは、ドレインは3.3Vに固定されていますが、ソースはRTSまたはDTRに接続されており0Vまたは3.3Vのどちらにもなりうるという点です。

ソース側が3.3Vになっていると、ドレインもソースも同じ電圧です。Q1、Q2のスイッチがONでもOFFでも電流は流れません。したがって、R22、R27にも電流は流れず、電圧降下は発生しません。この場合出力は3.3V(HIGH)となります。

ソース側が0Vの場合は、Q1、Q2がONかOFFかで出力が変わります。ONの場合、ドレインからソースに向かって電流が流れます。このとき、R22、R27では3.3V分の電圧降下が発生しますので出力は0V(LOW)となります。電流値としては0.3mAです。OFFであれば電流は流れませんので出力は3.3V(HIGH)です。

以上をまとめると、Q1のソースが0V、すなわちがLOW(負論理なので信号としてはHIGH)の場合にのみ、RESETはLOWになる可能性があります。実際にRESETがLOWになるのはQ1がONになる必要があり、これはがHIGH(負論理なので信号としてはLOW)の場合です。つまり、RTSがHIGHでDTRがLOWの場合のみ、RESETがLOWとなりESP-WROOM-02にはリセットがかかります。他の条件ではRESETはHIGHのままです。Q2は信号が逆に接続されていますので、RTSがLOWでDTRがHIGHの場合のみIO0がLOWとなります。

多くのシリアル端末ソフトでは、ハードウェアフロー制御を有効にしない限りはDTRとRTSを共にHIGHに初期化するか、LOWのまま放置するかという動作をしますので、リセットやIO0の誤動作は生じにくいと言えます。Arduino IDEからプログラムの書き込みを実行する場合、DTRとRTSのどちらか一方だけがHIGHになるように制御することでリセット端子とIO0端子を順番に操作できることになります。同時に操作することはできませんが、ESP-WROOM-02の起動よりも高速に操作できれば、リセット後にIO0をLOWにしてUART起動モードに設定することが可能となります。

ESP-WROOM-02の起動時間が遅いという前提で動作する制御方式ですので、理論上は失敗する可能性もありますが、電気的には問題点の少ない優れた制御方式だと思いますのでこの回路を採用しました。

R4とR26はQ1、Q2の誤動作を防ぐためのゲート抵抗です。抵抗値100はよく使われる値という以上の意味はありませんが、ゲート容量の充電にかかる時間を決定します。また、信号線に乗ってきたノイズのエネルギーを消費するという役割もあります。は共にR21、R23の10kΩでpull downされています。Q1、Q2がOFFになる場合、ゲート容量に溜まった電荷はゲート抵抗に加え、pull down抵抗を経由してグランドに抜けていきます。また、FT231XSが何も出力していなければ、Q1、Q2はOFFに固定されます。

リセット問題

これでうまくいくだろう、と思ったのですが実はリセット回路には機械式のスイッチも付いているという点が問題となりました。該当箇所を下図に示します。

SW1をONにすると、RESETのラインはR1の1kΩを経由してグランドにつながります。このとき、Q1がOFFであれば電源の3.3VはR22の10kΩとR1の1kΩで分圧され、RESET端子には0.3Vが入力されます。これはLOWとして認識され、EPS-WROOM-02はリセット状態になります。

ところが、がHIGH(信号としてはLOW)の場合には問題がありました。この状態でRESETのラインをLOWに下げると、Q1の寄生ダイオードが動作してからRESETへと電流が流れます。そうなると接続は以下のようになります。

とりあえず、電流はR22にはほとんど流れず、Q1のほうを主に流れるだろうと考えます。寄生ダイオードの電圧降下を0.6Vから1.2Vとして計算すると、RESET端子の電位は2.7Vから2.1Vくらいの範囲になりそうです。電流が微小なのでもう少し電圧降下は少なくなりRESET端子の電位は高くなるかもしれません。また、R22経由で流れてくる電流もRESET端子の電位を押し上げます。これはESP-8266のI/O電圧のHIGHである2.64Vに近い値で、LOWである0.8Vよりもはるかに高い値です。というわけでとても動作するとは言えない状況で、FT231XSがRTSをLOWに設定していると、手動リセットは動作しないという制限事項が生じることになりました。残念です。

問題が生じている状態でリセットボタンを押した場合のRESET端子の波形を下図に示します。

電圧が2.72Vまでしか下がっていません。差分は0.68Vというところでした。これはダイオードの順方向電圧降下(Vf)としてはありがちな数値です。

FT231XSは省電力モードに入るようにはしているものの、リセットも電源OFFもできない仕様で回路を作っており、ときどきリセット波形がおかしくなるのはどういう条件なのか、確定するのにやや時間がかかりました。FT231XSのリセット直後のはLOWかHi-Zになっているらしく、手動リセットが効くのですが一度USBケーブルを接続すると、それまでの通信状態次第でLOWかHIGHかわからなくなります。やはりFT231XSもリセットできるようにしておくか、電源を切れるようにしておくか、切り分けの手段は用意しておいたほうが不具合の調査にも有効でした。

今回はトランジスタの種類を統一したかったのでFETで設計しましたが、BJTを使っていれば逆接続時でも寄生ダイオードのような存在はありません。また、その状態でベース電流を流したとしても電流増幅率が低くエミッタ・コレクタ間にはさほど電流は流れません。BJTで設計しておけば動作しそうです。とはいえBJTの逆接続は応用例があることはありますが、あまり一般的な使い方ではなくメーカも非推奨としていることが多いのでイマイチな設計ではあります。

リセット回路周りは再設計しなければならないようですが、時間切れとなりました。簡単に解決する方法としては、ESP-WROOM-02のRST端子はFT231XS経由での操作のみで使うことにして、リセットボタンによる手動リセットはEN端子を使うように変更する方法が考えられます。これであれば配線の変更だけで対処可能です。FT231XSもまとめてリセットするという方法も考えられますが、この場合はリセットボタンを押すとUSBの接続が切れてしまうことになり、強力なリセット回路になる反面ちょっと不便になります。

波形

ESP-WROOM-02からみた受信側(RX)の波形を下図に示します。

同じく送信側(TX)の波形を下図に示します。

オーバーシュート、アンダーシュートは目立ちますが、通信に問題はないレベルではないかと思います。RXのほうがノイズは多いように見えますが、通信路を駆動しているFT231XSに由来するものではいかと思われます。

つぎにnodemcuリセット回路によるファームウェア書き込み時のリセットの様子を観測しました。

上図はチャンネル1(黄色)がリセット端子、チャンネル3(水色)がIO0端子の電圧です。横軸は1目盛20msとなっています。少し見難いのですが、リセット端子が100ms程度の間LOWになり、リセットの解除と同時にIO0がLOWに落ちるという動作がわかります。その後20ms程度経過した時点でチャンネル1、チャンネル3ともに上下に激しく振動してみえているのは、FETのゲートに強いノイズが混入していることが原因のようです。

信号の上げ下げのタイミングはGitHubのesp8266/Aruduino レポジトリに含まれるesptool.pyの_connect_attemptメソッドに記述されています。リセットを0.1秒LOWに維持(DTRをLOW, RTSをHIGH)、IO0を0.05秒LOWに維持(DTRをHIGH、RTSをLOW)、すべての制御信号をLOWに戻す(DTRをLOW、RTSをLOW)というシーケンスになっています。Pythonのスクリプトですのでタイマはさほど正確ではないはずです。通信開始後にIO0のレベルが少し変動しているのは最後にDTRをLOWに戻す処理が実行されたためと考えられます。タイミングに関しては概ね想定通りです。

問題はやたらと強いノイズですが、RTSの信号線を観測してみると下図のようになっています。

あきらかにUARTの速度域ではないノイズがのっています。周波数は26MHzで、これはCPUのクロック周波数と一致します。Pk-Pkが2.28Vありますのでかなりの大きさです。プリント基板上ではRTSは比較的長い配線となっている上、CTSとRTSを接続してループバックさせようとした結果、T字型のダイポールアンテナになっています。なかなか優れたアンテナを設計できました・・・・いやいや、これはパターン設計上の致命的な不具合ですね。ノイズの起源が本当にCPUクロックなのか、流入経路は本当に電磁波なのか、いろいろと定かではないのですが、とにかく再設計が必要なのは間違いありません。ファームウェアの書き込みが完了すると、このノイズは観測できなくなりますので、どうやら複合的な要因で強いノイズが生じるようです。普通に使う分には問題は出ていませんが、見つけてしまったからには直したくなります。

・・・というわけで、色々調べたところ、ピンリストに気になる記載がありました( [ESP8266 Pin List, 2018, ページ: Reg])。GPIO0の備考に” after reset, the default is function5 to export the clock”という記載があります。どうやら、IO0がクロック信号の出力端子になっていて、その信号が見えているということのようです。そもそもこの波形はノイズではなく、正しくクロック信号が出力されていたのでした。IO0はQ2を通してにつながっています。がLOW(DTRがHIGH)でがHIGH(RTSがLOW)になっているとQ2はONになります。この状態でIO0がHIGHになると保護抵抗なしでに電流が流れ込むことになります。本来はここに電流制限用の保護抵抗を入れるか、ダイオードでIO0からの電流出力を遮断する必要があるところでした。また、IO0端子に26MHzの高周波信号が流れるのであれば、パターン設計でも極力配線長を短くしてノイズの放射を押さえるべきでした。しかし、クロック信号の出力ピンは起動モードの選択ピンとは別にしたほうが良いんじゃないかなぁ・・・・?

同様にGPIO2(I2C_SDA)は起動時にUART0のTXになると書いてあるので、I2Cデバイスを誤動作させる可能性があるかもしれません。このGPIO0とGPIO2は要注意ですね。

USBの信号波形

FT231XSのUSB通信はUSB2.0対応とされていますが、速度はフルスピード(12Mbps)までとなっています。わかりにくいのですが、ハイスピード(480Mbps)よりもフルスピードのほうが遅いというのがUSBの仕様です。ビット幅はパルスの半分という計算なので、アナログ的には6MHzの矩形波を送受信しなければなりません。
MHz帯の信号を通すのは簡単ではありませんが、短い距離ならなんとかなるだろうという軽いのりでD+とD-で配線の長さだけ揃えるようにパターンを引いています。この矩形波を手元のアナログ帯域100MHzのオシロスコープに200MHzの1:10プローブという組み合わせで観測してみました。本来はテスト用のビットパターンで計測するのですが、時間もなかったのでファームウェアでデバッグメッセージを出力するようにして、立ち上がり立ち下がりの両エッジでトリガをかけて観測しています。大部分はSYNCメッセージの波形になるでしょう。

黄色がD+、紫がD-の波形です。ちょっとタイミングがずれてみえますが、それなりに0と1の分離は良さそうですね。案外動くものでした。

これがUSB2.0のハイスピード転送以上の速度になると一気に観測は難しくなると思われます。個人で買えるようなオシロスコープではちょっと無理です。USB3.0はほとんど絶望的です。仕事でもこれを観測できるようなオシロスコープは使っていない人が多いでしょう。マイコンの開発・デバッグ用のUSBシリアル変換でUSB3.0の速度が必要になる日はこないとは思いますが・・・。

第5回に続く…)

引用文献

  • Espressif Inc. (2015年8月1日). ESP8266EX Datasheet v4.4.
  • Espressif Inc. (2016年1月). ESP8266 System Description v1.4.
  • Espressif Inc. (2017年5月). ESP8266 Technical Reference v1.3.
  • Espressif Inc. (2018年3月). ESP-WROOM-02 Datasheet v2.6. 21.
  • Espressif Inc. (2018年12月). ESP8266 Hardware Degisn Guidelines v2.4.
  • Espressif Inc. (2018年12月13日). ESP8266 Pin List.
  • Espressif Inc. (2018年11月). ESP8266EX Datasheet v6.0.
  • Phillips Semiconductors. (2000年1月). I2Cバス仕様書 v2.1.
  • Pull up resistors. (2015年9月9日). 参照先: ESP8266 Developer Zone: https://bbs.espressif.com/viewtopic.php?t=1079#p4097

末永 洋樹

2019年11月14日 木曜日

2003年の入社以来SEILシリーズのファームウェア開発に取り組んでいましたが、最近は子会社のIIJ-IIでエッジコンピューティングを中心として次世代技術の動きを追っています。

Related
関連記事