背景
doit のESP32モジュールで arduino-esp32を試しているのですが、プログラムの書き込みが失敗することが多くストレスが溜まっていました。数回試してやっとプログラムを書き込める感じです。プログラム書込みモードへの遷移に失敗します。遷移せず、普通のリセットになってしまいます。
最初は、電源等の環境を疑っていたのですが、回路に問題があるように思えてきました。
プログラム書込みモードへの遷移
ESP32はリセット時 GPIO0,GPIO2の状態を見て動作モードを決定します。
下の図で、SPI Flash Boot とあるのが書込み済プログラムを実行するモードでDownload Bootというのがプログラム書込みモードです。
Pin | SPI Flash Boot | Download Boot |
---|---|---|
GPIO0 | 1 | 0 |
GPIO2 | X | 0 |
ESP32内部でGPIO0はプルアップ、GPIO02はプルダウンされていますので、GPIO0をLowにした状態でResetを解除、ENをHighに戻せばプログラム書込みモードに入ることができます。
GPIO0, EN制御回路
下の回路図は ESP32 Hardware Design Guidelinesに記載されているESP32-DevKitCの回路図の一部です。DTR/RTSはUSB-UARTインターフェースIC,CP2102に接続されています。RTSをLowにすることでEN(Reset)がLowになり、DTRをLowにすることでIO0(GPIO0)がLowになります。但しRTS,DTR両方をLowにするとEN,IO0ともにHiになります。多くのESP32/ESP8266のモジュールで、この回路が使用されていると思われます。
問題点
問題は USB経由だとUARTの制御線(RTSやDTR)をあまり高速に変化させることができないということです。制御線を変化させるには、USBにパケットを送出する必要があるので、高速にはできないのです。RTSがENに、DTRがIO0に直結されていれば、時間がかかってもDTRをLowにしたあとRTSをHiにすればいいのですが、上の回路を介しているためDTR=RTS=Lowの期間はEN=IO0=Hiになってしまいます。
プログラム書き込み時のEN, IO0信号をオシロで観測したところ、下のような波形になっていました。
こんな波形だと、プログラム書込みモードに入れることの方が不思議ですが、ENの立ち上がりでIO0の状態を見ているわけではなく、ENの立ち上がり、つまりリセットの解除で動き始めたプログラムが、あるタイミングでIO0の状態を取り込んでいるのではないかと想像しています。ESP8266で問題が起きなかった回路がESP32になり、処理が高速になり問題が発生したのかもしれません。
対策
EN-GND間に0.1uFのコンデンサを追加しました。これでプログラムの書き込みに失敗することは無くなりました。