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
  • 相关阅读:
    c:forTokens标签循环输出
    jsp转long类型为date,并且格式化
    spring中@Param和mybatis中@Param使用区别(暂时还没接触)
    734. Sentence Similarity 有字典数组的相似句子
    246. Strobogrammatic Number 上下对称的数字
    720. Longest Word in Dictionary 能连续拼接出来的最长单词
    599. Minimum Index Sum of Two Lists两个餐厅列表的索引和最小
    594. Longest Harmonious Subsequence强制差距为1的最长连续
    645. Set Mismatch挑出不匹配的元素和应该真正存在的元素
    409. Longest Palindrome 最长对称串
  • 原文地址:https://www.cnblogs.com/armfly/p/14421236.html
Copyright © 2011-2022 走看看