小型カラー液晶SSD1331とAdafruit GFX ライブラリを使用してbitmapを表示する

Amazonで購入した小型カラー液晶[SSD1331](https://www.amazon.co.jp/HiLetgo-0-95%E3%82%A4%E3%83%B3%E3%83%81-SPI-OLED%E3%83%87%E3%82%A3%E3%82%B9%E3%83%97%E3%83%AC%E3%82%A4%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E3%83%95%E3%83%AB%E3%82%AB%E3%83%A9%E3%83%BC65K%E3%82%AB%E3%83%A9%E3%83%BCSSD1331-7%E3%83%94%E3%83%B3Arduino%E3%81%AB%E5%AF%BE%E5%BF%9C/dp/B0711RKXB5/ref=sr_1_1?s=industrial&ie=UTF8&qid=1541640606&sr=1-1&keywords=SSD1331)でビットマップを表示してみました。

![スクリーンショット 2018-11-08 10.30.55.png](https://qiita-image-store.s3.amazonaws.com/0/59911/864af9c7-d96c-0a13-7088-f421c6283e82.png)

簡単なアニメーションを表示したかったので、ループで [drawPixel()](https://learn.adafruit.com/adafruit-gfx-graphics-library/graphics-primitives)をまわすのではなく、[drawBitmap()](https://github.com/adafruit/Adafruit-GFX-Library/issues/131)で画像を一度に表示することにしました。

```
void drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h, uint16_t color);
```
drawBitmap()はあくまでも1bitの白黒画像に色をつけて表示する仕組みのようです。
bitmapに２値画像を渡して、1が立っている場所はcolorの色で表示し、0のところは元の色を残してスキップします。

ですので、カラー画像を表示するためには版画の多色刷りのようになんども色を変えてdrawBitmap()する必要があります。

例えば赤、茶、白で構成されたりんごの画像 ![apple.png](https://qiita-image-store.s3.amazonaws.com/0/59911/3429910c-172f-9ccc-0ba0-3bd624d2be63.png) を表示したい場合、

```
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,1,1,1,0,1,1,1,1,0,0,0,0,
0,0,1,1,1,0,1,0,0,1,0,1,1,1,0,0,
0,1,1,1,1,1,0,0,0,0,1,1,1,1,1,0,
0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,
0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,
0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,
0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,
0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,
0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,
0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,
0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,

0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,
0,0,0,0,0,1,0,1,1,0,1,0,0,0,0,0,
0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
```
のような２値画像データを用意し、左上→右下の順でMSB->LSB,MSB->LSB,,
のように8ピクセルごとのデータを作っていきます。

```math
nが[0,1]とすると、左上のピクセルが(n_0<<7),左上から右に８番目のピクセルが(n_7<<0)となります。
```

```math
data[0] = (n_0<<7)+(n_1<<6)+(n_2<<5)+(n_3<<4)+(n_4<<3)+(n_5<<2)+(n_6<<1)+(n_7<<0);
```

```
[apple_red]
0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0xF0,
0x3A,0x5C,0x7C,0x3E,0x7F,0xEE,0x7F,0xF6,
0x7F,0xF6,0x7F,0xF6,0x3F,0xFE,0x1F,0xFC,
0x1F,0xFC,0x07,0xF8,0x01,0xE0,0x00,0x00,

[apple_dkred]
0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,
0x05,0xA0,0x03,0xC0,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x40,0x00,0x20,0x00,
0x20,0x00,0x18,0x00,0x06,0x00,0x00,0x00,
```

```
void drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bgcolor);
```
引数を一つ増やしてbgcolorに値を渡すと、ピクセルのない場所はスキップではなくbgcolorで描画するようになります。なので今回は、

- 赤い部分を表示＆背景を白で表示
- 茶色部分を表示（それ以外はヌキ）

の2回描画することで背景含め３色の画像を表示しています。

```
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1331.h>
#include <SPI.h>

#define sclk 13
#define mosi 11
#define cs   10
#define rst  8
#define dc   9

// Color definitions
#define RED             0xF800
#define DKRED           0x7000
#define WHITE           0xFFFF

#define PIC_SIZE_X (16)
#define PIC_SIZE_Y (16)

Adafruit_SSD1331 display = Adafruit_SSD1331(cs, dc, rst);

void setup(void) {
  display.begin();

  const uint8_t apple_red[] PROGMEM = {
    0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0xF0,
    0x3A,0x5C,0x7C,0x3E,0x7F,0xEE,0x7F,0xF6,
    0x7F,0xF6,0x7F,0xF6,0x3F,0xFE,0x1F,0xFC,
    0x1F,0xFC,0x07,0xF8,0x01,0xE0,0x00,0x00,
  };
  const uint8_t apple_dkred[] PROGMEM = {
    0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,
    0x05,0xA0,0x03,0xC0,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x40,0x00,0x20,0x00,
    0x20,0x00,0x18,0x00,0x06,0x00,0x00,0x00,
  };

  display.fillScreen(DKRED);
  display.drawBitmap(0, 0, (uint8_t*)apple_red, PIC_SIZE_X, PIC_SIZE_Y,  RED,WHITE);
  display.drawBitmap(0, 0, (uint8_t*)apple_dkred, PIC_SIZE_X, PIC_SIZE_Y, DKRED);
}

void loop() {
}
```
![IMG_6028.jpg](https://qiita-image-store.s3.amazonaws.com/0/59911/f51434eb-9d3b-6f7e-7bb6-1cc057997d2a.jpeg)

少し時間を置いてから別の画像を表示すればアニメーションとして表示が可能です
[Youtube](https://www.youtube.com/watch?v=uXAj-pl6QoA)

[追記]
秋葉原ラジオデパート3FのShigezoneで売っていた[bluepillクローン](https://www.amazon.co.jp/VKLSVAN-STM32F103C8T6-Minimum-%E9%96%8B%E7%99%BA%E3%83%9C%E3%83%BC%E3%83%89%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB-Arduino%E3%81%A8%E4%BA%92%E6%8F%9B/dp/B0811D7DR2/ref=sr_1_2?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&keywords=stm32&qid=1580349589&s=electronics&sr=1-2)でも表示してみました。

```
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1331.h>
#include <SPI.h>

// You can use any (4 or) 5 pins 
#define sclk PB9 //13
#define mosi PB8 //11
#define rst  PB7 //8
#define dc   PB6 //9
#define cs   PB5 //10

// Color definitions
#define RED             0xF800
#define DKRED           0x7000
#define WHITE           0xFFFF

#define PIC_SIZE_X (16)
#define PIC_SIZE_Y (16)

// Option 1: use any pins but a little slower
Adafruit_SSD1331 display = Adafruit_SSD1331(cs, dc, mosi, sclk, rst);  
//Adafruit_SSD1331 display = Adafruit_SSD1331(cs, dc, rst);

void setup(void) {
  pinMode(7, OUTPUT); // for Vcc
  digitalWrite(7, HIGH);
  
  display.begin();

  const uint8_t apple_red[] PROGMEM = {
    0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0xF0,
    0x3A,0x5C,0x7C,0x3E,0x7F,0xEE,0x7F,0xF6,
    0x7F,0xF6,0x7F,0xF6,0x3F,0xFE,0x1F,0xFC,
    0x1F,0xFC,0x07,0xF8,0x01,0xE0,0x00,0x00,
  };
  const uint8_t apple_dkred[] PROGMEM = {
    0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,
    0x05,0xA0,0x03,0xC0,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x40,0x00,0x20,0x00,
    0x20,0x00,0x18,0x00,0x06,0x00,0x00,0x00,
  };

  display.fillScreen(DKRED);
  display.drawBitmap(0, 0, (uint8_t*)apple_red, PIC_SIZE_X, PIC_SIZE_Y,  RED,WHITE);
  display.drawBitmap(0, 0, (uint8_t*)apple_dkred, PIC_SIZE_X, PIC_SIZE_Y, DKRED);
}

void loop() {
}
```

スケッチは液晶をそのままボードに挿せるよう、
高速のSPIモード
```Adafruit_SSD1331 display = Adafruit_SSD1331(cs, dc, rst);```
から低速のソフトウェアSPIモード
```Adafruit_SSD1331 display = Adafruit_SSD1331(cs, dc, mosi, sclk, rst);  ```
にしてピン番号を変えただけです。

また今回はPlatformIOでビルドしています。
BluePillクローンでビルドを通すために[こちらの処理](https://qiita.com/ELIXIR/items/d2dcbb4fe683f41e57e5)をしています。
また、必要なライブラリはPlatformIOのライブラリから
```Adafruit_GFX```
```Adafruit_SSD1331```
で検索すると出てくるのでポチッとインストールすればOKです。

![IMG_8655.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/6a252c41-2fd2-bf3a-8230-6e0c45f5d6a8.jpeg)