TouchGFX在STM32F429IGT6上的移植(RT-Thread版本)

目录

前言

一、新建BSP

二、使用CubeMX创建TouchGFX工程

1、配置FMC(SDRAM)

2、配置DMA2D,打开DMA2D中断

3、配置LTDC,打开LTDC中断

4、开启CRC

5、配置TouchGFX

6、执行TouchGFX Designer

6.1、TouchGFX Designer界面

6.2、添加GUI应用

6.3、生成代码

三、将TouchGFX移植到RT-Thread中

1、修改操作系统接口文件

2、新建touchgfx的应用示例文件

3、向工程添加文件

3.1、修改\board\KConfig

3.2、修改\libraries\STM32F4xx_HAL\SConscript

3.3、修改\board\SConscript

3.4、新增\board\CubeMX_Config\SConscript

4、添加触摸驱动

4.1 添加TOUCH驱动文件

4.2 完善 STM32TouchController.cpp

四、将图片放置到片外SPI FLASH

1、制作STM32F429的SPI FLASH下载算法

2、修改工程模版template.uvprojx

3、修改链接文件

4、将位图数据从外部FLASH拷贝到缓存

4.1、开启模拟SPI​

4.2、开启SFUD组件

4.3、设备初初始化

4.4、选中FAL软件包

4.5、修改TouchGFX驱动

四、将字体放置到片外SPI FLASH

五、移植时的注意事项


前言

在移植之前,需要对rt-thread比较熟悉并且会使用rtthread的ENV工具

一、新建BSP

rtthread针对STM32系列有一个详细的BSP制作教程,可以根据自己的板卡制作出自己的BSP,就不再这里赘述了,可以参考官网的文档说明

二、使用CubeMX创建TouchGFX工程

在创建好的BSP中,双击 ..\board\CubeMX_Config.ioc 打开CubeMX,配置相关外设并生成初始化代码,这些初始化代码在后面的touchgfx的示例文件中会用到

1、配置FMC(SDRAM)

一定要注意配置的GPIO要跟自己的硬件要一致!!!因为SDRAM有的引脚可以在多个GPIO上复用。还有就是生成的工程中有没有SDRAM的初始化程序

2、配置DMA2D,打开DMA2D中断

3、配置LTDC,打开LTDC中断

一定要注意配置的GPIO要跟自己的硬件要一致!!!

4、开启CRC

5、配置TouchGFX

打开TouchGFX软件包

配置TouchGFX

6、执行TouchGFX Designer

使用CubeMX生成工程后,先不要打开IAR工程,还需要执行Touch Designer来设计UI部分,完善工程。在Src目录下有个 ApplicationTemplate.touchgfx.part,点击这个链接就可以打开TouchGFX Designer。

6.1、TouchGFX Designer界面

6.2、添加GUI应用

如果之前已经使用TouchGFX Designer设计过UI,把相关的文件直接拷贝过来就可以了,就不必再按照我下面的步骤来设计UI了,点击Generate Code生成代码后,把下面的文件拷贝过来即可

第一步:创建screen1,放置一个Box控件和Button控件,设置Box的坐标为(0,0)大小为800x480,设置Button的坐标和按下释放时的背景图片,图片可以从阿里巴巴矢量图标库下载,然后放到…\Src\assets\images目录下;添加Interaction,实现通过点击按钮切换到screen2的功能

第二步:创建screen2,步骤跟第一步类似,只是多了7个Line控件用来显示7中颜色,实现了点击按钮切换到screen3的功能

第三步:创建screen3,主要添加了Animated Image控件,用于动态的定时切换图片,点击按钮又回到screen1

6.3、生成代码

点击Generate Code就可以生成代码,同时在Src目录下也会多出一个”xxxx.touchgfx“的文件,以后直接打开这个文件就可以继续使用TouchGFX Designer设计UI了

三、将TouchGFX移植到RT-Thread中

1、修改操作系统接口文件

拷贝OSWrappers.cpp,重命名为OSWrappers_rtt.cpp,更改代码

#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#include <touchgfx/hal/GPIO.hpp>
#include <touchgfx/hal/HAL.hpp>
#include <touchgfx/hal/OSWrappers.hpp>

using namespace touchgfx;

static rt_sem_t frame_buffer_sem;
static rt_mq_t vsync_q = 0;
using namespace touchgfx;

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

/*
 * Initialize frame buffer semaphore and queue/mutex for VSYNC signal.
 */
void OSWrappers::initialize()
{
	frame_buffer_sem = rt_sem_create("gfx_sem", 1, RT_IPC_FLAG_PRIO);
	// Create a queue of length 1
	vsync_q = rt_mq_create("gfx_mq", 1, 1, RT_IPC_FLAG_PRIO);
}

/*
 * Take the frame buffer semaphore. Blocks until semaphore is available.
 */
void OSWrappers::takeFrameBufferSemaphore()
{
	rt_sem_take(frame_buffer_sem, RT_WAITING_FOREVER);
}

/*
 * Release the frame buffer semaphore.
 */
void OSWrappers::giveFrameBufferSemaphore()
{
    rt_sem_release(frame_buffer_sem);
}

/*
 * Attempt to obtain the frame buffer semaphore. If semaphore is not available, do
 * nothing.
 *
 * Note must return immediately! This function does not care who has the taken the semaphore,
 * it only serves to make sure that the semaphore is taken by someone.
 */
void OSWrappers::tryTakeFrameBufferSemaphore()
{
    rt_sem_trytake(frame_buffer_sem);
}

/*
 * Release the frame buffer semaphore in a way that is safe in interrupt context. Called
 * from ISR.
 *
 * Release the frame buffer semaphore in a way that is safe in interrupt context.
 * Called from ISR.
 */
void OSWrappers::giveFrameBufferSemaphoreFromISR()
{
    // Since this is called from an interrupt, FreeRTOS requires special handling to trigger a
    // re-scheduling. May be applicable for other OSes as well.
	rt_sem_release(frame_buffer_sem);
}

/*
 * Signal that a VSYNC has occurred. Should make the vsync queue/mutex available.
 *
 * Note This function is called from an ISR, and should (depending on OS) trigger a
 * scheduling.
 */
void OSWrappers::signalVSync()
{
    if (vsync_q)
    {
        rt_mq_send(vsync_q, &dummy, 1);
    }
}

/*
 * This function blocks until a VSYNC occurs.
 *
 * Note This function must first clear the mutex/queue and then wait for the next one to
 * occur.
 */
void OSWrappers::waitForVSync()
{
    // First make sure the queue is empty, by trying to remove an element with 0 timeout.
    rt_mq_recv(vsync_q, &dummy, 1, 0);

    // Then, wait for next VSYNC to occur.
    rt_mq_recv(vsync_q, &dummy, 1, RT_WAITING_FOREVER);
}

/*
 * A function that causes executing task to sleep for a number of milliseconds.
 *
 * A function that causes executing task to sleep for a number of milliseconds.
 * This function is OPTIONAL. It is only used by the TouchGFX in the case of
 * a specific frame refresh strategy (REFRESH_STRATEGY_OPTIM_SINGLE_BUFFER_TFT_CTRL).
 * Due to backwards compatibility, in order for this function to be useable by the HAL
 * the function must be explicitly registered:
 * hal.registerTaskDelayFunction(&OSWrappers::taskDelay)
 *
 * see HAL::setFrameRefreshStrategy(FrameRefreshStrategy s)
 * see HAL::registerTaskDelayFunction(void (*delayF)(uint16_t))
 */
void OSWrappers::taskDelay(uint16_t ms)
{
	rt_thread_mdelay(ms);
}

static rt_base_t IdleTaskHook(void* p)
{
    if ((int)p) //idle task sched out
    {
        touchgfx::HAL::getInstance()->setMCUActive(true);
    }
    else //idle task sched in
    {
        touchgfx::HAL::getInstance()->setMCUActive(false);
    }
    return RT_TRUE;
}

2、新建touchgfx的应用示例文件

此文件用于初始化TouchGFX,并创建一个任务执行TouchGFX

3、向工程添加文件

3.1、修改\board\KConfig

在文件中添加 BSP_USING_LCD 、BSP_USING_LTDC、 BSP_USING_SDRAM、RT_TOUCHGFX的配置项,这样可以通过menuconfig来选择TouchGFX是否开启了

menu "Onboard Peripheral Drivers"
	...
	config BSP_USING_LCD
        bool "Enable RGB-LCD"
        select BSP_USING_LTDC
        select BSP_USING_SDRAM
        default n
endmenu

menu "On-chip Peripheral Drivers"
	...	
	config BSP_USING_LTDC
        bool
        default n
endmenu

menu "Board extended module Drivers"
    menuconfig RT_STEMWIN
        bool "Enable STemWin"
        default n
        if RT_STEMWIN
            config RT_STEMWIN_DEMO
            bool "Enable STemWin Demo"
            default n
        endif
    
    menuconfig RT_TOUCHGFX
        bool "Enable TouchGFX"
        default n
endmenu

在开启RT_TOUCHGFX之前,需要先开启BSP_USING_LCD

开启RT_TOUCHGFX

3.2、修改\libraries\STM32F4xx_HAL\SConscript

在文件中添加一下如下内容,这样在定义了BSP_USING_LTDC 后就能将HAL驱动的相关文件添加到工程中

if GetDepend(['BSP_USING_LTDC']):
    src += ['STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_ltdc.c']
    src += ['STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_ltdc_ex.c']
    src += ['STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma2d.c']
    src += ['STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_dma2d.c']
    src += ['STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dsi.c']
	src += ['STM32F4xx_HAL_Driver/Src/stm32f4xx_ltdc.c']

3.3、修改\board\SConscript

在文件末尾添加如下内容,这样如果开启了RT_TOUCHGFX,则会包含\board\CubeMX_Config目录下的SConscript文件

if GetDepend(['RT_TOUCHGFX']):
	group = group + SConscript(cwd + '/CubeMX_Config/SConscript')

3.4、新增\board\CubeMX_Config\SConscript

向工程中添加TouchGFX相关的分组,并包含相关的源文件和头文件

import os
import rtconfig
from building import *

cwd = GetCurrentDir()

# add general drivers
src = Split('''
Src/touchgfx_sample.c
Src/OSWrappers-rtt.cpp
Src/STM32DMA.cpp
Src/STM32TouchController.cpp
Src/TouchGFXGPIO.cpp
Src/TouchGFXConfiguration.cpp
Src/TouchGFXGeneratedHAL.cpp
Src/TouchGFXHAL.cpp
Src/app_touchgfx.c
''')

path =  [cwd + '/Src']
path += [cwd + '/Middlewares/ST/touchgfx/framework/include']


if rtconfig.CROSS_TOOL == 'gcc':
    src += [cwd + '/Middlewares/ST/touchgfx/lib/core/cortex_m4f/gcc/libtouchgfx.a']
elif rtconfig.CROSS_TOOL == 'keil':
    src += [cwd + '/Middlewares/ST/touchgfx/lib/core/cortex_m4f/Keil/touchgfx_core.lib']
elif rtconfig.CROSS_TOOL == 'iar':
    src += [cwd + '/Middlewares/ST/touchgfx/lib/core/cortex_m4f/IAR8.x/touchgfx_core.a']

group = DefineGroup('TouchGFX_app', src, depend = [''], CPPPATH = path)

# add TouchGFX generated
genSrc = Glob('./Src/generated/fonts/src/*.cpp')
genSrc += Glob('./Src/generated/gui_generated/src/*/*.cpp')
genSrc += Glob('./Src/generated/images/src/*.cpp')
genSrc += Glob('./Src/generated/texts/src/*.cpp')
genPath = [cwd + '/Src/generated/fonts/include']
genPath += [cwd + '/Src/generated/gui_generated/include']
genPath += [cwd + '/Src/generated/images/include']
genPath += [cwd + '/Src/generated/texts/include']
group = group + DefineGroup('TouchGFX_generated', genSrc, depend = [''], CPPPATH = genPath)

# add TouchGFX resource
resSrc = Glob('./Src/generated/images/src/*/*.cpp')
group = group + DefineGroup('TouchGFX_resource', resSrc, depend = [''])

# add TouchGFX gui
guiSrc = Glob('./Src/gui/src/*/*.cpp')
guiPath = [cwd + '/Src/gui/include']
group = group + DefineGroup('TouchGFX_gui', guiSrc, depend = [''], CPPPATH = guiPath)

Return('group')

最后生成的工程如下:

4、添加触摸驱动

在完成以上配置后,LCD液晶屏就可以点亮了,但是触摸屏还不能使用,还需要添加触摸驱动;触摸驱动的添加也比较简单,首先根据自己板卡的触摸芯片添加驱动代码

4.1 添加TOUCH驱动文件

新建drv_touch.c/h驱动文件;修改..\board\Kconfig添加BSP_USING_TOUCH的配置项

menu "Onboard Peripheral Drivers"
    ...
	config BSP_USING_TOUCH
        bool "Enable TOUCH Driver(TSC2046)"
        default n
		
endmenu

修改..\libraries\HAL_Drivers\SConscript,添加drv_touch.c,将其自动添加进工程

if GetDepend(['BSP_USING_TOUCH']):
	src += ['drv_touch.c']

4.2 完善 STM32TouchController.cpp

添加完touch驱动文件后,完善下 STM32TouchController.cpp 中的两个函数就可以了。注意!这里获取的坐标是(0,0)到(800,480)的逻辑坐标

四、将图片放置到片外SPI FLASH

1、制作STM32F429的SPI FLASH下载算法

通过该算法,可以将工程中生成的图片数据和字体数据存储到外部FLASH

https://blog.csdn.net/sinat_31039061/article/details/107220994

https://blog.csdn.net/Ningjianwen/article/details/100151158

2、修改工程模版template.uvprojx

3、修改链接文件

链接器选择位图的地址。默认情况下,TouchGFX中的所有位图都放入ExtFlashSection中,修改后就能将图片链接到片外FLASH了

LR_IROM1 0x08000000 0x00100000  {    ; load region size_region
  ER_IROM1 0x08000000 0x00100000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x20000000 0x00020000  {  ; RW data
   .ANY (+RW +ZI)
  }
}

LR_EROM1 0x90000000 0x00800000  {    ; load region size_region
  ER_EROM1 0x90000000 0x00800000  {  ; load address = execution address
   *.o (ExtFlashSection)
  }
}

4、将位图数据从外部FLASH拷贝到缓存

4.1、开启模拟SPI

4.2、开启SFUD组件

4.3、设备初初始化

spi_flash_init.c中添加如下内容,注册softspi1总线,注册softspi10设备并挂载到softspi1总线上;使能SFUD驱动W25Q64块设备

#include <rtthread.h>
#include "spi_flash.h"
#include "spi_flash_sfud.h"
#include "drv_soft_spi.h"

#if defined(BSP_USING_SPI_FLASH)
static int rt_hw_spi_flash_init(void)
{
    __HAL_RCC_GPIOG_CLK_ENABLE();
    rt_soft_spi_device_attach("softspi1", "softspi10", GPIOG, GPIO_PIN_10);

    if (RT_NULL == rt_sfud_flash_probe("W25Q64", "softspi10"))
    {
        return -RT_ERROR;
    }

    return RT_EOK;
}
INIT_COMPONENT_EXPORT(rt_hw_spi_flash_init);
#endif

4.4、选中FAL软件包

在ENV中开启FAL软件包,用于操作外部SPI FLASH

配置fal_cfg.h。tgfx分区用于touchgfx的资源存储

#ifndef _FAL_CFG_H_
#define _FAL_CFG_H_

#include <rtthread.h>
#include <board.h>

#define FLASH_SIZE_GRANULARITY_16K   (4 * 16 * 1024)
#define FLASH_SIZE_GRANULARITY_64K   (64 * 1024)
#define FLASH_SIZE_GRANULARITY_128K  (7 * 128 * 1024)

#define STM32_FLASH_START_ADRESS_16K  STM32_FLASH_START_ADRESS
#define STM32_FLASH_START_ADRESS_64K  (STM32_FLASH_START_ADRESS_16K + FLASH_SIZE_GRANULARITY_16K)
#define STM32_FLASH_START_ADRESS_128K (STM32_FLASH_START_ADRESS_64K + FLASH_SIZE_GRANULARITY_64K)

extern const struct fal_flash_dev stm32_onchip_flash_16k;
extern const struct fal_flash_dev stm32_onchip_flash_64k;
extern const struct fal_flash_dev stm32_onchip_flash_128k;
extern struct fal_flash_dev nor_flash0;

/* flash device table */
#define FAL_FLASH_DEV_TABLE                              \
{                                                        \
	&stm32_onchip_flash_16k,                                         \
    &stm32_onchip_flash_64k,                                         \
    &stm32_onchip_flash_128k,                                        \
    &nor_flash0,                                         \
}
/* ====================== Partition Configuration ========================== */
#ifdef FAL_PART_HAS_TABLE_CFG

/* partition table */
#define FAL_PART_TABLE                                                                                                     \
{                                                                                                                          \
    {FAL_PART_MAGIC_WROD, "bootloader", "onchip_flash_16k",  0 , FLASH_SIZE_GRANULARITY_16K , 0}, \
    {FAL_PART_MAGIC_WROD, "param",      "onchip_flash_64k",  0 , FLASH_SIZE_GRANULARITY_64K , 0}, \
    {FAL_PART_MAGIC_WROD, "app",        "onchip_flash_128k", 0 , FLASH_SIZE_GRANULARITY_128K, 0}, \
	{FAL_PART_MAGIC_WROD, "tgfx",       FAL_USING_NOR_FLASH_DEV_NAME,  0 , 4 * 1024 * 1024, 0}, \
}

#endif /* FAL_PART_HAS_TABLE_CFG */
#endif /* _FAL_CFG_H_ */

初始化fal

#include "fal.h"

int fs_init(void)
{
    /* partition initialized */
    fal_init();
	return 0;
}
INIT_COMPONENT_EXPORT(fs_init);

4.5、修改TouchGFX驱动

在缓存位图时,TouchGFX会将像素从原始位置复制到位图缓存中。这个复制是通过调用HAL类中的方法完成的,所以如果是将图片等数据缓存在外部的FLASH时,需要修改此函数来支持外部FLASH的读取。该函数在TouchGFXHAL.cpp中定义

#include <fal.h>

bool TouchGFXHAL::blockCopy(void* RESTRICT dest, const void* RESTRICT src, uint32_t numBytes)
{
	uint32_t dataOffset = (uint32_t)src;
	if (dataOffset >= 0x90000000 && dataOffset < 0x92000000)
	{
		const struct fal_partition *part;
		part = fal_partition_find("tgfx");

		dataOffset =  dataOffset - 0x90000000;
		// for copying data from there.
		if (part != RT_NULL)
		{
			fal_partition_read(part, dataOffset, (uint8_t *)dest, numBytes);
		}
		return true;
	}	
	else
	{
		// For all other addresses, just use the default implementation.
		// This is important, as blockCopy is also used for other things in the core framework.
		return HAL::blockCopy(dest, src, numBytes);
	}	
}

修改完 blockCopy 函数后,只是能从外部SPI FLASH读取图片数据了,但是读取之后要放在哪呢?也就是还需要设置图片的缓存地址,用来存储读取到的图片数据!!!!! 我这里设置到SDRAM中

void touchgfx_init()
{
    ...
	Bitmap::setCache((uint16_t *)0xC0300000,0x400000,128);
	Bitmap::cacheAll();
}

四、将字体放置到片外SPI FLASH

4.14版本的TouchGFX还没解决

4.15版本的TouchGFX官网有文档说明,应该是可以,没有验证

五、移植时的注意事项

1、编译报大量错误时,检查下IAR是否开启了C++编译

2、SDRAM和LTDC的引脚配置一定要跟硬件对应上,非常关键!!!

猜你喜欢

转载自blog.csdn.net/m0_37845735/article/details/109301620