eefocus_3891719 发表于 2024-11-29 10:14:13

【Avnet | NXP FRDM-MCXN947试用活动】测评6--移植触摸屏

# 触摸屏介绍


触摸屏介绍参见(https://www.eefocus.com/forum/forum.php?mod=forumdisplay&fid=353&filter=typeid&typeid=1316)

它的主要几个参数如下:

| 项目   | 参数                      | 单位   |
| ------ | ----------------------- | ------ |
| 有效区尺寸| 3.2                     | inch   |
| 触摸屏类型| 电容触摸屏                   | -      |
| 触摸屏分辨率 | 240x320               | pixels |
| 驱动IC   | FT6336U               | -      |
| 可视窗口尺寸 | 49.20±0.15(W)x65.40±(H) | mm   |
| 通信接口   | IIC                     | -      |
| 结构材质   | G+F                     | -      |
| 工作温度   | -20~60                  | ℃      |
| 存储温度   | -30~70                  | ℃      |

## 与MCXN947连接关系

触摸屏信号包含通信信号和复位信号。这里4个管脚全部配置为 GPIO ,用 GPIO 模拟 IIC。

| 编号| MCXN947 管脚   | 触摸屏管脚   | 说明                              |
| --- | -------------- | ------- | ------------------------------- |
| 1   | J4.6-- P0_14 | CTP_SCL | 电容触摸屏IIC总线时钟信号                  |
| 2   | J4.8-- P0_22 | CTP_RST | 电容触摸屏复位控制信号,低电平复位               |
| 3   | J4.10 -- P0_15 | CTP_SDA | 电容触摸屏IIC总线数据信号                  |
| 4   | J4.5-- P4_16 | CTP_INT | 电容触摸屏IIC总线触摸中断信号,产生触摸时,输入低电平到主控 |

# 移植触摸接口

这里选择GPIO模拟IIC的通信方式,简单,易于移植。

参考 (https://www.eefocus.com/forum/forum.php?mod=forumdisplay&fid=353&filter=typeid&typeid=1316)


## 管脚配置

使用 MCUXpresso Config Tools 大大方便管脚配置工作。

!(https://www.eefocus.com/forum/data/attachment/forum/202411/29/101218ghespc4rctrtmcce.png)


!(https://www.eefocus.com/forum/data/attachment/forum/202411/29/101253s2212w9ff2dh2mff.png)


保存配置生成代码,最终生成两个函数 `TFT_Touch_Init()`, `TFT_Touch_Deinit()` 其中 `TFT_Touch_Init()` 函数定义如下,会被 `BOARD_InitBootPins()` 调用,无需我们手动调用。

```c
void TFT_Touch_Init(void)
{
    /* Enables the clock for GPIO0: Enables clock */
    CLOCK_EnableClock(kCLOCK_Gpio0);
    /* Enables the clock for GPIO4: Enables clock */
    CLOCK_EnableClock(kCLOCK_Gpio4);
    /* Enables the clock for PORT0 controller: Enables clock */
    CLOCK_EnableClock(kCLOCK_Port0);
    /* Enables the clock for PORT4: Enables clock */
    CLOCK_EnableClock(kCLOCK_Port4);

    gpio_pin_config_t CTP_SCL_config = {
      .pinDirection = kGPIO_DigitalOutput,
      .outputLogic = 0U
    };
    /* Initialize GPIO functionality on pin PIO0_14 (pin E11)*/
    GPIO_PinInit(TFT_TOUCH_INIT_CTP_SCL_GPIO, TFT_TOUCH_INIT_CTP_SCL_PIN, &CTP_SCL_config);

    gpio_pin_config_t CTP_SDA_config = {
      .pinDirection = kGPIO_DigitalOutput,
      .outputLogic = 0U
    };
    /* Initialize GPIO functionality on pin PIO0_15 (pin G13)*/
    GPIO_PinInit(TFT_TOUCH_INIT_CTP_SDA_GPIO, TFT_TOUCH_INIT_CTP_SDA_PIN, &CTP_SDA_config);

    gpio_pin_config_t CTP_RST_config = {
      .pinDirection = kGPIO_DigitalOutput,
      .outputLogic = 0U
    };
    /* Initialize GPIO functionality on pin PIO0_22 (pin B8)*/
    GPIO_PinInit(TFT_TOUCH_INIT_CTP_RST_GPIO, TFT_TOUCH_INIT_CTP_RST_PIN, &CTP_RST_config);

    gpio_pin_config_t CTP_INT_config = {
      .pinDirection = kGPIO_DigitalInput,
      .outputLogic = 0U
    };
    /* Initialize GPIO functionality on pin PIO4_16 (pin R8)*/
    GPIO_PinInit(TFT_TOUCH_INIT_CTP_INT_GPIO, TFT_TOUCH_INIT_CTP_INT_PIN, &CTP_INT_config);

    /* PORT0_14 (pin E11) is configured as PIO0_14 */
    PORT_SetPinMux(TFT_TOUCH_INIT_CTP_SCL_PORT, TFT_TOUCH_INIT_CTP_SCL_PIN, kPORT_MuxAlt0);

    PORT0->PCR = ((PORT0->PCR &
                     /* Mask bits to zero which are setting */
                     (~(PORT_PCR_IBE_MASK)))

                      /* Input Buffer Enable: Enables. */
                      | PORT_PCR_IBE(PCR_IBE_ibe1));

    /* PORT0_15 (pin G13) is configured as PIO0_15 */
    PORT_SetPinMux(TFT_TOUCH_INIT_CTP_SDA_PORT, TFT_TOUCH_INIT_CTP_SDA_PIN, kPORT_MuxAlt0);

    PORT0->PCR = ((PORT0->PCR &
                     /* Mask bits to zero which are setting */
                     (~(PORT_PCR_IBE_MASK)))

                      /* Input Buffer Enable: Enables. */
                      | PORT_PCR_IBE(PCR_IBE_ibe1));

    /* PORT0_22 (pin B8) is configured as PIO0_22 */
    PORT_SetPinMux(TFT_TOUCH_INIT_CTP_RST_PORT, TFT_TOUCH_INIT_CTP_RST_PIN, kPORT_MuxAlt0);

    PORT0->PCR = ((PORT0->PCR &
                     /* Mask bits to zero which are setting */
                     (~(PORT_PCR_IBE_MASK)))

                      /* Input Buffer Enable: Enables. */
                      | PORT_PCR_IBE(PCR_IBE_ibe1));

    /* PORT4_16 (pin R8) is configured as PIO4_16 */
    PORT_SetPinMux(TFT_TOUCH_INIT_CTP_INT_PORT, TFT_TOUCH_INIT_CTP_INT_PIN, kPORT_MuxAlt0);

    PORT4->PCR = ((PORT4->PCR &
                     /* Mask bits to zero which are setting */
                     (~(PORT_PCR_IBE_MASK)))

                      /* Input Buffer Enable: Enables. */
                      | PORT_PCR_IBE(PCR_IBE_ibe1));
}
```

## 触摸接口文件说明

此屏幕厂商给的触摸屏相关的文件如下:

1. **touch.h** 是触摸屏对外的接口文件,声明 `TP_Init()` 函数和一个全局变量 `extern _m_tp_dev tp_dev` 表示触摸状态信息;
2. **touch.c** 是触摸屏接口实现文件,实现 `TP_init()` 函数并初始化全局变量 `tp_dev`;
3. **ctpiic.h** 是IIC接口的声明,这里以GPIO模拟IIC,所以需要提供 IIC 各种基础信号的声明,如发出起始信号、停止信号、发送一个字节、读取一个字节、发送ACK、接收ACK等基础信号的声明;
4. **ctpiic.c** 是IIC接口的实现,以GPIO模拟IIC的实现;
5. **ft6336.h** 是这颗 FT6336 触摸IC的驱动文件,包含寄存器定义和寄存器读写函数、获取触摸状态信息的函数的声明;
6. **ft6336.c** 是这颗 FT6336 触摸IC驱动的实现文件,包含寄存器读写函数的实现、扫描触摸屏获取状态的函数的实现;

## 触摸接口移植适配

主要适配工作是GPIO模拟IIC功能的实现,即修改 **ctpiic.c** 和 **ctpiic.h** 文件。

在头文件中需要提供几个宏定义,如下所示,因为是 GPIO 模拟 IIC,所以需要实现如下的 API:

1. `CTP_IIC_Init()` 初始化 IIC 两个管脚,初始配置为输出模式,高电平;
2. `CTP_IIC_Start()` IIC 作为 Master 发起起始信号;
3. `CTP_IIC_Stop()`IIC 作为 Master 发起结束信号;
4. `CTP_IIC_Send_Byte()` IIC 以GPIO模拟的方式,移位以 MSB 的方式发送一个字节;
5. `CTP_IIC_Read_Byte()`IIC 切换 SDA 为输入方向,读取一个字节;
6. `CTP_IIC_Wait_Ack()`IIC 作为 Master 等待 ACK 信号;
7. `CTP_IIC_Ack()` IIC 发送一个 ACK 信号;
8. `CTP_IIC_Nack()` IIC 发送一个 NAK 信号;

虽说有这么多的接口需要实现,但实际上我只需要实现 `CTP_IIC_Init()` 初始化 SCL/SDA 对应的两个管脚,然后实现下面的几个宏定义即可,如下代码所示:

1. `CTP_SDA_IN()` 切换 SDA 管脚为输入方向,每种MCU的驱动调用不同,这里调用 NXP 的 API 也同时以寄存器的访问方式相结合,实现 SDA 管脚切换为输入方式;
2. `CTP_SDA_OUT()` 切换为 SDA 管脚为输出方向,原理同上;
3. `CTP_IIC_SCL(n)` 实现 SCL 管脚输出高低电平;
4. `CTP_IIC_SDA(n)` 实现 SDA 管脚输出高低电平;
5. `CTP_READ_SDA` 实现读取 SDA 管脚输入电平,这几个宏定义直接调用 NXP 的库函数即可;

```c
#ifndef __CTPIIC_H
#define __CTPIIC_H

#include <stdint.h>
#include "pin_mux.h"
#include "fsl_gpio.h"

//IIC IO方向设置
#define CTP_SDA_IN() \
do { \
        GPIO_PortInputEnable(TFT_TOUCH_INIT_CTP_SDA_GPIO, TFT_TOUCH_INIT_CTP_SDA_GPIO_PIN_MASK);\
        TFT_TOUCH_INIT_CTP_SDA_GPIO->PDDR &= GPIO_FIT_REG(~(1UL << TFT_TOUCH_INIT_CTP_SDA_GPIO_PIN)); \
} while (0)

#define CTP_SDA_OUT() \
do { \
        GPIO_PortInputDisable(TFT_TOUCH_INIT_CTP_SDA_GPIO, TFT_TOUCH_INIT_CTP_SDA_GPIO_PIN_MASK); \
        TFT_TOUCH_INIT_CTP_SDA_GPIO->PDDR |= GPIO_FIT_REG(1UL << TFT_TOUCH_INIT_CTP_SDA_GPIO_PIN); \
} while (0)

//IO操作函数
#define CTP_IIC_SCL(n)                  GPIO_PinWrite(TFT_TOUCH_INIT_CTP_SCL_GPIO, TFT_TOUCH_INIT_CTP_SCL_GPIO_PIN, (n))
#define CTP_IIC_SDA(n)                  GPIO_PinWrite(TFT_TOUCH_INIT_CTP_SDA_GPIO, TFT_TOUCH_INIT_CTP_SDA_GPIO_PIN, (n))
#define CTP_READ_SDA                  GPIO_PinRead(TFT_TOUCH_INIT_CTP_SDA_GPIO, TFT_TOUCH_INIT_CTP_SDA_GPIO_PIN)

//IIC所有操作函数
void CTP_IIC_Init(void);
void CTP_IIC_Start(void);
void CTP_IIC_Stop(void);
void CTP_IIC_Send_Byte(uint8_t txd);
uint8_t CTP_IIC_Read_Byte(unsigned char ack);
uint8_t CTP_IIC_Wait_Ack(void);
void CTP_IIC_Ack(void);
void CTP_IIC_NAck(void);

#endif
```

后面的几个 API 都依赖于上面的宏定义,我们无需过多关心。下面给出其中一个函数的实现,可以看出都依赖于上面的宏定义。

```c
void CTP_IIC_Send_Byte(uint8_t txd)
{
        uint8_t t;
        CTP_SDA_OUT();
        CTP_IIC_SCL(0);//拉低时钟开始数据传输
        for (t = 0;t < 8;t++)
        {
                CTP_IIC_SDA((txd & 0x80) >> 7);
                txd <<= 1;
                CTP_IIC_SCL(1);
                CTP_Delay();
                CTP_IIC_SCL(0);
                CTP_Delay();
        }
}
```

# 运行效果

先运行厂商提供的触摸屏测试程序,发现很卡,屏幕刷新很卡,触摸屏也不灵敏。这个是由原因的,模组厂商的刷屏函数是一个一个打点,没有发挥 FLEXIO_SPI_EDMA 的优势,所以刷屏很卡,继而影响触摸效果。

视频参见B站:

(https://www.bilibili.com/video/BV1c4BRYtEBY/?vd_source=8f2bbf56b70c541bec2ea0b9f102ebee)

下一个帖子 LVGL 移植触摸,效果好很多。


页: [1]
查看完整版本: 【Avnet | NXP FRDM-MCXN947试用活动】测评6--移植触摸屏