写在前面
这篇文章主要是为了学习TouchGFX而写的,一方面是为了学习,另一方面是为了记录,为了今后方便查阅。本次的教程使用的是一块做好的开发板,方便使用,但是本次的教程都是从0开始讲起的,讲得非常细致,你一定可以成功的。你基本是无需做特别的准备,只需要准备好一块SPI的屏幕就行啦。
硬件准备
开发板
开发板实物图
开发板资料
准备一块开发板,这样对于TouchGFX的学习将会事半功倍,此次使用的是芯视界的一块开发板,这块板子可以通过淘宝购买,价格大概是150元。资料在我的百度云网盘里面有路径是:我的网盘/I我的资源/2.8寸touchgfx资料(不提供,需要自行淘宝购买)。
没有开发板也可以,只需要一个SPI的屏幕,QSPI的FLAH即可;倘若只是体验一下的话,也可以无需QSPI的FLAH,即可体验TouchGFX啦。
开发板原理图
下载器
下载器的选择
还需要有个下载器来下载程序,这个没有过多的限制,可以是DAPLINK,也可以是STLINK...
编写下载算法
只有下载器的话只能下载片内的FLASH,但是由于图形库使用的素材以及文字的体积很大,片内的FLASH是无法完全储存的,因此还需要一个外部下载算法。可以使用的下载算法一般是STM32 CubeProgrammer以及KEIL的下载算法,两者有类似之处,这个可以参考网上的资料编写,后续再出文章来讲解如何编写下载算法。
本篇只讲解如何移植,不使用外部下载算法,之后再讲解别的。
STM32CubeProgrammer下载算法
.....
Keil MDK下载算法
....
软件准备
STM32CubeMX 6.9.1
要使用TOUCHGFX图形库,必须使用cubemx来生成部分代码。此次使用的版本是MX.6.9.1。安装好软件后如果出现了闪退的情况,查看是否是配置好了java环境,查看jdk的版本是否符合安装的要求。
X-CUBE-TOUCHGFX 4.22.0
安装好了cubemx以后还需安装软件包,这样才能在cubeMX里面配置TouchGFX.
STM32CubeL4 Firmware Package V1.17.02
TouchGFX Designer 4.22.0
使用这个软甲可以实现可视化界面编辑,非常好用。同一台电脑上可以安装多个版本的软件,但是还是建议使用固定的一个版本,不同版本生成的代码是不一致的,会导致编译不通过。在软件包的安装目录下有对应版本的PC软件的安装包,可以直接安装。
开始创作
第一步是点亮屏幕,然后才能考虑后面的事情。这里不做多余的的讲解,根据各自的屏幕而定。唯一需要注意的是最好是使用DMA减小MCU的压力。本次使用的是SPI的屏幕,同时使用的是16BIT的数据传输,这样大大提高了传输的效率。
此外,采用FreeRTOS便于后面跑图形库。目前已经实现的功能,可以从这里开始。后面的代码都放在这里。
下面开始配置,从创建工程开始,
步骤如下:
CUBEMX的配置
1.配置时钟。
这个看自己的硬件环境了,这只是作为参考。由于我选用的芯片是STM32L431RCT6,最大时钟为80MHz。选择它的原因是因为价格比较合适大约是15块的样子,同时有QSPI可以存储映射。


2.配置调试接口
用于下载程序和串口用于打印一些信息。


3.添加屏幕的SPI以及GPIO
配置接口SPI,速度那是越快越好,当然也是要注意你的屏幕控制IC所支持的最大速度是多少,还有就是连接屏幕的线材和走线在高速信号的时候需要阻抗的问题。由于我们只需要给屏幕发数据,所以只要Transmit就行了。
关于屏幕的接口还需要哪些GPIO,这个需要是自己的情况而定了,这是我的接口,一共需要5个GPIO,LCD_BL是背光控制,LCD_REST是复位引脚,SPI1_SCL以及SPI1_SDA是数据传输的接口,LCD_DX是命名和数据切换的引脚.由于SPI_CS引脚已经直接接地了,所以不要配置了,如果你的板子上市有的话,你需要配置。



相信你注意到了我这里使用的是16BIT ,这需要你在屏幕的初始化代码里有所修改。




这里配置了其他的几个接口,需要注意上拉还是下拉,IO的速度,这些问题。
4.配置QSPI接口
本篇没有用到,但是先配置,后面会使用的。


5.添加FreeRTOS
只需要打开就行,无需别的配置。
6.添加 TouchGFX



7.配置定时器
首先需要添加一个定时器用于时间的Tick这个是用于屏幕帧的刷新,每进一次定时器中断就会发送一个信号量(FreeRTOS里面用到的),用于更新屏幕。这个时间不需要太快,大概是60HZ的速率就行了,大概取就是20ms就行也就是50HZ。
外设时钟为80M,那么80MHz / ( 80 * 20,000) = 50Hz ,开启自动重装载可以实现多次定时,而不用每次都开启,同时还要开启定时器中断。

5.生成代码先测试下


这个警告就是说我们需要改变HAL_timebase,点击 NO,

此外非常重要的一件事情,配置Timebase的中断优先级,不然你若使用HAL_Delay卡死!!!!

从新配置好Timebase以后,再次点击生成就不会警告了。
KEIL代码的修改
1.keil重定向printf

//
#include <stdio.h>
#include <usart.h>
#ifndef __MICROLIB
#pragma import(__use_no_semihosting)
void _sys_exit(int x)
{
x = x;
}
struct __FILE
{
int handle;
};
void _ttywrch(int ch){
return ;
}
FILE __stdout;
#endif
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,100);
return ch;
}
//
注意:这样就不要打开microlib了,不然c++下有警告。
2.编译一下
第一次生成的代码先编译下看看是否有问题。但是第一次生成的代码都会有错误,意思就是确实文件。这时候需要打开TouchGFX designer生成一下就行了。

找到工程目录下的TOUCHGFX 文件夹下有如下的文件,双击打开,
第一次进入的话会提示你添加UI,我们点击X,直接进入,
设置里面调一下显示的方向,
来都来了,那就先添加点内容吧,

生成完成了,再次回到keil.全点是,
再次编译,还是有错误,意思就是说缺少这两个函数的定义,那我们就添加,

首先我们需要在工程里先添加之前写好的屏幕驱动代码,这个添加的过程就略过了。
PS:关于屏幕的驱动你只需要可以实现在屏幕的指定地方显示色块就行了。
打开你写的屏幕驱动代码里定义3个函数:

这里的3个函数就是实现了将MCU内部的缓冲数据发送到屏幕的过程,
volatile uint8_t IsTransmittingBlock_=0;
/**
* Check if a Frame Buffer Block is beeing transmitted.
*/
int touchgfxDisplayDriverTransmitActive(void)
{
return IsTransmittingBlock_;
}
/**
* Check if a Frame Buffer Block ending at bottom may be sent.
*/
int touchgfxDisplayDriverShouldTransferBlock(uint16_t bottom)
{
return 1;
}
/**
* Transmit a Frame Buffer Block.
*/
void touchgfxDisplayDriverTransmitBlock(const uint8_t* pixels, uint16_t x, uint16_t y, uint16_t w, uint16_t h)
{
IsTransmittingBlock_=1;
LCD_Address_Set(x,y,x+w-1,y+h-1);//设置显示范围,这里的地址-1非常关键不然会造成撕裂的效果。
HAL_SPI_Transmit_DMA(&LCD_SPI_Handle,(uint8_t*)pixels,w*h);
}
其中的 IsTransmittingBlock_变量还需要在SPI的中断里面改变,它每次传输之前赋值为1,传输完成后在SPI的中断里面赋值为0,如此反复,实现屏幕的刷新。

extern void DisplayDriver_TransferCompleteCallback(void);
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
if (hspi->Instance == SPI1) {
IsTransmittingBlock_ = 0;
DisplayDriver_TransferCompleteCallback();
}
}
再次编译,
编译不再报错了!!
3.添加定时器中断回调
前面就已经提到了,这个定时器是用于给屏幕刷新提供时间的,你一定是想到了,这个函数里面需要写一些什么呢?那我们开始吧。
首先,在这个文件下添加一个刷新的函数,由于是C++的文件,所以要加extern c ,
//
#include <touchgfx/hal/OSWrappers.hpp>
//
extern "C"
void touchgfxTickHandler()
{
OSWrappers::signalVSync();
}
然后在main.c的中断回调函数下添加:
if (htim->Instance == TIM6) {
touchgfxTickHandler();
}
添加启动代码,以及初始化,
//
#include "app_touchgfx.h"
//
MX_TouchGFX_Process(); // forever in loop
LCD_Init();
HAL_TIM_Base_Start_IT(&htim6);
printf("Hello TouchGFX!!\n");
4.HELLO TOUCHGFX!!
编译下载
