【GD32E503评测】+ littlegl移植到GD32E503V-EVAL
[复制链接]
LittlevGL移植到GD32E503V
前面已经成功的移植了tos到GD32E503V处理器上,基于tos,将LittlevGL移植到GD32E503V-eval开发板。
LittlevGL介绍
LittlevGL是一个免费的开放源代码图形库,它提供创建嵌入式GUI所需的一切,它具有易于使用的图形元素,精美的视觉效果和低内存占用。
特性:
16, 32 or 64 bit microcontroller or processor
16 MHz clock speed
8 kB RAM for static data and >2 KB RAM for dynamic data (graphical objects)
64 kB program memory (flash)
支持GPU
硬件连接关系
LittleGL系统需要LCD显示器和触摸屏输入两样主要的硬件设备。
图 LCD和触摸屏接口
GD32E503V-EVAL开发板使用EXMC模块来控制LCD。通过GPIO模拟SPI接口连接触摸屏。
LCD和触摸屏接口
|
GD32E503V 端口
|
D0~D15
|
EXMC_D0~EXMC_D15
|
LCD_CS
|
PD7
|
LCD_RS
|
EXMC_A23
|
LCD_WR
|
PD5
|
LCD_RD
|
PD4
|
LCD_RST
|
NRST
|
TP_MISO
|
PA6
|
TP_MOSI
|
PA7
|
TP_SCK
|
PA5
|
TP_INT
|
PE5
|
TP_CS
|
PE6
|
驱动代码
- LCD驱动
我们在官方的驱动中已经包含了LCD的驱动代码,这里不详细解释。
- 触摸屏驱动
官方驱动中包含了触摸屏驱动代码,直接使用就可以,不详细解释。
LittleGL移植
- 目录结构
还包括一个example目录,我们在测试的时候会选择其中的一个加入工程中。
- 输入设备的移植
输入设备在lvgl/port/lv_port_indev.c中,包括触摸屏,鼠标,键盘,编码器,和按键输入五中输入手段。
本次仅移植触摸屏输入方式,在void lv_port_indev_init(void)函数中,除触摸屏输入的初始化外,其它输入方式暂时隐藏起来。
触摸屏需要完成如下几个函数的移植:
- static void touchpad_init(void)函数的移植,这个函数用来完成触摸屏的初始化工作,可以将官方提供的触摸屏初始化函数在此处调用。
touch_panel_gpio_configure();
- static bool touchpad_is_pressed(void)函数的移植,这个函数用来完成触摸屏被点击后的检测通知函数,将触摸屏的中断输入引脚PE5的状态检测放到这里。
- static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y)函数的移植,这个函数用来读取点击的触摸屏的位置信息。
static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y)
{
/*Your code comes here*/
uint16_t touch_ad_x,touch_ad_y;
touch_ad_xy_get(&touch_ad_x, &touch_ad_y);
(*x) = touch_coordinate_x_get(touch_ad_x);
(*y) = LCD_Y - touch_coordinate_y_get(touch_ad_y);
}
- 显示设备的移植
显示设备在lvgl/port/lv_port_disp.c中,包括显示设备初始化,和显示内容刷新及显示缓存的定义。
在void lv_port_disp_init(void)中,重点需要移植的内容:
- 显示设备的初始化
static void disp_init(void)函数,将官方驱动中,显示设备的初始化函数放在这个函数中,完成显示设备初始化。
- 显示缓存设置
这个是显存初始化中的一段说明,如下说明了显存包含3种类型的缓存,第一种为分配若干行的显示内容大小的内存作为显存,这是最小的显存分配方式,对于嵌入式系统中使用最广范的一种,通常分配为20行的内存空间;
第二种为分配两个大小相同的显示缓冲区,每个显示缓冲区为若干行显示内容对应的内存。这种方式通常采用DMA的方式刷新显示混存。
第三种为分配两个大小相同的显示缓冲区,每个显示缓冲区的大小为整个屏幕对应的显示内容对应的内存大小,这种方式对于屏幕的刷新速度是最快的,但是占用的内存也是最多的。
/* LittlevGL requires a buffer where it draws the objects. The buffer's has to be greater than 1 display row
*
* There are three buffering configurations:
* 1. Create ONE buffer with some rows:
* LittlevGL will draw the display's content here and writes it to your display
*
* 2. Create TWO buffer with some rows:
* LittlevGL will draw the display's content to a buffer and writes it your display.
* You should use DMA to write the buffer's content to the display.
* It will enable LittlevGL to draw the next part of the screen to the other buffer while
* the data is being sent form the first buffer. It makes rendering and flushing parallel.
*
* 3. Create TWO screen-sized buffer:
* Similar to 2) but the buffer have to be screen sized. When LittlevGL is ready it will give the
* whole frame to display. This way you only need to change the frame buffer's address instead of
* copying the pixels.
* */
/* Example for 1) */
static lv_disp_buf_t disp_buf_1;
static lv_color_t buf1_1[LV_HOR_RES_MAX * 20]; /*A buffer for 20 rows*/
lv_disp_buf_init(&disp_buf_1, buf1_1, NULL, LV_HOR_RES_MAX * 20); /*Initialize the display buffer*/
/* Example for 2) */
// static lv_disp_buf_t disp_buf_2;
// static lv_color_t buf2_1[LV_HOR_RES_MAX * 40]; /*A buffer for 10 rows*/
// static lv_color_t buf2_2[LV_HOR_RES_MAX * 40]; /*An other buffer for 10 rows*/
// lv_disp_buf_init(&disp_buf_2, buf2_1, buf2_2, LV_HOR_RES_MAX * 40); /*Initialize the display buffer*/
/* Example for 3) */
// static lv_disp_buf_t disp_buf_3;
// static lv_color_t buf3_1[LV_HOR_RES_MAX * LV_VER_RES_MAX]; /*A screen sized buffer*/
// static lv_color_t buf3_2[LV_HOR_RES_MAX * LV_VER_RES_MAX]; /*An other screen sized buffer*/
// lv_disp_buf_init(&disp_buf_3, buf3_1, buf3_2, LV_HOR_RES_MAX * LV_VER_RES_MAX); /*Initialize the display buffer*/
对于本次的显示缓存,采用第一种分配方式,20行的显示内容对应的内存大小。
- 屏幕尺寸大小定义
这个地方重新定义了屏幕的尺寸,GD32E503V-eval的评估板对应的显示器为320x240,因此填充为如下。
/*Set the resolution of the display*/
disp_drv.hor_res = 240;
disp_drv.ver_res = 320;
- 显示刷新函数的移植
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)的移植是最重要的物理设备接口函数,完成从显示缓存到LCD显示内容刷新的接口函数,利用官方提供的驱动接口,填充为:
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
/*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/
int32_t x;
int32_t y;
for(y = area->y1; y <= area->y2; y++) {
for(x = area->x1; x <= area->x2; x++) {
/* Put a pixel to the display. For example: */
/* put_px(x, y, *color_p)*/
lcd_point_set(x, y,color_p->full);
color_p++;
}
}
/* IMPORTANT!!!
* Inform the graphics library that you are ready with the flushing*/
lv_disp_flush_ready(disp_drv);
}
- 运行的其它移植
为了保证LittleGL的正确运行,还需要添加如下几个部分的添加。
- 1ms定时器的添加
在系统的1ms定时器,必须添加lv_tick_inc(1);的调用,用于gui的内容定时。
- 运行任务的添加
为了让gui显示允许,需要创建一个任务来定时的刷新gui的函数。
基于tos的gui运行任务,通常要求任务堆栈不小于4K,优先级应略高。
#define LVGL_TASK_STK_SIZE 4096
extern void lvgl_task_entry(void *arg);
osThreadDef(lvgl_task_entry, osPriorityNormal, 1, LVGL_TASK_STK_SIZE);
在任务中应定时调用gui的处理函数。
void lvgl_task_entry(void *arg)
{
lv_init();
lv_port_disp_init();
lv_port_indev_init();
demo_create();
while (1) {
lv_task_handler();
tos_task_delay(30);
}
}
到此LittleGL的gui移植已经基本完成。
LittleGL demon测试展示
我们在前面移植的基础上,添加example中的demo来展示一下实际的显示效果。
|