ArduinoでaitendoのTFT液晶(M-Z18SPI-2PB)を制御するライブラリを作成するための調査(2)

投稿者: | 2017年12月20日

はじめに

Adafruitライブラリのソースコードと、ST7735Sのデータシートから液晶モジュールの制御方法を調べます。後に思い出しやすいように、結果だけでなく過程を含めてまとめます。

調査

ソースコードの取得

まず、二つのライブラリのソースコードを取得します。過去のログなども確認したいので、zipファイルではなくgithubからクローンします。

ringo@stupiddog  $ git clone https://github.com/adafruit/Adafruit-ST7735-Library.git 
Cloning into 'Adafruit-ST7735-Library'...
remote: Counting objects: 461, done.
remote: Total 461 (delta 0), reused 0 (delta 0), pack-reused 461
Receiving objects: 100% (461/461), 146.80 KiB | 168.00 KiB/s, done.
Resolving deltas: 100% (198/198), done.

ringo@stupiddog  $ git clone https://github.com/adafruit/Adafruit-GFX-Library.git 
Cloning into 'Adafruit-GFX-Library'...
remote: Counting objects: 400, done.
remote: Total 400 (delta 0), reused 0 (delta 0), pack-reused 400
Receiving objects: 100% (400/400), 427.18 KiB | 187.00 KiB/s, done.
Resolving deltas: 100% (203/203), done.

ファイル構成の確認

ファイル構成は以下のようになっています。

ringo@stupiddog  $ tree  -F ./
./
├── Adafruit-GFX-Library/
│   ├── Adafruit_GFX.cpp*
│   ├── Adafruit_GFX.h*
│   ├── Adafruit_SPITFT.cpp
│   ├── Adafruit_SPITFT.h
│   ├── Adafruit_SPITFT_Macros.h
│   ├── Fonts/
│   │   ├── FreeMono12pt7b.h
│   │   ├── FreeMono18pt7b.h
│   │   ├── FreeMono24pt7b.h
│   │   ├── FreeMono9pt7b.h
│   │   ├── FreeMonoBold12pt7b.h
│   │   ├── FreeMonoBold18pt7b.h
│   │   ├── FreeMonoBold24pt7b.h
│   │   ├── FreeMonoBold9pt7b.h
│   │   ├── FreeMonoBoldOblique12pt7b.h
│   │   ├── FreeMonoBoldOblique18pt7b.h
│   │   ├── FreeMonoBoldOblique24pt7b.h
│   │   ├── FreeMonoBoldOblique9pt7b.h
│   │   ├── FreeMonoOblique12pt7b.h
│   │   ├── FreeMonoOblique18pt7b.h
│   │   ├── FreeMonoOblique24pt7b.h
│   │   ├── FreeMonoOblique9pt7b.h
│   │   ├── FreeSans12pt7b.h
│   │   ├── FreeSans18pt7b.h
│   │   ├── FreeSans24pt7b.h
│   │   ├── FreeSans9pt7b.h
│   │   ├── FreeSansBold12pt7b.h
│   │   ├── FreeSansBold18pt7b.h
│   │   ├── FreeSansBold24pt7b.h
│   │   ├── FreeSansBold9pt7b.h
│   │   ├── FreeSansBoldOblique12pt7b.h
│   │   ├── FreeSansBoldOblique18pt7b.h
│   │   ├── FreeSansBoldOblique24pt7b.h
│   │   ├── FreeSansBoldOblique9pt7b.h
│   │   ├── FreeSansOblique12pt7b.h
│   │   ├── FreeSansOblique18pt7b.h
│   │   ├── FreeSansOblique24pt7b.h
│   │   ├── FreeSansOblique9pt7b.h
│   │   ├── FreeSerif12pt7b.h
│   │   ├── FreeSerif18pt7b.h
│   │   ├── FreeSerif24pt7b.h
│   │   ├── FreeSerif9pt7b.h
│   │   ├── FreeSerifBold12pt7b.h
│   │   ├── FreeSerifBold18pt7b.h
│   │   ├── FreeSerifBold24pt7b.h
│   │   ├── FreeSerifBold9pt7b.h
│   │   ├── FreeSerifBoldItalic12pt7b.h
│   │   ├── FreeSerifBoldItalic18pt7b.h
│   │   ├── FreeSerifBoldItalic24pt7b.h
│   │   ├── FreeSerifBoldItalic9pt7b.h
│   │   ├── FreeSerifItalic12pt7b.h
│   │   ├── FreeSerifItalic18pt7b.h
│   │   ├── FreeSerifItalic24pt7b.h
│   │   ├── FreeSerifItalic9pt7b.h
│   │   ├── Org_01.h
│   │   ├── Picopixel.h
│   │   ├── Tiny3x3a2pt7b
│   │   └── TomThumb.h
│   ├── README.md
│   ├── fontconvert/
│   │   ├── Makefile
│   │   ├── fontconvert.c
│   │   ├── fontconvert_win.md
│   │   └── makefonts.sh*
│   ├── gfxfont.h
│   ├── glcdfont.c
│   ├── library.properties
│   └── license.txt
└── Adafruit-ST7735-Library/
    ├── Adafruit_ST7735.cpp*
    ├── Adafruit_ST7735.h*
    ├── README.txt
    ├── examples/
    │   ├── graphicstest/
    │   │   └── graphicstest.ino
    │   ├── rotationtest/
    │   │   └── rotationtest.ino
    │   ├── shieldtest/
    │   │   └── shieldtest.ino
    │   ├── soft_spitftbitmap/
    │   │   └── soft_spitftbitmap.ino
    │   └── spitftbitmap/
    │       └── spitftbitmap.ino
    └── library.properties

10 directories, 75 files

ソースコードの解析

前回」の動作確認プログラムで取り込んだヘッダファイルは3つです。

  • gfxfont.h
  • Adafruit_GFX.h
  • Adafruit_ST7735.h

ここから探りを入れます。

備考:"Adafruit_SPITFT"から始まるファイルが3つありますが「前回」の後で追加されたもです。これ以外のファイルは変更されていないので調査から省きます。

クラス構成

Adafruit-GFX-Library – Adafruit_GFX.h

Adafruit-GFX-Libraryの"Adafruit_GFX.h"を覗くと、"class Adafruit_GFX : public Print {"が見つかります。その他のファイルの拡張子から、c++で記述されたライブラリだと分かります。また、"gfxfont.h"をインクルードしていることが分かります。

#ifndef _ADAFRUIT_GFX_H
#define _ADAFRUIT_GFX_H
  
#if ARDUINO >= 100
  #include "Arduino.h"
  #include "Print.h"
#else
  #include "WProgram.h"
#endif
#include "gfxfont.h"
  
class Adafruit_GFX : public Print {
...

"arduino class print"でググると、"How to Use the Print Class – Arduino Playground"とArduino公式サイトのドキュメントがヒットします。そこからPrintクラスはArduinoで提供しているクラスだと分かります。

ライブラリを作成していて、印刷機能(シリアルライブラリで使用されているものと同じもの)を使用したい場合は、良いニュースです。それらのすべては単に「プリント」と呼ばれるクラスで定義されています。

How to Use the Print Classからの引用(Google翻訳)

さらに"Adafruit_GFX.h"を確認すると、他にもクラスが見つかります。

class Adafruit_GFX_Button {
...
class GFXcanvas1 : public Adafruit_GFX {
...
class GFXcanvas8 : public Adafruit_GFX {
...
class GFXcanvas16 : public Adafruit_GFX {
...

Adafruit-ST7735-Library – Adafruit_ST7735

同様に、Adafruit-ST7735-Libraryの"Adafruit_ST7735.h"も覗いてみます。"Adafruit_GFX.h"をインクルードしていることが分かります。クラスは"Adafruit_ST7735"の1つだけが定義されています。

...
#ifndef _ADAFRUIT_ST7735H_
#define _ADAFRUIT_ST7735H_

#include "Arduino.h"
#include "Print.h"
#include <Adafruit_GFX.h>
...
class Adafruit_ST7735 : public Adafruit_GFX {
...

"Adafruit_ST7735"クラスは、"Adafruit_GFX"クラスを継承しています。そして、動作確認のコードでは"Adafruit_ST7735"クラスのインスタンスを生成して液晶の制御を行っています。

Adafruit-GFX-Library – gfxfont.h

最後に"gfxfont.h"を覗くと2つの構造体が定義されています。

#ifndef _GFXFONT_H_
#define _GFXFONT_H_

typedef struct { // Data stored PER GLYPH
	uint16_t bitmapOffset;     // Pointer into GFXfont->bitmap
	uint8_t  width, height;    // Bitmap dimensions in pixels
	uint8_t  xAdvance;         // Distance to advance cursor (x axis)
	int8_t   xOffset, yOffset; // Dist from cursor pos to UL corner
} GFXglyph;

typedef struct { // Data stored for FONT AS A WHOLE:
	uint8_t  *bitmap;      // Glyph bitmaps, concatenated
	GFXglyph *glyph;       // Glyph array
	uint8_t   first, last; // ASCII extents
	uint8_t   yAdvance;    // Newline distance (y axis)
} GFXfont;

"GFXfont"構造体の使用場所を探ります。

ringo@stupiddog  $ grep -r GFXfont --include={*.h,*.c,*.cpp} .
./Adafruit-GFX-Library/Adafruit_GFX.cpp:void Adafruit_GFX::setFont(const GFXfont *f) {
./Adafruit-GFX-Library/Adafruit_GFX.cpp:    gfxFont = (GFXfont *)f;
./Adafruit-GFX-Library/Adafruit_GFX.h:    setFont(const GFXfont *f = NULL),
./Adafruit-GFX-Library/Adafruit_GFX.h:  GFXfont
./Adafruit-GFX-Library/fontconvert/fontconvert.c:	printf("const GFXfont %s PROGMEM = {\n", fontName);
./Adafruit-GFX-Library/Fonts/FreeMono12pt7b.h:const GFXfont FreeMono12pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeMono18pt7b.h:const GFXfont FreeMono18pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeMono24pt7b.h:const GFXfont FreeMono24pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeMono9pt7b.h:const GFXfont FreeMono9pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeMonoBold12pt7b.h:const GFXfont FreeMonoBold12pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeMonoBold18pt7b.h:const GFXfont FreeMonoBold18pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeMonoBold24pt7b.h:const GFXfont FreeMonoBold24pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeMonoBold9pt7b.h:const GFXfont FreeMonoBold9pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeMonoBoldOblique12pt7b.h:const GFXfont FreeMonoBoldOblique12pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeMonoBoldOblique18pt7b.h:const GFXfont FreeMonoBoldOblique18pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeMonoBoldOblique24pt7b.h:const GFXfont FreeMonoBoldOblique24pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeMonoBoldOblique9pt7b.h:const GFXfont FreeMonoBoldOblique9pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeMonoOblique12pt7b.h:const GFXfont FreeMonoOblique12pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeMonoOblique18pt7b.h:const GFXfont FreeMonoOblique18pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeMonoOblique24pt7b.h:const GFXfont FreeMonoOblique24pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeMonoOblique9pt7b.h:const GFXfont FreeMonoOblique9pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSans12pt7b.h:const GFXfont FreeSans12pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSans18pt7b.h:const GFXfont FreeSans18pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSans24pt7b.h:const GFXfont FreeSans24pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSans9pt7b.h:const GFXfont FreeSans9pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSansBold12pt7b.h:const GFXfont FreeSansBold12pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSansBold18pt7b.h:const GFXfont FreeSansBold18pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSansBold24pt7b.h:const GFXfont FreeSansBold24pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSansBold9pt7b.h:const GFXfont FreeSansBold9pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSansBoldOblique12pt7b.h:const GFXfont FreeSansBoldOblique12pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSansBoldOblique18pt7b.h:const GFXfont FreeSansBoldOblique18pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSansBoldOblique24pt7b.h:const GFXfont FreeSansBoldOblique24pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSansBoldOblique9pt7b.h:const GFXfont FreeSansBoldOblique9pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSansOblique12pt7b.h:const GFXfont FreeSansOblique12pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSansOblique18pt7b.h:const GFXfont FreeSansOblique18pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSansOblique24pt7b.h:const GFXfont FreeSansOblique24pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSansOblique9pt7b.h:const GFXfont FreeSansOblique9pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSerif12pt7b.h:const GFXfont FreeSerif12pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSerif18pt7b.h:const GFXfont FreeSerif18pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSerif24pt7b.h:const GFXfont FreeSerif24pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSerif9pt7b.h:const GFXfont FreeSerif9pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSerifBold12pt7b.h:const GFXfont FreeSerifBold12pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSerifBold18pt7b.h:const GFXfont FreeSerifBold18pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSerifBold24pt7b.h:const GFXfont FreeSerifBold24pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSerifBold9pt7b.h:const GFXfont FreeSerifBold9pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSerifBoldItalic12pt7b.h:const GFXfont FreeSerifBoldItalic12pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSerifBoldItalic18pt7b.h:const GFXfont FreeSerifBoldItalic18pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSerifBoldItalic24pt7b.h:const GFXfont FreeSerifBoldItalic24pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSerifBoldItalic9pt7b.h:const GFXfont FreeSerifBoldItalic9pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSerifItalic12pt7b.h:const GFXfont FreeSerifItalic12pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSerifItalic18pt7b.h:const GFXfont FreeSerifItalic18pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSerifItalic24pt7b.h:const GFXfont FreeSerifItalic24pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/FreeSerifItalic9pt7b.h:const GFXfont FreeSerifItalic9pt7b PROGMEM = {
./Adafruit-GFX-Library/Fonts/Org_01.h:const GFXfont Org_01 PROGMEM = {
./Adafruit-GFX-Library/Fonts/Picopixel.h:const GFXfont Picopixel PROGMEM = {
./Adafruit-GFX-Library/Fonts/TomThumb.h:const GFXfont TomThumb PROGMEM = {
./Adafruit-GFX-Library/gfxfont.h:// file and pass address of GFXfont struct to setFont().  Pass NULL to
./Adafruit-GFX-Library/gfxfont.h:	uint16_t bitmapOffset;     // Pointer into GFXfont->bitmap
./Adafruit-GFX-Library/gfxfont.h:} GFXfont;

まず、サブディレクトリ"Fonts"以下で見つかった行の"const GFXfont 変数名 PROGMEM = {"から定数を定義していることが分かります。内容とコメントからフォントデータだと推測できます。

参考として"./Adafruit-GFX-Library/Fonts/TomThumb.h"から抜粋

#define TOMTHUMB_USE_EXTENDED 0

const uint8_t TomThumbBitmaps[] PROGMEM = {
   0x00,                                /* 0x20 space */
   0x80, 0x80, 0x80, 0x00, 0x80,        /* 0x21 exclam */
   0xA0, 0xA0,                          /* 0x22 quotedbl */
...
const GFXfont TomThumb PROGMEM = {
  (uint8_t  *)TomThumbBitmaps,
  (GFXglyph *)TomThumbGlyphs,
  0x20, 0x7E, 6 };
  

 

まとめ

ここまでに見つけたファイルとクラスをまとめると以下のようになります。"GFXFont"に関する処理は後回しにします。

ここから、"Adafruit_GFX"クラスと"Adafruit_ST7735"クラスを解析していきます。