目的
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)した状態で、前述の 「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
さんが
2023/05/07
に
編集
をしました。
(メッセージ: 初版)
-
shimodash
さんが
2023/05/07
に
編集
をしました。
(メッセージ: その他(謝辞)に変更して追記 等)
-
shimodash
さんが
2023/05/07
に
編集
をしました。
-
shimodash
さんが
2023/05/07
に
編集
をしました。
-
shimodash
さんが
2023/05/07
に
編集
をしました。
(メッセージ: 240x180の表示のソースコードを更新)
ログインしてコメントを投稿する