GR-SAKURA
GR-KURUMI
GR-COTTON
GR-CITRUS
GR-PEACH
GR-KAEDE
GR-ADZUKI
GR-LYCHEE
GR-ROSE
GR-MANGO(*)
SNShield
Web Compiler
IDE for GR
TOPPERS関連
女子美コラボ
その他
※プロデューサミーティング中
作り方使い方資料
イベント関連
作品記事
体験記事
ライブラリ
ツール
その他・過去ファイル
がじぇるね岡宮です。
ルネナイ11を前にしてまとめサイトも作っておらずすみませんが、ちょっと遊んでしまいました。シールドはAmazonで買いました。4903円でした。
実は海外の方からお問合せがあり、GR-PEACHでILI9341が使えない→解決→スピードが出ない(0.2fpsぐらい)→5 fpsぐらい出せた、というものです。AdafruitのGitHubライブラリから若干変更が必要でしたので、こちらに添付したいと思います。少し嵌りました。320 x 240だと思ったら、240 x 320のため画像の回転が必要になりました。
遊んではいたのですが、GR-LYCHEEのライブラリにCameraクラスを追加して、必要になりそうなメンバー関数などを考えてました。今週中6/15までに一度V-upしたいと思います。
https://www.youtube.com/watch?v=9evulLSi32w
#include "Arduino.h"#include "Adafruit_GFX.h"#include "Adafruit_ILI9341.h"#include "camera_if.h"#define TFT_DC 9#define TFT_CS 10// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DCAdafruit_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);uint16_t buf_rgb565[VIDEO_PIXEL_HW * VIDEO_PIXEL_VW];void yuv2rgb565(unsigned char *in_adr, unsigned char *out_adr, int w, int h) { int y0, y1, u, v; int r, g, b; for (int i = 0; i < h; i++) { for (int j = 0; j < (w*2); j += 4) { y0 = (int)*in_adr; in_adr++; u = (int)*in_adr; in_adr++; y1 = (int)*in_adr; in_adr++; v = (int)*in_adr; in_adr++; r = (int) ((y0 - 16) + (1.370705 * (v - 128))); g = (int) ((y0 - 16) - (0.698001 * (v - 128)) - (0.337633 * (u - 128))); b = (int) ((y0 - 16) + (1.732446 * (u - 128))); if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255; if (r < 0) r = 0; if (g < 0) g = 0; if (b < 0) b = 0; *out_adr = (uint8_t)(((g << 3) & 0xe0) | ((b >> 3) & 0x1f)); out_adr++; *out_adr = (uint8_t)((r & 0xF8) | ((g >> 5) & 0x07)); out_adr++; r = (int) ((y1 - 16) + (1.370705 * (v - 128))); g = (int) ((y1 - 16) - (0.698001 * (v - 128)) - (0.337633 * (u - 128))); b = (int) ((y1 - 16) + (1.732446 * (u - 128))); if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255; if (r < 0) r = 0; if (g < 0) g = 0; if (b < 0) b = 0; *out_adr = (uint8_t)(((g << 3) & 0xe0) | ((b >> 3) & 0x1f)); out_adr++; *out_adr = (uint8_t)((r & 0xF8) | ((g >> 5) & 0x07)); out_adr++; } }}void rgb565_rotate90(uint16_t *in_adr, int w, int h){ uint16_t* buf; buf = (uint16_t*)malloc(sizeof(uint16_t)*w*h); memcpy(buf, in_adr, sizeof(uint16_t)*w*h); for(uint16_t i = 0; i < w; i++){ for(uint16_t j = 0; j < h; j++){ in_adr[i*h+j] = buf[w*(h-j-1)+i]; } } free(buf);}void setup() { Serial.begin(9600); tft.begin(); camera_start(); Serial.println("start");}void loop(void) { uint8_t* buf_yuv; static unsigned long old_time; old_time = millis(); buf_yuv = get_image_adr(); yuv2rgb565(buf_yuv, (uint8_t*)buf_rgb565, VIDEO_PIXEL_HW, VIDEO_PIXEL_VW); rgb565_rotate90(buf_rgb565, VIDEO_PIXEL_HW, VIDEO_PIXEL_VW); tft.drawRGBBitmap((int16_t)0, (int16_t)0, (uint16_t*)buf_rgb565, (int16_t)VIDEO_PIXEL_VW, (int16_t)VIDEO_PIXEL_HW); Serial.print((float)1/(millis()-old_time)*1000); Serial.println(" fps");#if 0 // slow in use of writePixel for(uint16_t i = 0; i < VIDEO_PIXEL_VW; i++){ for(uint16_t j = 0; j < VIDEO_PIXEL_HW; j++){ tft.writePixel(i,j,buf_rgb565[j+i*VIDEO_PIXEL_HW]); } }#endif}
すみません、試したのがV0.04の頃ですね。
以下のプログラムで試してみていただけますか。手元にシールドなく、試してはないです。
#include "Arduino.h"#include "Camera.h"#include "Adafruit_GFX.h"#include "Adafruit_ILI9341.h"#define VIDEO_PIXEL_HW 320#define VIDEO_PIXEL_VW 240#define TFT_DC 9#define TFT_CS 10// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DCAdafruit_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);uint16_t buf_rgb565[VIDEO_PIXEL_HW * VIDEO_PIXEL_VW];Camera camera(VIDEO_PIXEL_HW, VIDEO_PIXEL_VW);void yuv2rgb565(unsigned char *in_adr, unsigned char *out_adr, int w, int h) { int y0, y1, u, v; int r, g, b; for (int i = 0; i < h; i++) { for (int j = 0; j < (w*2); j += 4) { y0 = (int)*in_adr; in_adr++; u = (int)*in_adr; in_adr++; y1 = (int)*in_adr; in_adr++; v = (int)*in_adr; in_adr++; r = (int) ((y0 - 16) + (1.370705 * (v - 128))); g = (int) ((y0 - 16) - (0.698001 * (v - 128)) - (0.337633 * (u - 128))); b = (int) ((y0 - 16) + (1.732446 * (u - 128))); if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255; if (r < 0) r = 0; if (g < 0) g = 0; if (b < 0) b = 0; *out_adr = (uint8_t)(((g << 3) & 0xe0) | ((b >> 3) & 0x1f)); out_adr++; *out_adr = (uint8_t)((r & 0xF8) | ((g >> 5) & 0x07)); out_adr++; r = (int) ((y1 - 16) + (1.370705 * (v - 128))); g = (int) ((y1 - 16) - (0.698001 * (v - 128)) - (0.337633 * (u - 128))); b = (int) ((y1 - 16) + (1.732446 * (u - 128))); if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255; if (r < 0) r = 0; if (g < 0) g = 0; if (b < 0) b = 0; *out_adr = (uint8_t)(((g << 3) & 0xe0) | ((b >> 3) & 0x1f)); out_adr++; *out_adr = (uint8_t)((r & 0xF8) | ((g >> 5) & 0x07)); out_adr++; } }}void rgb565_rotate90(uint16_t *in_adr, int w, int h){ uint16_t* buf; buf = (uint16_t*)malloc(sizeof(uint16_t)*w*h); memcpy(buf, in_adr, sizeof(uint16_t)*w*h); for(uint16_t i = 0; i < w; i++){ for(uint16_t j = 0; j < h; j++){ in_adr[i*h+j] = buf[w*(h-j-1)+i]; } } free(buf);}void setup() { Serial.begin(9600); tft.begin(); camera.begin(); Serial.println("start");}void loop(void) { uint8_t* buf_yuv; static unsigned long old_time; old_time = millis(); buf_yuv = camera.getImageAdr(); yuv2rgb565(buf_yuv, (uint8_t*)buf_rgb565, VIDEO_PIXEL_HW, VIDEO_PIXEL_VW); rgb565_rotate90(buf_rgb565, VIDEO_PIXEL_HW, VIDEO_PIXEL_VW); tft.drawRGBBitmap((int16_t)0, (int16_t)0, (uint16_t*)buf_rgb565, (int16_t)VIDEO_PIXEL_VW, (int16_t)VIDEO_PIXEL_HW); Serial.print((float)1/(millis()-old_time)*1000); Serial.println(" fps");#if 0 // slow in use of writePixel for(uint16_t i = 0; i < VIDEO_PIXEL_VW; i++){ for(uint16_t j = 0; j < VIDEO_PIXEL_HW; j++){ tft.writePixel(i,j,buf_rgb565[j+i*VIDEO_PIXEL_HW]); } }#endif}
今、SAKURAでAdafruitオリジナルのライブラリを動作させたところ、そのまま動きました。CITRUSでも配線間違えなければ動くと思います。
以下はAdafruitのサイト、GithubからおとしてZIP化したものです。RZ用に変更したのは、確かARM系でifdefがあり、適合していなかったためだったと思います。
/* GR-SAKURA Sketch Template V2.20 */#include <Arduino.h>/*************************************************** This is our GFX example for the Adafruit ILI9341 Breakout and Shield ----> www.adafruit.com/.../1651 Check out the links above for our tutorials and wiring diagrams These displays use SPI to communicate, 4 or 5 pins are required to interface (RST is optional) Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! Written by Limor Fried/Ladyada for Adafruit Industries. MIT license, all text above must be included in any redistribution ****************************************************/#include "SPI.h"#include "Adafruit_GFX.h"#include "Adafruit_ILI9341.h"// For the Adafruit shield, these are the default.#define TFT_DC 9#define TFT_CS 10// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DCAdafruit_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);unsigned long testFillScreen() { unsigned long start = micros(); tft.fillScreen(ILI9341_BLACK); yield(); tft.fillScreen(ILI9341_RED); yield(); tft.fillScreen(ILI9341_GREEN); yield(); tft.fillScreen(ILI9341_BLUE); yield(); tft.fillScreen(ILI9341_BLACK); yield(); return micros() - start;}unsigned long testText() { tft.fillScreen(ILI9341_BLACK); unsigned long start = micros(); tft.setCursor(0, 0); tft.setTextColor(ILI9341_WHITE); tft.setTextSize(1); tft.println("Hello World!"); tft.setTextColor(ILI9341_YELLOW); tft.setTextSize(2); tft.println(1234.56); tft.setTextColor(ILI9341_RED); tft.setTextSize(3); tft.println(0xDEADBEEF, HEX); tft.println(); tft.setTextColor(ILI9341_GREEN); tft.setTextSize(5); tft.println("Groop"); tft.setTextSize(2); tft.println("I implore thee,"); tft.setTextSize(1); tft.println("my foonting turlingdromes."); tft.println("And hooptiously drangle me"); tft.println("with crinkly bindlewurdles,"); tft.println("Or I will rend thee"); tft.println("in the gobberwarts"); tft.println("with my blurglecruncheon,"); tft.println("see if I don't!"); return micros() - start;}unsigned long testLines(uint16_t color) { unsigned long start, t; int x1, y1, x2, y2, w = tft.width(), h = tft.height(); tft.fillScreen(ILI9341_BLACK); yield(); x1 = y1 = 0; y2 = h - 1; start = micros(); for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color); x2 = w - 1; for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color); t = micros() - start; // fillScreen doesn't count against timing yield(); tft.fillScreen(ILI9341_BLACK); yield(); x1 = w - 1; y1 = 0; y2 = h - 1; start = micros(); for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color); x2 = 0; for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color); t += micros() - start; yield(); tft.fillScreen(ILI9341_BLACK); yield(); x1 = 0; y1 = h - 1; y2 = 0; start = micros(); for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color); x2 = w - 1; for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color); t += micros() - start; yield(); tft.fillScreen(ILI9341_BLACK); yield(); x1 = w - 1; y1 = h - 1; y2 = 0; start = micros(); for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color); x2 = 0; for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color); yield(); return micros() - start;}unsigned long testFastLines(uint16_t color1, uint16_t color2) { unsigned long start; int x, y, w = tft.width(), h = tft.height(); tft.fillScreen(ILI9341_BLACK); start = micros(); for(y=0; y<h; y+=5) tft.drawFastHLine(0, y, w, color1); for(x=0; x<w; x+=5) tft.drawFastVLine(x, 0, h, color2); return micros() - start;}unsigned long testRects(uint16_t color) { unsigned long start; int n, i, i2, cx = tft.width() / 2, cy = tft.height() / 2; tft.fillScreen(ILI9341_BLACK); n = min(tft.width(), tft.height()); start = micros(); for(i=2; i<n; i+=6) { i2 = i / 2; tft.drawRect(cx-i2, cy-i2, i, i, color); } return micros() - start;}unsigned long testFilledRects(uint16_t color1, uint16_t color2) { unsigned long start, t = 0; int n, i, i2, cx = tft.width() / 2 - 1, cy = tft.height() / 2 - 1; tft.fillScreen(ILI9341_BLACK); n = min(tft.width(), tft.height()); for(i=n; i>0; i-=6) { i2 = i / 2; start = micros(); tft.fillRect(cx-i2, cy-i2, i, i, color1); t += micros() - start; // Outlines are not included in timing results tft.drawRect(cx-i2, cy-i2, i, i, color2); yield(); } return t;}unsigned long testFilledCircles(uint8_t radius, uint16_t color) { unsigned long start; int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2; tft.fillScreen(ILI9341_BLACK); start = micros(); for(x=radius; x<w; x+=r2) { for(y=radius; y<h; y+=r2) { tft.fillCircle(x, y, radius, color); } } return micros() - start;}unsigned long testCircles(uint8_t radius, uint16_t color) { unsigned long start; int x, y, r2 = radius * 2, w = tft.width() + radius, h = tft.height() + radius; // Screen is not cleared for this one -- this is // intentional and does not affect the reported time. start = micros(); for(x=0; x<w; x+=r2) { for(y=0; y<h; y+=r2) { tft.drawCircle(x, y, radius, color); } } return micros() - start;}unsigned long testTriangles() { unsigned long start; int n, i, cx = tft.width() / 2 - 1, cy = tft.height() / 2 - 1; tft.fillScreen(ILI9341_BLACK); n = min(cx, cy); start = micros(); for(i=0; i<n; i+=5) { tft.drawTriangle( cx , cy - i, // peak cx - i, cy + i, // bottom left cx + i, cy + i, // bottom right tft.color565(i, i, i)); } return micros() - start;}unsigned long testFilledTriangles() { unsigned long start, t = 0; int i, cx = tft.width() / 2 - 1, cy = tft.height() / 2 - 1; tft.fillScreen(ILI9341_BLACK); start = micros(); for(i=min(cx,cy); i>10; i-=5) { start = micros(); tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i, tft.color565(0, i*10, i*10)); t += micros() - start; tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i, tft.color565(i*10, i*10, 0)); yield(); } return t;}unsigned long testRoundRects() { unsigned long start; int w, i, i2, cx = tft.width() / 2 - 1, cy = tft.height() / 2 - 1; tft.fillScreen(ILI9341_BLACK); w = min(tft.width(), tft.height()); start = micros(); for(i=0; i<w; i+=6) { i2 = i / 2; tft.drawRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(i, 0, 0)); } return micros() - start;}unsigned long testFilledRoundRects() { unsigned long start; int i, i2, cx = tft.width() / 2 - 1, cy = tft.height() / 2 - 1; tft.fillScreen(ILI9341_BLACK); start = micros(); for(i=min(tft.width(), tft.height()); i>20; i-=6) { i2 = i / 2; tft.fillRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(0, i, 0)); yield(); } return micros() - start;}void setup() { Serial.begin(9600); Serial.println("ILI9341 Test!"); tft.begin(); // read diagnostics (optional but can help debug problems) uint8_t x = tft.readcommand8(ILI9341_RDMODE); Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX); x = tft.readcommand8(ILI9341_RDMADCTL); Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX); x = tft.readcommand8(ILI9341_RDPIXFMT); Serial.print("Pixel Format: 0x"); Serial.println(x, HEX); x = tft.readcommand8(ILI9341_RDIMGFMT); Serial.print("Image Format: 0x"); Serial.println(x, HEX); x = tft.readcommand8(ILI9341_RDSELFDIAG); Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX); Serial.println(F("Benchmark Time (microseconds)")); delay(10); Serial.print(F("Screen fill ")); Serial.println(testFillScreen()); delay(500); Serial.print(F("Text ")); Serial.println(testText()); delay(3000); Serial.print(F("Lines ")); Serial.println(testLines(ILI9341_CYAN)); delay(500); Serial.print(F("Horiz/Vert Lines ")); Serial.println(testFastLines(ILI9341_RED, ILI9341_BLUE)); delay(500); Serial.print(F("Rectangles (outline) ")); Serial.println(testRects(ILI9341_GREEN)); delay(500); Serial.print(F("Rectangles (filled) ")); Serial.println(testFilledRects(ILI9341_YELLOW, ILI9341_MAGENTA)); delay(500); Serial.print(F("Circles (filled) ")); Serial.println(testFilledCircles(10, ILI9341_MAGENTA)); Serial.print(F("Circles (outline) ")); Serial.println(testCircles(10, ILI9341_WHITE)); delay(500); Serial.print(F("Triangles (outline) ")); Serial.println(testTriangles()); delay(500); Serial.print(F("Triangles (filled) ")); Serial.println(testFilledTriangles()); delay(500); Serial.print(F("Rounded rects (outline) ")); Serial.println(testRoundRects()); delay(500); Serial.print(F("Rounded rects (filled) ")); Serial.println(testFilledRoundRects()); delay(500); Serial.println(F("Done!"));}void loop(void) { for(uint8_t rotation=0; rotation<4; rotation++) { tft.setRotation(rotation); testText(); delay(1000); }}
いや、GR-LYCHEEでも基本的に直下、あるいはフォルダを作ってその下にライブラリを置くという運用です。GR-LYCHEEのプロデューサミーティング用ボードと思いますので、V0.07のテンプレートで試してみていただきたいです。
GRボード全般的にテンプレートには以下のReadme.txtを付けており、その中の注意事項に記載の通り「gr_common下には置かないでください」としています。2017年の8月~9月にかけて適用しています。
ーーーーーーーーーーーーーーーーーーーーー
Webコンパイラのビルドは以下の手順で行われます。
1.makefileを生成 ルート以下全てのフォルダを検索してインクルードパスとして指定する。 ルート以下全てのソースファイル(.c, .cpp)をオブジェクト(.o)として指定する。 ルート以下全てのライブラリ(.a)をリンク対象として指定する。
2.makeの実行 生成されたmakefileでmakeする。これによって書き込み用のbinファイルが生成される。 gr_common以下のオブジェクト(.o)はgr_common.aとしてアーカイブ化する。 gr_common.aがすでにあれば、gr_common以外のソースだけコンパイルしてリンクする。(★これでビルド速度の改善を図ってます)
注意事項:・ソースやライブラリを追加する場合、gr_buildやgr_commonフォルダ内には配置しないでください。 それ以外の場所に配置すれば、上記手順の1にてインクルードパス、オブジェクトの指定が行われます。・gr_common内のライブラリを編集する場合、gr_common.aを削除することで編集が有効になります。・ルートにあるmakefileは自動生成されるため、編集しても無効となります。