Chapter 15_Common I2C bus module in Renesas MCU zero-based introductory tutorial series

This tutorial is written based on the DShanMCU-RA6M5 development board published by Weidongshan Baiwen . Students who need it can get it here: https://item.taobao.com/item.htm?id=728461040949

Obtain supporting information: https://renesas-docs.100ask.net

Summary of Renesas MCU zero-based entry series tutorials : https://blog.csdn.net/qq_35181236/article/details/132779862


Chapter 15 Common I2C Bus Module

Objectives of this chapter

  • Use RASC to quickly configure Common I2C modules
  • Learn to use i2c API to drive touch chips and obtain contact data

15.1 Use of Common I2C module

The I2C of the RA chip is divided into Simple I2C and Common I2C. Simple I2C is the I2C mode of the SCI module mentioned in "Chapter 8 SCI SPI" of this book. It uses a serial bus to simulate the I2C protocol, and the Common I2C mentioned in this chapter is a hardware I2C controller module that actually exists inside the chip. .

Thanks to the FSP encapsulation, there is no big difference in application between Simple I2C and Common I2C.

15.1.1 Configuration of I2C module

To configure the I2C module, first find "Connectivity:IIC" in "Peripherals" in "Pin Configuration" of RASC, and then select the I2C channel according to the hardware design. For example, this book uses P409/P410 as the SDA and SCL of I2C. These two IOs belong to the Group A pins of I2C2, so select "IIC2", and then select "Pin Group Selection" in the expanded pin configuration. _A_only" and enable the operating mode, as shown in the following figure:

Then go to "Stacks" to add the I2C module. Click "New Stack", select "Connectivity", and then select "I2C Master(r_iic_master)" inside. The goal of this chapter is to serve as the host to read the data of the touch screen, so select Master, as shown in the figure below:

After adding the I2C Master module, it is necessary to configure its parameters. In this chapter, the parameters of configuring I2C in RASC are shown in the figure below:

  • Name: The name of the I2C module, which needs to meet the C language string standard;
  • Channel: channel of I2C module;
  • Rate: I2C communication rate, the maximum rate supported by Standard is 400kbps, and the maximum rate supported by Fast mode is 1Mbps;
  • Rise/Fall Time: the time spent on the rising and falling edges of the SCL signal;

  • Duty Cycle: The duty cycle of the SCL clock line, the range is 4%~96%, and the default is 50%;
  • Slave Address: slave device address, set according to the slave chip;
  • Address Mode: address mode, support 7-Bit and 10-Bit;
  • Timeout Mode: Data detection timeout mode, supports long mode and short mode. The timeout counter of long mode is 16 bits, and the timeout counter of short mode is 14 bits; when the timeout count overflows and no data is detected, the communication is terminated;
  • Timeout during SCL Low: Whether to enable timeout detection when SCL is low, the default is Enabled;
  • Callback: interrupt callback function name, it is recommended to match the channel, such as i2c1_callback;
  • Interrupt Priority Level: I2C interrupt priority level;

15.1.2 Interpretation of configuration information

The configuration information is divided into two parts: pin configuration information and I2C module configuration information.

After using RASC to configure parameters and generate a project, the module's pin information will be generated in pin_data.c of the project, and the module's configuration information will be generated in hal_data.c.

  1. I2C module pin information

The pins involved in I2C, their configuration information is generated in pin_data.c of the project. For each pin configured in RASC, an ioport_pin_cfg_t array item will be generated in pin_data.c, and the content inside is consistent with the parameters selected during configuration. code show as below:

const ioport_pin_cfg_t g_bsp_pin_cfg_data[] = {
    
    
    ......(省略内容)
    {
    
     .pin = BSP_IO_PORT_04_PIN_09,
      .pin_cfg = ((uint32_t) IOPORT_CFG_DRIVE_MID 
                | (uint32_t) IOPORT_CFG_PERIPHERAL_PIN 
                | (uint32_t) IOPORT_PERIPHERAL_IIC)},
    {
    
     .pin = BSP_IO_PORT_04_PIN_10,
      .pin_cfg = ((uint32_t) IOPORT_CFG_DRIVE_MID 
                | (uint32_t) IOPORT_CFG_PERIPHERAL_PIN 
                | (uint32_t) IOPORT_PERIPHERAL_IIC)},
    ......(省略内容)
};

This constant array configures P5409 and P410 as I2C peripheral multiplexing functions.

  1. Configuration information of I2C module

The I2C configuration information will be defined in the i2c_master_cfg_t structure type constant g_i2c_master2_cfg in hal_data.c. The code is as follows:

const i2c_master_cfg_t g_i2c_master2_cfg =
{
    
    
    .channel             = 2,
    .rate                = I2C_MASTER_RATE_STANDARD,
    .slave               = 0x14,
    .addr_mode           = I2C_MASTER_ADDR_MODE_7BIT,
    ......(省略内容)
    .p_callback          = i2c2_callback,
    .p_context           = NULL,
    ......(省略内容)
    .ipl                 = (12),
    .p_extend            = &g_i2c_master2_extend,
};
  • Line 03: Channel set to 2;
  • Line 04: The communication rate is set to the standard rate;
  • Line 05: The slave address is 0x14;
  • Line 06: The address mode is 7bit mode;
  • Line 08: Set the interrupt function name to i2c2_callback;

When using the I2C open function, this constant will be used to initialize the I2C module.

15.1.3 Interrupt callback function

A function named "i2c1_callback" is used in g_i2c_master2_cfg. This function is only declared as follows in hal_data.h, but is not implemented:

#ifndef i2c1_callback
void i2c1_callback(i2c_master_callback_args_t * p_args);
#endif

Users need to implement this function, for example:

void i2c1_callback(i2c_master_callback_args_t * p_args)
{
    
    
    switch (p_args->event)
    {
    
    
    }
}

The parameter of this interrupt callback function is the i2c_master_callback_args_t structure pointer, the prototype of this structure is as follows:

typedef struct st_i2c_master_callback_args
{
    
    
    void const       * p_context;      ///< Pointer to user-provided context
    i2c_master_event_t event;          ///< Event code
} i2c_master_callback_args_t;

The event member is an enumeration type, including the following event types:

typedef enum e_i2c_master_event
{
    
    
    I2C_MASTER_EVENT_ABORTED     = 1,  ///< A transfer was aborted
    I2C_MASTER_EVENT_RX_COMPLETE = 2,  ///< A receive operation was completed successfully
    I2C_MASTER_EVENT_TX_COMPLETE = 3   ///< A transmit operation was completed successfully
} i2c_master_event_t;

It can be known from this that the reasons for triggering the I2C interrupt are: completion of sending, completion of reception, and suspension of transmission. After they trigger the interrupt, the callback function is called to execute the user's code.

15.1.4 API interface and its application

In the FSP library function header file r_i2c_master_api.h of the I2C module, the operation function structure i2c_master_api_t of the I2C host device is defined, and the prototype is as follows:

/** Interface definition for I2C access as master */
typedef struct st_i2c_master_api
{
    
    
    fsp_err_t (* open)(i2c_master_ctrl_t * const p_ctrl, 
                       i2c_master_cfg_t const * const p_cfg);
    fsp_err_t (* read)(i2c_master_ctrl_t * const p_ctrl, 
                       uint8_t * const p_dest, 
                       uint32_t const bytes,
                       bool const restart);
    fsp_err_t (* write)(i2c_master_ctrl_t * const p_ctrl, 
                        uint8_t * const p_src, 
                        uint32_t const bytes,
                        bool const restart);
    fsp_err_t (* abort)(i2c_master_ctrl_t * const p_ctrl);
    fsp_err_t (* slaveAddressSet)(i2c_master_ctrl_t * const p_ctrl, 
                                  uint32_t const slave,
                                  i2c_master_addr_mode_t const addr_mode);
    fsp_err_t (* callbackSet)(i2c_master_ctrl_t * const p_api_ctrl, 
                              void (* p_callback)(i2c_master_callback_args_t *),
                              void const * const p_context, 
                              i2c_master_callback_args_t * const p_callback_memory);
    fsp_err_t (* statusGet)(i2c_master_ctrl_t * const p_api_ctrl, 
                            i2c_master_status_t * p_status);
    fsp_err_t (* close)(i2c_master_ctrl_t * const p_ctrl);
} i2c_master_api_t;

The operations supported by the I2C host device include: open/read/write/close, etc. FSP implements this structure in r_iic_master.c:

/* IIC Implementation of I2C device master interface */
i2c_master_api_t const g_i2c_master_on_iic =
{
    
    
    .open            = R_IIC_MASTER_Open,
    .read            = R_IIC_MASTER_Read,
    .write           = R_IIC_MASTER_Write,
    .abort           = R_IIC_MASTER_Abort,
    .slaveAddressSet = R_IIC_MASTER_SlaveAddressSet,
    .close           = R_IIC_MASTER_Close,
    .statusGet       = R_IIC_MASTER_StatusGet,
    .callbackSet     = R_IIC_MASTER_CallbackSet
};

This chapter takes the opening and closing, reading and writing of the I2C host device as an example to analyze.

  1. Open the I2C host device

The prototype of the function pointer to open the I2C host device is as follows:

/** Opens the I2C Master driver and initializes the hardware.
 * @param[in] p_ctrl    Pointer to control block. Must be declared by user. Elements are set here.
 * @param[in] p_cfg     Pointer to configuration structure.
 */
fsp_err_t (* open)(i2c_master_ctrl_t * const p_ctrl, i2c_master_cfg_t const * const p_cfg);
  • p_ctrl: Point to the I2C master control block, such as g_i2c_master2_ctrl;
  • p_cfg: Points to the I2C host parameter configuration structure constant, such as g_i2c_master2_cfg;

The type of p_ctrl is the iic_master_instance_ctrl_t structure. During I2C communication, the device status, address value, read and write status, response status, etc. in this structure will be changed.

The type of p_cfg is i2c_master_cfg_t. This structure is used to represent the configuration of the I2C host, such as I2C channels, interrupt numbers, transceiver functions, and interrupt callback functions.

Users can refer to the following code to open the I2C host device, which will be initialized internally:

fsp_err_t err = g_i2c_master2.p_api->open(g_i2c_master2.p_ctrl, g_i2c_master2.p_cfg);
if (FSP_SUCCESS != err)
{
    
    
    printf("%s %d\r\n", __FUNCTION__, __LINE__);
    return;
}
  1. Turn off the I2C host device

The function pointer prototype for closing the I2C device is as follows:

fsp_err_t (* close)(i2c_master_ctrl_t * const p_ctrl);

Its parameter p_ctrl points to the I2C host control block. This function will change the I2C state in the control block to the off state.

  1. I2C receive data function

The function pointer prototype of I2C receiving data is as follows:

fsp_err_t (* read)(i2c_master_ctrl_t * const p_ctrl, 
                   uint8_t * const p_dest, 
                   uint32_t const bytes,
                   bool const restart);
  • p_ctrl: points to the I2C host device control block;
  • p_dest: the address of the destination data (used to receive data);
  • bytes: the number of data to be received, the unit is bytes;
  • restart: The operation after the host receives a frame of data, true - after receiving a frame of data, the host does not send a stop signal but sends a Start signal to continue transmission, false - after receiving a frame of data, the host sends a stop signal.

Developers can refer to the following code to read data:

fsp_err_t err = g_i2c_master2.p_api->read(g_i2c_master2.p_ctrl, buf, len, 0);
if (FSP_SUCCESS != err)
{
    
    
    printf("%s %d\r\n", __FUNCTION__, __LINE__);
    return;
}
  1. I2C send data function

The function pointer prototype for the I2C master device to send data to the slave device is as follows:

    fsp_err_t (* write)(i2c_master_ctrl_t * const p_ctrl, 
                        uint8_t * const p_src, 
                        uint32_t const bytes,
                        bool const restart);
  • p_ctrl: Execute the I2C host device control block. When the host sends data, it will initiate start signals, response signals, etc. based on the address and other information of the control block;
  • p_dest: the address of the destination data (used to receive data);
  • bytes: the number of data to be sent, in bytes;
  • restart: The operation after sending this frame of data: true means that the Stop signal will not be sent but the Start signal will be sent immediately - this can always occupy the I2C bus, false means that the Stop signal will be sent (everyone will compete for the I2C bus again);

Developers can refer to the following code to send I2C data:

fsp_err_t err = g_i2c_master2.p_api->write(g_i2c_master2.p_ctrl, tmpbuf, 2, 0);
if (FSP_SUCCESS != err)
{
    
    
    printf("%s %d\r\n", __FUNCTION__, __LINE__);
    return;
}

15.2 Common I2C driver touch screen experiment

15.2.1 Hardware connection

This chapter uses an external touch screen, which is connected to the motherboard using an FPC cable. The I2C schematic diagram of the FPC is as shown below:

The pins used are P409 and P410.

15.2.2 GT911 driver analysis

GT911 is a touch chip with 5 capacitive touch points, 26 drive channels and 14 sensing channels. It can identify the real-time accurate position, movement trajectory and touch area of ​​5 touch points at the same time, and according to the main control If necessary, read the touch information of the corresponding point.

The communication of GT911 is a standard I2C communication protocol. The host needs to meet the standard protocol of the I2C bus when communicating with GT911 through I2C. The I2C slave device address definition of GT911 is as shown in the figure below:

It supports two addresses, which address is used depends on the level of the INT pin after the GT911 resets. If the INT pin is high during reset, the address is 0x14/0x28/0x29; otherwise, it is 0x5D, 0xBA/0xBB.

The experimental design in this chapter chose address 0x14.

GT911 is driven by sending instructions and reading and writing data. Different instructions support different numbers of data: one instruction corresponds to the data of one register, or one instruction may correspond to the data of N registers. Taking the read point data command 0x8157 as an example, the user can continuously read 7 bytes of data (touch point ID and touch position information) after sending the 0x8157 command:

15.2.3 GT911 driver

The experiment in this chapter simply obtains the position information of the contact. For touch devices, since the basic requirement is to obtain touch point information, this chapter will be abstracted as "touch devices" and use a structure in drv_touch.h to describe this type of touch device:

typedef struct TouchDev{
    
    
    char *name;
    void (*Init)(struct TouchDev *ptDev);
    bool (*Read)(struct TouchDev *ptDev, unsigned short *pX, unsigned short *pY);
}TouchDev, *PTouchDev;

For this type of touch device, the application layer's operations only involve: initialization and reading the touch position. Therefore, there are only two function pointers, Init and Read, in the TouchDev structure.

For specific touch driver chips, you need to implement your own TouchDev structure. This chapter implements the TouchDev structure in drv_gt911.c, and then explains its functions one by one.

  1. Interrupt callback function

During the I2C communication process, the next transmission needs to be completed after the previous transmission is completed. Therefore, it is necessary to judge whether the previous transmission has been completed through the I2C interrupt trigger event. The code is as follows:

static volatile bool gI2C2TxCplt = false;
static volatile bool gI2C2RxCplt = false;
void i2c2_callback(i2c_master_callback_args_t * p_args)
{
    
    
    switch (p_args->event)
    {
    
    
        case I2C_MASTER_EVENT_TX_COMPLETE:
        {
    
    
            gI2C2TxCplt = true;
            break;
        }
        case I2C_MASTER_EVENT_RX_COMPLETE:
        {
    
    
            gI2C2RxCplt = true;
            break;
        }
        default:
        {
    
    
            gI2C2TxCplt = gI2C2RxCplt = false;
            break;
        }
    }
}
  • Lines 07~11: If the event type that triggers the interrupt is a send completion event, the send completion flag will be set to true;
  • Lines 12~16: If the event type that triggers the interrupt is a reception completion event, the reception completion flag will be set to true;
  1. Transceiver timeout waiting function

This chapter implements two waiting functions, adding a timeout mechanism. The code is as follows:

static void I2C2WaitTxCplt(void)
{
    
    
    uint16_t wTimeOut = 100;
    while(!gI2C2TxCplt && wTimeOut)
    {
    
    
        HAL_Delay(1);
        wTimeOut--;
    }
    gI2C2TxCplt = false;
}

static void I2C2WaitRxCplt(void)
{
    
    
    uint16_t wTimeOut = 100;
    while(!gI2C2RxCplt && wTimeOut)
    {
    
    
        HAL_Delay(1);
        wTimeOut--;
    }
    gI2C2RxCplt = false;
}
  1. Write GT911 register function

When writing the register of GT911, the register address and register data should be issued. The number of data may be different. The memory is dynamically allocated in the function to save the register address and register data, and then send them out at one time. Refer to the following code:

static void GT911DrvWriteReg(uint16_t reg, uint8_t *buf, uint8_t len)
{
    
    
    uint8_t regl = (uint8_t)(reg & 0xff);
    uint8_t regh = (uint8_t)(reg>>8);
    uint8_t * write_package = (uint8_t*)malloc((len + 2) * sizeof(uint8_t));
    memcpy(write_package, &regh, 1);
    memcpy(write_package + 1, &regl, 1);
    memcpy(write_package + 2, buf, len);
    fsp_err_t err = g_i2c_master2.p_api->write(g_i2c_master2.p_ctrl, write_package, len + 2, 0);
    if (FSP_SUCCESS != err)
    {
    
    
        printf("%s %d\r\n", __FUNCTION__, __LINE__);
        return;
    }
    I2C2WaitTxCplt();
    free(write_package);
}
  • Lines 05~08: Dynamically allocate data packets according to the length of the incoming data, and package the instructions and data so that they can be sent out at once by calling the I2C write function;
  • Line 09: Call the write function to send the data packet. After sending, the data will no longer be sent, so the last parameter restart=0;
  1. Read GT911 register function

When reading a register, first send out the register address, and then read in the data. code show as below:

static void GT911DrvReadReg(uint16_t reg, uint8_t *buf, uint8_t len)
{
    
    
    uint8_t tmpbuf[2];

    tmpbuf[0] = (uint8_t)(reg >> 8);
    tmpbuf[1] = (uint8_t)(reg &0xff);
    fsp_err_t err = g_i2c_master2.p_api->write(g_i2c_master2.p_ctrl, tmpbuf, 2, 0);
    if (FSP_SUCCESS != err)
    {
    
    
        printf("%s %d\r\n", __FUNCTION__, __LINE__);
        return;
    }
    I2C2WaitTxCplt();
    err = g_i2c_master2.p_api->read(g_i2c_master2.p_ctrl, buf, len, 0);
    if (FSP_SUCCESS != err)
    {
    
    
        printf("%s %d\r\n", __FUNCTION__, __LINE__);
        return;
    }
    I2C2WaitRxCplt();
}
  1. Various ID reading functions

GT911 has a variety of IDs for users to obtain. Taking the production ID of GT911 as an example, it requires the host to send register command 0x8140 to GT911, and then read 4 bytes of ID data. The code is as follows:

static uint32_t GT911DrvReadProductID(void)
{
    
    
    uint32_t id = 0;
    GT911DrvReadReg(GT911_PRODUCT_ID_REG, (uint8_t*)&id ,4);
    return id;
}

Other IDs can also be realized by referring to this writing method. The project 1501_i2c_touch in this chapter encapsulates these ID reading functions for readers:

static uint32_t GT911DrvReadProductID(void);
static uint32_t GT911DrvReadVendorID(void);
static uint8_t GT911DrvReadVersion(void);
static uint8_t GT911DrvGetGSTID(void);
  1. Clear point register

After reading the data of the touch point register each time, the data of the register needs to be cleared so that the data of the register can be updated when the next touch is made. If the data in the coordinate register is not cleared, a fixed value 0x7F will be obtained every time it is read.

The address of clearing the coordinate register is 0x814E. The user only needs to write a zero to this register. The code is as follows:

static void GT911DrvClearBuf(void)
{
    
    
    uint8_t data = {
    
    0};
    GT911DrvWriteReg(GT911_CLEARBUF_REG, (uint8_t*)&data, 1);
}
  1. Abstract GT911 touch screen device object

For the GT911 touch device, this chapter is encapsulated according to its parameter characteristics to represent the touch area and touch points of GT911. Refer to the following code design in drv_gt911.h:

typedef enum{
    
    
    TP_ROT_NONE = 0,
    TP_ROT_90,
    TP_ROT_180,
    TP_ROT_270
} TouchRotation_t;

/**用于存放每一个触控点的id,坐标,大小**/
typedef struct TouchPointInfo{
    
    
    unsigned char id;
    unsigned short x;
    unsigned short y;
    unsigned short size;
}TouchPointInfo_t;

/**类结构体**/
typedef struct TouchDrv{
    
    
    unsigned char  ucAddr;
    unsigned short wHeight;
    unsigned short wWidth;
    TouchRotation_t tRotation;
    TouchPointInfo_t tPointsInfo[TOUCH_POINT_TOTAL]; //用于存储五个触控点的坐标
}TouchDrv_t;

In the subsequent design, a GT911 device is represented by defining the structure TouchDrv_t variable:

static struct TouchDrv gTP;
  1. Read GT911 touch point function

When analyzing the data reading and writing of GT911, I used to read the data of a certain point as an example, and learned that one point has 7 data information. For GT911, there are 5 point information that can be obtained, and the corresponding register address is reflected in the form of macro definition in drv_gt911.h:

#define GT_TP1_REG      0X814F      //第一个触摸点数据地址
#define GT_TP2_REG      0X8157      //第二个触摸点数据地址
#define GT_TP3_REG      0X815F      //第三个触摸点数据地址
#define GT_TP4_REG      0X8167      //第四个触摸点数据地址
#define GT_TP5_REG      0X816F      //第五个触摸点数据地址

Under what circumstances do we need to read point information? When a touch event occurs. And how do users know whether GT911 has been touched? It is represented by a register:

  • Bit-7: buffer_status, 1 - there is touch data waiting for the host to read; 0 - no data;
  • Bit-6:large detect,1-indicates that a large area has been touched;
  • Bit-4:HaveKey,1-is being touched; 0-is not being touched or has released the touch;
  • Bit-[3:0]: The number of touch points;

Users can obtain the point information of each touch based on these 6 register instructions. Please refer to the following code:

static bool GT911DrvIsTouched(TouchDrv_t * tp)
{
    
    
    uint8_t touched_state, touch_num, buffer_status;
    touched_state = GT911DrvGetGSTID();
    touch_num = touched_state & 0xf;            //触点数量
    buffer_status = (touched_state >> 7) & 1;   // 帧状态

    if(buffer_status == 1 && (touch_num <= TOUCH_POINT_TOTAL) && (touch_num > 0))
    {
    
    
        uint16_t pointers_regs[TOUCH_POINT_TOTAL] = {
    
    GT_TP1_REG, GT_TP2_REG, GT_TP3_REG, GT_TP4_REG, GT_TP5_REG};
        // 获取每个触控点的坐标值并保存
        for (int i = 0; i < touch_num; ++i)
        {
    
    
            uint8_t point_info_per_size = 7;
            uint8_t * point_info_p = malloc(point_info_per_size * sizeof(uint8_t ));
            GT911DrvReadReg(pointers_regs[i], point_info_p, point_info_per_size);

            tp->tPointsInfo[i].id = point_info_p[0];
            tp->tPointsInfo[i].x = (unsigned short)(point_info_p[1] + (point_info_p[2] << 8));
            tp->tPointsInfo[i].y = (unsigned short)(point_info_p[3] + (point_info_p[4] << 8));
            tp->tPointsInfo[i].size = (unsigned short)(point_info_p[5] + (point_info_p[6] << 8));

            free(point_info_p);

            //旋转方向
            uint16_t temp;
            switch (tp->tRotation)
            {
    
    
                case TP_ROT_NONE:
                    tp->tPointsInfo[i].x = tp->wWidth - tp->tPointsInfo[i].x;
                    tp->tPointsInfo[i].y = tp->wHeight - tp->tPointsInfo[i].y;
                    break;
                case TP_ROT_270:
                    temp = tp->tPointsInfo[i].x;
                    tp->tPointsInfo[i].x = tp->wWidth - tp->tPointsInfo[i].y;
                    tp->tPointsInfo[i].y = temp;
                    break;
                case TP_ROT_180:
//                    tp->tPointsInfo[i].x = tp->tPointsInfo[i].x;
//                    tp->tPointsInfo[i].y = tp->tPointsInfo[i].y;
                    break;
                case TP_ROT_90:
                    temp = tp->tPointsInfo[i].x;
                    tp->tPointsInfo[i].x = tp->tPointsInfo[i].y;
                    tp->tPointsInfo[i].y = tp->wHeight - temp;
                    break;
                default:
                    break;
            }
        }
        GT911DrvClearBuf();
        return true;
    }
    //必须给GT911_POINT_INFO缓冲区置0,不然读取的数据一直为128!!!!
    GT911DrvClearBuf();
    return false;
}

In addition, in order to match the previously abstracted touch device (TouchDev), a Read function must be encapsulated on this basis:

static bool GT911DrvRead(struct TouchDev *ptDev, unsigned short *pX, unsigned short *pY)
{
    
    
    if(NULL == ptDev->name) return false;
    if(GT911DrvIsTouched(&gTP))
    {
    
    
        *pX = gTP.tPointsInfo[0].x;
        *pY = gTP.tPointsInfo[0].y;
        return true;
    }

    return false;
}
  1. GT911 initialization function

The experiment in this chapter did not make more detailed settings for GT911, so its registers were not modified.

The initialization function in this chapter only initializes the I2C device and reads the ID and touch range of GT911. Refer to the following code:

static void GT911DrvInit(struct TouchDev *ptDev)
{
    
    
    if(NULL == ptDev->name) return;
    uint8_t buf[4];
    gTP.ucAddr = (uint8_t)g_i2c_master2.p_cfg->slave;
    gTP.tRotation = TP_ROT_NONE;
    /* 初始化I2C驱动 */
    fsp_err_t err = g_i2c_master2.p_api->open(g_i2c_master2.p_ctrl, g_i2c_master2.p_cfg);
    if (FSP_SUCCESS != err)
    {
    
    
        printf("%s %d\r\n", __FUNCTION__, __LINE__);
        return;
    }
    /* 读ID */
    uint32_t nVendorID = GT911DrvReadVendorID();
    printf("gt911 vendor id: 0x%.4x\r\n", (int)nVendorID);
    uint32_t nProductID = GT911DrvReadProductID();
    printf("gt911 product id: 0x%.4x\r\n", (int)nProductID);
    uint8_t nVersion = GT911DrvReadVersion();
    printf("version = 0x%x\r\n", nVersion);
    GT911DrvReadReg(0x8048, buf, 2);
    gTP.wWidth = (unsigned short)((buf[1] << 8) | buf[0]);
    GT911DrvReadReg(0x804A, buf, 2);
    gTP.wHeight = (unsigned short)((buf[1] << 8) | buf[0]);
}
  1. Registration and acquisition of touch devices

Based on object-oriented thinking, a TouchDev structure gTouchDev is constructed. The code is as follows:

static struct TouchDev gTouchDev = {
    
    
                                    .name = "GT911",
                                    .Init = GT911DrvInit,
                                    .Read = GT911DrvRead
};

Then use a function to return this device to the upper application:

struct TouchDev* TouchDevGet(void)
{
    
    
    return &gTouchDev;
}

15.2.4 Test procedure

app_test.c is a test program that prints touch point information. The code is as follows:

void TouchAppTest(void)
{
    
    
    TouchDev *ptDev = TouchDevGet();
    if(NULL == ptDev)
    {
    
    
        printf("Error. Not Found Touch Device!\r\n");
        return;
    }
    ptDev->Init(ptDev);
    uint16_t x = 0, y = 0;
    while(1)
    {
    
    
        if(ptDev->Read(ptDev, &x, &y) == true)
        {
    
    
            printf("Touch-Position: (%d,%d)\r\n", x, y);
        }
    }
}

15.2.5 Computer Experiment

In the hal_entry() function in hal_entry.c, initialize the tick timer, initialize the debugging serial port, and then call the TouchAppTest function for testing.

When the screen is touched, the serial port assistant will print point coordinate information such as the following picture:


End of this chapter

Guess you like

Origin blog.csdn.net/qq_35181236/article/details/132789542