zoukankan      html  css  js  c++  java
  • 【STM32H7】第23章 ThreadX GUIX双缓冲的实现

    最新教程下载:http://www.armbbs.cn/forum.php?mod=viewthread&tid=98429

    第23章       ThreadX GUIX双缓冲的实现

    本章节为大家讲解GUIX双缓冲的实现方法。

    23.1初学者重要提示

    23.2理解STM32H7的LTDC水平消隐和垂直消隐

    23.3避免STM32H7的LTDC刷新撕裂感的解决办法

    23.4 GUIX双缓冲实现框架

    23.5 GUIX双缓冲实现方法

    23.6 实验例程设计框架

    23.7 实验例程

    23.8 总结

    23.1 初学者重要提示

    1.   本章节配套例子的实现效果和第22章是一样的,如果要学习此界面的实现效果,可以看第22章教程说明。
    2.   本章例子仅作了800*480分辨率大小的界面设计。
    3.   GUIX双缓冲实现的关键借助了LTDC垂直消隐。

    23.2 理解STM32H7的LTDC水平消隐和垂直消隐

    正常情况下,LCD的刷新就是从左到右,从上到下进行逐个像素点刷新。但仅刷新有效的显示区是不够的,比如800*480分辨率,我们不仅仅要刷800*480这段有效区域,边界区也是要刷新的,即下图总宽度以内,有效区以外的区域也是要刷新的。

     

    水平消隐就是LCD用户区一行结束到另一行开始的时间,这段消失的时间就是水平消隐,即HSYNC宽度+ HBP + HFP这段消失的时间。

    垂直消隐就是LCD用户区最后一行结束到第一行开始的时间,这段消失的时间就是垂直消隐,即VSYNC宽度+ VBP + VFP这段消失的时间。

    我们实际计算刷新率就是:

    刷新率 = LTDC输出时钟 /((Width + HSYNC_W  + HBP  + HFP )*(Height + VSYNC_W +VBP  +VFP  ))

    23.3 避免STM32H7的LTDC刷新撕裂感的解决办法

    如果用户快速刷新颜色差异比较大两种界面效果,容易遇到这种撕裂问题。

    出现这个问题的原因:

    用户更新显存数据期间,LTDC(H7带的LCD控制器)也在不断的读取显存的数据到显示屏上,如果用户才更新了部分界面数据,后面部分还没有更新,LTDC刷新到显示屏的界面效果出现撕裂感,即下面这种现象:

     

    解决这个问题的办法:

    LTDC刷新还在垂直消隐期间就将整个界面刷新完成,而我们如何只知道LTDC在垂直消隐期,通过函数HAL_LTDC_ProgramLineEvent设置刷新到指定行时进入中断即可,一般设置为第0行进入中断,然后设置个标志即可。一旦检测到这个标志,就通过DMA2D快速将界面刷新好,这样就有效的避免了撕裂感。

    23.4 GUIX双缓冲实现框架

    为了方便大家理解GUIX双缓冲的实现思路,制作了个实现框图,此方法借助了前面说的垂直消隐。

    核心就是一个显存地址的内容被LTDC刷新到显示屏时,GUIX画布的内容更新到另一个显存,从而实现双缓冲的效果。

    23.5 GUIX双缓冲实现方法

    23.5.1        第1步:开启LTDC行中断

    代码如下:

    /* 使能行中断 */
    HAL_LTDC_ProgramLineEvent(&hLTDC, VSYNC_W + VBP + Height);
        
    /* 使能LTDC中断,并配置其优先级 */
    HAL_NVIC_SetPriority(LTDC_IRQn, 0x02, 0x00);
    HAL_NVIC_EnableIRQ(LTDC_IRQn);

    当前程序行中断设置的位置:

     

    设置在这个位置,可以实现最大的垂直消隐时间。

    23.5.2        第2步:创建信号量用于双缓冲同步

    使用信号量实现任务同步,我们这里是通过LTDC中断发信号量给任务做同步。

    /*
    *********************************************************************************************************
    *    函 数 名: AppObjCreate
    *    功能说明: 创建任务通讯
    *    形    参: 无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    static  void  AppObjCreate (void)
    {
         /* 创建互斥信号量 */
        tx_mutex_create(&AppPrintfSemp,"AppPrintfSemp",TX_NO_INHERIT);
     
        /* GUIX双缓冲信号量 */
        tx_semaphore_create(&GuixSemaphore, "GUIX Semaphore", 1);      
    }

    23.5.3        第3步:LTDC行中断处理

     代码如下:

    /*
    *********************************************************************************************************
    *    函 数 名: LTDC_IRQHandler
    *    功能说明: LTDC中断服务程序
    *    形    参: 无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    extern TX_SEMAPHORE GuixSemaphore;
    extern __IO uint8_t  g_ucGuixFlag;
    void LTDC_IRQHandler(void) 
    {
        LTDC->ICR = (uint32_t)LTDC_IER_LIE;
     
        if(g_ucGuixFlag == 0)
        {
            g_ucGuixFlag = 1;
            
            /* 更新LTDC寄存器 */      
            __HAL_LTDC_LAYER(&hLTDC, 0)->CFBAR = 0xC0000000;     
            __HAL_LTDC_RELOAD_IMMEDIATE_CONFIG(&hLTDC); 
        }
        else
        {
            g_ucGuixFlag = 0;
            
             /* 更新LTDC寄存器 */      
            __HAL_LTDC_LAYER(&hLTDC, 0)->CFBAR = 0xC0200000;     
            __HAL_LTDC_RELOAD_IMMEDIATE_CONFIG(&hLTDC); 
        }
        
        tx_semaphore_put(&GuixSemaphore);
    }
    •   LTDC->ICR = (uint32_t)LTDC_IER_LIE

    清除行中断标志。

    •   __HAL_LTDC_LAYER(&hLTDC, 0)->CFBAR = 0xC0000000  
    •   __HAL_LTDC_RELOAD_IMMEDIATE_CONFIG(&hLTDC)

    这里是在垂直消隐期间设置的,设置新的显存地址,并立即生效。

    •   tx_semaphore_put(&GuixSemaphore)

    LTDC中断里面发送同步信号量给任务。

    23.5.4        第4步:双缓冲任务处理

     代码如下:

    /*
    *********************************************************************************************************
    *    函 数 名: AppTaskMsgPro
    *    功能说明: 消息处理,这里用作GUIX双缓冲处理
    *    形    参: thread_input 是在创建该任务时传递的形参
    *    返 回 值: 无
        优 先 级: 3
    *********************************************************************************************************
    */
    extern void DoubleBufferPro(void);
    static void AppTaskMsgPro(ULONG thread_input)
    {
        (void)thread_input;
        
        while(1)
        {     
            DoubleBufferPro();
        }   
    }
    /*
    *********************************************************************************************************
    *    函 数 名: DoubleBufferPro
    *    功能说明: 双缓冲处理
    *    形    参: 无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    void DoubleBufferPro(void)
    {
        tx_semaphore_get(&GuixSemaphore, TX_WAIT_FOREVER);
    
        if(g_ucGuixFlag == 1)
        {
            DMA2D->OMAR = (uint32_t)0xC0200000;
        }
        else
        {
            DMA2D->OMAR = (uint32_t)0xC0000000;
        }
    
        DMA2D->CR = 0x00000000UL | (1 << 9);
        DMA2D->FGMAR = (uint32_t)0xC0400000;
        DMA2D->FGOR = 0;
        DMA2D->OOR = 0;
    
        /* 前景层和输出区域都采用RGB565颜色格式 */
        DMA2D->FGPFCCR = LTDC_PIXEL_FORMAT_RGB565;
        DMA2D->OPFCCR = LTDC_PIXEL_FORMAT_RGB565;
        DMA2D->NLR = (uint32_t)(g_LcdWidth << 16) | (uint16_t)g_LcdHeight;
        DMA2D->CR |= DMA2D_CR_START;
    
        while (DMA2D->CR & DMA2D_CR_START) { tx_thread_sleep(1);}    
    }
    •   tx_semaphore_get(&GuixSemaphore, TX_WAIT_FOREVER)

    等待LTDC中断的信号量发送。

    •   DMA2D->OMAR = (uint32_t)0xC0200000
    •   DMA2D->OMAR = (uint32_t)0xC0000000

    LTDC中断里设置使用那块显存,这里设置使用另一块显存做DMA2D操作,实现双缓冲。

    •   DMA2D->FGMAR = (uint32_t)0xC0400000

    设置的画布地址。通过DMA2D,将GUIX画布中的内容更新到显存中。

    23.5.5        第5步:清空函数stm32h7_565rgb_buffer_toggle

     代码如下,暂时用不上,将其置空即可:

    /*
    *********************************************************************************************************
    *    函 数 名: stm32h7_565rgb_buffer_toggle
    *    功能说明: 更新canvas内容到LCD显存
    *    形    参: 无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    void stm32h7_565rgb_buffer_toggle(GX_CANVAS *canvas, GX_RECTANGLE *dirty)
    {
    
    }

    23.5.6        第6步:使用DTCM做主RAM

     为实现最高性能,使用DTCM做主RAM:

     

    23.5.7        第7步:合理设置任务优先级

    三个涉及到GUIX的任务(数值越小优先级越高):

    •   GUIX  System Thread

    GUIX系统任务,优先级设置为16。

    •   App Msp Pro

    GUIX双缓冲处理任务,优先级设置为17。

    •   App Task GUI

    GUIX应用任务,优先级设置为18。

    23.5.8        第8步:将触摸和GUIX放到一个任务

    为了触摸效果更好,将触摸功能和GUIX应用功能都放到一个任务里面,程序代码如下:

    /*
    *********************************************************************************************************
    *    函 数 名: MainTask
    *    功能说明: GUI主函数
    *    形    参: 无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    void MainTask(void) 
    {
        /* 省略未写 */
        
        while(1)
        {
            TOUCH_Scan();      /* 电阻触摸屏和计数 */
            TOUCH_CapScan();  /* 电容触摸屏 */
            tx_thread_sleep(1);
        }
    }

    23.6 实验例程设计框架

    本章例程的重点是GUIX双缓冲的实现。

    23.7 实验例程

    (注,如果是电阻屏,需要做触摸校准,校准方法看本教程附件章节A)

    配套例子:

    本章节配套了如下例子供大家移植参考:

    u  V7-2028_Window Sliding(only 800x480)

    GUIX Studio生成的代码在硬件平台实际运行的工程,含有MDK AC5和AC6两个版本工程。

    实验目的:

    1. 本章主要学习GUIX双缓冲的实现。

    实验内容:

    1. 共创建了如下几个任务,通过按下按键K1可以通过串口打印任务堆栈使用情况

    App Task Start任务  :启动任务,这里用作BSP驱动包处理。

    App Task MspPro任务 :消息处理,这里用作LED闪烁。

    App Task UserIF任务 :按键消息处理。

    App Task GUI任务    :GUI应用任务。

    App Task STAT任务   :统计任务。

    App Task IDLE任务   :空闲任务。

    GUIX System Thread  :GUI系统任务。

    System Timer Thread任务:系统定时器任务。

    实验效果:

     

    GUIX Studio的界面设计如下:

     

    串口打印任务执行情况:

    MDK AC5和AC6工程可以串口打印任务执行情况:按开发板的按键K1可以打印,波特率 115200,数据位 8,奇偶校验位无,停止位 1:

     

    23.8 总结

    本章节主要为大家讲解了滑动效果的实现,推荐大家熟练掌握本章节的函数用法。

    微信公众号:armfly_com 安富莱论坛:www.armbbs.cn 安富莱淘宝:https://armfly.taobao.com
  • 相关阅读:
    pyqt 过滤事件
    python 编码问题
    xpath使用
    BeautifulSoup
    webpack.config.js 大概架构(3)
    图片,html,和其他的打包(2)
    今天开始第一篇
    第一次面试前端,记录下
    阻止默认事件和冒泡
    cookit localStorage sessionStorage 区别
  • 原文地址:https://www.cnblogs.com/armfly/p/14421236.html
Copyright © 2011-2022 走看看