diff --git a/examples/nucleo_l452re/lvgl/main.cpp b/examples/nucleo_l452re/lvgl/main.cpp new file mode 100644 index 0000000000..03b6961d6f --- /dev/null +++ b/examples/nucleo_l452re/lvgl/main.cpp @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2021, Raphael Lehmann + * + * 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 + + +// Set the log level +#undef MODM_LOG_LEVEL +#define MODM_LOG_LEVEL modm::log::DEBUG + +using namespace Board; +using namespace modm::literals; + +static modm::Abandonment +test_assertion_handler(const modm::AssertionInfo &info) +{ + MODM_LOG_ERROR << "AssertionInfo.name: " << info.name << "\n"; + MODM_LOG_ERROR << "AssertionInfo.context: " << info.context << "\n"; + MODM_LOG_ERROR << "AssertionInfo.behavior: " << info.behavior << "\n"; + MODM_LOG_ERROR << modm::endl; + return modm::Abandonment::DontCare; +} +MODM_ASSERTION_HANDLER(test_assertion_handler); + + +namespace tft +{ + using DmaRx = Dma1::Channel2; + using DmaTx = Dma1::Channel3; + using Spi = SpiMaster1_Dma; + //using Spi = SpiMaster1; + using Cs = modm::platform::GpioC8; + using Sck = modm::platform::GpioA5; + using Miso = modm::platform::GpioA6; + using Mosi = modm::platform::GpioA7; + using DataCommands = modm::platform::GpioC5; + using Reset = modm::platform::GpioC6; + using Backlight = modm::platform::GpioC9; +} + +modm::Ili9341Spi< + tft::Spi, + tft::Cs, + tft::DataCommands, + tft::Reset, + tft::Backlight +> tftController; + +namespace touch +{ + using Spi = SpiMaster2; + using Cs = modm::platform::GpioB3; + using Sck = modm::platform::GpioB13; + using Miso = modm::platform::GpioB14; + using Mosi = modm::platform::GpioB15; + //using Interrupt = modm::platform::GpioA10; +} + +modm::Touch2046 touchController; + + +static lv_disp_buf_t disp_buf; +static constexpr size_t buf_size = LV_HOR_RES_MAX * LV_VER_RES_MAX / 8; +static lv_color_t buf[buf_size]; + +bool my_touchpad_read(lv_indev_drv_t* indev, lv_indev_data_t* data) +{ + data->state = RF_CALL_BLOCKING(touchController.isTouched()) ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; + if(data->state == LV_INDEV_STATE_PR) { + auto xy = RF_CALL_BLOCKING(touchController.getTouchPosition()); + data->point.x = std::get<0>(xy); + data->point.y = std::get<1>(xy); + } + return false; +} + +void my_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) +{ + tftController.drawRaw( + {area->x1, area->y1}, + (area->x2 - area->x1 +1), + (area->y2 - area->y1 + 1), + (modm::glcd::Color*)color_p); + lv_disp_flush_ready(disp_drv); +} + +static uint16_t btn2Counter = 0; + +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 = 500, + }; + touchController.setCalibration(cal); + + MODM_LOG_INFO << "modm LVGL example on Nucleo-L452RE board!\n\n"; + + if (FaultReporter::hasReport()) + { + MODM_LOG_ERROR << "\n\nHardFault! Copy the data into a 'coredump.txt' file, "; + MODM_LOG_ERROR << "then execute\n\n\tscons postmortem firmware=" << modm::hex; + for (const auto data : FaultReporter::buildId()) MODM_LOG_ERROR << data; + MODM_LOG_ERROR << "\n\n"; + for (const auto data : FaultReporter()) + MODM_LOG_ERROR << modm::hex << data << modm::flush; + MODM_LOG_ERROR << "\n\n\n" << modm::flush; + FaultReporter::clear(); + while (1) ; + } + + lv_init(); + + // Initialize the display buffer + lv_disp_buf_init(&disp_buf, buf, NULL, buf_size); + + // Initialize the display: + lv_disp_drv_t disp_drv; + lv_disp_drv_init(&disp_drv); + disp_drv.buffer = &disp_buf; + disp_drv.flush_cb = my_flush_cb; + disp_drv.hor_res = LV_HOR_RES_MAX; + disp_drv.ver_res = LV_VER_RES_MAX; + lv_disp_t * disp; + disp = lv_disp_drv_register(&disp_drv); + + // Initialize touchscreen driver: + 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_obj_t* scr = lv_disp_get_scr_act(disp); // Get the current screen + + lv_obj_t* labelA = lv_label_create(scr, NULL); + lv_label_set_text(labelA, "Hello world!"); + lv_obj_set_pos(labelA, 60, 10); + lv_obj_set_size(labelA, 120, 50); + + lv_obj_t* btn2 = lv_btn_create(lv_scr_act(), NULL); + lv_obj_set_pos(btn2, 60, 135); + lv_obj_set_size(btn2, 120, 50); + lv_obj_t* label2 = lv_label_create(btn2, NULL); + lv_label_set_text(label2, "Button2"); + lv_obj_set_event_cb(btn2, [](struct _lv_obj_t * obj, lv_event_t event) { + if(event == LV_EVENT_PRESSED) { + lv_label_set_text_fmt(lv_obj_get_child(obj, NULL), "Button 2: %d", ++btn2Counter); + } + }); + + uint16_t counter = 0; + + while (true) + { + lv_label_set_text_fmt(labelA, "counter=%d", ++counter); + lv_tick_inc(10); + lv_task_handler(); + modm::delay(10ms); + } + + return 0; +} diff --git a/examples/nucleo_l452re/lvgl/project.xml b/examples/nucleo_l452re/lvgl/project.xml new file mode 100644 index 0000000000..745507b19e --- /dev/null +++ b/examples/nucleo_l452re/lvgl/project.xml @@ -0,0 +1,22 @@ + + modm:nucleo-l452re + + + + + + + + + + modm:platform:fault + modm:platform:heap + modm:build:scons + modm:driver:ili9341 + modm:driver:touch2046 + modm:platform:spi:1 + modm:platform:spi:2 + modm:platform:dma + modm:lvgl + +