1.使用RTThread和TouchGFX实现DIY数字仪表(一)——使用STM32CUBMX5.6移植touchGFX4.13
2.使用RTThread和TouchGFX实现DIY数字仪表(二)——把TouchGFX移植到RTThread系统
3.使用RTThread和TouchGFX实现DIY数字仪表(三)——获取温湿度传感器数据
4.使用RTThread和TouchGFX实现DIY数字仪表(四)——同步网络时间
5.使用RTThread和TouchGFX实现DIY数字仪表(五)——同步天气信息
6.使用RTThread和TouchGFX实现DIY数字仪表(六)——链接阿里云物联网平台
7.使用RTThread和TouchGFX实现DIY数字仪表(七)——使用MQTT.fx模拟手机设备进行M2M设备间通信
8.使用RTThread和TouchGFX实现DIY数字仪表(八)——开发微信小程序
9.使用RTThread和TouchGFX实现DIY数字仪表(九)——TouchGFX控件使用教程
硬件: 野火挑战者STM32F767 V1开发版
软件: TouchGFXDesigner v4.13和 STM32CubeMX v5.6.0,MDK v5.29,RT-Thread env 工具
1.准备一套 野火挑战者STM32F767 开发版或其他核心板
2.安装 TouchGFXDesigner v4.13
3.安装STM32CubeMX v5.6.0和X_CUBE_TOUCHGFX软件包
4.安装 MDK v5.27以上版本
5.下载 RTThread源码包https://gitee.com/rtthread/rt-thread
代码持续更新中:github代码下载地址https://gitee.com/Aladdin-Wang/hellotouchGFX.git
关注公众号,加入技术交流群共同学习
把RT-Thread 系统实现DIY数字仪表(一)工程的以下文件拷贝到BSP模版CubeMX_Config文件夹中,替换掉原先的文件,打开demo1重新生成工程。
拷贝OSWrappers.cpp,重命名为OSWrappers_RTT.cpp文件
更改代码
/**
******************************************************************************
* File Name : OSWrappers.cpp
******************************************************************************
* @attention
*
* © Copyright (c) 2020 STMicroelectronics.
* All rights reserved.
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
#include
#include
#include
#include
#include
#include
#include
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;
}
// FreeRTOS specific handlers
extern "C"
{
void vApplicationStackOverflowHook(rt_thread_t xTask,
signed char* pcTaskName)
{
while (1);
}
void vApplicationMallocFailedHook(rt_thread_t xTask,
signed char* pcTaskName)
{
while (1);
}
void vApplicationIdleHook(void)
{
// Set task tag in order to have the "IdleTaskHook" function called when the idle task is
// switched in/out. Used solely for measuring MCU load, and can be removed if MCU load
// readout is not needed.
//vTaskSetApplicationTaskTag(NULL, IdleTaskHook);
}
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
添加代码如下:
#include
#include
#include
#include "app_touchgfx.h"
CRC_HandleTypeDef hcrc;
DMA2D_HandleTypeDef hdma2d;
LTDC_HandleTypeDef hltdc;
static void MX_CRC_Init(void);
static void MX_DMA2D_Init(void);
static void MX_LTDC_Init(void);
#define DISP_Pin GET_PIN(D, 4)
#define CTDL_BL_Pin GET_PIN(D, 7)
#define WIFI_Pin GET_PIN(G, 9)
/**
* @brief This function handles LTDC global interrupt.
*/
void LTDC_IRQHandler(void)
{
/* USER CODE BEGIN LTDC_IRQn 0 */
/* USER CODE END LTDC_IRQn 0 */
HAL_LTDC_IRQHandler(&hltdc);
/* USER CODE BEGIN LTDC_IRQn 1 */
/* USER CODE END LTDC_IRQn 1 */
}
/**
* @brief This function handles DMA2D global interrupt.
*/
void DMA2D_IRQHandler(void)
{
/* USER CODE BEGIN DMA2D_IRQn 0 */
/* USER CODE END DMA2D_IRQn 0 */
HAL_DMA2D_IRQHandler(&hdma2d);
/* USER CODE BEGIN DMA2D_IRQn 1 */
/* USER CODE END DMA2D_IRQn 1 */
}
/**
* @brief CRC Initialization Function
* @param None
* @retval None
*/
static void MX_CRC_Init(void)
{
/* USER CODE BEGIN CRC_Init 0 */
/* USER CODE END CRC_Init 0 */
/* USER CODE BEGIN CRC_Init 1 */
/* USER CODE END CRC_Init 1 */
hcrc.Instance = CRC;
hcrc.Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_ENABLE;
hcrc.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_ENABLE;
hcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_NONE;
hcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_DISABLE;
hcrc.InputDataFormat = CRC_INPUTDATA_FORMAT_BYTES;
if (HAL_CRC_Init(&hcrc) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN CRC_Init 2 */
/* USER CODE END CRC_Init 2 */
}
/**
* @brief DMA2D Initialization Function
* @param None
* @retval None
*/
static void MX_DMA2D_Init(void)
{
/* USER CODE BEGIN DMA2D_Init 0 */
/* USER CODE END DMA2D_Init 0 */
/* USER CODE BEGIN DMA2D_Init 1 */
/* USER CODE END DMA2D_Init 1 */
hdma2d.Instance = DMA2D;
hdma2d.Init.Mode = DMA2D_M2M;
hdma2d.Init.ColorMode = DMA2D_OUTPUT_RGB565;
hdma2d.Init.OutputOffset = 0;
hdma2d.LayerCfg[1].InputOffset = 0;
hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_RGB565;
hdma2d.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;
hdma2d.LayerCfg[1].InputAlpha = 0;
hdma2d.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA;
hdma2d.LayerCfg[1].RedBlueSwap = DMA2D_RB_REGULAR;
if (HAL_DMA2D_Init(&hdma2d) != HAL_OK)
{
Error_Handler();
}
if (HAL_DMA2D_ConfigLayer(&hdma2d, 1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN DMA2D_Init 2 */
/* USER CODE END DMA2D_Init 2 */
}
/**
* @brief LTDC Initialization Function
* @param None
* @retval None
*/
static void MX_LTDC_Init(void)
{
/* USER CODE BEGIN LTDC_Init 0 */
/* USER CODE END LTDC_Init 0 */
LTDC_LayerCfgTypeDef pLayerCfg = {0};
/* USER CODE BEGIN LTDC_Init 1 */
/* USER CODE END LTDC_Init 1 */
hltdc.Instance = LTDC;
hltdc.Init.HSPolarity = LTDC_HSPOLARITY_AL;
hltdc.Init.VSPolarity = LTDC_VSPOLARITY_AL;
hltdc.Init.DEPolarity = LTDC_DEPOLARITY_AL;
hltdc.Init.PCPolarity = LTDC_PCPOLARITY_IPC;
hltdc.Init.HorizontalSync = 0;
hltdc.Init.VerticalSync = 0;
hltdc.Init.AccumulatedHBP = 46;
hltdc.Init.AccumulatedVBP = 23;
hltdc.Init.AccumulatedActiveW = 846;
hltdc.Init.AccumulatedActiveH = 503;
hltdc.Init.TotalWidth = 866;
hltdc.Init.TotalHeigh = 525;
hltdc.Init.Backcolor.Blue = 0;
hltdc.Init.Backcolor.Green = 0;
hltdc.Init.Backcolor.Red = 0;
if (HAL_LTDC_Init(&hltdc) != HAL_OK)
{
Error_Handler();
}
pLayerCfg.WindowX0 = 0;
pLayerCfg.WindowX1 = 800;
pLayerCfg.WindowY0 = 0;
pLayerCfg.WindowY1 = 480;
pLayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_RGB565;
pLayerCfg.Alpha = 255;
pLayerCfg.Alpha0 = 0;
pLayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_CA;
pLayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_CA;
pLayerCfg.FBStartAdress = 0;
pLayerCfg.ImageWidth = 800;
pLayerCfg.ImageHeight = 480;
pLayerCfg.Backcolor.Blue = 0;
pLayerCfg.Backcolor.Green = 0;
pLayerCfg.Backcolor.Red = 0;
if (HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg, 0) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN LTDC_Init 2 */
rt_pin_mode(DISP_Pin, PIN_MODE_OUTPUT);
rt_pin_mode(CTDL_BL_Pin, PIN_MODE_OUTPUT);
rt_pin_mode(WIFI_Pin, PIN_MODE_OUTPUT);
rt_pin_write(DISP_Pin, 1);
rt_pin_write(CTDL_BL_Pin, 1);
rt_pin_write(WIFI_Pin, 0);
/* USER CODE END LTDC_Init 2 */
}
void touchgfx_thread_entry(void *parameter)
{
MX_CRC_Init();
MX_DMA2D_Init();
MX_LTDC_Init();
MX_TouchGFX_Init();
MX_TouchGFX_Process();
for(;;)
{
rt_thread_mdelay(100);
}
}
int TouchGFXTask(void)
{
rt_thread_t tid = NULL;
tid = rt_thread_create("TouchGFX",
touchgfx_thread_entry, RT_NULL,
4096, 20, 20);
if (tid != RT_NULL)
rt_thread_startup(tid);
else
return -1;
return RT_EOK;
}
INIT_APP_EXPORT(TouchGFXTask);
从上一个工程拷贝或新建以下文件到ports文件夹
qspi驱动代码如下:
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-11-27 zylx first version
*/
#include
#include
#include
#include
#include
#ifdef BSP_USING_QSPI_MemoryMapped
#include "qspi_memorymapped.h"
static QSPI_HandleTypeDef hqspi;
//HAL库中发送指令的函数为HAL_QSPI_Command,为了方便使用,对该函数进行如下封装
static void QSPI_SendCmd(uint32_t cmd,uint32_t cmdMode,uint32_t addr,uint32_t addrMode,uint32_t addrSize,uint32_t dataMode)
{
QSPI_CommandTypeDef s_command = {0};
s_command.Instruction = cmd; //指令
s_command.InstructionMode = cmdMode; //指令模式
s_command.Address = addr; //地址
s_command.AddressMode = addrMode; //地址模式
s_command.AddressSize = addrSize; //地址长度
s_command.DataMode = dataMode; //数据模式
if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
Error_Handler();
}
}
//QSPI发送与接收的HAL库函数为QSPI_Transmit与HAL_QSPI_Receive,为方便使用,对着两个函数进行如下封装
static void QSPI_Receive(uint8_t* buf,uint32_t len)
{
hqspi.Instance->DLR = len - 1; //配置数据长度
if(HAL_QSPI_Receive(&hqspi, buf, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
Error_Handler();
}
}
static uint8_t QSPI_Transmit(uint8_t* buf,uint32_t len)
{
hqspi.Instance->DLR = len - 1; //配置数据长度
if(HAL_QSPI_Transmit(&hqspi, buf, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
Error_Handler();
}
return 0;
}
//在初始化流程中需要设置QE为1,编写如下函数
static void W25QXX_SetQE(void)
{
uint8_t value = 0x02;
/* 1.写使能 */
QSPI_SendCmd(W25X_WriteEnable,QSPI_INSTRUCTION_1_LINE,0,0,0,0);
/* 2.发送写状态寄存器2命令 */
QSPI_SendCmd(W25X_WriteStatusReg2,QSPI_INSTRUCTION_1_LINE,0,0,0,QSPI_DATA_1_LINE);
/* 3.发送数据 */
QSPI_Transmit(&value, 1);
}
//在初始化流程中需要设置读参数,编写如下函数,该函数设置Bit4与Bit5为1,使得读取时最大速率可达104MHz
static void W25QXX_SetReadParam(void)
{
uint8_t para = 3 << 4;
/* 1.发送命令 */
QSPI_SendCmd(W25X_SetReadParam,QSPI_INSTRUCTION_4_LINES,0,0,0,QSPI_DATA_4_LINES);
/* 2.发送数据 */
QSPI_Transmit(¶, 1);
}
//最后添加一个读取ID的函数,通过该函数可检测是否初始化成功。根据手册可知,W25Q256的ID为0xEF18
static uint16_t W25QXX_ReadId(void)
{
uint8_t pData[2];
QSPI_SendCmd(W25X_ManufactDeviceID,QSPI_INSTRUCTION_4_LINES,
0,QSPI_ADDRESS_4_LINES,QSPI_ADDRESS_24_BITS,QSPI_DATA_4_LINES);
QSPI_Receive(pData,2);
return pData[1] | ( pData[0] << 8 );
}
//编写好初始化W25Q256程序后,调用一个进入内存映射模式的函数,该函数如下:
/**
* @brief Configure the QSPI in memory-mapped mode
* @param None
* @retval QSPI memory status
*/
static void W25QXX_MemoryMappedMode(uint32_t ADDRESS_BITS)
{
QSPI_CommandTypeDef s_command;
QSPI_MemoryMappedTypeDef s_mem_mapped_cfg;
/* Configure the command for the read instruction */
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES;
s_command.Instruction = W25X_FastReadData;
s_command.AddressMode = QSPI_ADDRESS_4_LINES;
s_command.AddressSize = ADDRESS_BITS;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_4_LINES;
s_command.DummyCycles = 8;
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
/* Configure the memory mapped mode */
s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;
s_mem_mapped_cfg.TimeOutPeriod = 0; //1;
if (HAL_QSPI_MemoryMapped(&hqspi, &s_command, &s_mem_mapped_cfg) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief QUADSPI Initialization Function
* @param None
* @retval None
*/
static void MX_QUADSPI_Init(void)
{
/* QUADSPI parameter configuration*/
hqspi.Instance = QUADSPI;
hqspi.Init.ClockPrescaler = 2;
hqspi.Init.FifoThreshold = 4;
hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
hqspi.Init.FlashSize = 23;
hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_4_CYCLE;
hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;
hqspi.Init.FlashID = QSPI_FLASH_ID_1;
hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE;
if (HAL_QSPI_Init(&hqspi) != HAL_OK)
{
Error_Handler();
}
}
//根据流程编写如下初始化流程函数。
//0XEF13,表示芯片型号为W25Q80
//0XEF14,表示芯片型号为W25Q16
//0XEF15,表示芯片型号为W25Q32
//0XEF16,表示芯片型号为W25Q64
//0XEF17,表示芯片型号为W25Q128
//0XEF18,表示芯片型号为W25Q256
int W25QXX_Init(void)
{
uint16_t W25QXX_ID;
MX_QUADSPI_Init();
W25QXX_SetQE();
rt_thread_mdelay(30);
W25QXX_ENTER_QSPI();
W25QXX_SetReadParam();//设置读参数
W25QXX_ID = W25QXX_ReadId();
if(W25QXX_ID != 0XEF18)
W25QXX_MemoryMappedMode(QSPI_ADDRESS_24_BITS);//进入内存映射模式
else
W25QXX_MemoryMappedMode(QSPI_ADDRESS_32_BITS);//进入内存映射模式
rt_kprintf("W25QXX enter MemoryMappedMode success! W25QXX_ID=%x\r\n",W25QXX_ID);
return RT_EOK;
}
INIT_DEVICE_EXPORT(W25QXX_Init);
#endif/* BSP_USING_QSPI_FLASH */
触摸驱动gt9xx.c需要更改中断,使用rtthread的pin设备接口
import os
import rtconfig
from building import *
cwd = GetCurrentDir()
# add general drivers
src = Split('''
Src/sample_touchgfx.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_m7/gcc/libtouchgfx.a']
elif rtconfig.CROSS_TOOL == 'keil':
src += [cwd + '/Middlewares/ST/touchgfx/lib/core/cortex_m7/Keil/touchgfx_core.lib']
elif rtconfig.CROSS_TOOL == 'iar':
src += [cwd + '/Middlewares/ST/touchgfx/lib/core/cortex_m7/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')
使用scons --target=mdk5 命令生成 MDK工程
SDRAM的前2M空间用于touchgfx,后边的空间给rtthread系统分配内存使用。
使用 gt9147 软件包需要在 RT-Thread 的包管理中选中它,具体路径如下:
RT-Thread online packages —>
peripheral libraries and drivers —>
touch drivers —>
gt9147: touch ic gt9147 for rt-thread
Version (latest) —>
gt9147 软件包初始化函数如下所示:
int rt_hw_gt9147_init(const char *name, struct rt_touch_config *cfg)
该函数需要由用户调用,函数主要完成的功能有,
开启软件I2C1
新建gtxx_ccollect.c文件,添加一下内容
#include
#include "gt9147.h"
#define DRV_DEBUG
#define LOG_TAG "gt9147"
#include
#define THREAD_PRIORITY 5
#define THREAD_STACK_SIZE 1024
#define THREAD_TIMESLICE 5
#define GT9147_RST_PIN 59
#define GT9147_IRQ_PIN 23
static rt_thread_t gt9147_thread = RT_NULL;
static rt_sem_t gt9147_sem = RT_NULL;
static rt_device_t dev = RT_NULL;
static struct rt_touch_data *read_data;
static struct rt_touch_info info;
struct rt_touch_data *read_coordinate(void)
{
return &read_data[0];
}
static void gt9147_entry(void *parameter)
{
rt_device_control(dev, RT_TOUCH_CTRL_GET_INFO, &info);
read_data = (struct rt_touch_data *)rt_malloc(sizeof(struct rt_touch_data) * info.point_num);
while (1)
{
rt_sem_take(gt9147_sem, RT_WAITING_FOREVER);
if (rt_device_read(dev, 0, read_data, info.point_num) == info.point_num)
{
for (rt_uint8_t i = 0; i < info.point_num; i++)
{
if (read_data[i].event == RT_TOUCH_EVENT_DOWN || read_data[i].event == RT_TOUCH_EVENT_MOVE)
{
LOG_D("%d %d %d %d %d\n", read_data[i].track_id,
read_data[i].x_coordinate,
read_data[i].y_coordinate,
read_data[i].timestamp,
read_data[i].width);
}
}
}
rt_device_control(dev, RT_TOUCH_CTRL_ENABLE_INT, RT_NULL);
}
}
static rt_err_t rx_callback(rt_device_t dev, rt_size_t size)
{
rt_sem_release(gt9147_sem);
rt_device_control(dev, RT_TOUCH_CTRL_DISABLE_INT, RT_NULL);
return 0;
}
static int rt_hw_gt9147_port(void)
{
struct rt_touch_config config;
rt_uint8_t rst;
rst = GT9147_RST_PIN;
config.dev_name = "i2c1";
config.irq_pin.pin = GT9147_IRQ_PIN;
config.irq_pin.mode = PIN_MODE_INPUT_PULLDOWN;
config.user_data = &rst;
rt_hw_gt9147_init("gt", &config);
return 0;
}
/* Test function */
int gt9147_init(void)
{
void *id;
rt_hw_gt9147_port();
dev = rt_device_find("gt");
if (dev == RT_NULL)
{
rt_kprintf("can't find device gt\n");
return -1;
}
if (rt_device_open(dev, RT_DEVICE_FLAG_INT_RX) != RT_EOK)
{
rt_kprintf("open device failed!");
return -1;
}
id = rt_malloc(sizeof(rt_uint8_t) * 8);
rt_device_control(dev, RT_TOUCH_CTRL_GET_ID, id);
rt_uint8_t * read_id = (rt_uint8_t *)id;
rt_kprintf("id = %c %c %c %c \n", read_id[0], read_id[1], read_id[2], read_id[3]);
//rt_device_control(dev, RT_TOUCH_CTRL_SET_X_RANGE, &x); /* if possible you can set your x y coordinate*/
//rt_device_control(dev, RT_TOUCH_CTRL_SET_Y_RANGE, &y);
rt_device_control(dev, RT_TOUCH_CTRL_GET_INFO, id);
rt_kprintf("range_x = %d \n", (*(struct rt_touch_info*)id).range_x);
rt_kprintf("range_y = %d \n", (*(struct rt_touch_info*)id).range_y);
rt_kprintf("point_num = %d \n", (*(struct rt_touch_info*)id).point_num);
rt_free(id);
rt_device_set_rx_indicate(dev, rx_callback);
gt9147_sem = rt_sem_create("dsem", 0, RT_IPC_FLAG_FIFO);
if (gt9147_sem == RT_NULL)
{
rt_kprintf("create dynamic semaphore failed.\n");
return -1;
}
gt9147_thread = rt_thread_create("gt9147",
gt9147_entry,
RT_NULL,
THREAD_STACK_SIZE,
THREAD_PRIORITY,
THREAD_TIMESLICE);
if (gt9147_thread != RT_NULL)
rt_thread_startup(gt9147_thread);
return 0;
}
//INIT_APP_EXPORT(gt9147_init);
更改TouchGFXConfiguration.cpp文件如下
此工程地址
hellotouchGFX/ 3_STM32F767_RTThread_TouchGFX / 3_rtthread_TouchGFX_transplant / stm32f767-fire-challenger
qspi flash 地址映射的驱动使用的依然是上一版的代码,没有使用rtthread的源码包里提供的qspi驱动,这个也可以整合进去
TouchGFX本身就是一个与硬件和操作系统无关的软件包,完全可以整合成RTThread的一个软件包来使用,此次移植的依然是通过cubmx生成的TouchGFX工程,没有制作成RTThread的通用软件包
参考文章:https://blog.csdn.net/baidu_33429980/article/details/104248352