一、工程配置
1.1 SPI配置
时钟配置什么的都会,直接配置SPI。选择主机发送模式,数据宽选择8位即可,SPI初始化需要发送8位数据。时钟分频根据自己的系统配置,其他默认即可,根据屏幕厂家资料进行配置。还需要另外配置4个GPIO分别用于控制位选、数据/命令、屏幕复位和背光。
1.2 TouchGFX配置
找到Middlew and Software Pack选项卡,选择X-CUBEMX-TOUCHGFX会弹出一个选择界面,这里我选择4.20.0版本(如果没有安装touchgfx的包,需要点击Install安装),点击OK即可。
然后按照下图进行配置,先开启CRC(touchgfx运行需要),再根据自己的需求进行配置,因为用的是SPI接口的屏幕,接口需要自定义,分辨率240*240,单缓冲,无操作系统。
1.3 TouchGFX心跳配置
touchgfx需要一个刷新心跳,这里可以定义一个定时器,开启中断,10ms左右刷新一次屏幕,可以配置1ms的定时器中断,累加10次左右刷新一次touchgfx。
然后直接点击生成工程代码,生成后先不要打开keil,会报错误,因为还没有将touchgfx的相关文件加载进来。
二、代码实现
2.1 TouchGFX Designer
打开工程目录,找到如图的文件并打开,选择一个合适的模板,这里我选择空的模板,在页面中添加一张Image,用于验证TouchGFX移植是否成功,点击F4生成代码,再打开keil工程进行编译。
2.2 屏幕驱动实现
需要实现屏幕的初始化,一般屏幕厂家会给的,还需要实现SPI数据发送功能,因为配置SPI时数据宽度是8位,驱动SPI彩色屏幕需要发送16位数据的颜色(RGB565)。以下是用HAL库函数实现数据发送。
/******************************************************************************
函数说明:LCD串行数据写入函数
入口数据:dat 要写入的串行数据
返回值: 无
******************************************************************************/
void LCD_Writ_Bus(u8 dat)
{
u8 i;
LCD_CS_Clr();
// for (i = 0; i < 8; i++)
// {
// LCD_SCLK_Clr();
// if (dat & 0x80)
// LCD_SDIN_Set();
// else
// LCD_SDIN_Clr();
// LCD_SCLK_Set();
// dat <<= 1;
// }
HAL_SPI_Transmit(&hspi1,&dat,1,100);
// SPI1->DR=dat;
LCD_CS_Set();
}
/******************************************************************************
函数说明:LCD写入数据
入口数据:dat 写入的数据
返回值: 无
******************************************************************************/
void LCD_WR_DATA(u16 dat)
{
uint8_t buff[2];
LCD_CS_Clr();
LCD_DC_Set();//写数据
buff[0]=dat>>8;
buff[1]=dat;
HAL_SPI_Transmit(&hspi1,buff,2,10000);
LCD_CS_Set();
}
还需要实现窗口设置的函数,在指定位置刷新图像数据,该代码厂家会提供。
/******************************************************************************
函数说明:设置起始和结束地址
入口数据:x1,x2 设置列的起始和结束地址
y1,y2 设置行的起始和结束地址
返回值: 无
******************************************************************************/
void LCD_Address_Set(u16 x1, u16 y1, u16 x2, u16 y2)
{
LCD_WR_REG(0x2a); //列地址设置
LCD_WR_DATA(x1);
LCD_WR_DATA(x2);
LCD_WR_REG(0x2b); //行地址设置
LCD_WR_DATA(y1);
LCD_WR_DATA(y2);
LCD_WR_REG(0x2c); //储存器写
}
为了HAL的函数能够在C++中兼容,需要对HAL_SPI_Transmit函数进行封装
void SendByte(uint8_t *dat)
{
HAL_SPI_Transmit(&hspi1,dat,2,100);
}
2.3 和TouchGFX对接
找到如图的文件,在文件中实现绘制代码。首先指定在rect中绘制代码,在LCD上开启一个窗口,然后将数据逐一写入即可,注意位选和数据端口使能,这里就完成了TouchGFX图像绘制的功能。
/**
* This function is called whenever the framework has performed a partial draw.
*
* @param rect The area of the screen that has been drawn, expressed in absolute coordinates.
*
* @see flushFrameBuffer().
*/
void TouchGFXHAL::flushFrameBuffer(const touchgfx::Rect& rect)
{
volatile uint16_t* buffer = getClientFrameBuffer()+(rect.y*DISPLAY_WIDTH)+rect.x;
uint16_t height,i;
LCD_Address_Set(rect.x,rect.y,rect.x+rect.width-1,rect.y+rect.height-1);
LCD_CS_Clr();
LCD_DC_Set();
for(height=0;height<rect.height;height++)
{
for(i=0;i<rect.width;i++)
{
uint8_t dat[2];
dat[0]=buffer[i]>>8;
dat[1]=buffer[i];
SendByte(dat);
}
buffer += DISPLAY_WIDTH;
}
LCD_CS_Set();
}
2.4 实现TouchGFX心跳
在TouchGFXHAL.cpp文件中实现函数,这里是20ms的刷新周期。
extern "C" void touchgfxTickHandler()
{
static uint8_t ms = 0;
static uint8_t isHigh = 0;
if(isInited)
{
ms++;
if(ms==20)
{
ms = 0;
isHigh = !isHigh;
if(isHigh)
{
HAL::getInstance()->vSync();
OSWrappers::signalVSync();
HAL::getInstance()->swapFrameBuffers();
}else
{
HAL::getInstance()->frontPorchEntered();
}
}
}
}
在main函数中开启定时器中断
使用HAL库中的中断回调函数实现定时器中断回调,至此完成Touchgfx的移植,不过还不能进行触摸,只能显示画面,不能使用外部操作进行交互。
/* USER CODE BEGIN 4 */
extern void touchgfxTickHandler();
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM6)
{
touchgfxTickHandler();
}
}
/* USER CODE END 4 */
下载到板子上的效果如下
三、后续更新
好了,移植过程有点繁琐,不过最后还是成功了,下期再进行触摸移植,实现控件的交互动作。