这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 板卡试用 » 【分享开发笔记,赚取电动螺丝刀】STM32F769LVGL优化显示

共1条 1/1 1 跳转至

【分享开发笔记,赚取电动螺丝刀】STM32F769LVGL优化显示

工程师
2025-03-07 15:23:37     打赏

【前言】

LVGL是一个开源的、免费的图形库,旨在为嵌入式系统提供轻量级且功能丰富的图形用户界面(GUI)解决方案。他的移植有很多文章都有介绍,但是一些对接LCD的显示优化的文章较小,今天我在移植完lvgl正常显示后,对显示的刷新方法进行了优化。现记录并分享如下:

1、最原始的方法,就是直接调用LCD的画点函数,比如我的工程里面就是lcd_draw_point(x, y, color_p->full);其刷新代码如下:

static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
    if(disp_flush_enabled) {
        /*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_draw_point(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);
}

这样,功能是可以实现,但是显示速度是非常慢的。

2、为了改进刷新速度,我们可以先获取disp_flush函数中,传入的一个显示块,即获取起始x、y坐标,结束x、y坐标。在disp_flush函数的参数中的指针const lv_area_t * area,即包含了他的这些全部信息,他的结构化原型为:

/** Represents an area of the screen.*/
typedef struct {
    lv_coord_t x1;
    lv_coord_t y1;
    lv_coord_t x2;
    lv_coord_t y2;
} lv_area_t;

这样我就可以得知他需要显示的区域是多少,使用LCD的设置坐标函数来设置他的显示区域即:

	lcd_set_address(startX, startY, endX, endY);

3、颜色参数信息是在lv_color_t * color_p 中传递过来的,我们找到他的原型如下:

image.png

他的颜色始为full这里。

常规的方法是,把full拆开两个8bit,然后再使用spi发送出去,由于我们的spi是可以一次传输16bit数据的,因此我们可以使用uint16_t来组织数据,并使用spi 的16bit方式来传递出去,这样速度就会大大的增加。

这个在我的另一篇帖子里【分享开发笔记,赚取电动螺丝刀】STM32F769驱动ST7789以及显示优化-电子产品世界论坛有详细的记录。

根据这样,我对代码进行了改进:

static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
    if(disp_flush_enabled) {
        /*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_draw_point(x, y, color_p->full);
        //         color_p++;
        //     }
        // }
        uint32_t width = area->x2 - area->x1 + 1;
        uint32_t height = area->y2 - area->y1 + 1;
        uint32_t pixel_count = width * height;

        // 确保缓冲区足够大
        printf(" pixel_count = %ld\r\n", pixel_count);
        uint16_t *buffer = (uint16_t *)malloc(pixel_count);
        if (buffer == NULL)
        {
            free(buffer);
            printf("malloc failed\r\n");
            return;
        }
        // 将像素数据复制到缓冲区
        for (uint32_t i = 0; i < pixel_count; i++){
            buffer[i] = color_p[i].full;
        }

        lcd_draw_block(area->x1, area->y1, area->x2, area->y2, buffer, pixel_count);
        free(buffer);
    }
    
    /*IMPORTANT!!!
     *Inform the graphics library that you are ready with the flushing*/
    lv_disp_flush_ready(disp_drv);
}

在最初,我对通过x、y的起始坐标,计算出这一次刷新数据的大小,并申请内存。然后对color数据进行组装,最后通过lcd_draw_block转发出去。

在lcd中,我组织函数代码如下:

void lcd_draw_block(uint16_t startX, uint16_t startY, uint16_t endX, uint16_t endY, uint16_t *color_buffer, uint32_t size)
{

	lcd_set_address(startX, startY, endX, endY);
	lcd_write_ram();
	lcd_write_data_dma(color_buffer, size*2);  //长度需要*2 不然dma写入不完整 
}

对应的lcd_write_data_dma原型如下:

void lcd_write_data_dma(uint16_t *data, uint16_t size)
{
	// 配置 SPI 为 16 位数据大小
	hspi2.Init.DataSize = SPI_DATASIZE_16BIT;
	if (HAL_SPI_Init(&hspi2) != HAL_OK)
	{
		printf("SPI re-init failed for 16-bit mode\r\n");
		return;
	}
	LCD_CS(0);
	LCD_WR(1);
	// 使用 DMA 发送数据
	if (HAL_SPI_Transmit_DMA(&hspi2, (uint8_t *)data, size) != HAL_OK)
	{
		printf("DMA transmission failed\r\n");
	}
	// 等待DMA传输完成
	// while (HAL_SPI_GetState(&hspi2) != HAL_SPI_STATE_READY)
	// 	;
	while(spi2_dma_tx_flag == 0)
	   ;
	spi2_dma_tx_flag = 0;  //重置标志
	// 配置 SPI 为 8 位数据大小
	hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
	if (HAL_SPI_Init(&hspi2) != HAL_OK)
	{
		printf("SPI re-init failed for 8-bit mode\r\n");
	}
}

在这里,由先把数据传输的宽度修改为16bit,传送结束后,再换成8bit。

【总结】

通过上述代码的优化,提高了数据的传速速度,从而提高了刷新速度。




关键词: STM32F769LVGL     优化     显示    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]