STM32F103を使ってみる

ILI9341の8ビットパラレルTFTライブラリ


こちらにIL9341 8ビットパラレルTFT用のライブラリが公開されています。
@ https://github.com/iwalpola/Adafruit_ILI9341_8bit_STM
A https://github.com/stevstrong/Adafruit_TFTLCD_8bit_STM32

この2つの違いは使用するピンの違いです。

@ https://github.com/iwalpola/Adafruit_ILI9341_8bit_STM
8 bit parallel interface
Port data |D7 |D6 |D5 |D4 |D3 |D2 |D1 |D0 |
Pin stm32 |PA7|PA6|PA5|PA4|PA3|PA2|PA1|PA0|

Control Pins
Control pins |RD |WR |RS |CS |RST|
Pin stm32 |PB4|PB5|PB6|PB7|PB8|

A https://github.com/stevstrong/Adafruit_TFTLCD_8bit_STM32
8 bit parallel interface
Port data |D7 |D6 |D5 |D4 |D3 |D2 |D1 |D0 |
Pin stm32 |PB7|PB6|PB5|PB4|PB3|PB2|PB1|PB0|
または
Port data |D7 |D6 |D5 |D4 |D3 |D2 |D1 |D0 |
Pin stm32 |PB15|PB14|PB13|PB12|PB11|PB10|PB9|PB8|

Control Pins
Control pins |RD |WR |RS |CS |RST|
Pin stm32 |PA0|PA1|PA2|PA3|PB10|

@はデータI/FにPAラインを、AはPBラインを使います。
PB2はBOOT1セレクターとして使われますが、BOOT0セレクターがGNDの時は、
普通のディジタルピンとして、Lチカが動きます。

Aをコンパイルする為には <libmaple/gpio.h> が必要になります。
これがどこにあるのか分からなかったので今回は@のライブラリを使い
examplesフォルダーにあるgraphicstest.inoを試してみました。
TFTは5V仕様のものを使い、BluePillの5Vピンから給電しています。

いつもの見慣れた画面が表示されます。
同じ8ビットパラレルTFTを使って、UNOと処理速度を比べて見ました。
前回試したSPI版も比較のために掲載します。
時間の単位はmicrosecondsです。

STM32F103(SPI) STM32F103(SPI-DMA) STM32F103(8Bit) Arduino UNO(8Bit)
Screen fill 705842 170778 315797 1379560
Text 46723 30783 26873 344024
Lines 413007 153931 127669 3390180
Horiz/Vert Lines 57334 15107 24582 144664
Rectangles (outline) 36807 10155 15937 104260
Rectangles (filled) 1465912 354919 656000 3267476
Circles (filled) 224149 94395 105220 1211484
Circles (outline) 178859 121121 94079 1475108
Triangles (outline) 131026 34792 30080 1075596
Triangles (filled) 473196 140148 209074 1721636
Rounded rects (outline) 80083 43570 39953 506428
Rounded rects (filled) 1604185 400474 708444 3795228

8ビットパラレル版はSPI-DMA版とSPI版の中間の処理速度となりました。
同じ8ビットでUNOと比べると1桁違います。
スケッチのサイズは結構大きくなりますが、フラッシュメモリのサイズが大きいのでUNOに比べてフラッシュの使用率は下ります。

STM32F103
最大65536バイトのフラッシュメモリのうち、スケッチが32156バイト(49%)を使っています。
最大20480バイトのRAMのうち、グローバル変数が4600バイト(22%)を使っていて、ローカル変数で15880バイト使うことができま す。

UNO
最大32256バイトのフラッシュメモリのうち、スケッチが19866バイト(61%)を使っています。
最大2048バイトのRAMのうち、グローバル変数が494バイト(24%)を使っていて、ローカル変数で1554バイト使うことができます。

以下の立方体(Cube)をぐるぐる回すコードも、ライブラリを変更するだけで動きました。
こちらも、ものすごい勢いで2つの立方体が回転します。
/*
  立方体(Cube)が回転するデモ
*/

#include <Adafruit_GFX.h>
#include "Adafruit_ILI9341_8bit_STM.h"

Adafruit_ILI9341_8bit_STM tft = Adafruit_ILI9341_8bit_STM();

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() {
}

次回はレジスター操作による高速Lチカを紹介します。

続く...