Blue Pillとも呼ばれるSTM32F103C8T6基板をArduino IDEで使えるArduino STM32でコントローラーSSD1306を利用したモノクロOLEDディスプレイ用のライブラリにはAdafruit_SSD1306やu8g2やArduino STM32に付属のOLED_I2Cがあります。
これとは別にAVR等の他のCPUで使えるTiny4kOLEDというコンパクトで 128x64, 128x32, 72x40, 64x48, 64x32 の解像度にも使えるライブラリがあります。Tiny4kOLED ライブラリでも Arduino_STM32 の Wire ライブラリにちょっと手を入れることで使えるようになることが分かりました。
そのまま使うとコンパイルは出来ますが絵が出ません。症状を見るとOLEDの初期化は出来ているのにフレームバッファのデータ転送が出来ていません。 Tiny4kOLEDのソースコードを見ると、ssd1306_send_byte()で0が帰ってきたら32バイトのバッファがいっぱいになっていると判断してssd1306_send_stop()でバッファの内容を送信して空にしてからssd1306_send_data_start()で再接続して33バイト目をバッファに入れることで転送を続けることが出来るようになっています。
Tiny4kOLED.cpp : static bool ssd1306_send_byte(uint8_t byte) { return wireWriteFn(byte); } static void ssd1306_send_stop(void) { wireEndTransmissionFn(); } static void ssd1306_send_data_byte(uint8_t byte) { if (combineFn) byte = (*combineFn)(oledX + writesSinceSetCursor, oledY, byte); if (ssd1306_send_byte(byte) == 0) { ssd1306_send_stop(); ssd1306_send_data_start(); ssd1306_send_byte(byte); } writesSinceSetCursor++; }
一方、Arduino STM32のWireライブラリのソースコードを見ると、I2Cのバッファを超える33バイト目を書き込もうとするとtx_buf_overflowフラグを立てて0を返します。そしてendTransmission()ではtx_buf_overflowフラグが立っているとバッファの送信をしません。
Wire\utility\WireBase.cpp : uint8 WireBase::endTransmission(bool stop) { uint8 retVal; if (tx_buf_overflow) { return EDATA; } retVal = process(stop);// Changed so that the return value from process is returned by this function see also the return line below tx_buf_idx = 0; tx_buf_overflow = false; return retVal;//SUCCESS; } ... size_t WireBase::write(uint8 value) { if (tx_buf_idx == BUFFER_LENGTH) { tx_buf_overflow = true; return 0; } tx_buf[tx_buf_idx++] = value; itc_msg.length++; return 1; }
これではTiny4kOLEDが期待しているAVRのWireの動作と違ってしまいます。33バイト目を書き込もうとしても0を返すだけでまだオーバーフローにしないか、tx_buf_overflowが立っていてもバッファの内容を転送するようにすれば動くでしょう。
tx_buf_overflowを立てている行をコメントアウトします。
Wire\utility\WireBase.cpp : size_t WireBase::write(uint8 value) { if (tx_buf_idx == BUFFER_LENGTH) { // tx_buf_overflow = true; return 0; } tx_buf[tx_buf_idx++] = value; itc_msg.length++; return 1; }
これで33バイト目を書き込もうとしても0を返すだけでオーバーフローにしません。 これだけで Arduino_STM32 でもTiny4kOLEDが動くようになりました。
Tiny4kOLEDは128x32のOLEDではCPU側にフレームバッファを持たずにOLED側のメモリでダブルバッファが出来るとか、TinyOLED-Fontsで色々なフォントが使える等面白い機能があります。
修正するWireBase.cppの場所は
C:\Users\user\AppData\Local\Arduino15\packages\stm32duino\hardware\STM32F1\2022.9.26\libraries\Wire\utility\WireBase.cpp です。
開発環境は STM32F1xx/GD32F1xx boards by stm32duino version 2022.9.26 です。
Arduino IDEの環境設定で追加のボードマネージャのURLに
http://dan.drown.org/stm32duino/package_STM32duino_index.json
を追加すると、ボードマネージャで"stm"を検索すれば出てきます。
Roger Clark版のArduino_STM32よりもちょっと古いバージョンですが、ボードマネージャでインストールや削除が簡単にできるので便利です。Arduino SAM Boards (32-bits ARM Cortex-M3) をインストールする手間も省けます。更新が止まっているので更新を気にする必要もありません。
現在の主流はSTM32 HALベースの Arduino_Core_STM32のようですが、なんだかとっつきにくくてまだ使ったことがありません。