From b7764f2aacd7ade8c24e4313c82599ec9c75524f Mon Sep 17 00:00:00 2001 From: guozhanxin Date: Tue, 26 Oct 2021 18:42:35 +0800 Subject: [PATCH] [bsp][stm32f469-st-disco] add lvgl port. --- bsp/stm32/stm32f469-st-disco/SConstruct | 3 + bsp/stm32/stm32f469-st-disco/board/Kconfig | 10 +- bsp/stm32/stm32f469-st-disco/board/SConscript | 5 +- .../stm32f469-st-disco/board/ports/SConscript | 12 + .../board/ports/lvgl/SConscript | 9 + .../board/ports/lvgl/lv_conf.h | 17 ++ .../board/ports/lvgl/lv_demo.c | 100 ++++++++ .../board/ports/lvgl/lv_port_disp.c | 214 ++++++++++++++++++ .../board/ports/lvgl/lv_port_disp.h | 23 ++ .../board/ports/lvgl/lv_port_indev.c | 46 ++++ .../board/ports/lvgl/lv_port_indev.h | 28 +++ .../board/ports/touch/drv_touch.c | 12 + .../board/ports/touch/drv_touch_ft.c | 2 + 13 files changed, 476 insertions(+), 5 deletions(-) create mode 100644 bsp/stm32/stm32f469-st-disco/board/ports/SConscript create mode 100644 bsp/stm32/stm32f469-st-disco/board/ports/lvgl/SConscript create mode 100644 bsp/stm32/stm32f469-st-disco/board/ports/lvgl/lv_conf.h create mode 100644 bsp/stm32/stm32f469-st-disco/board/ports/lvgl/lv_demo.c create mode 100644 bsp/stm32/stm32f469-st-disco/board/ports/lvgl/lv_port_disp.c create mode 100644 bsp/stm32/stm32f469-st-disco/board/ports/lvgl/lv_port_disp.h create mode 100644 bsp/stm32/stm32f469-st-disco/board/ports/lvgl/lv_port_indev.c create mode 100644 bsp/stm32/stm32f469-st-disco/board/ports/lvgl/lv_port_indev.h diff --git a/bsp/stm32/stm32f469-st-disco/SConstruct b/bsp/stm32/stm32f469-st-disco/SConstruct index 1684dc06b0..d12fb5b0d1 100644 --- a/bsp/stm32/stm32f469-st-disco/SConstruct +++ b/bsp/stm32/stm32f469-st-disco/SConstruct @@ -56,5 +56,8 @@ objs.extend(SConscript(os.path.join(libraries_path_prefix, stm32_library, 'SCons # include drivers objs.extend(SConscript(os.path.join(libraries_path_prefix, 'HAL_Drivers', 'SConscript'))) +# include ports +objs.extend(SConscript(os.path.join(os.getcwd(), 'board', 'ports', 'SConscript'))) + # make a building DoBuilding(TARGET, objs) diff --git a/bsp/stm32/stm32f469-st-disco/board/Kconfig b/bsp/stm32/stm32f469-st-disco/board/Kconfig index a1dd9ff7f7..c85eae3a19 100644 --- a/bsp/stm32/stm32f469-st-disco/board/Kconfig +++ b/bsp/stm32/stm32f469-st-disco/board/Kconfig @@ -8,6 +8,14 @@ config SOC_STM32F469NI default y menu "Onboard Peripheral Drivers" + + config BSP_USING_LVGL + bool "Enable LVGL" + select BSP_USING_LCD_OTM8009A + select BSP_USING_TOUCH + select PKG_USING_LVGL + default n + config BSP_USING_SDRAM bool "Enable SDRAM" select BSP_USING_FMC @@ -23,7 +31,7 @@ menu "Onboard Peripheral Drivers" select BSP_USING_LTDC select BSP_USING_LCD_MIPI default n - + config BSP_USING_QSPI_FLASH bool "Enable QSPI FLASH (N25Q128A qspi1)" select BSP_USING_QSPI diff --git a/bsp/stm32/stm32f469-st-disco/board/SConscript b/bsp/stm32/stm32f469-st-disco/board/SConscript index 9521cc5907..5f31252268 100644 --- a/bsp/stm32/stm32f469-st-disco/board/SConscript +++ b/bsp/stm32/stm32f469-st-disco/board/SConscript @@ -20,10 +20,7 @@ if GetDepend(['PKG_USING_FAL']): if GetDepend(['BSP_USING_LCD_OTM8009A']): src += ['ports/drv_otm8009a.c'] - -if GetDepend(['BSP_USING_TOUCH']): - src += Glob('ports/touch/*.c') - + if GetDepend(['BSP_USING_SDCARD']): src += ['ports/drv_sdcard.c'] diff --git a/bsp/stm32/stm32f469-st-disco/board/ports/SConscript b/bsp/stm32/stm32f469-st-disco/board/ports/SConscript new file mode 100644 index 0000000000..3c57bc9c6d --- /dev/null +++ b/bsp/stm32/stm32f469-st-disco/board/ports/SConscript @@ -0,0 +1,12 @@ +import os +from building import * + +objs = [] +cwd = GetCurrentDir() + +list = os.listdir(cwd) +for item in list: + if os.path.isfile(os.path.join(cwd, item, 'SConscript')): + objs = objs + SConscript(os.path.join(item, 'SConscript')) + +Return('objs') diff --git a/bsp/stm32/stm32f469-st-disco/board/ports/lvgl/SConscript b/bsp/stm32/stm32f469-st-disco/board/ports/lvgl/SConscript new file mode 100644 index 0000000000..cb74975f39 --- /dev/null +++ b/bsp/stm32/stm32f469-st-disco/board/ports/lvgl/SConscript @@ -0,0 +1,9 @@ +from building import * + +cwd = GetCurrentDir() + +src = Glob('*.c') +CPPPATH = [cwd] + +group = DefineGroup('LVGL-port', src, depend = ['BSP_USING_LVGL'], CPPPATH = CPPPATH) +Return('group') diff --git a/bsp/stm32/stm32f469-st-disco/board/ports/lvgl/lv_conf.h b/bsp/stm32/stm32f469-st-disco/board/ports/lvgl/lv_conf.h new file mode 100644 index 0000000000..ac9f12680a --- /dev/null +++ b/bsp/stm32/stm32f469-st-disco/board/ports/lvgl/lv_conf.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-10-18 Meco Man First version + */ + +#ifndef LV_CONF_H +#define LV_CONF_H + +#define LV_USE_PERF_MONITOR 1 +#define LV_COLOR_DEPTH 32 + +#endif diff --git a/bsp/stm32/stm32f469-st-disco/board/ports/lvgl/lv_demo.c b/bsp/stm32/stm32f469-st-disco/board/ports/lvgl/lv_demo.c new file mode 100644 index 0000000000..2818a4d8fa --- /dev/null +++ b/bsp/stm32/stm32f469-st-disco/board/ports/lvgl/lv_demo.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-10-17 Meco Man First version + */ +#include +#include +#define DBG_TAG "LVGL" +#define DBG_LVL DBG_INFO +#include +#include +#include + +#ifndef LV_THREAD_STACK_SIZE +#define LV_THREAD_STACK_SIZE 4096 +#endif + +#ifndef LV_THREAD_PRIO +#define LV_THREAD_PRIO (RT_THREAD_PRIORITY_MAX*2/3) +#endif + +static void event_handler(lv_event_t * e) +{ + lv_event_code_t code = lv_event_get_code(e); + lv_obj_t * obj = lv_event_get_target(e); + + if(code == LV_EVENT_VALUE_CHANGED) { + lv_calendar_date_t date; + if(lv_calendar_get_pressed_date(obj, &date)) { + LV_LOG_USER("Clicked date: %02d.%02d.%d", date.day, date.month, date.year); + } + } +} + +void lv_example_calendar_1(void) +{ + lv_obj_t * calendar = lv_calendar_create(lv_scr_act()); + lv_obj_set_size(calendar, LCD_WIDTH, LCD_HEIGHT); + lv_obj_align(calendar, LV_ALIGN_CENTER, 0, 60); + lv_obj_add_event_cb(calendar, event_handler, LV_EVENT_ALL, NULL); + + lv_calendar_set_today_date(calendar, 2021, 02, 23); + lv_calendar_set_showed_date(calendar, 2021, 02); + + /*Highlight a few days*/ + static lv_calendar_date_t highlighted_days[3]; /*Only its pointer will be saved so should be static*/ + highlighted_days[0].year = 2021; + highlighted_days[0].month = 02; + highlighted_days[0].day = 6; + + highlighted_days[1].year = 2021; + highlighted_days[1].month = 02; + highlighted_days[1].day = 11; + + highlighted_days[2].year = 2022; + highlighted_days[2].month = 02; + highlighted_days[2].day = 22; + + lv_calendar_set_highlighted_dates(calendar, highlighted_days, 3); + +#if LV_USE_CALENDAR_HEADER_DROPDOWN + lv_calendar_header_dropdown_create(lv_scr_act()); +#elif LV_USE_CALENDAR_HEADER_ARROW + lv_calendar_header_arrow_create(lv_scr_act(), calendar, 25); +#endif +} + +static void lvgl_thread(void *parameter) +{ + /*assign buttons to coordinates*/ + const lv_point_t points_array[] = {{200,35},{0,0},{70,35},{0,0}}; + lv_indev_set_button_points(button_indev, points_array); + + lv_example_calendar_1(); + + while(1) + { + lv_task_handler(); + rt_thread_mdelay(10); + } +} + +static int lvgl_demo_init(void) +{ + rt_thread_t tid; + + tid = rt_thread_create("LVGL", lvgl_thread, RT_NULL, LV_THREAD_STACK_SIZE, LV_THREAD_PRIO, 0); + if(tid == RT_NULL) + { + LOG_E("Fail to create 'LVGL' thread"); + } + rt_thread_startup(tid); + + return 0; +} +INIT_APP_EXPORT(lvgl_demo_init); diff --git a/bsp/stm32/stm32f469-st-disco/board/ports/lvgl/lv_port_disp.c b/bsp/stm32/stm32f469-st-disco/board/ports/lvgl/lv_port_disp.c new file mode 100644 index 0000000000..c8f1a48230 --- /dev/null +++ b/bsp/stm32/stm32f469-st-disco/board/ports/lvgl/lv_port_disp.c @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-10-18 Meco Man The first version + */ +#include +#include + +/*A static or global variable to store the buffers*/ +static lv_disp_draw_buf_t disp_buf; + +rt_device_t lcd_device = 0; +static struct rt_device_graphic_info info; + +static lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/ + +typedef struct +{ + uint8_t blue; + uint8_t green; + uint8_t red; +} lv_color24_t; + +static void color_to16_maybe(lv_color16_t *dst, lv_color_t *src) +{ +#if (LV_COLOR_DEPTH == 16) + dst->full = src->full; +#else + dst->ch.blue = src->ch.blue; + dst->ch.green = src->ch.green; + dst->ch.red = src->ch.red; +#endif +} + +static void color_to24(lv_color24_t *dst, lv_color_t *src) +{ + dst->blue = src->ch.blue; + dst->green = src->ch.green; + dst->red = src->ch.red; +} + +/*Flush the content of the internal buffer the specific area on the display + *You can use DMA or any hardware acceleration to do this operation in the background but + *'lv_disp_flush_ready()' has to be called when finished.*/ +static void lcd_fb_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p) +{ + int x1, x2, y1, y2; + + x1 = area->x1; + x2 = area->x2; + y1 = area->y1; + y2 = area->y2; + + /*Return if the area is out the screen*/ + if (x2 < 0) + return; + if (y2 < 0) + return; + if (x1 > info.width - 1) + return; + if (y1 > info.height - 1) + return; + + /*Truncate the area to the screen*/ + int32_t act_x1 = x1 < 0 ? 0 : x1; + int32_t act_y1 = y1 < 0 ? 0 : y1; + int32_t act_x2 = x2 > info.width - 1 ? info.width - 1 : x2; + int32_t act_y2 = y2 > info.height - 1 ? info.height - 1 : y2; + + uint32_t x; + uint32_t y; + long int location = 0; + + /* 8 bit per pixel */ + if (info.bits_per_pixel == 8) + { + uint8_t *fbp8 = (uint8_t *)info.framebuffer; + //TODO color convert maybe + for (y = act_y1; y <= act_y2; y++) + { + for (x = act_x1; x <= act_x2; x++) + { + location = (x) + (y)*info.width; + fbp8[location] = color_p->full; + color_p++; + } + + color_p += x2 - act_x2; + } + } + + /* 16 bit per pixel */ + else if (info.bits_per_pixel == 16) + { + lv_color16_t *fbp16 = (lv_color16_t *)info.framebuffer; + + for (y = act_y1; y <= act_y2; y++) + { + for (x = act_x1; x <= act_x2; x++) + { + location = (x) + (y)*info.width; + color_to16_maybe(&fbp16[location], color_p); + color_p++; + } + + color_p += x2 - act_x2; + } + } + + /* 24 bit per pixel */ + else if (info.bits_per_pixel == 24) + { + lv_color24_t *fbp24 = (lv_color24_t *)info.framebuffer; + + for (y = act_y1; y <= act_y2; y++) + { + for (x = act_x1; x <= act_x2; x++) + { + location = (x) + (y)*info.width; + color_to24(&fbp24[location], color_p); + color_p++; + } + + color_p += x2 - act_x2; + } + } + + /* 32 bit per pixel */ + else if (info.bits_per_pixel == 32) + { + uint32_t *fbp32 = (uint32_t *)info.framebuffer; + //TODO + for (y = act_y1; y <= act_y2; y++) + { + for (x = act_x1; x <= act_x2; x++) + { + location = (x) + (y)*info.width; + fbp32[location] = color_p->full; + color_p++; + } + + color_p += x2 - act_x2; + } + } + + struct rt_device_rect_info rect_info; + + rect_info.x = x1; + rect_info.y = y1; + rect_info.width = x2 - x1 + 1; + rect_info.height = y2 - y1 + 1; + rt_device_control(lcd_device, RTGRAPHIC_CTRL_RECT_UPDATE, &rect_info); + + lv_disp_flush_ready(disp_drv); +} + +void lv_port_disp_init(void) +{ + rt_err_t result; + lv_color_t *fbuf; + + lcd_device = rt_device_find("lcd"); + if (lcd_device == 0) + { + rt_kprintf("error!\n"); + return; + } + result = rt_device_open(lcd_device, 0); + if (result != RT_EOK) + { + rt_kprintf("error!\n"); + return; + } + /* get framebuffer address */ + result = rt_device_control(lcd_device, RTGRAPHIC_CTRL_GET_INFO, &info); + if (result != RT_EOK) + { + rt_kprintf("error!\n"); + /* get device information failed */ + return; + } + + RT_ASSERT(info.bits_per_pixel == 8 || info.bits_per_pixel == 16 || + info.bits_per_pixel == 24 || info.bits_per_pixel == 32); + + fbuf = rt_malloc(info.width * info.height / 10); + if (!fbuf) + { + rt_kprintf("Error: alloc disp buf fail\n"); + return; + } + + /*Initialize `disp_buf` with the buffer(s). With only one buffer use NULL instead buf_2 */ + lv_disp_draw_buf_init(&disp_buf, fbuf, RT_NULL, info.width * 10); + + lv_disp_drv_init(&disp_drv); /*Basic initialization*/ + + /*Set the resolution of the display*/ + disp_drv.hor_res = info.width; + disp_drv.ver_res = info.height; + + /*Set a display buffer*/ + disp_drv.draw_buf = &disp_buf; + + /*Used to copy the buffer's content to the display*/ + disp_drv.flush_cb = lcd_fb_flush; + + /*Finally register the driver*/ + lv_disp_drv_register(&disp_drv); +} diff --git a/bsp/stm32/stm32f469-st-disco/board/ports/lvgl/lv_port_disp.h b/bsp/stm32/stm32f469-st-disco/board/ports/lvgl/lv_port_disp.h new file mode 100644 index 0000000000..ef39eb03cd --- /dev/null +++ b/bsp/stm32/stm32f469-st-disco/board/ports/lvgl/lv_port_disp.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-10-18 Meco Man The first version + */ +#ifndef LV_PORT_DISP_H +#define LV_PORT_DISP_H + +#ifdef __cplusplus +extern "C" { +#endif + +void lv_port_disp_init(void); + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif diff --git a/bsp/stm32/stm32f469-st-disco/board/ports/lvgl/lv_port_indev.c b/bsp/stm32/stm32f469-st-disco/board/ports/lvgl/lv_port_indev.c new file mode 100644 index 0000000000..b190a32a91 --- /dev/null +++ b/bsp/stm32/stm32f469-st-disco/board/ports/lvgl/lv_port_indev.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-10-18 Meco Man The first version + */ +#include +#include +#include + +#include + +static lv_indev_state_t last_state = LV_INDEV_STATE_REL; +static rt_int16_t last_x = 0; +static rt_int16_t last_y = 0; + +static void input_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data) +{ + data->point.x = last_x; + data->point.y = last_y; + data->state = last_state; +} + +void lv_port_indev_input(rt_int16_t x, rt_int16_t y, lv_indev_state_t state) +{ + last_state = state; + last_x = x; + last_y = LCD_HEIGHT - y; +} + +lv_indev_t * button_indev; + +void lv_port_indev_init(void) +{ + static lv_indev_drv_t indev_drv; + + lv_indev_drv_init(&indev_drv); /*Basic initialization*/ + indev_drv.type = LV_INDEV_TYPE_POINTER; + indev_drv.read_cb = input_read; + + /*Register the driver in LVGL and save the created input device object*/ + button_indev = lv_indev_drv_register(&indev_drv); +} diff --git a/bsp/stm32/stm32f469-st-disco/board/ports/lvgl/lv_port_indev.h b/bsp/stm32/stm32f469-st-disco/board/ports/lvgl/lv_port_indev.h new file mode 100644 index 0000000000..d15f0e5cfa --- /dev/null +++ b/bsp/stm32/stm32f469-st-disco/board/ports/lvgl/lv_port_indev.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-10-18 Meco Man The first version + */ +#ifndef LV_PORT_INDEV_H +#define LV_PORT_INDEV_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +extern lv_indev_t * button_indev; + +void lv_port_indev_init(void); +void lv_port_indev_input(rt_int16_t x, rt_int16_t y, lv_indev_state_t state); + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif diff --git a/bsp/stm32/stm32f469-st-disco/board/ports/touch/drv_touch.c b/bsp/stm32/stm32f469-st-disco/board/ports/touch/drv_touch.c index 53437f34ef..3dd47068ee 100644 --- a/bsp/stm32/stm32f469-st-disco/board/ports/touch/drv_touch.c +++ b/bsp/stm32/stm32f469-st-disco/board/ports/touch/drv_touch.c @@ -16,6 +16,10 @@ #include #elif defined(PKG_USING_LITTLEVGL2RTT) #include +#elif defined(PKG_USING_LVGL) +#include +#include +static rt_bool_t touch_down = RT_FALSE; #endif #define BSP_TOUCH_SAMPLE_HZ (50) @@ -50,6 +54,9 @@ static void post_down_event(rt_uint16_t x, rt_uint16_t y, rt_tick_t ts) rtgui_server_post_event(&emouse.parent, sizeof(emouse)); #elif defined(PKG_USING_LITTLEVGL2RTT) littlevgl2rtt_send_input_event(x, y, LITTLEVGL2RTT_INPUT_DOWN); +#elif defined(PKG_USING_LVGL) + touch_down = RT_TRUE; + lv_port_indev_input(x, y, (touch_down == RT_TRUE) ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL); #endif } @@ -70,6 +77,8 @@ static void post_motion_event(rt_uint16_t x, rt_uint16_t y, rt_tick_t ts) rtgui_server_post_event(&emouse.parent, sizeof(emouse)); #elif defined(PKG_USING_LITTLEVGL2RTT) littlevgl2rtt_send_input_event(x, y, LITTLEVGL2RTT_INPUT_MOVE); +#elif defined(PKG_USING_LVGL) + lv_port_indev_input(x, y, (touch_down == RT_TRUE) ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL); #endif } @@ -90,6 +99,9 @@ static void post_up_event(rt_uint16_t x, rt_uint16_t y, rt_tick_t ts) rtgui_server_post_event(&emouse.parent, sizeof(emouse)); #elif defined(PKG_USING_LITTLEVGL2RTT) littlevgl2rtt_send_input_event(x, y, LITTLEVGL2RTT_INPUT_MOVE); +#elif defined(PKG_USING_LVGL) + touch_down = RT_FALSE; + lv_port_indev_input(x, y, (touch_down == RT_TRUE) ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL); #endif } diff --git a/bsp/stm32/stm32f469-st-disco/board/ports/touch/drv_touch_ft.c b/bsp/stm32/stm32f469-st-disco/board/ports/touch/drv_touch_ft.c index e85e793573..bd2db859ba 100644 --- a/bsp/stm32/stm32f469-st-disco/board/ports/touch/drv_touch_ft.c +++ b/bsp/stm32/stm32f469-st-disco/board/ports/touch/drv_touch_ft.c @@ -13,6 +13,8 @@ #include #include #include "drv_touch.h" + +#include #include #ifdef BSP_USING_TOUCH