※現在、ブログ記事を移行中のため一部表示が崩れる場合がございます。
順次修正対応にあたっておりますので何卒ご了承いただけますよう、お願い致します。

Arduinoではオブジェクトの使い回しでメモリ不足を回避


2019年 07月 29日

128×64ドットで、多数jの文字を表示するのは、1画面ならOKだが、2画面だとダメだった。

ということで、次のような実験をした。

  1. 画面を128×64ではなく、128x32を指定してみた。
  2. 表示する文字数をぐっと半分以下に減らしてみた。

これだと、ディスプレイの上半分だけが使われるのだろうか。

プログラム全体を以下に示す。

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
#define OLED_RESET     4

Adafruit_SSD1306 display1(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_SSD1306 display2(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

void setup() {
Serial.begin(115200);
display1.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display2.begin(SSD1306_SWITCHCAPVCC, 0x3D);

displayText(display1, "Arduino is an open-source hardware and software company,"
"project and user community ");

displayText(display2, "that designs and manufactures "
"single-board microcontrollers and microcontroller kits " );
}

void loop() {

}

void displayText(Adafruit_SSD1306 disp, char* text) {
disp.setTextColor(WHITE);
disp.clearDisplay();
disp.setTextSize(1);
disp.setCursor(0,0);
disp.print(text);
disp.display();
}

すると、結果はこうなった。

OLED-128x32displa2.JPG

文字が縦に倍に伸ばされているようだ。1行の文字数には変化がない。

さて、どうして、128×64では動かず、128×32にしたら動いたのであろうか。

たぶん、以下のような理由ではないかと思う。

画面が128x64ドットということは、128×64 = 8192画素なので、モノクロ画面イメージを保持するには8192ビット、つまり1KBのメモリが必要になる。

すると、次の2行で、

Adafruit_SSD1306 display1(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_SSD1306 display2(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

2つのオブジェクトが作られ、各オブジェクトには画面イメージ1024バイト必要で、オブジェクトにはその他の値も少しは保持されるので、1オブジェクトが1KBよりやや大きいはずである。

ところで、Arduinoのメインメモリ(SRAM)は2048バイトしかない。

一部の特殊なものは多数のメモリを搭載している。例えば、Arduino Zeroは32ビットCPUのArmが載っていて、SRAM 32KBとなっている。Zeroがついていると、性能が落ちると思い込んではいけない。

ということは、それぞれの画面毎にオブジェクトを作ったら、それだけでメモリが足りなくなるので、動作しないのは当然だ。

それでも、それぞれの画面に、小さい字で8行表示したいと思い、次のように変更した。

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET     4

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

void setup() {
Serial.begin(115200);

displayText(0x3C,"Arduino is an open-source hardware and software company,"
"project and user community that designs and manufactures "
"single-board microcontrollers and microcontroller kits " );
displayText(0X3D,"for building digital devices and interactive objects "
"that can sense and control both physically and digitally.");
}

void loop() {
exit(0);
}

void displayText( int addr, char* text) {
display.begin(SSD1306_SWITCHCAPVCC, addr );
display.setTextColor(WHITE);
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0,0);
display.print(text);
display.display();
}

そして結果は、めでたくこうなった。

DSCN4799-400.JPG

要するに、オブジェクトは1つ作るだけで、displayText関数には、I2Cのアドレスと文字列を渡すことにした。

そして、displayText()では、最初に渡されたI2Cアドレスを指定して初期化してから表示処理をするようにした。

蛇足だが、このOLEDでは、送られてきた画面データはずっと保持されているので、最初のOLEDは放置して、次のOLEDの処理を行うことができる。

これを上手く使えば、多数のOLEDの表示を、1つのArduinoで制御できる。

OLEDの話が予定より長くなってしまった。次からは、別の話題にする。