lovyanGFXライブラリのインストール
サンプルを呼び出す
ファイル>スケッチ例>LovyanGFX>HowToUse>2_user_setting
これを元に必要な個所を変更、削除していく
それがこれ
#define LGFX_USE_V1
#include <LovyanGFX.hpp>
class LGFX : public lgfx::LGFX_Device
{
lgfx::Panel_ILI9341 _panel_instance;
lgfx::Bus_SPI _bus_instance;
lgfx::Light_PWM _light_instance;
lgfx::Touch_XPT2046 _touch_instance;
public:
LGFX(void)
{
{
auto cfg = _bus_instance.config();
// SPIバスの設定
cfg.spi_host = VSPI_HOST;
cfg.spi_mode = 0;
cfg.freq_write = 40000000;
cfg.freq_read = 16000000;
cfg.spi_3wire = true;
cfg.use_lock = true;
cfg.dma_channel = SPI_DMA_CH_AUTO;
cfg.pin_sclk = 14; // 変更
cfg.pin_mosi = 13; // 変更
cfg.pin_miso = 12; // 変更
cfg.pin_dc = 2; // 変更
_bus_instance.config(cfg);
_panel_instance.setBus(&_bus_instance);
}
{
auto cfg = _panel_instance.config();
cfg.pin_cs = 15; // 変更
cfg.pin_rst = -1; // 変更
cfg.pin_busy = -1; // 変更
cfg.panel_width = 240;
cfg.panel_height = 320;
cfg.offset_x = 0;
cfg.offset_y = 0;
cfg.offset_rotation = 0;
cfg.dummy_read_pixel = 8;
cfg.dummy_read_bits = 1;
cfg.readable = true;
cfg.invert = false;
cfg.rgb_order = false;
cfg.dlen_16bit = false;
cfg.bus_shared = false; // 変更
_panel_instance.config(cfg);
}
{
auto cfg = _light_instance.config();
cfg.pin_bl = 21; // 変更
cfg.invert = false;
cfg.freq = 44100;
cfg.pwm_channel = 7;
_light_instance.config(cfg);
_panel_instance.setLight(&_light_instance);
}
{
auto cfg = _touch_instance.config();
cfg.x_min = 300; // 変更
cfg.x_max = 3900; // 変更
cfg.y_min = 3700; // 変更
cfg.y_max = 200; // 変更
cfg.pin_int = -1; // 変更
cfg.bus_shared = false; // 変更
cfg.offset_rotation = 0;
cfg.spi_host = HSPI_HOST; // 変更
cfg.freq = 1000000;
cfg.pin_sclk = 25; // 変更
cfg.pin_mosi = 32; // 変更
cfg.pin_miso = 39; // 変更
cfg.pin_cs = 33; // 変更
_touch_instance.config(cfg);
_panel_instance.setTouch(&_touch_instance);
}
setPanel(&_panel_instance);
}
};
LGFX display;
void setup(void)
{
// SPIバスとパネルの初期化を実行すると使用可能になります。
display.init();
display.setTextSize((std::max(display.width(), display.height()) + 255) >> 8);
// タッチが使用可能な場合のキャリブレーションを行います。(省略可)
if (display.touch())
{
if (display.width() < display.height()) display.setRotation(display.getRotation() ^ 1);
// 画面に案内文章を描画します。
display.setTextDatum(textdatum_t::middle_center);
display.drawString("touch the arrow marker.", display.width()>>1, display.height() >> 1);
display.setTextDatum(textdatum_t::top_left);
// タッチを使用する場合、キャリブレーションを行います。画面の四隅に表示される矢印の先端を順にタッチしてください。
std::uint16_t fg = TFT_WHITE;
std::uint16_t bg = TFT_BLACK;
if (display.isEPD()) std::swap(fg, bg);
display.calibrateTouch(nullptr, fg, bg, std::max(display.width(), display.height()) >> 3);
}
display.fillScreen(TFT_BLACK);
}
uint32_t count = ~0;
void loop(void)
{
display.startWrite();
display.setRotation(++count & 7);
display.setColorDepth((count & 8) ? 16 : 24);
display.setTextColor(TFT_WHITE);
display.drawNumber(display.getRotation(), 16, 0);
display.setTextColor(0xFF0000U);
display.drawString("R", 30, 16);
display.setTextColor(0x00FF00U);
display.drawString("G", 40, 16);
display.setTextColor(0x0000FFU);
display.drawString("B", 50, 16);
display.drawRect(30,30,display.width()-60,display.height()-60,count*7);
display.drawFastHLine(0, 0, 10);
display.endWrite();
int32_t x, y;
if (display.getTouch(&x, &y)) {
display.fillRect(x-2, y-2, 5, 5, count*7);
}
}
これでLovyanGFXが動くようになったから次はLVGLを組み込んでいく
LVGLライブラリのインストール
ライブラリフォルダのlvgl>lv_conf_template.hをlvgl>src>lv_conf.hにコピーする。conf.hの該当箇所を変更していく
#if 0 /*Set it to "1" to enable content*/
を
#if 1 /*Set it to "1" to enable content*/
にする
#define LV_COLOR_DEPTH 32
を
#define LV_COLOR_DEPTH 16
にする
arduinoでつかうので
#define LV_TICK_CUSTOM 0
を
#define LV_TICK_CUSTOM 1
にする
設定できたのでサンプルを呼び出す
ファイル>スケッチ例>LVGL>arduino>LVGL_Arduino
そのままではtft_espi仕様なのでLovyanGFXを使うように変更していく
static const uint16_t screenWidth = 320;
static const uint16_t screenHeight = 280;
パネルサイズを合わせる
TFT_eSPI tft = TFT_eSPI(screenWidth, screenHeight); /* TFT instance */
を
LGFX tft;
にする
tft.pushColors( ( uint16_t * )&color_p->full, w * h, true );
はLovyanGFXにはないので
tft.writePixels((lgfx::rgb565_t *)&color_p->full, w * h );
に変更する
bool touched = tft.getTouch( &touchX, &touchY, 600 );
getTouch関数はあるがLovyanGFXでは最後の引数がないので
bool touched = tft.getTouch( &touchX, &touchY);
に変更する
ここまでで最低限のコードにはなったけど悲しいのでボタンでも追加する
lvgl>examples>get_started>lv_example_get_started_1.cにボタンのサンプルがあるからそこからコピペでもってくる
できたコード
#include <lvgl.h>
#define LGFX_USE_V1
#include <LovyanGFX.hpp>
class LGFX : public lgfx::LGFX_Device
{
lgfx::Panel_ILI9341 _panel_instance;
lgfx::Bus_SPI _bus_instance;
lgfx::Light_PWM _light_instance;
lgfx::Touch_XPT2046 _touch_instance;
public:
LGFX(void)
{
{
auto cfg = _bus_instance.config();
// SPIバスの設定
cfg.spi_host = VSPI_HOST;
cfg.spi_mode = 0;
cfg.freq_write = 40000000;
cfg.freq_read = 16000000;
cfg.spi_3wire = true;
cfg.use_lock = true;
cfg.dma_channel = SPI_DMA_CH_AUTO;
cfg.pin_sclk = 14; // 変更
cfg.pin_mosi = 13; // 変更
cfg.pin_miso = 12; // 変更
cfg.pin_dc = 2; // 変更
_bus_instance.config(cfg);
_panel_instance.setBus(&_bus_instance);
}
{
auto cfg = _panel_instance.config();
cfg.pin_cs = 15; // 変更
cfg.pin_rst = -1; // 変更
cfg.pin_busy = -1; // 変更
cfg.panel_width = 240;
cfg.panel_height = 320;
cfg.offset_x = 0;
cfg.offset_y = 0;
cfg.offset_rotation = 0;
cfg.dummy_read_pixel = 8;
cfg.dummy_read_bits = 1;
cfg.readable = true;
cfg.invert = false;
cfg.rgb_order = false;
cfg.dlen_16bit = false;
cfg.bus_shared = false; // 変更
_panel_instance.config(cfg);
}
{
auto cfg = _light_instance.config();
cfg.pin_bl = 21; // 変更
cfg.invert = false;
cfg.freq = 44100;
cfg.pwm_channel = 7;
_light_instance.config(cfg);
_panel_instance.setLight(&_light_instance);
}
{
auto cfg = _touch_instance.config();
cfg.x_min = 300; // 変更
cfg.x_max = 3900; // 変更
cfg.y_min = 3700; // 変更
cfg.y_max = 200; // 変更
cfg.pin_int = -1; // 変更
cfg.bus_shared = false; // 変更
cfg.offset_rotation = 0;
cfg.spi_host = HSPI_HOST; // 変更
cfg.freq = 1000000;
cfg.pin_sclk = 25; // 変更
cfg.pin_mosi = 32; // 変更
cfg.pin_miso = 39; // 変更
cfg.pin_cs = 33; // 変更
_touch_instance.config(cfg);
_panel_instance.setTouch(&_touch_instance);
}
setPanel(&_panel_instance);
}
};
// 準備したクラスのインスタンスを作成します。
LGFX tft;
/*Change to your screen resolution*/
static const uint16_t screenWidth = 320;
static const uint16_t screenHeight = 280;
static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf[ screenWidth * 10 ];
/* Display flushing */
void my_disp_flush( lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p )
{
uint32_t w = ( area->x2 - area->x1 + 1 );
uint32_t h = ( area->y2 - area->y1 + 1 );
tft.startWrite();
tft.setAddrWindow( area->x1, area->y1, w, h );
//tft.pushColors( ( uint16_t * )&color_p->full, w * h, true );
tft.writePixels((lgfx::rgb565_t *)&color_p->full, w * h );
tft.endWrite();
lv_disp_flush_ready( disp );
}
/*Read the touchpad*/
void my_touchpad_read( lv_indev_drv_t * indev_driver, lv_indev_data_t * data )
{
uint16_t touchX, touchY;
bool touched = tft.getTouch( &touchX, &touchY);
if( !touched )
{
data->state = LV_INDEV_STATE_REL;
}
else
{
data->state = LV_INDEV_STATE_PR;
/*Set the coordinates*/
data->point.x = touchX;
data->point.y = touchY;
Serial.print( "Data x " );
Serial.println( touchX );
Serial.print( "Data y " );
Serial.println( touchY );
}
}
void setup()
{
Serial.begin( 115200 ); /* prepare for possible serial debug */
tft.begin(); /* TFT init */
tft.setRotation( 3 ); /* Landscape orientation, flipped */
tft.setBrightness(255); //液晶のバックライトを最大の明るさにする
uint16_t calData[] = { 267, 3671, 267, 180, 3843, 3717, 3846, 143 }; //事前に調べたキャリブレーション値
tft.setTouchCalibrate( calData ); //キャリブレーション値の設定
lv_init();
lv_disp_draw_buf_init( &draw_buf, buf, NULL, screenWidth * 10 );
/*Initialize the display*/
static lv_disp_drv_t disp_drv;
lv_disp_drv_init( &disp_drv );
/*Change the following line to your display resolution*/
disp_drv.hor_res = screenWidth;
disp_drv.ver_res = screenHeight;
disp_drv.flush_cb = my_disp_flush;
disp_drv.draw_buf = &draw_buf;
lv_disp_drv_register( &disp_drv );
/*Initialize the (dummy) input device driver*/
static lv_indev_drv_t indev_drv;
lv_indev_drv_init( &indev_drv );
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = my_touchpad_read;
lv_indev_drv_register( &indev_drv );
lv_example_get_started_1(); //ボタン追加
}
void loop()
{
lv_timer_handler(); /* let the GUI do its work */
delay( 5 );
}
static void btn_event_cb(lv_event_t * e)
{
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t * btn = lv_event_get_target(e);
if(code == LV_EVENT_CLICKED) {
static uint8_t cnt = 0;
cnt++;
/*Get the first child of the button which is the label and change its text*/
lv_obj_t * label = lv_obj_get_child(btn, 0);
lv_label_set_text_fmt(label, "Button: %d", cnt);
lv_obj_clean(lv_scr_act()); //現在のスクリーンをクリア
lv_obj_t * btn = lv_btn_create(lv_scr_act()); /*Add a button the current screen*/
lv_obj_set_pos(btn, 50, 50); /*Set its position*/
//lv_obj_align(btn3,LV_ALIGN_CENTER,0,0);
lv_obj_set_size(btn, 120, 50); /*Set its size*/
lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_ALL, NULL); /*Assign a callback to the button*/
lv_obj_t * label2 = lv_label_create(btn); /*Add a label to the button*/
lv_label_set_text(label2, "NewButton"); /*Set the labels text*/
lv_obj_center(label2);
}
}
/**
* Create a button with a label and react on click event.
*/
void lv_example_get_started_1(void)
{
lv_obj_t * btn = lv_btn_create(lv_scr_act()); /*Add a button the current screen*/
//lv_obj_set_pos(btn, 10, 10); /*Set its position*/
lv_obj_align(btn,LV_ALIGN_CENTER,0,0);
lv_obj_set_size(btn, 120, 50); /*Set its size*/
lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_ALL, NULL); /*Assign a callback to the button*/
lv_obj_t * label = lv_label_create(btn); /*Add a label to the button*/
lv_label_set_text(label, "Button"); /*Set the labels text*/
lv_obj_center(label);
}
本来はボタンを押すたびに数字が増えていくコードだけど少し変更してます
中央のボタン押すと一度クリアして新たなボタンを配置するようになってます(2度目以降の押下は見た目は変わらないけど一応クリアされて再びボタンが配置されてます)