社区导航

 

搜索
查看: 27619|回复: 25

[原创] TouchGFX的stm32移植教程

  [复制链接]

102

TA的帖子

0

TA的资源

一粒金砂(中级)

Rank: 2

发表于 2015-12-3 19:38 | 显示全部楼层 |阅读模式
本帖最后由 feiting94 于 2015-12-4 18:32 编辑

还在玩emwin的小伙伴们,你们可以看看touchGFX啦,可以看看这个效果



什么是touchGFX?
它是一款UI设计软件,专为低功耗、低主频的cortex-m系列单片机打造
目前支持的芯片有
QQ截图20151203162130.png



之前我在stm32论坛发了入门的知识,感觉太冷清了,还是来eeworld发帖子了
touchGFX移植主要分四个部分,基本思想是按照这张图来的
QQ截图20151203185437.png
移植的思想就是初始化正确,对上层应用来说底层是透明且有效的,我们的移植就成功了
(1)内部lcd控制器,外部sram,外部flash正确初始化
就是裸机的时候这些模块都是正常工作的,其中外部flash不是必须的,但因为sdram的部分要作为显存,因此sdram必须要有,这个因为不同的开发板都不同,我就不说了

(2)通过继承 touchGFX::HAL 得到适合自己MCU系列的子类,
目的是对上层屏蔽底层MCU硬件的差别
主要实现5个函数
FUNCTION PURPOSE
configureInterrupts() 配置DMA中断和LCD的VSYNC中断,两个中断的优先级必须相同,因为两个中断服务程序都经过touchGFX内部状态信息,不能出现抢占竞争状态
注:如果使用freeRTOS,必须保证中断优先级功能上低于(也就是数目上大于) configMAX_SYSCALL_INTERRUPT_PRIORITY  这个宏,这样就
enableLCDControllerInterrupt() 使能LCD控制器的VSYNC中断
disableInterrupts() 失能LCD控制器中断和 DMA中断
enableInterrupts() 使能LCD控制器中断和 DMA中断,这个函数和上面的函数配合使用保护临界区域,
getTFTFrameBuffer() 得到TFT控制器的显存的首地址,
setTFTFrameBuffer() 设置TFT控制器的显存首地址

以stm32f746为例可以看到 例程是如何初始化的
代码来自 STM32F7HAL.cpp 文件
  1. uint16_t* STM32F7HAL::getTFTFrameBuffer() const
  2. {
  3.   return (uint16_t*)LTDC_Layer1->CFBAR;
  4. }

  5. void STM32F7HAL::setTFTFrameBuffer(uint16_t* adr)
  6. {
  7.   LTDC_Layer1->CFBAR = (uint32_t)adr;

  8.   /* Reload immediate */
  9.   LTDC->SRCR = (uint32_t)LTDC_SRCR_IMR;
  10. }

  11. void STM32F7HAL::configureInterrupts()
  12. {
  13.   NVIC_SetPriority(DMA2D_IRQn, 9);
  14.   NVIC_SetPriority(LTDC_IRQn, 9);
  15. }

  16. static uint16_t lcd_int_active_line;
  17. static uint16_t lcd_int_porch_line;

  18. /* Enable LCD line interrupt, when entering video (active) area */
  19. void STM32F7HAL::enableLCDControllerInterrupt()
  20. {
  21.   lcd_int_active_line = (LTDC->BPCR & 0x7FF) - 1;
  22.   lcd_int_porch_line = (LTDC->AWCR & 0x7FF) - 1;
  23.   LTDC->LIPCR =  lcd_int_active_line;
  24.   LTDC->IER = 1;
  25. }

  26. void STM32F7HAL::disableInterrupts()
  27. {
  28.     NVIC_DisableIRQ(LTDC_IRQn);
  29.     NVIC_DisableIRQ(DMA2D_IRQn);
  30. }

  31. void STM32F7HAL::enableInterrupts()
  32. {
  33.     NVIC_EnableIRQ(LTDC_IRQn);
  34.     NVIC_EnableIRQ(DMA2D_IRQn);
  35. }
复制代码
其中
STM32F7HAL继承自 public touchgfx::HAL
代码中用的寄存器,可以查阅寄存器手册

(3)OS抽象层,
目的:对上层屏蔽不同操作系统的区别
FUNCTION PURPOSE
initialize() 创建两个二值信号量/互斥量/队列
signalVSync() 当VSYNC中断发生时,调用这个函数,使vsync queue或mutex有效,注意这个函数是在中断中调用的,并且会触发调度
waitForVSync() 阻塞直到VSYNC 发生,函数首先清除 mutex/queue,然后等待下一个VSYNC 中断发生
takeFrameBufferSemaphore() 阻塞方式获得 frame buffer semaphore ,阻塞直到获得该semaphore(信号量)
tryTakeFrameBufferSemaphore() 非阻塞方式获得  frame buffer semaphore,获得不到立即返回
giveFrameBufferSemaphore() 释放frame buffer semaphore
giveFrameBufferSemaphoreFromISR 在中断上下文以一种安全的方式 释放frame buffer semaphore

来看 OSWrappers.cpp文件
  1. using namespace touchgfx;

  2. static xSemaphoreHandle frame_buffer_sem;
  3. static xQueueHandle vsync_q = 0;

  4. // Just a dummy value to insert in the VSYNC queue.
  5. static uint8_t dummy = 0x5a;

  6. void OSWrappers::initialize()
  7. {
  8.     vSemaphoreCreateBinary(frame_buffer_sem);
  9.     // Create a queue of length 1
  10.     vsync_q = xQueueGenericCreate( 1, 1, 0 );
  11. }

  12. void OSWrappers::takeFrameBufferSemaphore()
  13. {
  14.     xSemaphoreTake(frame_buffer_sem, portMAX_DELAY);
  15. }
  16. void OSWrappers::giveFrameBufferSemaphore()
  17. {
  18.     xSemaphoreGive(frame_buffer_sem);
  19. }

  20. void OSWrappers::tryTakeFrameBufferSemaphore()
  21. {
  22.     xSemaphoreTake(frame_buffer_sem, 0);
  23. }

  24. void OSWrappers::giveFrameBufferSemaphoreFromISR()
  25. {
  26.     // Since this is called from an interrupt, FreeRTOS requires special handling to trigger a
  27.     // re-scheduling. May be applicable for other OSes as well.
  28.     portBASE_TYPE px = pdFALSE;
  29.     xSemaphoreGiveFromISR(frame_buffer_sem, &px);
  30.     portEND_SWITCHING_ISR(px);
  31. }

  32. void OSWrappers::signalVSync()
  33. {
  34.     if (vsync_q)
  35.     {
  36.         // Since this is called from an interrupt, FreeRTOS requires special handling to trigger a
  37.         // re-scheduling. May be applicable for other OSes as well.
  38.         portBASE_TYPE px = pdFALSE;
  39.         xQueueSendFromISR(vsync_q, &dummy, &px);
  40.         portEND_SWITCHING_ISR(px);
  41.     }
  42. }

  43. void OSWrappers::waitForVSync()
  44. {
  45.     // First make sure the queue is empty, by trying to remove an element with 0 timeout.
  46.     xQueueReceive(vsync_q, &dummy, 0);

  47.     // Then, wait for next VSYNC to occur.
  48.     xQueueReceive(vsync_q, &dummy, portMAX_DELAY);
  49. }

  50. static portBASE_TYPE IdleTaskHook(void* p)
  51. {
  52.   if ((int)p) //idle task sched out
  53.   {
  54.     touchgfx::HAL::getInstance()->setMCUActive(true);
  55.   }
  56.   else //idle task sched in
  57.   {
  58.     touchgfx::HAL::getInstance()->setMCUActive(false);
  59.   }
  60.   return pdTRUE;
  61. }
复制代码


官方文档中用的 RTOS是 freeRTOS ,用其他的操作系统也可以的,这里就只用了几个信号量和队列,很好更换系统至于freeRTOS的移植stm32官网是可以直接使用的,
(4)配置好LCD的 VSYNC中断和 DMA中断(在stm32就是 DMA2D中断)
同样在 STM32F7HAL.cpp 文件
  1. extern "C"
  2. __irq void LTDC_IRQHandler( void )
  3. {
  4.   if (LTDC->ISR & 1)
  5.   {
  6.     LTDC->ICR = 1;
  7.     if (LTDC->LIPCR == lcd_int_active_line)
  8.     {
  9.       //entering active area
  10.       LTDC->LIPCR = lcd_int_porch_line;
  11.       OSWrappers::signalVSync();
  12.       // Swap frame buffers immediately instead of waiting for the task to be scheduled in.
  13.       // Note: task will also swap when it wakes up, but that operation is guarded and will not have
  14.       // any effect if already swapped.
  15.       HAL::getInstance()->swapFrameBuffers();
  16.       GPIO::set(GPIO::VSYNC_FREQ);

  17.     }
  18.     else
  19.     {
  20.       //exiting active area
  21.        LTDC->LIPCR = lcd_int_active_line;
  22.        GPIO::clear(GPIO::VSYNC_FREQ);
  23.        HAL::getInstance()->frontPorchEntered();
  24.     }
  25.   }
  26. }

  27. extern "C"
  28. __irq void DMA2D_IRQHandler( void )
  29. {
  30.   if (DMA2D->ISR & 2)
  31.   {
  32.     DMA2D->IFCR = 2;
  33.     touchgfx::HAL::getInstance()->signalDMAInterrupt();
  34.   }
  35. }
复制代码
LCD的 VSYNC中断分两种情况,如果进中断是在这一行同步中断的末尾,即 LTDC->LIPCR = lcd_int_porch_line, 那么开始对下一行的渲染(rendering pass); 如果是在这一行的开头,考虑前面的无效区域,即LTDC->LIPCR == lcd_int_active_line ,那么就开始传输 DMA队列,开启DMA传输
(5)GPIO配置,这里不是真正的GPIO,而是touchGFX内部虚拟的GPIO,目的是测试性能,不是很重要,一共有下面四个引脚ID
  1.   typedef enum
  2.   {
  3.     VSYNC_FREQ,  /// Pin is toggled at each VSYNC
  4.     RENDER_TIME, /// Pin is high when frame rendering begins, low when finished
  5.     FRAME_RATE,  /// Pin is toggled when the frame buffers are swapped.
  6.     MCU_ACTIVE   /// Pin is high when the MCU is doing work (ie. not in idle task).
  7.   } GPIO_ID;
复制代码
(6)触摸屏配置,这个很简单,继承 touchGFX::TouchController函数,重新实现init()和 sampleTouch(int32_t& x, int32_t& y)这两个函数即可,从裸机程序移植过来即可
  1. using namespace touchgfx;

  2. void STM32F746GTouchController::init()
  3. {
  4.   BSP_TS_Init(BSP_LCD_GetXSize(), BSP_LCD_GetYSize());
  5. }

  6. bool STM32F746GTouchController::sampleTouch(int32_t& x, int32_t& y)
  7. {
  8.   TS_StateTypeDef state;
  9.   BSP_TS_GetState(&state);
  10.   if (state.touchDetected)
  11.   {
  12.     x = state.touchY[0];
  13.     y = state.touchX[0];
  14.    
  15.     return true;
  16.   }
  17.   return false;   
  18. }
复制代码


这样整个系统就已经移植好了,下面来看初始化过程
  1.     void hw_init()
  2.     {
  3.       HAL_Init();
  4.         
  5.       SystemClock_Config(); //200MHz overdrive, FL6
  6.         
  7.       /* Initialize the QSPI */
  8.       BSP_QSPI_Init();
  9.       BSP_QSPI_MemoryMappedMode();  
  10.       HAL_NVIC_DisableIRQ(QUADSPI_IRQn);

  11.       BSP_SDRAM_Init();
  12.       BSP_LCD_Init();
  13.       BSP_LCD_LayerDefaultInit(0, frameBuf0);
  14.       BSP_LCD_DisplayOn();
  15.       
  16.       GPIO::init();
  17.       SCB_EnableDCache();
  18.       SCB_EnableICache();
  19.     }   
  20.    
  21.     STM32F7DMA dma;
  22.     STM32F746GTouchController tc;
  23.     STM32F7Instrumentation mcuInstr;
  24.     LCD16bpp display;

  25.     void touchgfx_init()
  26.     {
  27.       HAL& hal = touchgfx_generic_init<STM32F7HAL>(dma, display, tc, 480, 272, 0, 0);
  28.       os_inited = true;
  29.       hal.setFrameBufferStartAddress((uint16_t*)frameBuf0);
  30.       hal.setTouchSampleRate(3);
  31.       hal.setFingerSize(1);

  32.       // This platform can handle simultaneous DMA and TFT accesses to SDRAM, so disable lock to increase performance.
  33.       hal.lockDMAToFrontPorch(false);
  34.       
  35.       mcuInstr.init();

  36.       //Set MCU instrumentation and Load calculation
  37.       hal.setMCUInstrumentation(&mcuInstr);
  38.       hal.enableMCULoadCalculation(true);
  39.     }
复制代码
首先是系统时钟为200MHz, systick配置为1ms中断,抢占位设置为四位
接着依次初始化QSPI,SDRAM和LCD控制器,在 touchGFX_init()中,实现一个STM32F7HAL类的实例化,设置显存首地址,设置触摸采样频率
值得注意的一点是 如果使用QSPI的话,sct文件也要修改,加入一个输入段,下载hex文件也只能用 st-link utility,st-link utility很不错哦,还是坛友告诉我的
看一下sct文件,在 “project/options for target/Linker ”的 scatter file
可以看到,点edit
  1. LR_IROM1 0x08000000 0x00200000  {    ; load region size_region
  2.   intflash.bin 0x08000000 0x00200000  {  ; load address = execution address
  3.    *.o (RESET, +First)
  4.    *(InRoot$Sections)
  5.    .ANY (+RO)
  6.   }
  7.   RW_IRAM1 0x20000000 0x00030000  {  ; RW data
  8.    .ANY (+RW +ZI)
  9.   }
  10. }

  11. <font color="#ff0000">LR_EROM1 0x90000000 0x01000000  {    ; load region size_region
  12.   extflash.bin 0x90000000 0x01000000  {  ; load address = execution address
  13.    *.o (ExtFlashSection)
  14.   }
  15. }</font>
复制代码
红色是额外加的部分,可以看到 一个特殊的段 -- ExtFlashSection
寻找一下,可以看到在 Config.hpp 有如下定义
  1. #ifdef SIMULATOR
  2. #define LOCATION_EXTFLASH_PRAGMA
  3. #define LOCATION_EXTFLASH_ATTRIBUTE
  4. #else
  5. #ifdef __GNUC__
  6. #ifdef __CODE_RED
  7. #include <cr_section_macros.h>
  8. #define LOCATION_EXTFLASH_PRAGMA
  9. #define LOCATION_EXTFLASH_ATTRIBUTE __RODATA(SPIFI)
  10. #else
  11. #define LOCATION_EXTFLASH_PRAGMA
  12. #define LOCATION_EXTFLASH_ATTRIBUTE __attribute__ ((section ("ExtFlashSection"))) __attribute__ ((aligned(4)))
  13. #endif
  14. #elif defined __ICCARM__
  15. #define LOCATION_EXTFLASH_PRAGMA _Pragma("location="ExtFlashSection"")
  16. #define LOCATION_EXTFLASH_ATTRIBUTE
  17. <font color="#ff0000">#elif defined(__ARMCC_VERSION)
  18. #define LOCATION_EXTFLASH_PRAGMA
  19. #define LOCATION_EXTFLASH_ATTRIBUTE __attribute__ ((section ("ExtFlashSection"))) __attribute__ ((aligned(4)))</font>
  20. #endif
  21. #endif
复制代码
用keil编译器的话,只有最后一部分是有效的,这里只是不同编译器分配段的形式差别
对于你想放在外部flash的图片数组,加上这个 LOCATION_EXTFLASH_ATTRIBUTE 就OK了


最后来看main函数
  1. #define configGUI_TASK_PRIORITY                 ( tskIDLE_PRIORITY + 3 )

  2. #define configGUI_TASK_STK_SIZE                 ( 512 )


  3. static void GUITask(void* params)
  4. {
  5.   touchgfx::HAL::getInstance()->taskEntry();
  6. }


  7. int main (void)
  8. {
  9.   hw_init();
  10.   touchgfx_init();

  11.   xTaskCreate( GUITask, (TASKCREATE_NAME_TYPE)"GUITask",
  12.                configGUI_TASK_STK_SIZE,
  13.                NULL,
  14.                configGUI_TASK_PRIORITY,
  15.                NULL);

  16.   vTaskStartScheduler();

  17.   for(;;);

  18. }
复制代码


初始化之后,直接就进入task调度了,移植过程完了,后面我会以一个完整的例子来讲 touchGFX的 UI设计思想 MVP(model-view - presenter),这和emwin是完全不一样的,和 qt的MVC设计思想类似


附上几个demo程序
STM32F746-DISCO_demos.rar (9.38 MB, 下载次数: 1926)

评分

2

查看全部评分


回复

使用道具 举报

1022

TA的帖子

0

TA的资源

纯净的硅(初级)

Rank: 4

发表于 2015-12-4 09:12 | 显示全部楼层

回复

使用道具 举报

2930

TA的帖子

1

TA的资源

版主

Rank: 6Rank: 6

测评达人

发表于 2015-12-4 10:02 | 显示全部楼层
不错,支持!

回复

使用道具 举报

499

TA的帖子

0

TA的资源

版主

Rank: 6Rank: 6

发表于 2015-12-4 11:09 | 显示全部楼层
本帖最后由 weizhongc 于 2015-12-4 11:11 编辑

uGFX GUI的GUIBuilder下载及其注册方法   转载

官方下载地址:http://studio.ugfx.org/
此软件是采用Qt5开发。
=========================================
如果要使用的话一定要在这里简单注册即可,然后系统会给您的邮箱发送
GUIBuilder的下载地址和激活码. 002NDCCLgy6WYjBInxQ1e&amp;690.png 002NDCCLgy6WYjBN73J6b&amp;690.png 002NDCCLgy6WYjAK6SWd6&amp;690.jpg
uGFX GUI的GUIBuilder下载及其注册方法

uGFX GUI的GUIBuilder下载及其注册方法

==================================
uGFX的GUIBuilder功能比较emWin的要强很多。主界面如下:
uGFX GUI的GUIBuilder下载及其注册方法

点评

您是安富莱啊?  详情 回复 发表于 2015-12-4 12:51

回复

使用道具 举报

4193

TA的帖子

9

TA的资源

五彩晶圆(高级)

Rank: 9Rank: 9Rank: 9

测评达人

发表于 2015-12-4 12:51 | 显示全部楼层
weizhongc 发表于 2015-12-4 11:09
uGFX GUI的GUIBuilder下载及其注册方法   转载

官方下载地址:http://studio.ugfx.org/
此软件是采 ...

您是安富莱啊?

回复

使用道具 举报

4193

TA的帖子

9

TA的资源

五彩晶圆(高级)

Rank: 9Rank: 9Rank: 9

测评达人

发表于 2015-12-4 12:51 | 显示全部楼层
谢谢楼主分享了,静下来我要仔细看下楼主的分享了。

点评

不是啊,也没什么啊 就building 工具而已啊  详情 回复 发表于 2015-12-4 13:03

回复

使用道具 举报

499

TA的帖子

0

TA的资源

版主

Rank: 6Rank: 6

发表于 2015-12-4 13:03 | 显示全部楼层
huaiqiao 发表于 2015-12-4 12:51
谢谢楼主分享了,静下来我要仔细看下楼主的分享了。

不是啊,也没什么啊 就building 工具而已啊

点评

哦哦,也多谢分享,之前看license要收费就没管。有空静下来好好看看  详情 回复 发表于 2015-12-4 13:35

回复

使用道具 举报

4193

TA的帖子

9

TA的资源

五彩晶圆(高级)

Rank: 9Rank: 9Rank: 9

测评达人

发表于 2015-12-4 13:35 | 显示全部楼层
weizhongc 发表于 2015-12-4 13:03
不是啊,也没什么啊 就building 工具而已啊

哦哦,也多谢分享,之前看license要收费就没管。有空静下来好好看看

回复

使用道具 举报

1727

TA的帖子

4

TA的资源

一粒金砂(高级)

Rank: 3Rank: 3

发表于 2015-12-4 14:14 | 显示全部楼层
顶顶,有没有实际移植好的Demo程序,

点评

赞,赞,赞,赞,赞,赞,赞,赞,赞,赞,赞,赞,赞,赞,赞,赞,赞,赞,赞,赞,赞,赞,赞,赞,  详情 回复 发表于 2015-12-7 08:33
我已经重新附录了  详情 回复 发表于 2015-12-4 18:32

回复

使用道具 举报

10

TA的帖子

0

TA的资源

一粒金砂(中级)

Rank: 2

发表于 2015-12-4 14:23 | 显示全部楼层
多谢分享

回复

使用道具 举报

102

TA的帖子

0

TA的资源

一粒金砂(中级)

Rank: 2

 楼主| 发表于 2015-12-4 18:32 | 显示全部楼层
DavidZH 发表于 2015-12-4 14:14
顶顶,有没有实际移植好的Demo程序,

我已经重新附录了

回复

使用道具 举报

1085

TA的帖子

0

TA的资源

五彩晶圆(中级)

Rank: 8Rank: 8

荣誉会员勋章

发表于 2015-12-4 19:22 | 显示全部楼层
这个必须顶啊!
如果真有源码 就好了。。。

回复

使用道具 举报

5

TA的帖子

0

TA的资源

一粒金砂(初级)

Rank: 1

发表于 2015-12-4 22:22 | 显示全部楼层
试用版都是会带水印的。

点评

我也发现了这个问题,怎么破?  详情 回复 发表于 2015-12-4 22:42

回复

使用道具 举报

102

TA的帖子

0

TA的资源

一粒金砂(中级)

Rank: 2

 楼主| 发表于 2015-12-4 22:42 | 显示全部楼层
lzp20 发表于 2015-12-4 22:22
试用版都是会带水印的。

我也发现了这个问题,怎么破?

回复

使用道具 举报

1727

TA的帖子

4

TA的资源

一粒金砂(高级)

Rank: 3Rank: 3

发表于 2015-12-7 08:33 | 显示全部楼层
DavidZH 发表于 2015-12-4 14:14
顶顶,有没有实际移植好的Demo程序,

赞,赞,赞,赞,赞,赞,赞,赞,赞,赞,赞,赞,赞,赞,赞,赞,赞,赞,赞,赞,赞,赞,赞,赞,

回复

使用道具 举报

56

TA的帖子

0

TA的资源

一粒金砂(中级)

Rank: 2

发表于 2015-12-7 17:13 | 显示全部楼层
这个不错  emwin 感觉是上个时代的界面

回复

使用道具 举报

6

TA的帖子

0

TA的资源

一粒金砂(初级)

Rank: 1

发表于 2016-2-16 11:13 | 显示全部楼层
touchGFX的设计帖子打算什么时候发?

回复

使用道具 举报

21

TA的帖子

0

TA的资源

一粒金砂(初级)

Rank: 1

发表于 2016-2-17 09:56 | 显示全部楼层
要收费???

回复

使用道具 举报

176

TA的帖子

0

TA的资源

一粒金砂(中级)

Rank: 2

发表于 2016-3-15 13:39 | 显示全部楼层
得会C++,才玩得起。

回复

使用道具 举报

2

TA的帖子

0

TA的资源

一粒金砂(初级)

Rank: 1

发表于 2017-9-24 23:00 | 显示全部楼层
Demo有水印。注定推广不起来。 凡是在中国一开始有全功能盗版的后期都有可能广泛用起来。一开始没有盗版的肯定用不起来。

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

关闭

站长推荐上一条 /5 下一条

  • 论坛活动 E手掌握

    扫码关注
    EEWORLD 官方微信

  • EE福利  唾手可得

    扫码关注
    EE福利 唾手可得

Archiver|手机版|小黑屋|电子工程世界 ( 京ICP证 060456 )

GMT+8, 2020-2-21 10:30 , Processed in 0.564694 second(s), 18 queries , Gzip On, MemCache On.

快速回复 返回顶部 返回列表