shimodashのアイコン画像
shimodash 2023年05月07日作成 (2023年05月07日更新) © GPL-3.0+
セットアップや使用方法 セットアップや使用方法 閲覧数 1445
shimodash 2023年05月07日作成 (2023年05月07日更新) © GPL-3.0+ セットアップや使用方法 セットアップや使用方法 閲覧数 1445

1.3インチLCDをSPRESENSEで使ってみました

1.3インチLCDをSPRESENSEで使ってみました

目的

SPRESENSEのLCDパネルの使用例はインタフェースボードがILI9341の情報が沢山
あるのですが、自宅にある中国のECサイトで購入したST7789での情報が少なく
色々なコミュニティに聞きながらセットアップができたので、その情報を共有します。

また、このLCDは240x240ですのでカメラから変換した320x240の画像の一部のみ
を表示しています。カメラがどの部分を撮影しているか、大体の目安がわかる目的
に限定しています。

カメラ設定で240x180のがサイズに変更し表示をしています。

ハードウェア構成

No 品名 購入先 備考
1 SPRESENSEメインボード switchscience
2 SPRESENSE拡張ボード switchscience
3 SPRESENSEカメラ switchscience
4 1.3インチLCD (*1) aliexpress 当時の購入先
5 オスーメスジャンパワイヤ switchscience

(*1) CS端子がないLCDで少し特殊なLCDでした。

ソフトウェア開発

Arduino-IDEでの開発環境を使用しました。
SPRESENSEでのArduino開発について、公式サイトを参照下さい。
LCDのライブラリについては、Lovyan様のライブラリを使わせて頂きました。
また、昨年度のSPRESENSEコンテストでST7789を使用していたこちらも参考にさせて頂きました。

ソフト及び各ライブラリのバージョンは以下です。

No ソフトライブラリ バージョン 備考
1 Arduino-IDE 1.8.19
2 SPRESENSEライブラリ 3.0.1
3 LovyanGFX 1.1.6

LCDとの接続

個人的にはI2Cの接続と思うような端子名ですが
以下の様に接続をします。

No LCD端子名 拡張ボード接続先 端子番号 備考
1 GND GND -
2 VCC AREF -
3 SCK SPI4_SCK D13
4 SDA SPI4_MOSI D11
5 RES PWM2 D09
6 DC SPI2_MISO D08

設定ライブラリの変更

ライブラリの設定での注意点は以下です。

  • SPI_MODE3で動作
  • パネルの明暗を反転する設定が必要

SPRESENSE_sample.hpp

#pragma once #define LGFX_USE_V1 #include <LovyanGFX.hpp> // SPRESENSEでLovyanGFXを独自設定で利用する場合の設定例 /* このファイルを複製し、新しい名前を付けて、環境に合わせて設定内容を変更してください。 作成したファイルをユーザープログラムからincludeすることで利用可能になります。 複製したファイルはライブラリのlgfx_userフォルダに置いて利用しても構いませんが、 その場合はライブラリのアップデート時に削除される可能性があるのでご注意ください。 安全に運用したい場合はバックアップを作成しておくか、ユーザープロジェクトのフォルダに置いてください。 //*/ /// 独自の設定を行うクラスを、LGFX_Deviceから派生して作成します。 class LGFX : public lgfx::LGFX_Device { /* クラス名は"LGFX"から別の名前に変更しても構いません。 AUTODETECTと併用する場合は"LGFX"は使用されているため、LGFX以外の名前に変更してください。 また、複数枚のパネルを同時使用する場合もそれぞれに異なる名前を付けてください。 ※ クラス名を変更する場合はコンストラクタの名前も併せて同じ名前に変更が必要です。 名前の付け方は自由に決めて構いませんが、設定が増えた場合を想定し、 例えば SPRESENSE でSPI接続のILI9341の設定を行った場合、 LGFX_SPRESENSE_SPI_ILI9341 のような名前にし、ファイル名とクラス名を一致させておくことで、利用時に迷いにくくなります。 //*/ // 接続するパネルの型にあったインスタンスを用意します。 //lgfx::Panel_GC9A01 _panel_instance; //lgfx::Panel_GDEW0154M09 _panel_instance; //lgfx::Panel_HX8357B _panel_instance; //lgfx::Panel_HX8357D _panel_instance; //lgfx::Panel_ILI9163 _panel_instance; //lgfx::Panel_ILI9341 _panel_instance; //lgfx::Panel_ILI9342 _panel_instance; //lgfx::Panel_ILI9481 _panel_instance; //lgfx::Panel_ILI9486 _panel_instance; //lgfx::Panel_ILI9488 _panel_instance; //lgfx::Panel_IT8951 _panel_instance; //lgfx::Panel_SH110x _panel_instance; // SH1106, SH1107 //lgfx::Panel_SSD1306 _panel_instance; //lgfx::Panel_SSD1327 _panel_instance; //lgfx::Panel_SSD1331 _panel_instance; //lgfx::Panel_SSD1351 _panel_instance; // SSD1351, SSD1357 //lgfx::Panel_SSD1963 _panel_instance; //lgfx::Panel_ST7735 _panel_instance; //lgfx::Panel_ST7735S _panel_instance; lgfx::Panel_ST7789 _panel_instance; //lgfx::Panel_ST7796 _panel_instance; // SPIバスのインスタンスを用意します。 lgfx::Bus_SPI _bus_instance; // SPIバスのインスタンス public: // コンストラクタを作成し、ここで各種設定を行います。 // クラス名を変更した場合はコンストラクタも同じ名前を指定してください。 LGFX(void) { { // バス制御の設定を行います。 auto cfg = _bus_instance.config(); // バス設定用の構造体を取得します。 cfg.spi_mode = 3; // SPI通信モードを設定 (0 ~ 3) (*) cfg.freq_write = 30000000; // 送信時のSPIクロック cfg.freq_read = 16000000; // 受信時のSPIクロック cfg.pin_dc = 8; // SPIのD/Cピン番号を設定 (-1 = disable) cfg.spi_port = 4; // Arduino拡張ボードの場合は 4 _bus_instance.config(cfg); // 設定値をバスに反映します。 _panel_instance.setBus(&_bus_instance); // バスをパネルにセットします。 } { // 表示パネル制御の設定を行います。 auto cfg = _panel_instance.config(); // 表示パネル設定用の構造体を取得します。 // cfg.pin_cs = -1; // CSが接続されているピン番号 (-1 = disable) HW CSピンの場合は-1を指定 cfg.pin_rst = 9; // RSTが接続されているピン番号 (-1 = disable) cfg.pin_busy = -1; // BUSYが接続されているピン番号 (-1 = disable) // ※ 以下の設定値はパネル毎に一般的な初期値が設定されていますので、不明な項目はコメントアウトして試してみてください。 cfg.panel_width = 240; // 実際に表示可能な幅 cfg.panel_height = 240; // 実際に表示可能な高さ cfg.offset_x = 0; // パネルのX方向オフセット量 cfg.offset_y = 0; // パネルのY方向オフセット量 cfg.offset_rotation = 0; // 回転方向の値のオフセット 0~7 (4~7は上下反転) cfg.dummy_read_pixel = 8; // ピクセル読出し前のダミーリードのビット数 cfg.dummy_read_bits = 1; // ピクセル以外のデータ読出し前のダミーリードのビット数 cfg.readable = true; // データ読出しが可能な場合 trueに設定 cfg.invert = true; // パネルの明暗が反転してしまう場合 trueに設定(*) cfg.rgb_order = false; // パネルの赤と青が入れ替わってしまう場合 trueに設定 cfg.dlen_16bit = false; // データ長を16bit単位で送信するパネルの場合 trueに設定 cfg.bus_shared = true; // SDカードとバスを共有している場合 trueに設定(drawJpgFile等でバス制御を行います) // 以下はST7735やILI9163のようにピクセル数が変更できるドライバでのみ設定してください。 // cfg.memory_width = 240; // ドライバICがサポートしている最大の幅 // cfg.memory_height = 320; // ドライバICがサポートしている最大の高さ _panel_instance.config(cfg); } setPanel(&_panel_instance); // 使用するパネルをセットします。 } };

Arduinoソースコード

tft.setSwapBytes(true); を設定しないと以下の画面のようになりました。
  tft.setSwapBytes(true)を入れない画像

また、tft.setSwapBytes(true)した状態で、前述の 「cfg.invert = false;」にした状態だと
以下の画面のようになりました。
cfg.invert = falseの場合の画像

sample.ino

/* * camera.ino - Simple camera example sketch * Copyright 2018, 2022 Sony Semiconductor Solutions Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * This is a test app for the camera library. * This library can only be used on the Spresense with the FCBGA chip package. */ #include <SDHCI.h> #include <stdio.h> /* for sprintf */ #include <Camera.h> //lovyan #define LGFX_AUTODETECT // 自動認識 (D-duino-32 XS, WT32-SC01, PyBadge はパネルID読取りが出来ないため自動認識の対象から外れています) // 複数機種の定義を行うか、LGFX_AUTODETECTを定義することで、実行時にボードを自動認識します。 // ヘッダをincludeします。 #include <LovyanGFX.hpp> #include "LGFX_SPRESENSE_sample.hpp" #include <LGFX_AUTODETECT.hpp> // クラス"LGFX"を準備します static LGFX tft; // LGFXのインスタンスを作成。 // #define BAUDRATE (115200) /** * Print error message */ void printError(enum CamErr err) { Serial.print("Error: "); switch (err) { case CAM_ERR_NO_DEVICE: Serial.println("No Device"); break; case CAM_ERR_ILLEGAL_DEVERR: Serial.println("Illegal device error"); break; case CAM_ERR_ALREADY_INITIALIZED: Serial.println("Already initialized"); break; case CAM_ERR_NOT_INITIALIZED: Serial.println("Not initialized"); break; case CAM_ERR_NOT_STILL_INITIALIZED: Serial.println("Still picture not initialized"); break; case CAM_ERR_CANT_CREATE_THREAD: Serial.println("Failed to create thread"); break; case CAM_ERR_INVALID_PARAM: Serial.println("Invalid parameter"); break; case CAM_ERR_NO_MEMORY: Serial.println("No memory"); break; case CAM_ERR_USR_INUSED: Serial.println("Buffer already in use"); break; case CAM_ERR_NOT_PERMITTED: Serial.println("Operation not permitted"); break; default: break; } } /** * Callback from Camera library when video frame is captured. */ void CamCB(CamImage img) { /* Check the img instance is available or not. */ if (img.isAvailable()) { /* If you want RGB565 data, convert image data format to RGB565 */ img.convertPixFormat(CAM_IMAGE_PIX_FMT_RGB565); // tft.pushImage(0, 0,320,240,(uint16_t *)img.getImgBuff()); tft.pushImage(0, 0,240,180,(uint16_t *)img.getImgBuff()); /* You can use image data directly by using getImgSize() and getImgBuff(). * for displaying image to a display, etc. */ Serial.print("Image data size = "); Serial.print(img.getImgSize(), DEC); Serial.print(" , "); Serial.print("buff addr = "); Serial.print((unsigned long)img.getImgBuff(), HEX); Serial.println(""); } else { Serial.println("Failed to get video stream image"); } } /** * @brief Initialize camera */ void setup() { CamErr err; /* Open serial communications and wait for port to open */ Serial.begin(BAUDRATE); while (!Serial) { ; /* wait for serial port to connect. Needed for native USB port only */ } // OR use this initializer (uncomment) if using a 1.3" or 1.54" 240x240 TFT: tft.init(); // Init ST7789 240x240 tft.setSwapBytes(true); // バイト順変換を有効にする。 /* begin() without parameters means that * number of buffers = 1, 30FPS, QVGA, YUV 4:2:2 format */ Serial.println("Prepare camera"); // err = theCamera.begin(); err = theCamera.begin(1, CAM_VIDEO_FPS_30, 240, 180, CAM_IMAGE_PIX_FMT_YUV422, 7 ); if (err != CAM_ERR_SUCCESS) { printError(err); } /* Start video stream. * If received video stream data from camera device, * camera library call CamCB. */ Serial.println("Start streaming"); err = theCamera.startStreaming(true, CamCB); if (err != CAM_ERR_SUCCESS) { printError(err); } /* Auto white balance configuration */ Serial.println("Set Auto white balance parameter"); err = theCamera.setAutoWhiteBalanceMode(CAM_WHITE_BALANCE_DAYLIGHT); if (err != CAM_ERR_SUCCESS) { printError(err); } /* Set parameters about still picture. * In the following case, QUADVGA and JPEG. */ Serial.println("Set still picture format"); err = theCamera.setStillPictureImageFormat( CAM_IMGSIZE_QUADVGA_H, CAM_IMGSIZE_QUADVGA_V, CAM_IMAGE_PIX_FMT_JPG); if (err != CAM_ERR_SUCCESS) { printError(err); } } /** * @brief Take picture with format JPEG per second */ void loop() { sleep(1); /* wait for one second to take still picture. */ /* You can change the format of still picture at here also, if you want. */ /* theCamera.setStillPictureImageFormat( * CAM_IMGSIZE_HD_H, * CAM_IMGSIZE_HD_V, * CAM_IMAGE_PIX_FMT_JPG); */ }``` # その他(謝辞) この記事を作成する上でお世話になったコミュニティ ・SPRESENSE USER GROUP(facebook内) また、オープンエッジデバイス研究会(connpass内) で話せたらと思います。
1
shimodashのアイコン画像
会社員をしています。 Myms-techという活動名で、子供向けの電子工作ワークショップを しています。 URLは https://shimodash.github.io/Myms-tech facebookは https://www.facebook.com/mymstech twitterは https://twitter.com/shimodash_home もしよかったらSNSフォローを ※発言は個人的なものです。
ログインしてコメントを投稿する