STM32F103を使ってみる

ILI9341のSPI-TFTライブラリ


Maple Core には2つのSPI TFTライブラリが含まれています。
@ Adafruit_ILI9341:SPI TFT ライブラリ(通常のSPI通信)
A Adafruit_ILI9341_STM:SPI TFTライブラリ(DMA転送によるSPI通信)

そこで、これらのライブラリを試してみました。
どちらのライブラリにも、examplesフォルダーに「graphicstest」と「stm32_graphicstest」が有りますが実 質同じです。

TFTモジュールとの結線は以下の様になります。
どちらのライブラリも同じ結線で動きます。
ILI9341 TFT STM32F103
Vcc 3.3V
Gnd Gnd
CS PB4(※1)
Reset PB3(※1)
D/C PA15(※1)
MOSI PA7(※2)
SCK PA5(※2)
LED 3.3V
MISO PA6(※2)

(※1)スケッチの以下の部分を変更することで好きなピンが使えます。
tftオブジェクトを初期化するときには必ずRSTピンを指定する必要が有ります。
#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

// For the Adafruit shield, these are the default.
#define TFT_CS         PB4                 
#define TFT_DC         PA15               
#define TFT_RST        PB3 

// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC
//Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
// If using the breakout, change pins as desired
//Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST); // Use hardware SPI

(※2)これらのピンは変更できません。

いつもの見慣れた画面が表示されますが、メチャクチャ早いです。
ビュンビュン表示が切り替わります。
Adafruit_ILI9341+graphicstestは色々なプラットフォームで動きます。
そこで、ESP-WROOM-02、UNOと処理速度を比べて見ました。
時間の単位はmicrosecondsです。

STM32F103(SPI版) STM32F103(SPI-DMA版) ESP-WROOM-02 Arduino UNO
Screen fill 705842 170778 2255980 2126412
Text 46723 30783 162806 236188
Lines 413007 153931 1621856 2240664
Horiz/Vert Lines 57334 15107 184861 179176
Rectangles (outline) 36807 10155 119662 118732
Rectangles (filled) 1465912 354919 4666803 4416408
Circles (filled) 224149 94395 768345 902776
Circles (outline) 178859 121121 707693 972052
Triangles (outline) 131026 34792 513731 711068
Triangles (filled) 473196 140148 1577506 1829404
Rounded rects (outline) 80083 43570 294545 370648
Rounded rects (filled) 1604185 400474 5127320 4895232

ESPやUNOと比べるとSPI版で3倍、DMA版だと1桁違います。
テキスト表示のデモは一瞬で終わります。
DMA版だと何をテストしているのかも分からないぐらいです。

立方体(Cube)をぐるぐる回すコードを見つけました。
DMA版で試してみましたが、ものすごい勢いで2つの立方体が回転します。
ちょっと感動します。Lチカの次にぜひ試して欲しいです。
/*
  立方体(Cube)が回転するデモ
*/

#include "SPI.h"
#include <Adafruit_GFX_AS.h>    // Core graphics library, with extra fonts.
#include <Adafruit_ILI9341_STM.h> // STM32 DMA Hardware-specific library

// For the Adafruit shield, these are the default.
#define TFT_CS         PB4                 
#define TFT_DC         PA15               
#define TFT_RST        PB3 

Adafruit_ILI9341_STM tft = Adafruit_ILI9341_STM(TFT_CS, TFT_DC, TFT_RST); // Use hardware SPI

const float sin_d[] = {
  0, 0.17, 0.34, 0.5, 0.64, 0.77, 0.87, 0.94, 0.98, 1, 0.98, 0.94,
  0.87, 0.77, 0.64, 0.5, 0.34, 0.17, 0, -0.17, -0.34, -0.5, -0.64,
  -0.77, -0.87, -0.94, -0.98, -1, -0.98, -0.94, -0.87, -0.77,
  -0.64, -0.5, -0.34, -0.17
};
const float cos_d[] = {
  1, 0.98, 0.94, 0.87, 0.77, 0.64, 0.5, 0.34, 0.17, 0, -0.17, -0.34,
  -0.5, -0.64, -0.77, -0.87, -0.94, -0.98, -1, -0.98, -0.94, -0.87,
  -0.77, -0.64, -0.5, -0.34, -0.17, 0, 0.17, 0.34, 0.5, 0.64, 0.77,
  0.87, 0.94, 0.98
};
const float d = 5;
float cube1_px[] = {
  -d,  d,  d, -d, -d,  d,  d, -d
};
float cube1_py[] = {
  -d, -d,  d,  d, -d, -d,  d,  d
};
float cube1_pz[] = {
  -d, -d, -d, -d,  d,  d,  d,  d
};

float cube1_p2x[] = {
  0, 0, 0, 0, 0, 0, 0, 0
};
float cube1_p2y[] = {
  0, 0, 0, 0, 0, 0, 0, 0
};

int cube1_r[] = {
  0, 0, 0
};
const float d2 = 10;
float cube2_px[] = {
  -d2,  d2,  d2, -d2, -d2,  d2,  d2, -d2
};
float cube2_py[] = {
  -d2, -d2,  d2,  d2, -d2, -d2,  d2,  d2
};
float cube2_pz[] = {
  -d2, -d2, -d2, -d2,  d2,  d2,  d2,  d2
};

float cube2_p2x[] = {
  0, 0, 0, 0, 0, 0, 0, 0
};
float cube2_p2y[] = {
  0, 0, 0, 0, 0, 0, 0, 0
};

int cube2_r[] = {
  0, 0, 0
};

uint16 cube1_x, cube1_y, cube2_x, cube2_y, cube1_color, cube2_color;


void cube(float *px, float *py, float *pz, float *p2x, float *p2y, int *r, uint16 *x, uint16 *y, uint16 *color) {

  for (int i = 0; i < 3; i++) {
    tft.drawLine(p2x[i], p2y[i], p2x[i + 1], p2y[i + 1], ILI9341_WHITE);
    tft.drawLine(p2x[i + 4], p2y[i + 4], p2x[i + 5], p2y[i + 5], ILI9341_WHITE);
    tft.drawLine(p2x[i], p2y[i], p2x[i + 4], p2y[i + 4], ILI9341_WHITE);
  }
  tft.drawLine(p2x[3], p2y[3], p2x[0], p2y[0], ILI9341_WHITE);
  tft.drawLine(p2x[7], p2y[7], p2x[4], p2y[4], ILI9341_WHITE);
  tft.drawLine(p2x[3], p2y[3], p2x[7], p2y[7], ILI9341_WHITE);

  r[0] = r[0] + 1;
  r[1] = r[1] + 1;
  if (r[0] == 36) r[0] = 0;
  if (r[1] == 36) r[1] = 0;
  if (r[2] == 36) r[2] = 0;
  for (int i = 0; i < 8; i++)
  {
    float px2 = px[i];
    float py2 = cos_d[r[0]] * py[i] - sin_d[r[0]] * pz[i];
    float pz2 = sin_d[r[0]] * py[i] + cos_d[r[0]] * pz[i];

    float px3 = cos_d[r[1]] * px2 + sin_d[r[1]] * pz2;
    float py3 = py2;
    float pz3 = -sin_d[r[1]] * px2 + cos_d[r[1]] * pz2;

    float ax = cos_d[r[2]] * px3 - sin_d[r[2]] * py3;
    float ay = sin_d[r[2]] * px3 + cos_d[r[2]] * py3;
    float az = pz3 - 190;

    p2x[i] = *x + ax * 500 / az;
    p2y[i] = *y + ay * 500 / az;
  }

  for (int i = 0; i < 3; i++) {
    tft.drawLine(p2x[i], p2y[i], p2x[i + 1], p2y[i + 1], *color);
    tft.drawLine(p2x[i + 4], p2y[i + 4], p2x[i + 5], p2y[i + 5], *color);
    tft.drawLine(p2x[i], p2y[i], p2x[i + 4], p2y[i + 4], *color);
  }
  tft.drawLine(p2x[3], p2y[3], p2x[0], p2y[0], *color);
  tft.drawLine(p2x[7], p2y[7], p2x[4], p2y[4], *color);
  tft.drawLine(p2x[3], p2y[3], p2x[7], p2y[7], *color);
}


void setup() {
  delay (1000);
  Serial.begin(9600);
  tft.begin();
  tft.fillScreen(ILI9341_WHITE);
  cube1_x = ((tft.width()) / 4);
  cube1_y = ((tft.height()) / 4);
  cube2_x = ((tft.width()) / 2);
  cube2_y = ((tft.height()) / 2);
  cube1_color = ILI9341_BLACK;
  cube2_color = ILI9341_RED;

  uint16 x = 0;
  for (uint32_t n = 247583650 ; n > 247400000 ; n--) {
    x = sqrt (n);
    cube(cube1_px, cube1_py, cube1_pz, cube1_p2x, cube1_p2y, cube1_r, &cube1_x, &cube1_y, &cube1_color);
    cube(cube2_px, cube2_py, cube2_pz, cube2_p2x, cube2_p2y, cube2_r, &cube2_x, &cube2_y, &cube2_color);
  }

}

void loop() {
}

このパフォーマンスならば動画再生も可能だと思います。
探したらこちらにBlue Pill+FT800モニターを使った高速描画のデモが有りました。
巨大な電源ユニットが使われています。

次回は8ビットパラレルTFTライブラリを紹介します。

続く...