Arduino環境で、RP2040(Raspberry Pi pico)のSPI接続、ESP32(BananaPi PicoW)のSPI接続での表示をします。
I2Cとの表示速度比較、OLEDを複数接続してTripple Monitorで使ってみます。
紹介するもの
OLED SSD1306 0.96inch <SPI>
特徴
同じSSD1306を使用しますが通信方式には4線式I2Cと、7線のSPI接続の方式があります。
購入時にはどちらかの通信方式を使用するか確認してください。
本記事ではSPI単色表示について記載します。
I2C接続でのSSD1306についてはこちら。
製品情報
サイズ | 0.96 ~ 2.42inch 各種 当記事では 0.96を使用します。 |
解像度(X, Y) | 128, 64 |
表示色 | 白、青、黄、黄+青 黄+青の場合、それぞれのエリアが決まっていて、 色の変更はできないようです。 |
電源電圧 | 3.3 – 5.0V |
通信方式 | 購入時にどちらで通信するか選択 I2C SPI |
ドライバ | SSD1306 |
入手 | 電子部品ショップ、ネットショップ 入手性は非常に良く、安く大量買いする場合はAli Express |
外観
前面
背面
比較
vs I2C
SSD1306の0.96inchには、I2CモデルとSPIモデルがあります。
同時に同ストアで購入したものではないので単純な製品比較にはならないかもしれませんが並べてみます。(画像左がSPI, 右がI2C)
画面の大きさは同じ0.96inchですがSPIのほうが若干大きいですが、画素の有効範囲や大きさは同じに見えます。
ダイナミック点灯なので、撮影のタイミングで色合いに変化が出てしまいますが、輝度には差異が感じられませんでした。
表示速度はSPIのほうが早いです。
一瞬でAdafruitロゴスクロールまで到達しました。
同じ命令セットですが、単純な通信速度だけでもない気もします。
SCROLL命令では、SPIは縦軸にも動きますが、I2Cでは横方向にしか動きませんでした。
使用したサンプルは以下のサンプルに、ピン番号の変更とdelay()はすべて消去しています。
ファイル(F) > スケッチ例 > Adafruit SSD1306 > ssd1306_128x64_i2c
ファイル(F) > スケッチ例 > Adafruit SSD1306 > ssd1306_128x64_spi
使用感
I2Cのデフォルト表示速度と比べると速いです。
I2Cより配線の量が多くて煩わしいですが、いくつでもOLEDを接続できるメリットがあります。
マイコン側のI/Oピンの少ないものではSPIが多くのピンを占有するので、最終的な完成系に必要なI/Oが確保できるかを検討する必要があります。
SPIで接続する場合は、同じ配線数で表現力の豊かなカラーOLEDを使用することもできます。
このサイズでは価格にそれほど差はありません。
準備
ライブラリ
ライブラリは以下2つのライブラリを使用します。
I2Cと同じライブラリを使用します。
ライブラリ | Adafruit SSD1306 by Adafruit Ver2.5.1 Adafruit GFX Library Ver 1.11.1 |
赤太字箇所をライブラリマネージャの検索欄に入力することで検索できます。
使い方
SPIによる表示(RP2040系 Raspberry Pi Pico)
SPIを使ったOLEDの表示です。
配線
Raspberry Pi Pico | 配線 | SSD1306 |
---|---|---|
GND | 黒 | GND |
3V3 | 赤 | VDD |
GPIO18(SPI0 SCK) | 紫 | SCK |
GPIO19(SPI0 MOSI) | 緑 | SDA |
GPIO22 | 青 | RES |
GPIO28 | 橙 | DC |
GPIO17(SPI0 CS) | 黄 | CS |
スケッチ
/**********************************************************************
【ライセンスについて】
Copyright(c) 2022 by tamanegi
Released under the MIT license
'http://tamanegi.digick.jp/about-licence/
【マイコン基板】
Raspberry Pi Pico
【スケッチの説明】
SSD1306 OLEDの制御をします。
【ライブラリ】
Raspberry Pi Pico/RP2040 > Raspberry Pi Pico
Adafruit SSD1306 by Adafruit
Adafruit GFX Library by Adafruit
【準備】
マイコン基板 <-> SSD1306(SPI)
GND <-> GND
3V3 <-> VDD
GPIO18(SPI0 SCK) <-> SCK
GPIO19(SPI0 MOSI) <-> SDA
GPIO22 <-> RES
GPIO28 <-> DC
GPIO17(SPI0 CS) <-> CS
【バージョン情報】
2023/03/20 : 新規
**********************************************************************/
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 //解像度 128 x 64 で使用します。
#define SCREEN_HEIGHT 64 //SCREEN_HEIGHTは 32 に設定することができます。
#define OLED_SCK 18
#define OLED_MOSI 19
#define OLED_RST 22
#define OLED_DC 28
#define OLED_CS 17
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &SPI, OLED_DC, OLED_RST, OLED_CS);
// Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT,
// OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
void setup() {
//RP2040系では、この命令セットでSPIピンを設定する。
SPI.setTX(OLED_MOSI);
SPI.setSCK(OLED_SCK);
if(!display.begin(SSD1306_SWITCHCAPVCC)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
display.clearDisplay(); //何か表示されている場合に備えて表示クリア
display.setTextSize(2); //フォントサイズは2(番目に小さい)
display.setTextColor(SSD1306_WHITE); //色指定はできないが必要
display.setCursor(20, 10); //テキストの表示開始位置
display.print(F("TAMANEGI")); //表示文字列
display.setCursor(25, 30);
display.print(F("SSD1306"));
display.setCursor(45, 50);
display.print(F("SPI0"));
display.display(); //バッファ転送(表示)
}
void loop() {
}
結果
SPIによる表示(ESP32系 Banana Pi PicoW)
配線
Banana Pi PicoW | 配線 | SSD1306 |
---|---|---|
GND | 黒 | GND |
3V3 | 赤 | VDD |
GPIO18(SPI0 SCK) | 紫 | SCK |
GPIO19(SPI0 MOSI) | 緑 | SDA |
GPIO22 | 青 | RES |
GPIO28 | 橙 | DC |
GPIO17(SPI0 CS) | 黄 | CS |
スケッチ
/**********************************************************************
【ライセンスについて】
Copyright(c) 2022 by tamanegi
Released under the MIT license
'http://tamanegi.digick.jp/about-licence/
【マイコン基板】
micro:bit
【スケッチの説明】
SSD1306 OLEDの制御をします。
【ライブラリ】
Nordic Semiconductor nRF5 Boards > BBC micro:bit
Adafruit SSD1306 by Adafruit
Adafruit GFX Library by Adafruit
【準備】
マイコン基板 <-> SSD1306(SPI)
GND <-> GND
3V3 <-> VDD
GPIO3(SPI0 SCK) <-> SCK
GPIO4(SPI0 MOSI) <-> SDA
GPIO7 <-> RES
GPIO10 <-> DC
GPIO2(SPI0 CS) <-> CS
【バージョン情報】
2023/03/20 : 新規
**********************************************************************/
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 //解像度 128 x 64 で使用します。
#define SCREEN_HEIGHT 64 //SCREEN_HEIGHTは 32 に設定することができます。
#define OLED_SCK 3
#define OLED_MOSI 4
#define OLED_RST 7
#define OLED_DC 10
#define OLED_CS1 2
Adafruit_SSD1306 display1(SCREEN_WIDTH, SCREEN_HEIGHT, &SPI, OLED_DC, OLED_RST, OLED_CS);
// Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT,
// OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
void setup() {
//ESP32系では、この命令セットでSPIピンを設定する。
SPI.begin(OLED_SCK, -1, OLED_MOSI, OLED_CS);
if(!display.begin(SSD1306_SWITCHCAPVCC)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
display.clearDisplay(); //何か表示されている場合に備えて表示クリア
display.setTextSize(2); //フォントサイズは2(番目に小さい)
display.setTextColor(SSD1306_WHITE); //色指定はできないが必要
display.setCursor(20, 10); //テキストの表示開始位置
display.print(F("TAMANEGI")); //表示文字列
display.setCursor(25, 30);
display.print(F("SSD1306"));
display.setCursor(45, 50);
display.print(F("SPI0"));
display.display(); //バッファ転送(表示)
}
void loop() {
}
結果
SPIを使ったトリプルモニタ
同じI2C0 ライン上には異なるI2Cアドレスのモジュールを配線します。
スケッチにはそれぞれのアドレスに対して個別の表示ができます。
配線
SPI0を使用し、MOSIとSCKは共通で使用します。
CSとRESとDCは各モニタ用に割り当てます。
マイコンのピンアサイン表にはSPI CSの記載がありますが、デフォルトから変更して使用する場合はどのピンを使用しても良いようです。
RaspberryPiPico | 配線 | SSD1306(0.96) | 配線 | SSD1306(1.54) | 配線 | SSD1306(2.42) |
---|---|---|---|---|---|---|
GND | 赤 | VCC | 赤 | VCC | 赤 | VCC |
3V3 | 黒 | GND | 黒 | GND | 黒 | GND |
GPIO18 (SPI0 SCK) | 紫 | SCK | 紫 | SCK | 紫 | SCK |
GPIO19 (SPI0 MOSI) | 緑 | SDA | 緑 | SDA | 緑 | SDA |
GPIO22 | 青 | RES | ||||
GPIO28 | 橙 | DC | ||||
GPIO17 (SPI0 CS) | 黄 | CS | ||||
GPIO15 | 青 | 青 | RES | |||
GPIO14 | 橙 | 橙 | DC | |||
GPIO13 | 茶 | 茶 | CS | |||
GPIO2 | 青 | 青 | RES | |||
GPIO1 | 橙 | 橙 | DC | |||
GPIO0 | 白 | 白 | CS |
スケッチ
/**********************************************************************
【ライセンスについて】
Copyright(c) 2022 by tamanegi
Released under the MIT license
'http://tamanegi.digick.jp/about-licence/
【マイコン基板】
Raspberry Pi Pico
【スケッチの説明】
SSD1306 OLED (SPI)を3個チェーン制御をします。
【ライブラリ】
Raspberry Pi Pico/RP2040 > Raspberry Pi Pico
Adafruit SSD1306 by Adafruit
Adafruit GFX Library by Adafruit
【準備】
マイコン基板 <-> SSD1306(SPI) 1台目
GND <-> GND
3V3 <-> VDD
GPIO18(SPI0 SCK) <-> SCK
GPIO19(SPI0 MOSI) <-> SDA
GPIO22 <-> RES
GPIO28 <-> DC
GPIO17(SPI0 CS) <-> CS
マイコン基板 <-> SSD1306(SPI) 2台目
GND <-> GND
3V3 <-> VDD
GPIO18(SPI0 SCK) <-> SCK
GPIO19(SPI0 MOSI) <-> SDA
GPIO15 <-> RES
GPIO14 <-> DC
GPIO13 <-> CS
マイコン基板 <-> SSD1306(SPI) 3台目
GND <-> GND
3V3 <-> VDD
GPIO18(SPI0 SCK) <-> SCK
GPIO19(SPI0 MOSI) <-> SDA
GPIO2 <-> RES
GPIO1 <-> DC
GPIO0 <-> CS
【バージョン情報】
2023/03/20 : 新規
**********************************************************************/
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 //解像度 128 x 64 で使用します。
#define SCREEN_HEIGHT 64 //SCREEN_HEIGHTは 32 に設定することができます。
//共通で使用するSPIのピン定義
#define OLED_SCK 18
#define OLED_MOSI 19
//モニタ1 0.96inchのピン定義
#define OLED_CS1 17
#define OLED_RST1 22
#define OLED_DC1 28
//モニタ2 1.54inchのピン定義
#define OLED_CS2 13
#define OLED_RST2 15
#define OLED_DC2 14
//モニタ3 2.42inchのピン定義
#define OLED_CS3 0
#define OLED_RST3 2
#define OLED_DC3 1
Adafruit_SSD1306 display1(SCREEN_WIDTH, SCREEN_HEIGHT, &SPI, OLED_DC1, OLED_RST1, OLED_CS1);
Adafruit_SSD1306 display2(SCREEN_WIDTH, SCREEN_HEIGHT, &SPI, OLED_DC2, OLED_RST2, OLED_CS2);
Adafruit_SSD1306 display3(SCREEN_WIDTH, SCREEN_HEIGHT, &SPI, OLED_DC3, OLED_RST3, OLED_CS3);
void setup() {
//RP2040系では、この命令セットでSPIピンを設定する。
//共通で使用するSPI0
SPI.setTX(OLED_MOSI);
SPI.setSCK(OLED_SCK);
//モニタ1 0.96inchの初期化
if(!display1.begin(SSD1306_SWITCHCAPVCC)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
//モニタ2 1.54inchの初期化
if(!display2.begin(SSD1306_SWITCHCAPVCC)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
//モニタ3 2.42inchの初期化
if(!display3.begin(SSD1306_SWITCHCAPVCC)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
//モニタ1 0.96inchの表示
display1.clearDisplay(); //何か表示されている場合に備えて表示クリア
display1.setTextSize(2); //フォントサイズは2(番目に小さい)
display1.setTextColor(SSD1306_WHITE); //色指定はできないが必要
display1.setCursor(20, 10); //テキストの表示開始位置
display1.print(F("TAMANEGI")); //表示文字列
display1.setCursor(25, 30);
display1.print(F("SSD1306"));
display1.setCursor(20, 50);
display1.print(F("0.96inch"));
display1.display(); //バッファ転送(表示)
//モニタ2 1.54inchの表示
display2.clearDisplay(); //何か表示されている場合に備えて表示クリア
display2.setTextSize(2); //フォントサイズは2(番目に小さい)
display2.setTextColor(SSD1306_WHITE); //色指定はできないが必要
display2.setCursor(20, 10); //テキストの表示開始位置
display2.print(F("TAMANEGI")); //表示文字列
display2.setCursor(25, 30);
display2.print(F("SSD1306"));
display2.setCursor(20, 50);
display2.print(F("1.54inch"));
display2.display(); //バッファ転送(表示)
//モニタ3 2.42inchの表示
display3.clearDisplay(); //何か表示されている場合に備えて表示クリア
display3.setTextSize(2); //フォントサイズは2(番目に小さい)
display3.setTextColor(SSD1306_WHITE); //色指定はできないが必要
display3.setCursor(20, 10); //テキストの表示開始位置
display3.print(F("TAMANEGI")); //表示文字列
display3.setCursor(25, 30);
display3.print(F("SSD1306"));
display3.setCursor(20, 50);
display3.print(F("2.42inch"));
display3.display(); //バッファ転送(表示)
}
void loop() {
}
結果
同じサイズのSPI OLEDを複数所有していないので、サイズ違いのSPIを使用しています。
I2Cはアドレスによりスレーブの識別をしていますが、SPIではCS(SS)によりスレーブの識別をしているので、IOの多く使用できる基板では多くのスレーブを使用することができます。
コメント
初歩的な質問ですみませんが、
Adafruit SSD1306 by Adafruit Ver2.5.1
Adafruit GFX Library Ver 1.11.1
をインストールしていますが、
コンパイルすると、以下のようにAVR固有の表現らしいところで、多数エラーが出ます。
Adafruit_SSD1306.cpp:45:6: error: expected unqualified-id before ‘const’
45 | (*(const unsigned char *)(addr)) ///< PROGMEM workaround for non-AVR
回避する方法はありませんでしょうか?
この行は AVR系とESP32, ESP8266以外のSocを搭載したボードを選択してコンパイルした時に実行される行と思います。
現象については使用されているライブラリバージョンと同じにしてRP2040搭載ボード(Raspberry Pi Pico)でコンパイルと実行をしましたが、当方にて同様のエラーは再現できていません。
念のため、AVR系(Arduino nano (ATMEGA328P)), ESP8266, ESP32-C3)でのコンパイルと実行をしましたが、エラーは再現できませんでした。
現在考えられる対策としては、エラーの再現ができていないのですが、\Documents\Arduino\libraries\Adafruit_SSD1306\Adafruit_SSD1306.cpp はご自身の環境のフォルダ名です)
C:\Users\
の 44行目を以下のようにコメントアウトすることで回避とはならないでしょうか? (フォルダの
//#define pgm_read_byte(addr)
(*(const unsigned char *)(addr)) ///< PROGMEM workaround for non-AVR もともとコンパイルエラーの無かった箇所ですが、Raspberry Pi Picoでは掲載サンプルが動作しました。 もしこの方法で回避できた場合、ライブラリ(Adafruit SSD1306)のバージョンを更新すると修正したファイルが上書きされてエラーが再発することが考えられますので、 同じ手順で修正されるのが良いかと思います。
ライブラリを再インストールすることで解消できました。ありがとうございました。