ESP32 GPIOのErrata

More than 1 year has passed since last update.


概要

ESP32で実験を行っていたら、GPIOの理解不能な動作に遭遇した。

原因を調べたところ CPUのバグ(Eratta)であることが判明。

原因がわからないと、かなり厄介な現象なので報告する。


現象

ESP32で8bitパラレル接続のTFT-LCD(コントローラはST7781)に表示を行おうとするのだが、時々おかしな点が描画される。下の写真は、現象を観測しやすくするため、RGBの3色で縦線を3本描画している。上はErattaを回避後の正常動作の写真で、下は回避前の写真。

170313a2.jpg

170313a5m.jpg

オシロスコープで信号を観測したところ、WR = Lowでデータ書き込み時に CS=Highになっている場合があることが判明した。


Eratta

問題のerattaは、Espressifの文書 ECO and Workarounds for Bugs in ESP32の「3.3. When the CPU accesses peripherals and writes one address repeatedly, random data loss occurs」。

タイトルからは、わかり難いが、対象に GPIOの主要レジスタが含まれている。GPIO以外は、UARTやI2SのFIFOなど。

対象となるチップのリビジョンは、 2016-09リリースのリビジョン0で、2017-02リリースのリビジョン1では修正されている模様。


回避方法

文書に書かれている回避方法は簡単で、別のアドレスでレジスタにアクセスしてくださいとのこと。

今回関係するレジスタだけ抜き出すと次のようになる。

Registers
Original addr
Changed addr

GPIO_OUT_W1TS_REG
0x3ff44008
0x60004008

GPIO_OUT_W1TC_REG
0x3ff4400c
0x6000400c

文書にW1TSの方は含まれていなかったが、これは記述抜けではないかと思う。

Original addrからのアクセスとChanged addrからのアクセスではタイミングがずれるようなので、変更するのであれば全部変更する方が好ましい。


esp-idf, Arduinoの状況

esp-idfやArduinoではGPIO操作をGPIOという名前の構造体を使って行っている。

この構造体のアドレスは tools/sdk/ld/esp32.peripherals.ldというファイルに定義されているが、値は0x3ff44000となっていた。これを0x60004000に変更すれば解決かと思われたが現象は変化しなかった。ライブラリの再生成などが必要なのかもしれない。 これを0x60004000に変更することで、回避することができた。 (2017/3/24 訂正)


esp32.peripherals.ld

/* PROVIDE ( GPIO = 0x3ff44000 ); */

PROVIDE ( GPIO = 0x60004000 );


動作確認

以下のように GPIO_OUT_W1TS,GPIO_OUT_W1TCレジスタと、各信号線の操作を定義したところ、プログラムはErrataを回避し、期待通りの動作をした。

#define GPIO_OUT_W1TS   ESP_REG(0x60004008)

#define GPIO_OUT_W1TC ESP_REG(0x6000400C)
#define RD_ACTIVE GPIO_OUT_W1TC = _BV(LCD_RD)
#define RD_IDLE GPIO_OUT_W1TS = _BV(LCD_RD)
#define WR_ACTIVE GPIO_OUT_W1TC = _BV(LCD_WR)
#define WR_IDLE GPIO_OUT_W1TS = _BV(LCD_WR)
#define CD_COMMAND GPIO_OUT_W1TC = _BV(LCD_CD)
#define CD_DATA GPIO_OUT_W1TS = _BV(LCD_CD)


最後に

Errataは、一度目を通していたはずなのに、この問題の原因と気が付くまで、かなり時間がかかってしまった。まだまだ修行が足りない。

この文章が誰かのお役に立てれば幸いです。