Porting of TouchGFX on STM32F429IGT6 (RT-Thread version)

table of Contents

Preface

1. New BSP

2. Use CubeMX to create a TouchGFX project

1. Configure FMC (SDRAM)

2. Configure DMA2D and enable DMA2D interrupt

3. Configure LTDC and enable LTDC interrupt

4. Turn on CRC

5. Configure TouchGFX

6. Execute TouchGFX Designer

6.1, TouchGFX Designer interface

6.2, add GUI application

6.3, generate code

3. Porting TouchGFX to RT-Thread

1. Modify the operating system interface file

2. Create a new application example file of touchgfx

3. Add files to the project

3.1, modify \board\KConfig

3.2. Modify \libraries\STM32F4xx_HAL\SConscript

3.3, modify \board\SConscript

3.4. Added \board\CubeMX_Config\SConscript

4. Add touch driver

4.1 Add TOUCH driver file

4.2 Improve STM32TouchController.cpp

Fourth, place the picture on the off-chip SPI FLASH

1. Make STM32F429 SPI FLASH download algorithm

2. Modify the project template template.uvprojx

3. Modify the link file

4. Copy the bitmap data from the external FLASH to the cache

4.1, open analog SPI​

4.2, open SFUD components

4.3, initial initialization of the device

4.4, select FAL software package

4.5, modify the TouchGFX driver

Fourth, place the font on the off-chip SPI FLASH

Five, matters needing attention when transplanting


Preface

Before porting, you need to be familiar with rt-thread and use the ENV tool of rtthread

1. New BSP

rtthread has a detailed BSP making tutorial for the STM32 series, you can make your own BSP according to your own board, so I won’t repeat it here, you can refer to the documentation on the official website

2. Use CubeMX to create a TouchGFX project

In the created BSP, double-click ..\board\CubeMX_Config.ioc ​​to open CubeMX, configure related peripherals and generate initialization code, which will be used in the touchgfx sample file later

1. Configure FMC (SDRAM)

Be sure to note that the configured GPIO must be consistent with your own hardware! ! ! Because some pins of SDRAM can be multiplexed on multiple GPIOs. There is no SDRAM initialization program in the generated project

2. Configure DMA2D and enable DMA2D interrupt

3. Configure LTDC and enable LTDC interrupt

Be sure to note that the configured GPIO must be consistent with your own hardware! ! !

4. Turn on CRC

5. Configure TouchGFX

Open the TouchGFX software package

Configure TouchGFX

6. Execute TouchGFX Designer

After using CubeMX to generate a project, do not open the IAR project first, but also need to execute Touch Designer to design the UI part and improve the project. There is an ApplicationTemplate.touchgfx.part in the Src directory. Click this link to open TouchGFX Designer.

6.1, TouchGFX Designer interface

6.2, add GUI application

If you have used TouchGFX Designer to design the UI before, just copy the relevant files directly. You don’t need to follow the steps below to design the UI. Click Generate Code to generate the code and copy the following files.

The first step: Create screen1, place a Box control and a Button control, set the coordinates of the Box to (0, 0) and the size of 800x480, set the coordinates of the Button and the background image when it is pressed and released. The image can be from the Alibaba Vector Icon Library Download and put it in the …\Src\assets\images directory; add Interaction to realize the function of switching to screen2 by clicking the button

Step 2: Create screen2. The steps are similar to the first step, except that there are 7 more Line controls to display 7 colors, and the function of clicking the button to switch to screen3 is realized

The third step: create screen3, mainly add the Animated Image control, which is used to dynamically switch pictures at a fixed time, click the button to return to screen1

6.3, generate code

Click Generate Code to generate the code. At the same time, there will be an additional "xxxx.touchgfx" file in the Src directory, and you can continue to use TouchGFX Designer to design the UI by opening this file directly.

3. Porting TouchGFX to RT-Thread

1. Modify the operating system interface file

Copy OSWrappers.cpp, rename it to OSWrappers_rtt.cpp, change the code

#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. Create a new application example file of touchgfx

This file is used to initialize TouchGFX and create a task to execute TouchGFX

3. Add files to the project

3.1, modify \board\KConfig

Add the configuration items of BSP_USING_LCD, BSP_USING_LTDC, BSP_USING_SDRAM, RT_TOUCHGFX in the file , so that you can select whether TouchGFX is turned on through menuconfig

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

Before turning on RT_TOUCHGFX , you need to turn on BSP_USING_LCD

Turn on RT_TOUCHGFX

3.2. Modify \libraries\STM32F4xx_HAL\SConscript

Add the following content to the file, so that the relevant files of the HAL driver can be added to the project after BSP_USING_LTDC is defined

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, modify \board\SConscript

Add the following content at the end of the file, so that if RT_TOUCHGFX is turned on, it will include the SConscript file in the \board\CubeMX_Config directory

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

3.4. Added \board\CubeMX_Config\SConscript

Add TouchGFX related groups to the project, and include related source files and header files

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')

The final generated project is as follows:

4. Add touch driver

After completing the above configuration, the LCD screen can be lit, but the touch screen cannot be used yet, and a touch driver needs to be added; the addition of the touch driver is also relatively simple, first add the driver code according to the touch chip of your board

4.1 Add TOUCH driver file

Create a new drv_touch.c/h driver file; modify ..\board\Kconfig to add the configuration item of BSP_USING_TOUCH

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

Modify ..\libraries\HAL_Drivers\SConscript, add drv_touch.c, and add it to the project automatically

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

4.2 Improve STM32TouchController.cpp

After adding the touch driver file, complete the two functions in STM32TouchController.cpp. note! The coordinates obtained here are logical coordinates from (0,0) to (800,480)

Fourth, place the picture on the off-chip SPI FLASH

1. Make STM32F429 SPI FLASH download algorithm

Through this algorithm, the image data and font data generated in the project can be stored in the external FLASH

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

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

2. Modify the project template template.uvprojx

3. Modify the link file

The linker selects the address of the bitmap. By default, all bitmaps in TouchGFX are placed in ExtFlashSection, and after modification, the pictures can be linked to the off-chip 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. Copy the bitmap data from the external FLASH to the cache

4.1, open analog SPI

4.2, open SFUD components

4.3, initial initialization of the device

Add the following content in spi_flash_init.c , register softspi1 bus, register softspi10 device and mount it on softspi1 bus; enable SFUD to drive W25Q64 block device

#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, select FAL software package

Open the FAL software package in ENV for operating external SPI FLASH

Configure fal_cfg.h. Tgfx partition is used for resource storage of 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_ */

Initialize fal

#include "fal.h"

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

4.5, modify the TouchGFX driver

When the bitmap is cached, TouchGFX will copy the pixels from the original location to the bitmap cache. This copy is done by calling the method in the HAL class, so if the data such as pictures is cached in the external FLASH, this function needs to be modified to support the reading of the external FLASH. This function is defined in 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);
	}	
}

After modifying the blockCopy function, only the image data can be read from the external SPI FLASH, but where should I put it after reading? That is to say, you also need to set the picture cache address to store the read picture data!!!!! I set it to SDRAM here

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

Fourth, place the font on the off-chip SPI FLASH

4.14 version of TouchGFX has not been resolved

The 4.15 version of TouchGFX official website has documentation, it should be possible, there is no verification

Five, matters needing attention when transplanting

1. When a large number of errors are reported during compilation, check whether C++ compilation is enabled in IAR

2. The pin configuration of SDRAM and LTDC must correspond to the hardware, which is very important! ! !

 

 

Guess you like

Origin blog.csdn.net/m0_37845735/article/details/109301620