STM32 LittlevGLを使う

2020年02月27日 カテゴリー:STM32



03s_255_1lvp.jpg
LittlevGLは、組み込み機器のGUI向けのグラフィックライブラリです。これを使いこなせれば、きれいな画面や使いやすい操作が実現できると思われます。公式の導入方法ではわかりにくい部分があるので、デモの実行方法をまとめておくことにしました。使用したNucleoボードはNUCLEO-F401REです。※メモリ使用量はRAM46kB、FLASH407kBとなったので、それなりに容量が必要となります。



<準備>
まずは以前の記事(STM32 SPI接続タッチパネル付ディスプレイを使う)の手順を行って、ディスプレイの動作確認をします。そしてそのプロジェクトをそのまま利用し、以下の操作をしていきます。



<ダウンロード>



<LittlevGLコンフィグファイル編集>



<main.cファイル編集>
以前の記事(STM32 SPI接続タッチパネル付ディスプレイを使う)で記述したものは消去し、下記4か所に記載

▼/* USER CODE BEGIN Includes */ の下
#include "ili9341.h"
#include "ili9341_touch.h"
#include "lvgl/lvgl.h"
#include "lv_examples/lv_apps/demo/demo.h"

▼/* USER CODE BEGIN 0 */ の下
lv_disp_buf_t disp_buf;               // ディスプレイバッファの構造体
lv_color_t buf_1[ILI9341_WIDTH * 10]; // ディスプレイバッファ1
lv_color_t buf_2[ILI9341_WIDTH * 10]; // ディスプレイバッファ2

lv_disp_drv_t disp_drv;   // ディスプレイドライバの構造体
lv_indev_drv_t indev_drv; // タッチパッドドライバの構造体

void my_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) // 画面描画
{
  int32_t w = area->x2 - area->x1 + 1;
  int32_t h = area->y2 - area->y1 + 1;
  ILI9341_DrawImage(area->x1, area->y1, w, h, (uint16_t*)color_p);
  lv_disp_flush_ready(disp_drv); // 描画終了をライブラリへ知らせる
}

bool my_input_read(lv_indev_drv_t * drv, lv_indev_data_t * data) // タッチパッドのタッチ検出とタッチ位置取得
{
  static uint16_t x = 0, last_x = 0;
  static uint16_t y = 0, last_y = 0;
  if(ILI9341_TouchPressed())
  {
    ILI9341_TouchGetCoordinates(&x, &y);
    data->point.x = x;
    data->point.y = ILI9341_HEIGHT - y; // 上下逆さま
    last_x = data->point.x;
    last_y = data->point.y;
    data->state = LV_INDEV_STATE_PR; // タッチあり
  }
  else
  {
    data->point.x = last_x;
    data->point.y = last_y;
    data->state = LV_INDEV_STATE_REL; // タッチなし
  }
  return false;
}

void init() // ディスプレイ初期化
{
  ILI9341_Unselect();
  ILI9341_TouchUnselect();
  ILI9341_Init();
}
my_flush_cb関数に画面描画を行うコードを、my_input_read関数にタッチパッドに関するコードを記述します。他のディスプレイを使う場合でも、ここに該当するコードを記述すればうまく動作するはずです。

▼/* USER CODE BEGIN 2 */ の下
  init();    // ディスプレイ初期化
  lv_init(); // ライブラリ初期化
  lv_disp_buf_init(&disp_buf, buf_1, buf_2, ILI9341_WIDTH*10); // ディスプレイバッファ初期化

  lv_disp_drv_init(&disp_drv);     // ディスプレイドライバ初期化
  disp_drv.buffer = &disp_buf;     // ディスプレイバッファ登録
  disp_drv.flush_cb = my_flush_cb; // 画面描画関数登録
  lv_disp_drv_register(&disp_drv); // ディスプレイドライバ登録

  lv_indev_drv_init(&indev_drv);          // タッチパッドドライバ初期化
  indev_drv.type = LV_INDEV_TYPE_POINTER; // 入力タイプをタッチパッドに指定
  indev_drv.read_cb = my_input_read;      // タッチ検出関数登録
  lv_indev_drv_register(&indev_drv);      // タッチパッドドライバ登録

  demo_create(); // デモ呼び出し

▼/* USER CODE BEGIN 3 */ の下
    HAL_Delay(100);
    lv_tick_inc(100);  // ライブラリへ経過時間を知らせる
    lv_task_handler(); // ライブラリ実行(画面更新)
メインループ内で100msごとに画面を更新します。画面描画が速ければもっと短い間隔で更新してもよいでしょう。ライブラリへ経過時間を知らせるのは、アニメーションの動作に関係していると思われます。

ビルドには1分程度かかる場合があります。SPIの通信速度が遅いので、アニメーションはさすがに無理がありそうです。狭い範囲の表示更新については特に問題なさそうな感じです。