From bd1c3560ecc62d825220060eb0f098d935cd3da4 Mon Sep 17 00:00:00 2001 From: Frank Altheim <60691237+frnktank@users.noreply.github.com> Date: Tue, 17 Dec 2024 20:00:41 +0100 Subject: [PATCH] [example] Add LGVL example on NUCLEO-L476RG --- examples/nucleo_l476rg/lvgl/lv_conf_local.h | 39 +++++ examples/nucleo_l476rg/lvgl/main.cpp | 164 ++++++++++++++++++++ examples/nucleo_l476rg/lvgl/project.xml | 16 ++ examples/nucleo_l476rg/lvgl/test_screen.cpp | 78 ++++++++++ examples/nucleo_l476rg/lvgl/test_screen.h | 24 +++ 5 files changed, 321 insertions(+) create mode 100644 examples/nucleo_l476rg/lvgl/lv_conf_local.h create mode 100644 examples/nucleo_l476rg/lvgl/main.cpp create mode 100644 examples/nucleo_l476rg/lvgl/project.xml create mode 100644 examples/nucleo_l476rg/lvgl/test_screen.cpp create mode 100644 examples/nucleo_l476rg/lvgl/test_screen.h diff --git a/examples/nucleo_l476rg/lvgl/lv_conf_local.h b/examples/nucleo_l476rg/lvgl/lv_conf_local.h new file mode 100644 index 0000000000..ca11dff9bc --- /dev/null +++ b/examples/nucleo_l476rg/lvgl/lv_conf_local.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024, Frank Altheim + * + * This file is part of the modm project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// ---------------------------------------------------------------------------- + +#ifndef LV_CONF_H +# error "Don't include this file directly, use 'lv_conf.h' instead!" +#endif + +// Maximal resolutions +#define LV_HOR_RES_MAX 240 +#define LV_VER_RES_MAX 320 +#define LV_DPI 200 + +/* Color depth: + * - 1: 1 byte per pixel + * - 8: RGB332 + * - 16: RGB565 + * - 32: ARGB8888 + */ +#define LV_COLOR_DEPTH 16 + +// Enable logging at INFO level +#define LV_USE_LOG 1 +#define LV_LOG_LEVEL LV_LOG_LEVEL_INFO + +// Fonts: +#define LV_FONT_MONTSERRAT_36 1 +#define LV_FONT_MONTSERRAT_24 1 +#define LV_FONT_MONTSERRAT_16 1 + +// Disable anti-aliasing +#define LV_ANTIALIAS 0 diff --git a/examples/nucleo_l476rg/lvgl/main.cpp b/examples/nucleo_l476rg/lvgl/main.cpp new file mode 100644 index 0000000000..201d8665b4 --- /dev/null +++ b/examples/nucleo_l476rg/lvgl/main.cpp @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2024, Frank Altheim + * + * This file is part of the modm project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// ---------------------------------------------------------------------------- + +#include +#include +#include +#include +#include + +#include + +// USER INCLUDES +#include "test_screen.h" + + +// Set the log level +#undef MODM_LOG_LEVEL +#define MODM_LOG_LEVEL modm::log::DEBUG + +using namespace Board; +using namespace modm::literals; + + +namespace tft +{ + using DmaRx = Dma1::Channel2; + using DmaTx = Dma1::Channel3; + using Spi = SpiMaster1_Dma; + //using Spi = SpiMaster1; + using Cs = Board::D10; + using Sck = Board::D13; + using Miso = Board::D12; + using Mosi = Board::D11; + using DataCommands = Board::D9; + using Reset = Board::D8; + using Backlight = modm::platform::GpioC9; +} + +modm::Ili9341Spi< + tft::Spi, + tft::Cs, + tft::DataCommands, + tft::Reset, + tft::Backlight +> tftController; + +namespace touch +{ + using Spi = SpiMaster3; + using Cs = modm::platform::GpioD2; + using Sck = modm::platform::GpioC10; + using Miso = modm::platform::GpioC11; + using Mosi = modm::platform::GpioC12; + using Interrupt = modm::platform::GpioC9; +} + +modm::Touch2046 touchController; + +// Define display buffer 1 +static constexpr size_t buf_size = 240 * 320 / 8; +static lv_color_t modm_aligned(4) buf[buf_size]; + +// Define display buffer 2 +static constexpr size_t buf2_size = 240 * 320 / 8; +static lv_color_t modm_aligned(4) buf2[buf2_size]; + +void my_touchpad_read(lv_indev_t*, lv_indev_data_t* data) +{ + data->state = touchController.isTouched() ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED; + if(data->state == LV_INDEV_STATE_PRESSED) { + std::tuple xy = touchController.getTouchPosition(); + data->point.x = std::get<0>(xy); + data->point.y = std::get<1>(xy); + + std::tuple xyRAW = touchController.getRawValues(); + int16_t rawX = std::get<0>(xyRAW); + int16_t rawY = std::get<1>(xyRAW); + // Display on test screen + setTouchText(data->point.x, data->point.y, rawX, rawY); + + } +} + +void disp_flush(lv_display_t* disp, const lv_area_t* area, uint8_t* px_map) +{ + tftController.drawRaw( + {uint16_t(area->x1), uint16_t(area->y1)}, + (area->x2 - area->x1 +1), + (area->y2 - area->y1 + 1), + (modm::color::Rgb565*)px_map); + lv_display_flush_ready(disp); +} + +int +main() +{ + Board::initialize(); + Dma1::enable(); + + tft::Spi::connect< + tft::Sck::Sck, + tft::Miso::Miso, + tft::Mosi::Mosi>(); + tft::Spi::initialize(); + tftController.initialize(); + tftController.enableBacklight(true); + + touch::Spi::connect< + touch::Sck::Sck, + touch::Miso::Miso, + touch::Mosi::Mosi>(); + touch::Spi::initialize(); + modm::touch2046::Calibration cal{ + .OffsetX = -11, + .OffsetY = 335, + .FactorX = 22018, + .FactorY = -29358, + .MaxX = 240, + .MaxY = 320, + .ThresholdZ = 100, + }; + touchController.setCalibration(cal); + + MODM_LOG_INFO << "reflow-display on nucleo-l476rg!\n\n"; + + lv_display_t *disp = lv_display_create(240, 320); + lv_display_set_flush_cb(disp, disp_flush); + lv_display_set_buffers(disp, buf, buf2, sizeof(buf), LV_DISPLAY_RENDER_MODE_PARTIAL); + + // Initialize touchscreen driver: + lv_indev_t* indev = lv_indev_create(); + // Assert touchscreen driver was created successfully: + if (indev == NULL) { + MODM_LOG_ERROR << "Failed to create input device\n"; + while (1) {} + } + + lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER); + lv_indev_set_read_cb(indev, my_touchpad_read); + + drawTestScreen(); + + modm::ShortPeriodicTimer tmr{20ms}; + + while (true) + { + lv_timer_handler(); + + if (tmr.execute()) + { + setLblText(); + } + } + + return 0; +} diff --git a/examples/nucleo_l476rg/lvgl/project.xml b/examples/nucleo_l476rg/lvgl/project.xml new file mode 100644 index 0000000000..c9e0420b14 --- /dev/null +++ b/examples/nucleo_l476rg/lvgl/project.xml @@ -0,0 +1,16 @@ + + modm:nucleo-l476rg + + + + + modm:build:scons + modm:processing:timer + modm:driver:ili9341 + modm:driver:touch2046 + modm:platform:spi:1 + modm:platform:spi:3 + modm:platform:dma + modm:lvgl + + diff --git a/examples/nucleo_l476rg/lvgl/test_screen.cpp b/examples/nucleo_l476rg/lvgl/test_screen.cpp new file mode 100644 index 0000000000..91b3adbad4 --- /dev/null +++ b/examples/nucleo_l476rg/lvgl/test_screen.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2024, Frank Altheim + * + * This file is part of the modm project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// ---------------------------------------------------------------------------- + +#include "test_screen.h" +#include + +static lv_obj_t* screen; +static uint16_t counter = 0; +static lv_obj_t* labelA; +static lv_obj_t* labelTouch; +static lv_obj_t* labelRawTouch; + +void btn_event_cb(lv_event_t *event) +{ + static uint16_t btnCounter = 0; + lv_label_set_text_fmt((lv_obj_t*) lv_event_get_user_data(event), + "Button: %d", ++btnCounter); +} + +void drawTestScreen(void) +{ + screen = lv_obj_create(NULL); + + labelA = lv_label_create(screen); + lv_label_set_text(labelA, "Hello world!"); + lv_obj_set_pos(labelA, 60, 10); + lv_obj_set_size(labelA, 120, 50); + + labelTouch = lv_label_create(screen); + lv_label_set_text_fmt(labelTouch, "Pos Touch: x = %d, y = %d", 0, 0); + lv_obj_set_pos(labelTouch, 60, 30); + lv_obj_set_size(labelTouch, 120, 50); + + labelRawTouch = lv_label_create(screen); + lv_label_set_text_fmt(labelRawTouch, "Raw Touch: x = %d, y = %d", 0, 0); + lv_obj_set_pos(labelRawTouch, 60, 80); + lv_obj_set_size(labelRawTouch, 120, 50); + + lv_obj_t* btn = lv_button_create(screen); + lv_obj_set_pos(btn, 60, 135); + lv_obj_set_size(btn, 120, 50); + + lv_obj_t* btnLabel = lv_label_create(btn); + lv_label_set_text(btnLabel, "Button"); + + static lv_style_t style_btn_pressed; + lv_style_init(&style_btn_pressed); + lv_style_set_bg_color(&style_btn_pressed, lv_palette_main(LV_PALETTE_ORANGE)); + + lv_obj_add_style(btn, &style_btn_pressed, LV_STATE_PRESSED); + lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_PRESSED, btnLabel); + lv_obj_t* labelB = lv_label_create(screen); + lv_label_set_text(labelB, "Big Font"); + lv_obj_set_pos(labelB, 40, 260); + lv_obj_set_style_text_font(labelB, &lv_font_montserrat_36, LV_PART_MAIN); + + // Load screen + lv_scr_load(screen); +} + +void setLblText(void) +{ + lv_label_set_text_fmt(labelA, "counter=%d", ++counter); +} + +void setTouchText(int16_t x, int16_t y, int16_t rawX, int16_t rawY) +{ + lv_label_set_text_fmt(labelTouch, "Pos Touch: x = %d, y = %d", x, y); + lv_label_set_text_fmt(labelRawTouch, "Raw Touch: x = %d, y = %d", rawX, rawY); +} diff --git a/examples/nucleo_l476rg/lvgl/test_screen.h b/examples/nucleo_l476rg/lvgl/test_screen.h new file mode 100644 index 0000000000..66eb60bd22 --- /dev/null +++ b/examples/nucleo_l476rg/lvgl/test_screen.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024, Frank Altheim + * + * This file is part of the modm project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// ---------------------------------------------------------------------------- + +#ifndef TEST_SCREEN_H +#define TEST_SCREEN_H + +#pragma once + +#include + +void drawTestScreen(void); +void setLblText(void); +void setTouchText(int16_t x, int16_t y, int16_t rawX, int16_t rawY); + + +#endif //TEST_SCREEN_H