LVGL で ePaper に QR コードを描画する
takeharak
ePaper に QR コードを LVGL (Light and Versatile Graphics Library) で表示する省電力 ESP デバイスを試作する
今回の環境
TL;DR
ファームウェアビルド環境の準備
brew tap espressif/eim
brew install eim
eim install -i v6.1
dependency の追加
idf.py add-dependency "dzarda7/esp_epaper^0.1.0"
idf.py add-dependency "lvgl/lvgl^9.3.0"
examples コード
../managed_components/dzarda7__esp_epaper/examples/epaper_lvgl/main/main.c .
panel 情報追加
// gdem0154z91.c
+ #include "epd_private.h"
+
+ static const epd_init_cmd_t gdem0154z91_init[] = {
+ { 0x3C, 1, { 0x05 } }, /* border waveform: follow the LUT1 white level */
+ { 0x21, 2, { 0x00, 0x80 } }, /* 128 px of glass on 176 sources: use S8..S167 */
+ { 0x18, 1, { 0x80 } }, /* waveform compensation from the internal temperature sensor */
+ };
+
+ const epd_panel_desc_t epd_panel_gdem0154z91 = {
+ .name = "GDEM0154Z91",
+ .controller = &epd_controller_ssd1680,
+ .width = 152,
+ .height = 152,
+ .gate_lines = 152,
+ .init_cmds = gdem0154z91_init,
+ .init_cmd_count = sizeof(gdem0154z91_init) / sizeof(gdem0154z91_init[0]),
+ .busy_active_high = true,
+ .reset_low_ms = 10,
+ .reset_high_ms = 10,
+ .power_on_delay_ms = 10,
+ .full_refresh_ms = 14000,
+ .partial_refresh_ms = 500,
+ .supports_partial = false,
+ };
init
// main/main.c
#include <stdlib.h>
#include <string.h>
...
static esp_lcd_panel_handle_t display_init(void)
{
const spi_bus_config_t bus_cfg = {
- .mosi_io_num = EPINK_SHELF_29_PIN_MOSI,
+ .mosi_io_num = GPIO_NUM_7,
.miso_io_num = -1,
- .sclk_io_num = EPINK_SHELF_29_PIN_SCLK,
+ .sclk_io_num = GPIO_NUM_6,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 4096,
};
- ESP_ERROR_CHECK(spi_bus_initialize(EPINK_SHELF_29_SPI_HOST, &bus_cfg, SPI_DMA_CH_AUTO));
+ ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &bus_cfg, SPI_DMA_CH_AUTO));
const esp_lcd_panel_io_spi_config_t io_cfg = {
- .cs_gpio_num = EPINK_SHELF_29_PIN_CS,
- .dc_gpio_num = EPINK_SHELF_29_PIN_DC,
+ .cs_gpio_num = GPIO_NUM_10,
+ .dc_gpio_num = GPIO_NUM_3,
.spi_mode = 0,
- .pclk_hz = EPINK_SHELF_29_PIXEL_CLK_HZ,
+ .pclk_hz = 2 * 1000 * 1000,
.trans_queue_depth = 10,
.lcd_cmd_bits = 8,
.lcd_param_bits = 8,
};
esp_lcd_panel_io_handle_t io = NULL;
- ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)EPINK_SHELF_29_SPI_HOST, &io_cfg, &io));
+ ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)SPI2_HOST, &io_cfg, &io));
esp_lcd_epaper_config_t epd_cfg = {
.panel = &epd_panel_gdey029t94,
- .busy_gpio_num = EPINK_SHELF_29_PIN_BUSY,
- .power_ctrl = epink_shelf_29_power_ctrl, /* board switches the panel rail */
- .rotation = EPD_ROTATION_90,
- .refresh_mode = EPD_REFRESH_AUTO,
+ .busy_gpio_num = GPIO_NUM_0,
+ .rotation = EPD_ROTATION_180,
+ .refresh_mode = EPD_REFRESH_FULL,
.full_refresh_interval = 20,
};
const esp_lcd_panel_dev_config_t panel_cfg = {
- .reset_gpio_num = EPINK_SHELF_29_PIN_RST,
+ .reset_gpio_num = GPIO_NUM_1,
.bits_per_pixel = 1,
.vendor_config = &epd_cfg,
};
esp_lcd_panel_handle_t panel = NULL;
ESP_ERROR_CHECK(esp_lcd_new_panel_epaper(io, &panel_cfg, &panel));
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel));
ESP_ERROR_CHECK(esp_lcd_panel_init(panel));
return panel;
}
...
QR コード
// main/main.c
#include <stdlib.h>
#include <string.h>
...
static esp_lcd_panel_handle_t s_panel;
- static lv_obj_t *s_counter_label;
+ static lv_obj_t *s_qr_code;
...
static void build_ui(void)
{
lv_obj_t *scr = lv_screen_active();
lv_obj_set_style_bg_color(scr, lv_color_white(), 0);
- lv_obj_t *title = lv_label_create(scr);
- lv_label_set_text(title, "esp_epaper + LVGL");
- lv_obj_set_style_text_font(title, &lv_font_montserrat_24, 0);
- lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 8);
-
- s_counter_label = lv_label_create(scr);
- lv_label_set_text(s_counter_label, "0");
- lv_obj_set_style_text_font(s_counter_label, &lv_font_montserrat_24, 0);
- lv_obj_align(s_counter_label, LV_ALIGN_CENTER, 0, 10);
-
- lv_obj_t *line = lv_obj_create(scr);
- lv_obj_set_size(line, DISP_WIDTH - 40, 3);
- lv_obj_set_style_bg_color(line, lv_color_black(), 0);
- lv_obj_set_style_border_width(line, 0, 0);
- lv_obj_align(line, LV_ALIGN_TOP_MID, 0, 42);
+ s_qr_code = lv_qrcode_create(lv_scr_act());
+ lv_obj_align(s_qr_code, LV_ALIGN_CENTER, 0, 0);
+ lv_qrcode_set_size(s_qr_code, 152);
+ lv_qrcode_set_dark_color(s_qr_code, lv_color_black());
+ lv_qrcode_set_light_color(s_qr_code, lv_color_white());
}
...
void app_main(void)
{
s_panel = display_init();
...
ESP_LOGI(TAG, "UI created, entering LVGL loop");
- uint32_t counter = 0;
uint32_t next_tick = 0;
while (1) {
uint32_t now = lvgl_tick_cb();
if (now >= next_tick) {
next_tick = now + 10000; /* one update every 10 s */
- lv_label_set_text_fmt(s_counter_label, "%" LV_PRIu32, counter++);
+ const char * data = "Hello world";
+ lv_qrcode_set_data(s_qr_code, data);
}
uint32_t wait_ms = lv_timer_handler();
if (wait_ms == LV_NO_TIMER_READY || wait_ms > LVGL_TICK_PERIOD_MS * 4) {
wait_ms = LVGL_TICK_PERIOD_MS * 4;
}
vTaskDelay(pdMS_TO_TICKS(wait_ms ? wait_ms : LVGL_TICK_PERIOD_MS));
}
}
DEEPSLEEP
// main/main.c
...
+ #include "esp_sleep.h"
+ #include "esp_attr.h"
...
+ ESP_LOGI(TAG, "Entering deep sleep...");
+ esp_sleep_enable_timer_wakeup(30 * 1000 * 1000);
+ esp_deep_sleep_start();
...
実行
idf.py set-target esp32c3
idf.py -p $PORT build
idf.py -p $PORT flash
