ThreadX GUIX移植到STM32H7(MDK AC5)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ThreadX GUIX移植到STM32H7(MDK AC5)相关的知识,希望对你有一定的参考价值。

​​

第7章   ThreadX GUIX移植到STM32H7(MDK AC5)

本章节将为大家介绍ThreadX GUIX的MDK AC5方式移植和设计框架,理论上不建议初学者直接学习,因为本章节涉及到的知识点很多,建议对GUIX的应用有一些了解后再来看,这样将事半功倍。但是本章的工程模板框架一定要学习。本章节提供的移植方法支持RGB565和ARGB8888两种颜色格式的实现。同时可以自适应我们生产的4.3寸,5寸和7寸的电阻屏和电容屏。

虽然本章节是以我们开发板为例进行移植的,但是教会大家如何移植到自己的板子上以及移植过程中的注意事项是本章节的重点。

7.1初学者重要提示

7.2移植前的准备工作以及移植GUIX的流程

7.3第1步:ThreadX内核模板框架设计

7.4第2步:GUIX模板框架设计(重要)

7.5第3步:下载GUIX库并添加到ThreadX内核工程模板

7.6第4步:SDRAM驱动的实现

7.7第5步:LTDC涉及到的引脚配置和时序配置

7.8第6步:电阻屏和电容屏触摸驱动的实现

7.9第7步:GUIX底层接口函数和配置

7.10第8步:SDRAM的MPU Cache配置

7.11第9步:添加GUI应用进行测试。

7.12显示屏闪烁文件解决方法

7.13避免显示屏上电瞬间高亮和撕裂感

7.14实验例程

7.15 总结

 

 

7.1   初学者重要提示

  1. 学习本章节前,务必保证已经学习了本教程的第4章,第5章和第6章,这三章是移植前的必备知识。
  2. 注意ThreadX MDK AC5工程提供的Port文件问题,移植必读:​​http://www.armbbs.cn/forum.php?mod=viewthread&tid=99306​​ 。
  3. 为了方便大家移植,推荐直接添加我们的工程文件到自己的工程或者直接使用我们的工程模板,按照本章的修改说明移植即可。
  4. 提供了ARGB8888和RGB565两种颜色格式的移植工程,移植方法是一样的,仅添加的接口文件不同。
  5. 本章节是以移植到ThreadX上为例进行说明的,移植到其它小型RTOS方法,后面章节再为大家介绍。
  6. 由于开发板要自适应4.3寸,5寸和7寸显示屏,而且还分电阻触摸和电容触摸,所以移植过程中添加的文件稍多。虽然移植是以我们的开发板为例进行讲解的,但是重点依然是告诉大家如何移植自己的板子以及移植过程中需要注意的事项。
  7. 对于本章节的移植,我们需要先从整体上把控。由于开发板已经把需要移植的文件都整理好了,用户仅需添加文件就可以使用。我们这里着重介绍如何移植到自己的板子上面,这个才是本章节的重点。
  • 显示屏的移植

GUIX需要的底层接口函数已经全部集成在gx_display_driver_stm32h7_24xrgb.c文件和gx_display_driver_stm32h7_565rgb.c里面。对于这两个文件,用户仅需学会使用里面的两个宏配置以及LTDC涉及到的引脚和时序配置函数,这个是需要用户自己去实现的,配置方法已经在本章节的7.7小节进行讲解。

另外还有一个显示屏背光调节函数LCD_SetBackLight的调用,其它都不用做任何修改。这三个地方都设置了,GUIX的显示屏移植就完成了。

  • 触摸的移植

电容触摸的移植比较容易,因为电容触摸芯片可以自动触摸校准,所以仅需配置完触摸芯片后将触摸芯片返回的触摸坐标(电容触摸芯片返回的就是实际的坐标值),按下,松手和移动三种状态发送给GUIX即可。

电阻触摸的移植要稍麻烦些,由于电阻触摸板的线性度不是很好,如果不做触摸校准和滤波处理会有点击不准确和飞点问题。当前配套2点和4点触摸校准算法,大家可以根据需要选择,默认是用的2点触摸校准算法。其中触摸滤波方法是检测到触摸后先延迟30ms,消除抖动,然后采集10组坐标值做升序排列,去掉最大的几组坐标和最小的几组坐标,对中间的几组求平均作为最终的数值(电容触摸芯片返回的是ADC数值,不是实际坐标值)。然后将最终的数值代入通过触摸校准建立的线性公式来获得实际的坐标值,此时就可以将触摸坐标和触摸按下,松手和移动状态发送给GUIX。

7.2   移植前的准备工作以及移植GUIX的流程

移植前注意以下两个问题:

  • 本章节的IDE开发环境务必是MDK5.30及其以上版本,镜像下载地址:

​http://www.armbbs.cn/forum.php?mod=viewthread&tid=96992​​ 。

  • 准备一个简单的ThreadX工程,越简单越好,我们就在这个简单的工程上面移植即可:

配套模板名称:V7-2004_ThreadX Kernel Template

 

GUIX的移植通过以下9步完成,下面各个小节详细讲解每一步:

  • 第1步:ThreadX内核模板框架设计
  • 第2步:GUIX模板框架设计(重要)
  • 第3步:下载GUIX库并添加到ThreadX内核工程模板
  • 第4步:SDRAM驱动的实现
  • 第5步:LTDC涉及到的引脚配置和时序配置
  • 第6步:电阻屏和电容屏触摸驱动的实现
  • 第7步:GUIX底层接口函数和配置
  • 第8步:SDRAM的MPU Cache配置
  • 第9步:添加GUI应用进行测试。

7.3   第1步:了解ThreadX内核模板框架设计

移植GUIX前,我们优先了解下ThreadX内核模板程序的框图。

7.3.1  准备一个ThreadX内核工程模板

首先准备好一个简单的ThreadX工程模板,工程模板的制作在ThreadX内核教程里面有详细说明,这里的重点是教大家移植GUIX,对应的例子名称:V7-2004_ThreadX Kernel Template。准备好的工程模板如下图所示(特别注意,我们这个模板已经添加裸机LCD操作所需的文件)。

【STM32H7】第7章

 

7.3.2  内核框架整体把控(重要)

为了帮助大家更好的理解ThreadX内核例子模板,专门制作了一个框图,可以让大家整体把控模板设计:

【STM32H7】第7章

下面把几个关键点逐一为大家做个说明。

7.3.3  各种头文件汇总includes.h

这个文件主要实现工程中各种头文件的汇总,大家用到的都可以将其放到这个头文件里面。其它应用源文件有调用到的,直接调用这个头文件includes.h即可。

使用这个头文件主要是方便各种头文件的管理。

/*
*********************************************************************************************************
* 标准库
*********************************************************************************************************
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

/*
*********************************************************************************************************
* OS
*********************************************************************************************************
*/
#include "tx_api.h"
#include "tx_timer.h"


/*
*********************************************************************************************************
* APP / BSP
*********************************************************************************************************
*/

#include <bsp.h>

/*
*********************************************************************************************************
* 变量和函数
*********************************************************************************************************
*/
/* 方便RTOS里面使用 */
extern void SysTick_ISR(void);

#define

7.3.4  TheadX配置文件tx_user.h

此文件主要用于ThreadX内核的配置,内核相关的几个宏配置基本都已经整理到这个文件里面。

/*
*********************************************************************************************************
* 宏定义
*********************************************************************************************************
*/
/*
最快速度优化需要开启的选项 :

TX_MAX_PRIORITIES 32
TX_DISABLE_PREEMPTION_THRESHOLD
TX_DISABLE_REDUNDANT_CLEARING
TX_DISABLE_NOTIFY_CALLBACKS
TX_NOT_INTERRUPTABLE
TX_TIMER_PROCESS_IN_ISR
TX_REACTIVATE_INLINE
TX_DISABLE_STACK_FILLING
TX_INLINE_THREAD_RESUME_SUSPEND

最小代码优化需要开启的选项:

TX_MAX_PRIORITIES 32
TX_DISABLE_PREEMPTION_THRESHOLD
TX_DISABLE_REDUNDANT_CLEARING
TX_DISABLE_NOTIFY_CALLBACKS
TX_NOT_INTERRUPTABLE
TX_TIMER_PROCESS_IN_ISR
*/


/* 覆盖tx_port.h 里面的宏定义 */
/*
#define TX_MAX_PRIORITIES 32
#define TX_MINIMUM_STACK ????
#define TX_THREAD_USER_EXTENSION ????
#define TX_TIMER_THREAD_STACK_SIZE ????
#define TX_TIMER_THREAD_PRIORITY ????
*/

/*
确定定时器是否到期的处理,比如应用定时器,溢出时间和函数tx_thread_sleep调用等,是在系统定时器任务里面还是在定时器中断里面调用。
默认是在定时任务里面,当定义了下面函数后,将直接在定时器中断里面处理,可以去掉定时器任务所消耗资源。 */
//#define TX_TIMER_PROCESS_IN_ISR


/* 用于设置定时器激活是否采用内联方式,默认此功能是关闭的。如果使能后,内联方式的执行速度快,但增加代码量 */
//#define TX_REACTIVATE_INLINE


/* 用于设置是否关闭栈填充,默认情况下是使能的,所有任务的栈空间全部填充为0xEF,
* 带有ThreadX调试组件或者运行时栈检测会用到。
*/
//#define TX_DISABLE_STACK_FILLING


/* 用于使能栈检测,默认是关闭的。此选项使能后,而TX_DISABLE_STACK_FILLING没使能时,栈填充将开启,方便栈检测 */
//#define TX_ENABLE_STACK_CHECKING


/* 用于设置是否关闭抢占阀值,默认是开启的。如果应用程序不需要此功能,关闭后可以降低代码需求,提升性能 */
//#define TX_DISABLE_PREEMPTION_THRESHOLD


/* 用于设置是否清零ThreadX全局变量,如果编译器启动代码在ThreadX运行前清除了.bss段,那么可以关闭不必要的清零 */
//#define TX_DISABLE_REDUNDANT_CLEARING


/* 确定是否不需要定时器组,禁止后需要用户注释掉tx_initialize_low_level文件里面tx_timer_interrupt的调用。
另外,禁止后,必须使能TX_TIMER_PROCESS_IN_ISR */
/*
#define TX_NO_TIMER
#ifndef TX_TIMER_PROCESS_IN_ISR
#define TX_TIMER_PROCESS_IN_ISR
#endif
*/

/* 用于设置是否关闭通知回调,默认是使能的。如果应用程序没有用到消息回调,关闭掉后可以减小代码,并且可以提升性能。 */
//#define TX_DISABLE_NOTIFY_CALLBACKS


/* 使能tx_thread_resume和tx_thread_suspend使用内联代码,优势是提升这两个函数的执行性能,劣势是增加代码量 */
//#define TX_INLINE_THREAD_RESUME_SUSPEND


/* 设置TreadX内核不可中断,好处是降低处理负担,并且产生的代码小。但增加锁时间 */
//#define TX_NOT_INTERRUPTABLE


/* 使能事件Trace,会稍微增加点代码 */
//#define TX_ENABLE_EVENT_TRACE


/* 使能BLOCK_POOL信息获取 */
//#define TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO


/* 使能BYTE_POOL信息获取 */
//#define TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO


/* 使能事件标志信息获取 */
//#define TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO


/* 使能互斥信号量信息获取 */
//#define TX_MUTEX_ENABLE_PERFORMANCE_INFO


/* 使能消息对象信息获取 */
//#define TX_QUEUE_ENABLE_PERFORMANCE_INFO

/* 使能信号量信息获取 */
//#define TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO


/* 使能任务信息获取 */
//#define TX_THREAD_ENABLE_PERFORMANCE_INFO


/* 使能定时器信息获取 */
//#define TX_TIMER_ENABLE_PERFORMANCE_INFO

7.3.5  系统时钟节拍配置tx_initialize_low_level.s

这个汇编文件里面有个重要参数需要大家配置,即芯片主频和系统时钟节拍。

SYSTEM_CLOCK       EQU     400000000
SYSTICK_CYCLES EQU ((SYSTEM_CLOCK / 1000) -1)

400000000是系统时钟主频,1000对应的就是系统时钟节拍,这里1000就表示1000Hz。

7.3.6  TheadX任务管理main.c

ThreadX所有任务基本都在main.c里面创建,方便统一管理。如果有GUIX,FileX等组件的任务需要运行,实际运行函数会在其它源文件里面,并将这个函数extern到main.C文件里面,放到相应的任务里面执行。

另外,任务优先级,任务栈大小,任务控制块等也都放到main.C文件里面,方便管理:

/*
*********************************************************************************************************
* 任务优先级,数值越小优先级越高
*********************************************************************************************************
*/
#define APP_CFG_TASK_START_PRIO 2u
#define APP_CFG_TASK_MsgPro_PRIO 3u
#define APP_CFG_TASK_USER_IF_PRIO 4u
#define APP_CFG_TASK_COM_PRIO 5u
#define APP_CFG_TASK_STAT_PRIO 30u
#define APP_CFG_TASK_IDLE_PRIO 31u


/*
*********************************************************************************************************
* 任务栈大小,单位字节
*********************************************************************************************************
*/
#define APP_CFG_TASK_START_STK_SIZE 4096u
#define APP_CFG_TASK_MsgPro_STK_SIZE 4096u
#define APP_CFG_TASK_COM_STK_SIZE 4096u
#define APP_CFG_TASK_USER_IF_STK_SIZE 4096u
#define APP_CFG_TASK_IDLE_STK_SIZE 1024u
#define APP_CFG_TASK_STAT_STK_SIZE 1024u

/*
*********************************************************************************************************
* 静态全局变量
*********************************************************************************************************
*/
static TX_THREAD AppTaskStartTCB;
static uint64_t AppTaskStartStk[APP_CFG_TASK_START_STK_SIZE/8];

static TX_THREAD AppTaskMsgProTCB;
static uint64_t AppTaskMsgProStk[APP_CFG_TASK_MsgPro_STK_SIZE/8];

static TX_THREAD AppTaskCOMTCB;
static uint64_t AppTaskCOMStk[APP_CFG_TASK_COM_STK_SIZE/8];

static TX_THREAD AppTaskUserIFTCB;
static uint64_t AppTaskUserIFStk[APP_CFG_TASK_USER_IF_STK_SIZE/8];

static TX_THREAD AppTaskIdleTCB;
static uint64_t AppTaskIdleStk[APP_CFG_TASK_IDLE_STK_SIZE/8];

static TX_THREAD AppTaskStatTCB;
static uint64_t AppTaskStatStk[APP_CFG_TASK_STAT_STK_SIZE/8];

7.3.7  TheadX启动任务

启动任务里面主要做了四个工作:

  • 优先执行一次任务统计OSStatInit。
  • 外设初始化bsp_Init。
  • 任务创建AppTaskCreate和通信组件创建AppObjCreate。
  • 需要周期性处理的程序bsp_ProPer1ms,对应裸机工程调用的SysTick_ISR。这个的实现非常重要,这样之前裸机里面使用的API,就可以直接在ThreadX里面直接调用。

 

代码如下:

/*
*********************************************************************************************************
* 函 数 名: AppTaskStart
* 功能说明: 启动任务。
* 形 参: thread_input 是在创建该任务时传递的形参
* 返 回 值: 无
优 先 级: 2
*********************************************************************************************************
*/
static void AppTaskStart (ULONG thread_input)

(void)thread_input;

/* 先挂起定时器组 */
#ifndef TX_NO_TIMER
tx_thread_suspend(&_tx_timer_thread);
#endif

/* 优先执行任务统计 */
OSStatInit();

/* 恢复定时器组 */
#ifndef TX_NO_TIMER
tx_thread_resume(&_tx_timer_thread);
#endif

/* 内核开启后,恢复HAL里的时间基准 */
HAL_ResumeTick();

/* 外设初始化 */
bsp_Init();

/* 创建任务 */
AppTaskCreate();

/* 创建任务间通信机制 */
AppObjCreate();

while (1)

/* 需要周期性处理的程序,对应裸机工程调用的SysTick_ISR */
bsp_ProPer1ms();
tx_thread_sleep(1);

7.3.8  HAL库时间基准stm32h7xx_hal_timbase_tim.c

ThreadX系统时钟节拍默认是用的滴答定时器,STM32的HAL库时间基准也是用的滴答定时器。对于这种情况,我们一般的情况下是使用其他的通用定时器替代,不过要额外的占用一点系统性能。简单的处理办法是重新实现下面两个函数即可,让HAL库和ThreadX都使用滴答定时器:

/*
*********************************************************************************************************
* 函 数 名: HAL_Delay
* 功能说明: 重定向毫秒延迟函数。替换HAL中的函数。因为HAL中的缺省函数依赖于Systick中断,如果在USB、SD
* 卡中断中有延迟函数,则会锁死。也可以通过函数HAL_NVIC_SetPriority提升Systick中断
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void HAL_Delay(uint32_t Delay)

bsp_DelayMS(Delay);


HAL_StatusTypeDef HAL_InitTick (uint32_t TickPriority)

return HAL_OK;


uint32_t HAL_GetTick (void)

static uint32_t ticks = 0U;
uint32_t i;

if (_tx_thread_system_state == TX_INITIALIZE_IS_FINISHED)

return ((uint32_t)_tx_time_get());


/* 如果ThreadX还没有运行,采用下面方式 */
for (i = (SystemCoreClock >> 14U); i > 0U; i--)

__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();


return ++ticks;

7.3.9  ThreadX使能硬件浮点

这个是移植的坑王,大家移植后,可以测试下多任务的FPU计算是否有异常。比如两个任务运行相同的浮点运算和刷新速度,看看两个任务的输出是否同步变化,这个测试非常重要:

【STM32H7】第7章

 

那么问题来了,正确的使能姿势是什么?务必保证C和汇编的预定义宏里面都使能。

C里面对应的使能:

【STM32H7】第7章

 

汇编里面对应的使能:

【STM32H7】第7章

 

7.4   第2步:了解GUIX模板框架设计

以往我们做教程都是先介绍如何移植,然后看最后的移植效果。这次我们反过来,先看移植完成的效果,然后移植。

7.4.1  GUIX工程模板

GUIX工程模板移植完成后,大体是下面这种效果:

【STM32H7】第7章

 

7.4.2  GUIX框架整体把控(重要)

为了帮助大家更好的理解GUIX内核例子模板,专门制作了一个框图,可以让大家整体把控模板设计:

【STM32H7】第7章

下面把几个关键点逐一为大家做个说明。

7.4.3  GUIX配置文件gx_user.h

此文件主要用于GUIX的配置,GUIX相关的宏定义配置非常多,当前先把这个文件预留出来,随着后面章节的进行,用到那些宏定义了再添加。

7.4.4  外设驱动初始化文件bsp.c

使用GUIX,主要涉及到SDRAM初始化,触摸初始化,LTDC初始化(放到了GUIX底层驱动接口文件里面了),背光开启和EEPROM初始化(用于存储电阻触摸屏校准参数):

/*
*********************************************************************************************************
* 函 数 名: bsp_Init
* 功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_Init(void)

bsp_InitDWT(); /* 初始化DWT时钟周期计数器 */
bsp_InitKey(); /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
bsp_InitUart(); /* 初始化串口 */
bsp_InitExtIO(); /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */
bsp_InitLed(); /* 初始化LED */
bsp_InitTimer(); /* 初始化滴答定时器 */

bsp_InitExtSDRAM(); /* 初始化SDRAM */

bsp_InitI2C(); /* 初始化I2C总线,用于EEPROM */
TOUCH_InitHard();

/* 延迟200ms再点亮背光,避免瞬间高亮 */
bsp_DelayMS(200);
LCD_SetBackLight(255);

7.4.5  外设驱动头文件汇总bsp.h

此文件主要用于添加了那些外设驱动文件后,使能相应头文件,特别工程GUIX工程里面添加的一批LCD驱动和触摸驱动文件,支持的头文件如下:

/* 通过取消注释或者添加注释的方式控制是否包含底层驱动模块 */
//#include "bsp_msg.h"
//#include "bsp_user_lib.h"
#include "bsp_timer.h"
#include "bsp_led.h"
#include "bsp_key.h"
#include "bsp_dwt.h"

//#include "bsp_cpu_rtc.h"
//#include "bsp_cpu_adc.h"
//#include "bsp_cpu_dac.h"
#include "bsp_uart_fifo.h"
//#include "bsp_uart_gps.h"
//#include "bsp_uart_esp8266.h"
//#include "bsp_uart_sim800.h"

//#include "bsp_spi_bus.h"
//#include "bsp_spi_ad9833.h"
//#include "bsp_spi_ads1256.h"
//#include "bsp_spi_dac8501.h"
//#include "bsp_spi_dac8562.h"
//#include "bsp_spi_flash.h"
//#include "bsp_spi_tm7705.h"
//#include "bsp_spi_vs1053b.h"

#include "bsp_fmc_sdram.h"
//#include "bsp_fmc_nand_flash.h"
//#include "bsp_fmc_ad7606.h"
//#include "bsp_fmc_oled.h"
#include "bsp_fmc_io.h"

#include "bsp_i2c_gpio.h"
//#include "bsp_i2c_bh1750.h"
//#include "bsp_i2c_bmp085.h"
#include "bsp_i2c_eeprom_24xx.h"
//#include "bsp_i2c_hmc5883l.h"
//#include "bsp_i2c_mpu6050.h"
//#include "bsp_i2c_si4730.h"
//#include "bsp_i2c_wm8978.h"

#include "bsp_tft_h7.h"
#include "bsp_tft_lcd.h"
#include "bsp_ts_touch.h"
#include "bsp_ts_ft5x06.h"
#include "bsp_ts_gt811.h"
#include "bsp_ts_gt911.h"
#include "bsp_ts_stmpe811.h"

#include "bsp_beep.h"
#include "bsp_tim_pwm.h"
//#include "bsp_sdio_sd.h"
//#include "bsp_dht11.h"
//#include "bsp_ds18b20.h"
//#include "bsp_ps2.h"
//#include "bsp_ir_decode.h"
//#include "bsp_camera.h"
//#include "bsp_rs485_led.h"
//#include "bsp_can.h"

7.4.6  LCD裸机驱动文件

STM32H7的LCD控制器LTDC控制有两个相关的驱动文件,即bsp_tft_h7.c和bsp_tft_lcd.c。移植GUIX时,这两个文件基本用不上了,已经把这两个文件实现的LTDC配置全部集成到了GUIX的底层接口驱动文件里面,方便大家移植。

7.4.7  电阻和电容触摸驱动文件

电阻和电容触摸主要用的以下几个文件:

  • 总触摸文件,用于识别各种触摸:bsp_ts_touch.c
  • 电容触摸文件bsp_ts_ft5x06.c
  • 电容触摸文件bsp_ts_gt811.c
  • 电容触摸文件bsp_ts_gt911.c
  • 电阻触摸文件bsp_ts_stmpe811

7.4.8  电阻触摸校准参数存储到EEPROM

EEPROM的驱动主要涉及到两个文件:

  • bsp_i2c_gpio.c

配置EEPROM用到的两个引脚。

  • bsp_i2c_eeprom_24xx.c

EEPROM的读写API。

 

而触摸校准参数的实现是在bsp_ts_touch.c文件末尾封装好的两个函数里面:

/*
*********************************************************************************************************
* 函 数 名: TOUCH_SaveParam
* 功能说明: 保存校准参数 s_usAdcX1 s_usAdcX2 s_usAdcY1 s_usAdcX2
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
static void TOUCH_SaveParam(void)


g_tTPParam.TouchDirection = g_LcdDirection;/* 2014-09-11 添加屏幕方向, 用于屏幕旋转时无需再次校准 */

#if 1
/* 写入EEPROM */
ee_WriteBytes((uint8_t *)&g_tTPParam, TP_PARAM_EE_ADDR, sizeof(g_tTPParam));
#else
/* 写入CPU Flash */
bsp_WriteCpuFlash(TP_PARAM_FLASH_ADDR, (uint8_t *)&g_tTPParam, sizeof(g_tTPParam));
#endif


/*
*********************************************************************************************************
* 函 数 名: TOUCH_LoadParam
* 功能说明: 读取校准参数
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
static void TOUCH_LoadParam(void)

#if 1
/* 读取EEPROM中的参数 */
ee_ReadBytes((uint8_t *)&g_tTPParam, TP_PARAM_EE_ADDR, sizeof(g_tTPParam));
#else
/* 读取CPU Flash中的参数 */
bsp_ReadCpuFlash(TP_PARAM_FLASH_ADDR, (uint8_t *)&g_tTPParam, sizeof(g_tTPParam
#endif

if (g_tTPParam.TouchDirection > 4)

g_tTPParam.TouchDirection = 0;
TOUCH_SaveParam();

7.4.9  GUIX底层驱动接口文件

当前制作了两个底层驱动接口文件:

  • gx_display_driver_stm32h7_565rgb.c 对应硬件RGB565接口。
  • gx_display_driver_stm32h7_24xrgb.c 对应硬件RGB888接口。

 

大家可以根据需要选择相应驱动。

7.4.10        GUIX源码文件

GUIX的源码文件非常多,一个文件一个API,有1200个左右,大家移植的时候最好都加上。

【STM32H7】第7章

 

7.4.11        GUIX应用文件

几个应用文件的作用如下:

【STM32H7】第7章

 

随着后面的章节的学习,逐渐就熟练了。

7.5   第3步:添加GUIX库所有相关文件到ThreadX内核工程模板

了解了ThreadX内核框架和GUIX框架后,介绍下如何将GUIX移植到ThreadX内核工程模板里面。我们这里一步到位,直接把所有相关的文件都加上,然后再介绍如何修改,方便大家移植到自己的板子上。

7.5.1  第3.1步,下载GUIX源码包

按照第2章2.3.1小节讲解的方法下载GUIX软件包guix-6.0.1_rel(如果软件包升级了,数字6.0.1略有不同),下面是GUIX软件包内容:

【STM32H7】第7章

 

主要用到两个文件夹:

common文件夹里面是源码文件。

ports文件夹里面是移植文件。

7.5.2  第3.2步,创建GUIX文件夹到工程模板

在工程模板创建GUIX文件夹

【STM32H7】第7章

 

GUIX的M7内核port文件夹里面只有一个GNU(对应路径ports\\cortex_m7),为了方便我们管理,再创建IAR,AC5和AC6三个文件夹,文件夹里面的内容和GNU里面的一样,并且再添加一个src文件夹,整体效果就是下面这样:

【STM32H7】第7章

 

新建的src文件夹是用来存放GUIX底层驱动接口文件用。

7.5.3  第3.3步,添加底层驱动接口文件

添加驱动接口文件到第3.2步创建的ac5->src和ac5-inc文件夹里面(h文件添加到inc文件夹,c文件放到src文件夹)

【STM32H7】第7章

 

为了移植方便,大家直接复制本周教程配套例子在此文件夹下的文件即可。

7.5.4  第3.4步,添加Port文件和源码文件到工程

将源码文件和ports文件添加到MDK的工程项目中,添加后的效果如下:

【STM32H7】第7章

 

推荐使用下面的方法添加,否则MDK会非常卡:

【STM32H7】第7章

 

7.5.5  第3.5步,添加配置文件gx_user.h

在User文件夹下添加文件gx_user.h,直接从本章节教程配套例子的User文件夹复制即可。此文件主要用于GUIX配置。

【STM32H7】第7章

 

为了方便管理,我们这里将路径GUIX\\ports\\cortex_m7\\ac5\\inc里面的gx_port.h文件也添加进来了。

7.5.6  第3.5步,添加GUIX应用文件

在User文件夹添加文件夹GUIX,直接从本章节教程配套例子的User文件夹复制即可,此文件夹主要是GUIX的应用部分,内容如下:

【STM32H7】第7章

 

7.5.7  第3.6步,添加BSP驱动文件

需要添加的BSP驱动文件如下:

【STM32H7】第7章

 

除了SDRAM,LTDC,EEPROM和触摸两个的文件以外,还要添加bsp_tim_pwm.c,这个是用于设置PWM背光用的。

另外注意一点,bsp_tft_lcd.c文件还关联了一些字库文件,大家最好也将其添加到工程里面。这些字库文件位于本章配套例子的User文件夹下,大家直接复制到自己工程的工程里面添加即可,添加后效果如下:

【STM32H7】第7章

 

7.5.8  第3.7步,添加HAL库文件

相关BSP驱动关联到的HAL库文件都添加了进来,简单省事些,大家也可以把HAL库所有文件都添加进来:

【STM32H7】第7章

 

7.5.9  第3.8步,添加预定义宏

C/C++文件中添加的预定义宏如下:

  • USE_HAL_DRIVER
  • STM32H743xx
  • TX_ENABLE_FPU_SUPPORT    用于支持硬件FPU
  • TX_ENABLE_STACK_CHECKING 用于栈检测
  • TX_INCLUDE_USER_DEFINE_FILE 用于包含tx_user.h
  • GX_INCLUDE_USER_DEFINE_FILE 用于包含gx_user.h

【STM32H7】第7章

 

ASM汇编文件里面添加的宏定义:

  • TX_ENABLE_FPU_SUPPORT

【STM32H7】第7章

 

7.5.10        第3.9步,添加头文件路径

需要添加的路径如下:

【STM32H7】第7章

 

至此,我们需要的GUIX文件都已经添加完毕。下面为大家介绍如何修改用于自己的板子。

7.6   第4步:SDRAM驱动实现(用于显存,动态内存和画布)

一定要保证SDRAM大批量读写数据时是正常的,SDRAM的测试可以自己专门做一个工程测试下。对于SDRAM的驱动实现,可以学习我们写的BSP驱动教程第49章:​​http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980​​ 。

不管你使用的是镁光的,海力士的,三星的,ISSI的或者华邦的,基本实现方法都是一样的。教程配套的板子使用的是ISSI的32位带宽的SDRAM,如果想最大限度发挥STM32H7驱动SDRAM的性能,强烈建议使用32位带宽的SDRAM,或者两个16位SDRAM组成32位带宽的SDRAM也是可以的。那SDRAM主要起到什么作用呢?作用有二:

  • 用作显示屏的显存

STM32H7的LTDC外接RGB接口屏是没有显存的,所以需要SDRAM用作显存。如果用户选择STM32H7 LTDC的颜色格式是32位色ARGB8888,那么所需要显存大小(单位字节)是:显示屏宽 * 显示屏高 * (32/8), 其中32/8是表示这种颜色格式的一个像素点需要4个字节来表示。又比如配置颜色格式是16位色的RGB565,那么需要的显存大小是:显示屏宽 * 显示屏高 * (16/8),其中16/8是表示这种颜色格式的一个像素点需要2个字节来表示。其它的颜色格式,依此类推。

  • 用作GUIX动态内存和canvas幕布

GUIX要做的炫酷,是比较消耗动态内存的,所以用户可以将SDRAM除了用于显存以外的所有内存全部用作GUIX动态内存和canvas幕布。

============================================================

如果SDRAM的驱动测试已经没有问题了,就可以将其添加到工程里面了,开发板使用的SDRAM驱动文件是bsp_fmc_sdram.c。

【STM32H7】第7章

 

添加到工程里面后要分配SDRAM的使用,教程配套开发板使用的是32MB,32位带宽的SDRAM。

7.7   第5步:LTDC涉及到的引脚配置和时序配置

7.7.1  LTDC时序配置

用户仅需配置LTDC涉及到的引脚和时序即可,配置函数封装到下面两个接口文件的末尾。

  • gx_display_driver_stm32h7_565rgb.c 对应硬件RGB565接口。
  • gx_display_driver_stm32h7_24xrgb.c 对应硬件RGB888接口。

另外,由于开发板配套了4.3寸,5寸和7寸屏显示屏,所以要对这几种尺寸的显示屏做自适应,每个屏的时序配置都是不一样的,具体实现在gx_display_driver_stm32h7_565rgb.c和gx_display_driver_stm32h7_24xrgb.c接口文件末尾的,即函数LCD_LL_Init。大家在给自己的显示屏移植时主要修改这个函数即可,引脚配置需要在这个函数里面实现。下面我们再结合函数LCD_LL_Init的实现,讲解下配置时要注意的一些问题,具体代码如下:

1.    /*
2. ******************************************************************************************************
3. * 函 数 名: LCD_LL_Init
4. * 功能说明: 配置LTDC
5. * 形 参: 无
6. * 返 回 值: 无
7. * 笔 记:
8. * LCD_TFT 同步时序配置(整理自官方做的一个截图,言简意赅):
9. * ----------------------------------------------------------------------------
10. *
11. * Total Width
12. * <--------------------------------------------------->
13. * Hsync width HBP Active Width HFP
14. * <---><--><--------------------------------------><-->
15. * ____ ____|_______________________________________|____
16. * |___| | | |
17. * | | |
18. * __| | | |
19. * /|\\ /|\\ | | | |
20. * | VSYNC| | | | |
21. * |Width\\|/ |__ | | |
22. * | /|\\ | | | |
23. * | VBP | | | | |
24. * | \\|/_____|_________|_______________________________________| |
25. * | /|\\ | | / / / / / / / / / / / / / / / / / / / | |
26. * | | | |/ / / / / / / / / / / / / / / / / / / /| |
27. * Total | | | |/ / / / / / / / / / / / / / / / / / / /| |
28. * Heigh | | | |/ / / / / / / / / / / / / / / / / / / /| |
29. * |Active| | |/ / / / / / / / / / / / / / / / / / / /| |
30. * |Heigh | | |/ / / / / / Active Display Area / / / /| |
31. * | | | |/ / / / / / / / / / / / / / / / / / / /| |
32. * | | | |/ / / / / / / / / / / / / / / / / / / /| |
33. * | | | |/ / / / / / / / / / / / / / / / / / / /| |
34. * | | | |/ / / / / / / / / / / / / / / / / / / /| |
35. * | | | |/ / / / / / / / / / / / / / / / / / / /| |
36. * | \\|/_____|_________|_______________________________________| |
37. * | /|\\ | |
38. * | VFP | | |
39. * \\|/ \\|/_____|______________________________________________________|
40. *
41. *
42. * 每个LCD设备都有自己的同步时序值:
43. * Horizontal Synchronization (Hsync)
44. * Horizontal Back Porch (HBP)
45. * Active Width
46. * Horizontal Front Porch (HFP)
47. *
48. * Vertical Synchronization (Vsync)
49. * Vertical Back Porch (VBP)
50. * Active Heigh
51. * Vertical Front Porch (VFP)
52. *
53. * LCD_TFT 窗口水平和垂直的起始以及结束位置 :
54. * ----------------------------------------------------------------
55. *
56. * HorizontalStart = (Offset_X + Hsync + HBP);
57. * HorizontalStop = (Offset_X + Hsync + HBP + Window_Width - 1);
58. * VarticalStart = (Offset_Y + Vsync + VBP);
59. * VerticalStop = (Offset_Y + Vsync + VBP + Window_Heigh - 1);
60. *
61. ******************************************************************************************************
62. */
63. static void LCD_LL_Init(void)
64.
65. /* 配置LCD相关的GPIO */
66.
67. /* GPios Configuration */
68. /*
69. +------------------------+-----------------------+----------------------------+
70. + LCD pins assignment +
71. +------------------------+-----------------------+----------------------------+
72. | LCDH7_TFT R0 <-> PI.15 | LCDH7_TFT G0 <-> PJ.07 | LCDH7_TFT B0 <-> PJ.12 |
73. | LCDH7_TFT R1 <-> PJ.00 | LCDH7_TFT G1 <-> PJ.08 | LCDH7_TFT B1 <-> PJ.13 |
74. | LCDH7_TFT R2 <-> PJ.01 | LCDH7_TFT G2 <-> PJ.09 | LCDH7_TFT B2 <-> PJ.14 |
75. | LCDH7_TFT R3 <-> PJ.02 | LCDH7_TFT G3 <-> PJ.10 | LCDH7_TFT B3 <-> PJ.15 |
76. | LCDH7_TFT R4 <-> PJ.03 | LCDH7_TFT G4 <-> PJ.11 | LCDH7_TFT B4 <-> PK.03 |
77. | LCDH7_TFT R5 <-> PJ.04 | LCDH7_TFT G5 <-> PK.00 | LCDH7_TFT B5 <-> PK.04 |
78. | LCDH7_TFT R6 <-> PJ.05 | LCDH7_TFT G6 <-> PK.01 | LCDH7_TFT B6 <-> PK.05 |
79. | LCDH7_TFT R7 <-> PJ.06 | LCDH7_TFT G7 <-> PK.02 | LCDH7_TFT B7 <-> PK.06 |
80. -------------------------------------------------------------------------------
81. | LCDH7_TFT HSYNC <-> PI.12 | LCDTFT VSYNC <-> PI.13 |
82. | LCDH7_TFT CLK <-> PI.14 | LCDH7_TFT DE <-> PK.07 |
83. -----------------------------------------------------
84. */
85. GPIO_InitTypeDef GPIO_Init_Structure;
86.
87. /*##-1- Enable peripherals and GPIO Clocks #################################*/
88. /* 使能LTDC和DMA2D时钟 */
89. __HAL_RCC_LTDC_CLK_ENABLE();
90. __HAL_RCC_DMA2D_CLK_ENABLE();
91.
92. /* 使能GPIO时钟 */
93. __HAL_RCC_GPIOI_CLK_ENABLE();
94. __HAL_RCC_GPIOJ_CLK_ENABLE();
95. __HAL_RCC_GPIOK_CLK_ENABLE();
96.
97. /* GPIOI 配置 */
98. GPIO_Init_Structure.Pin = GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
99. GPIO_Init_Structure.Mode = GPIO_MODE_AF_PP;
100. GPIO_Init_Structure.Pull = GPIO_NOPULL;
101. GPIO_Init_Structure.Speed = GPIO_SPEED_FREQ_HIGH;
102. GPIO_Init_Structure.Alternate = GPIO_AF14_LTDC;
103. HAL_GPIO_Init(GPIOI, &GPIO_Init_Structure);
104.
105. /* GPIOJ 配置 */
106. GPIO_Init_Structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | \\
107. GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | \\
108. GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | \\
109. GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
110. GPIO_Init_Structure.Mode = GPIO_MODE_AF_PP;
111. GPIO_Init_Structure.Pull = GPIO_NOPULL;
112. GPIO_Init_Structure.Speed = GPIO_SPEED_FREQ_HIGH;
113. GPIO_Init_Structure.Alternate = GPIO_AF14_LTDC;
114. HAL_GPIO_Init(GPIOJ, &GPIO_Init_Structure);
115.
116. /* GPIOK 配置 */
117. GPIO_Init_Structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | \\
118. GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
119. GPIO_Init_Structure.Mode = GPIO_MODE_AF_PP;
120. GPIO_Init_Structure.Pull = GPIO_NOPULL;
121. GPIO_Init_Structure.Speed = GPIO_SPEED_FREQ_HIGH;
122. GPIO_Init_Structure.Alternate = GPIO_AF14_LTDC;
123. HAL_GPIO_Init(GPIOK, &GPIO_Init_Structure);
124.
125.
126. /*##-2- LTDC初始化 #############################################################*/
127.
128. uint16_t Width, Height, HSYNC_W, HBP, HFP, VSYNC_W, VBP, VFP;
129. RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = 0;
130. LTDC_LayerCfgTypeDef pLayerCfg = 0;
131.
132. /* 支持6种面板 */
133. switch (g_LcdType)
134.
135. case LCD_35_480X320: /* 3.5寸 480 * 320 */
136. Width = 480;
137. Height = 272;
138. HSYNC_W = 10;
139. HBP = 20;
140. HFP = 20;
141. VSYNC_W = 20;
142. VBP = 20;
143. VFP = 20;
144. break;
145.
146. case LCD_43_480X272: /* 4.3寸 480 * 272 */
147. Width = 480;
148. Height = 272;
149.
150. HSYNC_W = 40;
151. HBP = 2;
152. HFP = 2;
153. VSYNC_W = 9;
154. VBP = 2;
155. VFP = 2;
156.
157. /* LCD 时钟配置 */
158. /* PLL3_VCO Input = HSE_VALUE/PLL3M = 25MHz/5 = 5MHz */
159. /* PLL3_VCO Output = PLL3_VCO Input * PLL3N = 5MHz * 48 = 240MHz */
160. /* PLLLCDCLK = PLL3_VCO Output/PLL3R = 240 / 10 = 24MHz */
161. /* LTDC clock frequency = PLLLCDCLK = 24MHz */
162. /*
163. 刷新率 = 24MHz /((Width + HSYNC_W + HBP + HFP)*(Height + VSYNC_W + VBP + VFP))
164. = 24000000/((480 + 40 + 2 + 2)*(272 + 9 + 2 + 2))
165. = 24000000/(524*285)
166. = 160Hz
167.
168. 当前这个配置方便用户使用PLL3Q输出的48MHz时钟供USB使用。
169. */
170. PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
171. PeriphClkInitStruct.PLL3.PLL3M = 5;
172. PeriphClkInitStruct.PLL3.PLL3N = 48;
173. PeriphClkInitStruct.PLL3.PLL3P = 2;
174. PeriphClkInitStruct.PLL3.PLL3Q = 5;
175. PeriphClkInitStruct.PLL3.PLL3R = 10;
176. HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
177. break;
178.
179. case LCD_50_480X272: /* 5.0寸 480 * 272 */
180. Width = 480;
181. Height = 272;
182.
183. HSYNC_W = 40;
184. HBP = 2;
185. HFP = 2;
186. VSYNC_W = 9;
187. VBP = 2;
188.

以上是关于ThreadX GUIX移植到STM32H7(MDK AC5)的主要内容,如果未能解决你的问题,请参考以下文章

STM32H7第26章 ThreadX GUIX波形控件Line Chart

STM32H7第27章 ThreadX GUIX数字小键盘的实现

STM32H7第3章 ThreadX USBX协议栈移植到STM32H7

ThreadX NetXDUO网络协议栈移植到STM32H7

BSP视频教程STM32H7视频教程第11期:STM32H7的GPIO实战,深化非阻塞编程思想,移植驱动到全新器件上,开启Event Recorder狂暴模式

STM32H7第22章 ThreadX动态内存管理