这几天我用ESP32通过LVGL成功驱动了一块ILI9488的TFT。
但是遇到一个问题始终不能解决。
无论我放置什么组件到屏幕的右侧边缘(屏幕的 x = 0 在最左边)总会出现一串亮点,并且有从上到下越来越亮的现象。
效果是这样:
[attachment=1]微信图片_40.jpg[/attachment]
或者这样:
[attachment=0]微信图片_20.jpg[/attachment]
是不是很有趣的现象?
起初问题的表现为图1,经过我的观察,总共有8个亮点,而我的屏幕y轴分辨率为 320.
仔细思考后,猜测,是否再刷新LCD时,LVGL把整个屏幕分成了8块,而每一块的最后一个点数据错误,导致变色。
随后我更改了 lvgl_helpers.h 中的这个宏定义:
#elif defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_ILI9488
#define DISP_BUF_SIZE (LV_HOR_RES_MAX * 40) /* 我将 40 改为20 */
因为 40 * 8 刚好是 320 , 而他定义的 DISP_BUF_SIZE 是屏幕宽度(480)的 40 倍,这样算下来刚好 8 次刷满一个屏幕。
现在我把常数 40 改为 20 , 会不会出现16个渐渐变亮的点呢?
图2,正是我修改后的结果。不多不少整整16个。
后来我又怀疑是不是屏幕本身的质量问题,导致了这样的结果。经过反复测试,无论我把屏幕定义为多大,
也就是:
#define LV_HOR_RES_MAX 480
#define LV_VER_RES_MAX 320
这无论无何改变,所规定的屏幕边缘区域都会出现这样一排亮点。
也就是说 如果我把屏幕变为 LV_HOR_RES_MAX 320 ,假设是一块320 x 320的屏幕,在屏幕 X = 320 的纵轴上依然会出现这样的亮点。
下面是我目前的代码:
1>gui任务初始化部分
static void guiTask(void *pvParameter)
{
(void)pvParameter;
xGuiSemaphore = xSemaphoreCreateMutex();
lv_init();
/* Initialize SPI or I2C bus used by the drivers */
lvgl_driver_init();
lv_color_t *buf1 = heap_caps_malloc(DISP_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);
assert(buf1 != NULL);
static lv_color_t *buf2 = NULL;
static lv_disp_draw_buf_t disp_buf;
uint32_t size_in_px = DISP_BUF_SIZE; /* 就是这里传入了显示BUFF的大小 480 x 40 */
/* Initialize the working buffer depending on the selected display.
* NOTE: buf2 == NULL when using monochrome displays. */
lv_disp_draw_buf_init(&disp_buf, buf1, buf2, size_in_px);
lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.flush_cb = disp_driver_flush;
disp_drv.hor_res = LV_HOR_RES_MAX;
disp_drv.ver_res = LV_VER_RES_MAX;
disp_drv.draw_buf = &disp_buf;
lv_disp_drv_register(&disp_drv);
/* Register an input device when enabled on the menuconfig */
#if CONFIG_LV_TOUCH_CONTROLLER != TOUCH_CONTROLLER_NONE
lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);
indev_drv.read_cb = touch_driver_read;
indev_drv.type = LV_INDEV_TYPE_POINTER;
lv_indev_drv_register(&indev_drv);
#endif
/* Create and start a periodic timer interrupt to call lv_tick_inc */
const esp_timer_create_args_t periodic_timer_args = {
.callback = &lv_tick_task,
.name = "periodic_gui"};
esp_timer_handle_t periodic_timer;
ESP_ERROR_CHECK(esp_timer_create(&periodic_timer_args, &periodic_timer));
ESP_ERROR_CHECK(esp_timer_start_periodic(periodic_timer, portTICK_PERIOD_MS * 1000));
/* Create the demo application */
create_demo_application();
while (1)
{
/* Delay 1 tick (assumes FreeRTOS tick is 10ms */
vTaskDelay(pdMS_TO_TICKS(10));
/* Try to take the semaphore, call lvgl related function on success */
if (pdTRUE == xSemaphoreTake(xGuiSemaphore, portMAX_DELAY))
{
lv_task_handler();
xSemaphoreGive(xGuiSemaphore);
}
}
/* A task should NEVER return */
free(buf1);
#ifndef CONFIG_LV_TFT_DISPLAY_MONOCHROME
free(buf2);
#endif
vTaskDelete(NULL);
}
2>界面实体部分
LV_IMG_DECLARE(back_img); /* 用于桌面背景的图片 size = 480 x 320 */
static void create_demo_application(void)
{
#if 1 /* 这里显示的图片就是背景图片,图片本身没有问题,我也用纯色的图片测试过,甚至改变桌面的颜色 结果都一样 */
lv_obj_t *back_img_hal = lv_img_create(lv_scr_act());
lv_img_set_src(back_img_hal, &back_img);
lv_obj_align(back_img_hal, LV_ALIGN_TOP_LEFT, 0, 0);
....以下绘制了一些用于显示内容的 box ,无论是否编译对该问题没有影响。
.
.
.
.
.
}
有没有大神帮忙分析一下,问题出在哪里?我该如何处理?
谢谢您的解答,不甚感激!
求助,有趣的LVGL驱动ILI9488,屏幕边缘有一排亮点。[已解决]
求助,有趣的LVGL驱动ILI9488,屏幕边缘有一排亮点。[已解决]
- Attachments
-
- 微信图片_20.jpg (364.92 KiB) Viewed 6688 times
-
- 微信图片_40.jpg (331.64 KiB) Viewed 6688 times
Re: 求助,有趣的LVGL驱动ILI9488,屏幕边缘有一排亮点。
排版出了点问题,图片位置怎么跑到最后去了。还有代码没有了缩进。
Re: 求助,有趣的LVGL驱动ILI9488,屏幕边缘有一排亮点。
有木有人啊?给个建议也好啊~!~~~
Re: 求助,有趣的LVGL驱动ILI9488,屏幕边缘有一排亮点。
求人不如求己,问题找到了。也从一定程度上解决了。但是本质问题还没找到,目前采用补窟窿的方式解决的。
在这里留个记号,如果有朋友遇到此问题可以这样解决或者大家一起讨论。
LVGL刷屏的本质动作是 , 设定起点坐标和终点坐标, 用连续传输模式,使用DMA传输。
在每一次传输一块图像前,都有
/*Column addresses*/
ili9488_send_cmd(ILI9488_CMD_COLUMN_ADDRESS_SET);
ili9488_send_data(xb, 4);/* 起点X 终点X 每个占用2字节 */
/*Page addresses*/
ili9488_send_cmd(ILI9488_CMD_PAGE_ADDRESS_SET);
ili9488_send_data(yb, 4);/* 起点Y 终点Y 每个占用2字节 */
我以前不上GUI的时候,采用的是只设置起点,并用连续模式传输多少个点,来完成的。
他设置了起点和终点。这是一种什么思路?我是真的不懂,请指教。
他每次传输的块的大小等于你设定的 (屏幕宽度 * 40),单位是点。
每次回调 flush 都是只刷新 这么大一块。
可是问题就就就出现在 假设我连续传输 sum 个点,理论上是 buf[0]~buf[sum-1],
可是就是这个 buf[sum - 1] 不会被正确的传输,可能根本就没传输?。经过验证,所申请的DMA空间的该reg的值是正确的。
可能是我线长的问题,毕竟用的杜邦线。
也可能是底层驱动的BUG.这个等我画好板子,再测试。
目前解决方案:
/* 该函数在flush 最后调用 */
ili9488_send_color((void *) mybuf, size * 3); /* 原本的 */
ili9488_send_color((void *) (&mybuf[size*3]), 3); /* 我添加的,实际上就是把最后一个点手动画了一次,问题就这么被我糊弄过去了 */
// free buff .. fun end
在这里留个记号,如果有朋友遇到此问题可以这样解决或者大家一起讨论。
LVGL刷屏的本质动作是 , 设定起点坐标和终点坐标, 用连续传输模式,使用DMA传输。
在每一次传输一块图像前,都有
/*Column addresses*/
ili9488_send_cmd(ILI9488_CMD_COLUMN_ADDRESS_SET);
ili9488_send_data(xb, 4);/* 起点X 终点X 每个占用2字节 */
/*Page addresses*/
ili9488_send_cmd(ILI9488_CMD_PAGE_ADDRESS_SET);
ili9488_send_data(yb, 4);/* 起点Y 终点Y 每个占用2字节 */
我以前不上GUI的时候,采用的是只设置起点,并用连续模式传输多少个点,来完成的。
他设置了起点和终点。这是一种什么思路?我是真的不懂,请指教。
他每次传输的块的大小等于你设定的 (屏幕宽度 * 40),单位是点。
每次回调 flush 都是只刷新 这么大一块。
可是问题就就就出现在 假设我连续传输 sum 个点,理论上是 buf[0]~buf[sum-1],
可是就是这个 buf[sum - 1] 不会被正确的传输,可能根本就没传输?。经过验证,所申请的DMA空间的该reg的值是正确的。
可能是我线长的问题,毕竟用的杜邦线。
也可能是底层驱动的BUG.这个等我画好板子,再测试。
目前解决方案:
/* 该函数在flush 最后调用 */
ili9488_send_color((void *) mybuf, size * 3); /* 原本的 */
ili9488_send_color((void *) (&mybuf[size*3]), 3); /* 我添加的,实际上就是把最后一个点手动画了一次,问题就这么被我糊弄过去了 */
// free buff .. fun end
Re: 求助,有趣的LVGL驱动ILI9488,屏幕边缘有一排亮点。
我也试了一下你的方法,之前我就怀疑是缺失一些字节的问题,我怀疑过dma或者spi总线问题,通过调整lvgl缓冲buff大小那个点点的数量也会相应的变多或者变小
-
- Posts: 5
- Joined: Thu May 05, 2022 1:50 am
Re: 求助,有趣的LVGL驱动ILI9488,屏幕边缘有一排亮点。[已解决]
参考楼主的,已解决问题哈哈,这个问题卡了我半年
在函数void ili9488_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_map)
里最后
ili9488_send_color((void *) mybuf, size * 3);
ili9488_send_color((void *) (&mybuf[(size*3) - 3]), 3);//增加的
heap_caps_free(mybuf);
在函数void ili9488_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_map)
里最后
ili9488_send_color((void *) mybuf, size * 3);
ili9488_send_color((void *) (&mybuf[(size*3) - 3]), 3);//增加的
heap_caps_free(mybuf);
-
- Posts: 5
- Joined: Thu May 05, 2022 1:50 am
Re: 求助,有趣的LVGL驱动ILI9488,屏幕边缘有一排亮点。[已解决]
根因已找到了,是因为数据加入发送队列的之后,我们就free掉buffer了,所以存在野数据问题,野数据是导致亮点的原因。在发送和free之间加入disp_wait_for_pending_transactions();也可以解决这问题(弊端是会降低刷新率,这部分弊端和楼主的解决方案是一样的)。
完美解决方案如下
完美解决方案如下
- void ili9488_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_map)
- {
- uint32_t size = lv_area_get_width(area) * lv_area_get_height(area);
- lv_color16_t *buffer_16bit = (lv_color16_t *) color_map;
- static uint8_t *mybuf = NULL;
- if (mybuf != NULL){
- disp_wait_for_pending_transactions();//等待发完后重新申请地址
- heap_caps_free(mybuf);
- mybuf = NULL;
- }
- do {
- mybuf = (uint8_t *) heap_caps_malloc(3 * size * sizeof(uint8_t), MALLOC_CAP_DMA);
- if (mybuf == NULL) ESP_LOGW(TAG, "Could not allocate enough DMA memory!");
- } while (mybuf == NULL);
- uint32_t LD = 0;
- uint32_t j = 0;
- for (uint32_t i = 0; i < size; i++) {
- LD = buffer_16bit[i].full;
- mybuf[j] = (uint8_t) (((LD & 0xF800) >> 8) | ((LD & 0x8000) >> 13));
- j++;
- mybuf[j] = (uint8_t) ((LD & 0x07E0) >> 3);
- j++;
- mybuf[j] = (uint8_t) (((LD & 0x001F) << 3) | ((LD & 0x0010) >> 2));
- j++;
- }
- /* Column addresses */
- uint8_t xb[] = {
- (uint8_t) (area->x1 >> 8) & 0xFF,
- (uint8_t) (area->x1) & 0xFF,
- (uint8_t) (area->x2 >> 8) & 0xFF,
- (uint8_t) (area->x2) & 0xFF,
- };
- /* Page addresses */
- uint8_t yb[] = {
- (uint8_t) (area->y1 >> 8) & 0xFF,
- (uint8_t) (area->y1) & 0xFF,
- (uint8_t) (area->y2 >> 8) & 0xFF,
- (uint8_t) (area->y2) & 0xFF,
- };
- /*Column addresses*/
- ili9488_send_cmd(ILI9488_CMD_COLUMN_ADDRESS_SET);
- ili9488_send_data(xb, 4);
- /*Page addresses*/
- ili9488_send_cmd(ILI9488_CMD_PAGE_ADDRESS_SET);
- ili9488_send_data(yb, 4);
- /*Memory write*/
- ili9488_send_cmd(ILI9488_CMD_MEMORY_WRITE);
- ili9488_send_color((void *) mybuf, size * 3);
- // heap_caps_free(mybuf);
- }
Who is online
Users browsing this forum: Google [Bot] and 55 guests