国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

電容觸摸屏驅(qū)動(dòng)(Linux驅(qū)動(dòng)開發(fā)篇)

這篇具有很好參考價(jià)值的文章主要介紹了電容觸摸屏驅(qū)動(dòng)(Linux驅(qū)動(dòng)開發(fā)篇)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

1.電容觸摸屏簡介

  • 電容屏只需要手指輕觸即可,而電阻屏是需要手指
    給予一定的壓力才有反應(yīng),而且電容屏不需要校準(zhǔn)。
  • 如果要做人機(jī)交互設(shè)備的開發(fā),多點(diǎn)電容觸摸屏基本是不可能繞過去的。

2. 驅(qū)動(dòng)器件

  • 正點(diǎn)原子ATK-7016 這款屏幕其實(shí)是由 TFT LCD+觸摸屏組合起來的。底下是 LCD 面板,上面是觸摸面板,將兩個(gè)封裝到一起就成了帶有觸摸屏的 LCD 屏幕
  • 電容觸摸屏也是需要一個(gè)驅(qū)動(dòng) IC的,驅(qū)動(dòng) IC 一般會(huì)提供一個(gè) I2C 接口給主控制器主控制器可以通過 I2C 接口來讀取驅(qū)動(dòng) IC里面的觸摸坐標(biāo)數(shù)據(jù)
  • ATK-7016、ATK-7084這兩款屏幕使用的觸摸控制 IC 是 FT5426。
    1.FT5426 這款驅(qū)動(dòng) IC 采用 15*28 的驅(qū)動(dòng)結(jié)構(gòu),也就是 15 個(gè)感應(yīng)通道,28 個(gè)驅(qū)動(dòng)通道,
    2.最多支持5點(diǎn)電容觸摸。
  • ATK-7016的電容觸摸屏部分有4個(gè) IO用于連接主控制器: SCL、 SDA、RST 和 INT。
    1.SCL 和 SDA 是 I2C 引腳,
    2.RST 是復(fù)位引腳,INT 是中斷引腳。
    一般通過 INT 引腳來通知主控制器有觸摸點(diǎn)按下,然后在INT 中斷服務(wù)函數(shù)中讀取觸摸數(shù)據(jù)。也可以不使用中斷功能,采用輪詢的方式不斷查詢是否有觸摸點(diǎn)按下。
  • 和所有的 I2C 器件一樣,F(xiàn)T5426 也是通過讀寫寄存器來完成初始化和觸摸坐標(biāo)數(shù)據(jù)讀取的主要工作就是讀寫FT5426 的寄存器
  • FT5426 的 I2C 設(shè)備地址為 0X38,F(xiàn)T5426 的寄存器有很多,本章我們只用到了其中的一部分:
    電容觸摸屏驅(qū)動(dòng)(Linux驅(qū)動(dòng)開發(fā)篇)電容觸摸屏驅(qū)動(dòng)(Linux驅(qū)動(dòng)開發(fā)篇)
  • 觸摸屏與單片機(jī)接觸引腳如下:
    1.觸摸屏連接著I.MX6U的I2C2,
    2.INT引腳連接著I.MX6U的GPIO1_IO9,
    3.RST 引腳連接著 I.MX6U 的 SNVS_TAMPER9。

裸機(jī)驅(qū)動(dòng)

  • 同樣用的是和前面I2C驅(qū)動(dòng)的一樣的是,主機(jī)驅(qū)動(dòng)設(shè)備驅(qū)動(dòng)
  • 主機(jī)驅(qū)動(dòng)就是配置SOC的代碼

主機(jī)驅(qū)動(dòng)bsp_i2c.h

#ifndef _BSP_I2C_H
#define _BSP_I2C_H
#include "imx6ul.h"

/* 相關(guān)宏定義 */
#define I2C_STATUS_OK				(0)
#define I2C_STATUS_BUSY				(1)
#define I2C_STATUS_IDLE				(2)
#define I2C_STATUS_NAK				(3)
#define I2C_STATUS_ARBITRATIONLOST	(4)
#define I2C_STATUS_TIMEOUT			(5)
#define I2C_STATUS_ADDRNAK			(6)

/*
 * I2C方向枚舉類型
 */
enum i2c_direction
{
    kI2C_Write = 0x0, 		/* 主機(jī)向從機(jī)寫數(shù)據(jù) */
    kI2C_Read = 0x1,  		/* 主機(jī)從從機(jī)讀數(shù)據(jù) */
} ;

/*
 * 主機(jī)傳輸結(jié)構(gòu)體
 */
struct i2c_transfer
{
    unsigned char slaveAddress;      	/* 7位從機(jī)地址 			*/
    enum i2c_direction direction; 		/* 傳輸方向 			*/
    unsigned int subaddress;       		/* 寄存器地址			*/
    unsigned char subaddressSize;    	/* 寄存器地址長度 			*/
    unsigned char *volatile data;    	/* 數(shù)據(jù)緩沖區(qū) 			*/
    volatile unsigned int dataSize;  	/* 數(shù)據(jù)緩沖區(qū)長度 			*/
};

/*
 *函數(shù)聲明
 */
void i2c_init(I2C_Type *base);
unsigned char i2c_master_start(I2C_Type *base, unsigned char address, enum i2c_direction direction);
unsigned char i2c_master_repeated_start(I2C_Type *base, unsigned char address,  enum i2c_direction direction);
unsigned char i2c_check_and_clear_error(I2C_Type *base, unsigned int status);
unsigned char i2c_master_stop(I2C_Type *base);
void i2c_master_write(I2C_Type *base, const unsigned char *buf, unsigned int size);
void i2c_master_read(I2C_Type *base, unsigned char *buf, unsigned int size);
unsigned char i2c_master_transfer(I2C_Type *base, struct i2c_transfer *xfer);

#endif

主機(jī)驅(qū)動(dòng)bsp_i2c.c

#include "bsp_i2c.h"
#include "bsp_delay.h"
#include "stdio.h"

/*
 * @description		: 初始化I2C,波特率100KHZ
 * @param - base 	: 要初始化的IIC設(shè)置
 * @return 			: 無
 */
void i2c_init(I2C_Type *base)
{
	/* 1、配置I2C */
	base->I2CR &= ~(1 << 7); /* 要訪問I2C的寄存器,首先需要先關(guān)閉I2C */

    /* 設(shè)置波特率為100K
     * I2C的時(shí)鐘源來源于IPG_CLK_ROOT=66Mhz
 	 * IC2 時(shí)鐘 = PERCLK_ROOT/dividison(IFDR寄存器)
	 * 設(shè)置寄存器IFDR,IFDR寄存器參考IMX6UL參考手冊P1260頁,表29-3,
	 * 根據(jù)表29-3里面的值,挑選出一個(gè)還是的分頻數(shù),比如本例程我們
	 * 設(shè)置I2C的波特率為100K, 因此當(dāng)分頻值=66000000/100000=660.
	 * 在表29-3里面查找,沒有660這個(gè)值,但是有640,因此就用640,
	 * 即寄存器IFDR的IC位設(shè)置為0X15
	 */
	base->IFDR = 0X15 << 0;

	/*
     * 設(shè)置寄存器I2CR,開啟I2C
     * bit[7] : 1 使能I2C,I2CR寄存器其他位其作用之前,此位必須最先置1
	 */
	base->I2CR |= (1<<7);
}

/*
 * @description			: 發(fā)送重新開始信號(hào)
 * @param - base 		: 要使用的IIC
 * @param - addrss		: 設(shè)備地址
 * @param - direction	: 方向
 * @return 				: 0 正常 其他值 出錯(cuò)
 */
unsigned char i2c_master_repeated_start(I2C_Type *base, unsigned char address,  enum i2c_direction direction)
{
	/* I2C忙并且工作在從模式,跳出 */
	if(base->I2SR & (1 << 5) && (((base->I2CR) & (1 << 5)) == 0))		
		return 1;

	/*
     * 設(shè)置寄存器I2CR
     * bit[4]: 1 發(fā)送
     * bit[2]: 1 產(chǎn)生重新開始信號(hào)
	 */
	base->I2CR |=  (1 << 4) | (1 << 2);

	/*
     * 設(shè)置寄存器I2DR
     * bit[7:0] : 要發(fā)送的數(shù)據(jù),這里寫入從設(shè)備地址
     *            參考資料:IMX6UL參考手冊P1249
	 */ 
	base->I2DR = ((unsigned int)address << 1) | ((direction == kI2C_Read)? 1 : 0);
	
	return 0;
}

/*
 * @description			: 發(fā)送開始信號(hào)
 * @param - base 		: 要使用的IIC
 * @param - addrss		: 設(shè)備地址
 * @param - direction	: 方向
 * @return 				: 0 正常 其他值 出錯(cuò)
 */
unsigned char i2c_master_start(I2C_Type *base, unsigned char address,  enum i2c_direction direction)
{
	if(base->I2SR & (1 << 5))			/* I2C忙 */
		return 1;

	/*
     * 設(shè)置寄存器I2CR
     * bit[5]: 1 主模式
     * bit[4]: 1 發(fā)送
	 */
	base->I2CR |=  (1 << 5) | (1 << 4);

	/*
     * 設(shè)置寄存器I2DR
     * bit[7:0] : 要發(fā)送的數(shù)據(jù),這里寫入從設(shè)備地址
     *            參考資料:IMX6UL參考手冊P1249
	 */ 
	base->I2DR = ((unsigned int)address << 1) | ((direction == kI2C_Read)? 1 : 0);
	return 0;
}

/*
 * @description		: 檢查并清除錯(cuò)誤
 * @param - base 	: 要使用的IIC
 * @param - status	: 狀態(tài)
 * @return 			: 狀態(tài)結(jié)果
 */
unsigned char i2c_check_and_clear_error(I2C_Type *base, unsigned int status)
{
	/* 檢查是否發(fā)生仲裁丟失錯(cuò)誤 */
	if(status & (1<<4))
	{
		base->I2SR &= ~(1<<4);		/* 清除仲裁丟失錯(cuò)誤位 			*/

		base->I2CR &= ~(1 << 7);	/* 先關(guān)閉I2C 				*/
		base->I2CR |= (1 << 7);		/* 重新打開I2C 				*/
		return I2C_STATUS_ARBITRATIONLOST;
	} 
	else if(status & (1 << 0))     	/* 沒有接收到從機(jī)的應(yīng)答信號(hào) */
	{
		return I2C_STATUS_NAK;		/* 返回NAK(No acknowledge) */
	}
	return I2C_STATUS_OK;
}

/*
 * @description		: 停止信號(hào)
 * @param - base	: 要使用的IIC
 * @param			: 無
 * @return 			: 狀態(tài)結(jié)果
 */
unsigned char i2c_master_stop(I2C_Type *base)
{
	unsigned short timeout = 0xffff;

	/*
	 * 清除I2CR的bit[5:3]這三位
	 */
	base->I2CR &= ~((1 << 5) | (1 << 4) | (1 << 3));

	/* 等待忙結(jié)束 */
	while((base->I2SR & (1 << 5)))
	{
		timeout--;
		if(timeout == 0)	/* 超時(shí)跳出 */
			return I2C_STATUS_TIMEOUT;
	}
	return I2C_STATUS_OK;
}

/*
 * @description		: 發(fā)送數(shù)據(jù)
 * @param - base 	: 要使用的IIC
 * @param - buf		: 要發(fā)送的數(shù)據(jù)
 * @param - size	: 要發(fā)送的數(shù)據(jù)大小
 * @param - flags	: 標(biāo)志
 * @return 			: 無
 */
void i2c_master_write(I2C_Type *base, const unsigned char *buf, unsigned int size)
{
	/* 等待傳輸完成 */
	while(!(base->I2SR & (1 << 7))); 
	
	base->I2SR &= ~(1 << 1); 	/* 清除標(biāo)志位 */
	base->I2CR |= 1 << 4;		/* 發(fā)送數(shù)據(jù) */
	
	while(size--)
	{
		base->I2DR = *buf++; 	/* 將buf中的數(shù)據(jù)寫入到I2DR寄存器 */
		
		while(!(base->I2SR & (1 << 1))); 	/* 等待傳輸完成 */	
		base->I2SR &= ~(1 << 1);			/* 清除標(biāo)志位 */

		/* 檢查ACK */
		if(i2c_check_and_clear_error(base, base->I2SR))
			break;
	}
	
	base->I2SR &= ~(1 << 1);
	i2c_master_stop(base); 	/* 發(fā)送停止信號(hào) */
}

/*
 * @description		: 讀取數(shù)據(jù)
 * @param - base 	: 要使用的IIC
 * @param - buf		: 讀取到數(shù)據(jù)
 * @param - size	: 要讀取的數(shù)據(jù)大小
 * @return 			: 無
 */
void i2c_master_read(I2C_Type *base, unsigned char *buf, unsigned int size)
{
	volatile uint8_t dummy = 0;

	dummy++; 	/* 防止編譯報(bào)錯(cuò) */
	
	/* 等待傳輸完成 */
	while(!(base->I2SR & (1 << 7))); 
	
	base->I2SR &= ~(1 << 1); 				/* 清除中斷掛起位 */
	base->I2CR &= ~((1 << 4) | (1 << 3));	/* 接收數(shù)據(jù) */
	
	/* 如果只接收一個(gè)字節(jié)數(shù)據(jù)的話發(fā)送NACK信號(hào) */
	if(size == 1)
        base->I2CR |= (1 << 3);

	dummy = base->I2DR; /* 假讀 */
	
	while(size--)
	{
		while(!(base->I2SR & (1 << 1))); 	/* 等待傳輸完成 */	
		base->I2SR &= ~(1 << 1);			/* 清除標(biāo)志位 */

	 	if(size == 0)
        {
        	i2c_master_stop(base); 			/* 發(fā)送停止信號(hào) */
        }

        if(size == 1)
        {
            base->I2CR |= (1 << 3);
        }
		*buf++ = base->I2DR;
	}
}

/*
 * @description	: I2C數(shù)據(jù)傳輸,包括讀和寫
 * @param - base: 要使用的IIC
 * @param - xfer: 傳輸結(jié)構(gòu)體
 * @return 		: 傳輸結(jié)果,0 成功,其他值 失敗;
 */
unsigned char i2c_master_transfer(I2C_Type *base, struct i2c_transfer *xfer)
{
	unsigned char ret = 0;
	 enum i2c_direction direction = xfer->direction;	

	base->I2SR &= ~((1 << 1) | (1 << 4));			/* 清除標(biāo)志位 */

	/* 等待傳輸完成 */
	while(!((base->I2SR >> 7) & 0X1)){}; 

	/* 如果是讀的話,要先發(fā)送寄存器地址,所以要先將方向改為寫 */
    if ((xfer->subaddressSize > 0) && (xfer->direction == kI2C_Read))
    {
        direction = kI2C_Write;
    }

	ret = i2c_master_start(base, xfer->slaveAddress, direction); /* 發(fā)送開始信號(hào) */
    if(ret)
    {	
		return ret;
	}

	while(!(base->I2SR & (1 << 1))){};			/* 等待傳輸完成 */

    ret = i2c_check_and_clear_error(base, base->I2SR);	/* 檢查是否出現(xiàn)傳輸錯(cuò)誤 */
    if(ret)
    {
      	i2c_master_stop(base); 						/* 發(fā)送出錯(cuò),發(fā)送停止信號(hào) */
        return ret;
    }
	
    /* 發(fā)送寄存器地址 */
    if(xfer->subaddressSize)
    {
        do
        {
			base->I2SR &= ~(1 << 1);			/* 清除標(biāo)志位 */
            xfer->subaddressSize--;				/* 地址長度減一 */
			
            base->I2DR =  ((xfer->subaddress) >> (8 * xfer->subaddressSize)); //向I2DR寄存器寫入子地址
  
			while(!(base->I2SR & (1 << 1)));  	/* 等待傳輸完成 */

            /* 檢查是否有錯(cuò)誤發(fā)生 */
            ret = i2c_check_and_clear_error(base, base->I2SR);
            if(ret)
            {
             	i2c_master_stop(base); 				/* 發(fā)送停止信號(hào) */
             	return ret;
            }  
        } while ((xfer->subaddressSize > 0) && (ret == I2C_STATUS_OK));

        if(xfer->direction == kI2C_Read) 		/* 讀取數(shù)據(jù) */
        {
            base->I2SR &= ~(1 << 1);			/* 清除中斷掛起位 */
            i2c_master_repeated_start(base, xfer->slaveAddress, kI2C_Read); /* 發(fā)送重復(fù)開始信號(hào)和從機(jī)地址 */
    		while(!(base->I2SR & (1 << 1))){};/* 等待傳輸完成 */

            /* 檢查是否有錯(cuò)誤發(fā)生 */
			ret = i2c_check_and_clear_error(base, base->I2SR);
            if(ret)
            {
             	ret = I2C_STATUS_ADDRNAK;
                i2c_master_stop(base); 		/* 發(fā)送停止信號(hào) */
                return ret;  
            }
           	          
        }
    }	

    /* 發(fā)送數(shù)據(jù) */
    if ((xfer->direction == kI2C_Write) && (xfer->dataSize > 0))
    {
    	i2c_master_write(base, xfer->data, xfer->dataSize);
	}

    /* 讀取數(shù)據(jù) */
    if ((xfer->direction == kI2C_Read) && (xfer->dataSize > 0))
    {
       	i2c_master_read(base, xfer->data, xfer->dataSize);
	}
	return 0;	
}

這就是驅(qū)動(dòng)的分離和分層思想,主機(jī)驅(qū)動(dòng)具有通用性,對(duì)于我們只要篇編寫設(shè)備驅(qū)動(dòng)就行,這里主要就是傳感器FT5426的編寫

設(shè)備驅(qū)動(dòng)bsp_ft5xx5.h

此文件里面描寫都是設(shè)備的信息,和寄存器打交道的讀寫函數(shù)

#ifndef _FT5XX6_H
#define _FT5XX6_H

#include "imx6ul.h"
#include "bsp_gpio.h"

/* 宏定義 */
#define FT5426_ADDR				0X38	/* FT5426設(shè)備地址 		*/

#define FT5426_DEVICE_MODE		0X00 	/* 模式寄存器 			*/
#define FT5426_IDGLIB_VERSION	0XA1 	/* 固件版本寄存器 			*/
#define FT5426_IDG_MODE			0XA4	/* 中斷模式				*/
#define FT5426_TD_STATUS		0X02	/* 觸摸狀態(tài)寄存器 			*/
#define FT5426_TOUCH1_XH		0X03	/* 觸摸點(diǎn)坐標(biāo)寄存器,
										 * 一個(gè)觸摸點(diǎn)用4個(gè)寄存器存儲(chǔ)坐標(biāo)數(shù)據(jù)*/
										 
#define FT5426_XYCOORDREG_NUM	30		/* 觸摸點(diǎn)坐標(biāo)寄存器數(shù)量 */
#define FT5426_INIT_FINISHED	1		/* 觸摸屏初始化完成 			*/
#define FT5426_INIT_NOTFINISHED	0		/* 觸摸屏初始化未完成 			*/

#define FT5426_TOUCH_EVENT_DOWN			0x00	/* 按下 		*/
#define FT5426_TOUCH_EVENT_UP			0x01	/* 釋放 		*/
#define FT5426_TOUCH_EVENT_ON			0x02	/* 接觸 		*/
#define FT5426_TOUCH_EVENT_RESERVED		0x03	/* 沒有事件 */

/* 觸摸屏結(jié)構(gòu)體 */
struct ft5426_dev_struc
{	
	unsigned char initfalg;		/* 觸摸屏初始化狀態(tài) */
	unsigned char intflag;		/* 標(biāo)記中斷有沒有發(fā)生 */
	unsigned char point_num;	/* 觸摸點(diǎn) 		*/
	unsigned short x[5];		/* X軸坐標(biāo) 	*/
	unsigned short y[5];		/* Y軸坐標(biāo) 	*/

};

extern struct ft5426_dev_struc ft5426_dev;

/* 函數(shù)聲明 */
void ft5426_init(void);
void gpio1_io9_irqhandler(void);
unsigned char ft5426_write_byte(unsigned char addr,unsigned char reg, unsigned char data);
unsigned char ft5426_read_byte(unsigned char addr,unsigned char reg);
void ft5426_read_len(unsigned char addr,unsigned char reg,unsigned char len,unsigned char *buf);
void ft5426_read_tpnum(void);
void ft5426_read_tpcoord(void);

#endif

設(shè)備驅(qū)動(dòng)bsp_ft5xx5.c

電容觸摸屏驅(qū)動(dòng)(Linux驅(qū)動(dòng)開發(fā)篇)
這里用的是I2C2

#include "bsp_ft5xx6.h"
#include "bsp_i2c.h"
#include "bsp_int.h"
#include "bsp_delay.h"
#include "stdio.h"

struct ft5426_dev_struc ft5426_dev;

/*
 * @description	: 初始化觸摸屏,其實(shí)就是初始化FT5426
 * @param		: 無
 * @return 		: 無
 */
void ft5426_init(void)
{
	unsigned char reg_value[2];

	ft5426_dev.initfalg = FT5426_INIT_NOTFINISHED;
	int i;
	for( i = 0; i < 5; i++ )
	{	/* 避免編譯器自動(dòng)賦值 */
		ft5426_dev.x[i] = 0;
		ft5426_dev.y[i] = 0;
	}
	ft5426_dev.point_num = 0;

	/* 1、初始化IIC2 IO
     * I2C2_SCL -> UART5_TXD
     * I2C2_SDA -> UART5_RXD
     */
	IOMUXC_SetPinMux(IOMUXC_UART5_TX_DATA_I2C2_SCL,1);
	IOMUXC_SetPinMux(IOMUXC_UART5_RX_DATA_I2C2_SDA,1);

	/* 配置I2C2 IO屬性	
	 *bit 16:0 HYS關(guān)閉
	 *bit [15:14]: 1 默認(rèn)47K上拉
	 *bit [13]: 1 pull功能
	 *bit [12]: 1 pull/keeper使能 
	 *bit [11]: 0 關(guān)閉開路輸出
	 *bit [7:6]: 10 速度100Mhz
	 *bit [5:3]: 110 驅(qū)動(dòng)能力為R0/6
	 *bit [0]: 1 高轉(zhuǎn)換率
	 */
	IOMUXC_SetPinConfig(IOMUXC_UART5_TX_DATA_I2C2_SCL,0x70B0);
	IOMUXC_SetPinConfig(IOMUXC_UART5_RX_DATA_I2C2_SDA,0X70B0);
	
	/* 2、初始化觸摸屏中斷IO和復(fù)位IO */
	gpio_pin_config_t ctintpin_config;

	IOMUXC_SetPinMux(IOMUXC_GPIO1_IO09_GPIO1_IO09,0);		/* 復(fù)用為GPIO1_IO9 */
	IOMUXC_SetPinMux(IOMUXC_SNVS_SNVS_TAMPER9_GPIO5_IO09,0);/* 復(fù)用為GPIO5_IO9 */
	
	IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO09_GPIO1_IO09,0xF080);
	IOMUXC_SetPinConfig(IOMUXC_SNVS_SNVS_TAMPER9_GPIO5_IO09,0X10B0);

	/* 中斷IO初始化 */
	ctintpin_config.direction = kGPIO_DigitalInput;
	ctintpin_config.interruptMode = kGPIO_IntRisingOrFallingEdge;
	gpio_init(GPIO1, 9, &ctintpin_config);

	GIC_EnableIRQ(GPIO1_Combined_0_15_IRQn);				/* 使能GIC中對(duì)應(yīng)的中斷 */
	system_register_irqhandler(GPIO1_Combined_0_15_IRQn, (system_irq_handler_t)gpio1_io9_irqhandler, NULL);	/* 注冊中斷服務(wù)函數(shù) */
	gpio_enableint(GPIO1, 9);								/* 使能GPIO1_IO18的中斷功能 */

	/* 復(fù)位IO初始化 */
    ctintpin_config.direction=kGPIO_DigitalOutput;	
    ctintpin_config.interruptMode=kGPIO_NoIntmode;	
    ctintpin_config.outputLogic=1;					   
    gpio_init(GPIO5, 9, &ctintpin_config); 

	/* 3、初始化I2C */
	i2c_init(I2C2);	

	/* 4、初始化FT5426 */
	gpio_pinwrite(GPIO5, 9, 0);	/* 復(fù)位FT5426 */
	delayms(20);
	gpio_pinwrite(GPIO5, 9, 1); /* 停止復(fù)位FT5426 */
	delayms(20);

	ft5426_write_byte(FT5426_ADDR, FT5426_DEVICE_MODE, 0); 	/* 進(jìn)入正常模式 				*/
	ft5426_write_byte(FT5426_ADDR, FT5426_IDG_MODE, 1); 	/* FT5426中斷模式 			*/

	
	ft5426_read_len(FT5426_ADDR, FT5426_IDGLIB_VERSION, 2, reg_value);
	printf("Touch Frimware Version:%#X\r\n", ((unsigned short)reg_value[0] << 8) + reg_value[1]);
	
	ft5426_dev.initfalg = FT5426_INIT_FINISHED;	/* 標(biāo)記FT5426初始化完成 */
	ft5426_dev.intflag = 0;
}

/*
 * @description			: GPIO1_IO9最終的中斷處理函數(shù)
 * @param				: 無
 * @return 				: 無
 */
void gpio1_io9_irqhandler(void)
{ 
	if(ft5426_dev.initfalg == FT5426_INIT_FINISHED)
	{
		//ft5426_dev.intflag = 1;
		ft5426_read_tpcoord();
	}
	gpio_clearintflags(GPIO1, 9); /* 清除中斷標(biāo)志位 */
}


/*
 * @description	: 向FT5429寫入數(shù)據(jù)
 * @param - addr: 設(shè)備地址
 * @param - reg : 要寫入的寄存器
 * @param - data: 要寫入的數(shù)據(jù)
 * @return 		: 操作結(jié)果
 */
unsigned char ft5426_write_byte(unsigned char addr,unsigned char reg, unsigned char data)
{
    unsigned char status=0;
    unsigned char writedata=data;
    struct i2c_transfer masterXfer;
	
    /* 配置I2C xfer結(jié)構(gòu)體 */
   	masterXfer.slaveAddress = addr; 			/* 設(shè)備地址 				*/
    masterXfer.direction = kI2C_Write;			/* 寫入數(shù)據(jù) 				*/
    masterXfer.subaddress = reg;				/* 要寫入的寄存器地址 			*/
    masterXfer.subaddressSize = 1;				/* 地址長度一個(gè)字節(jié) 			*/
    masterXfer.data = &writedata;				/* 要寫入的數(shù)據(jù) 				*/
    masterXfer.dataSize = 1;  					/* 寫入數(shù)據(jù)長度1個(gè)字節(jié)			*/

    if(i2c_master_transfer(I2C2, &masterXfer))
        status=1;
        
    return status;
}

/*
 * @description	: 從FT5426讀取一個(gè)字節(jié)的數(shù)據(jù)
 * @param - addr: 設(shè)備地址
 * @param - reg : 要讀取的寄存器
 * @return 		: 讀取到的數(shù)據(jù)。
 */
unsigned char ft5426_read_byte(unsigned char addr,unsigned char reg)
{
	unsigned char val=0;
	
	struct i2c_transfer masterXfer;	
	masterXfer.slaveAddress = addr;				/* 設(shè)備地址 				*/
    masterXfer.direction = kI2C_Read;			/* 讀取數(shù)據(jù) 				*/
    masterXfer.subaddress = reg;				/* 要讀取的寄存器地址 			*/
    masterXfer.subaddressSize = 1;				/* 地址長度一個(gè)字節(jié) 			*/
    masterXfer.data = &val;						/* 接收數(shù)據(jù)緩沖區(qū) 				*/
    masterXfer.dataSize = 1;					/* 讀取數(shù)據(jù)長度1個(gè)字節(jié)			*/
	i2c_master_transfer(I2C2, &masterXfer);

	return val;
}

/*
 * @description	: 從FT5429讀取多個(gè)字節(jié)的數(shù)據(jù)
 * @param - addr: 設(shè)備地址
 * @param - reg : 要讀取的開始寄存器地址
 * @param - len : 要讀取的數(shù)據(jù)長度.
 * @param - buf : 讀取到的數(shù)據(jù)緩沖區(qū)
 * @return 		: 無
 */
void ft5426_read_len(unsigned char addr,unsigned char reg,unsigned char len,unsigned char *buf)
{	
	struct i2c_transfer masterXfer;	
	
	masterXfer.slaveAddress = addr;				/* 設(shè)備地址 				*/
    masterXfer.direction = kI2C_Read;			/* 讀取數(shù)據(jù) 				*/
    masterXfer.subaddress = reg;				/* 要讀取的寄存器地址 			*/
    masterXfer.subaddressSize = 1;				/* 地址長度一個(gè)字節(jié) 			*/
    masterXfer.data = buf;						/* 接收數(shù)據(jù)緩沖區(qū) 				*/
    masterXfer.dataSize = len;					/* 讀取數(shù)據(jù)長度1個(gè)字節(jié)			*/
	i2c_master_transfer(I2C2, &masterXfer);
} 

/*
 * @description	: 讀取當(dāng)前觸摸點(diǎn)個(gè)數(shù)
 * @param 		: 無
 * @return 		: 無
 */
void ft5426_read_tpnum(void)
{
	ft5426_dev.point_num = ft5426_read_byte(FT5426_ADDR, FT5426_TD_STATUS);
}

/*
 * @description	: 讀取當(dāng)前所有觸摸點(diǎn)的坐標(biāo)
 * @param 		: 無
 * @return 		: 無
 */
void ft5426_read_tpcoord(void)
{
	unsigned char i = 0;
	unsigned char type = 0;
	//unsigned char id = 0;
	unsigned char pointbuf[FT5426_XYCOORDREG_NUM];
	
	ft5426_dev.point_num = ft5426_read_byte(FT5426_ADDR, FT5426_TD_STATUS);

	/*
  	 * 從寄存器FT5426_TOUCH1_XH開始,連續(xù)讀取30個(gè)寄存器的值,這30個(gè)寄存器
  	 * 保存著5個(gè)點(diǎn)的觸摸值,每個(gè)點(diǎn)占用6個(gè)寄存器。
	 */
	ft5426_read_len(FT5426_ADDR, FT5426_TOUCH1_XH, FT5426_XYCOORDREG_NUM, pointbuf);
		
	for(i = 0; i < ft5426_dev.point_num ; i++)
	{
		unsigned char *buf = &pointbuf[i * 6];
		/* 以第一個(gè)觸摸點(diǎn)為例,寄存器TOUCH1_XH(地址0X03),各位描述如下:
		 * bit7:6  Event flag  0:按下 1:釋放 2:接觸 3:沒有事件
		 * bit5:4  保留
		 * bit3:0  X軸觸摸點(diǎn)的11~8位。
		 */
		ft5426_dev.x[i] = ((buf[2] << 8) | buf[3]) & 0x0fff;
		ft5426_dev.y[i] = ((buf[0] << 8) | buf[1]) & 0x0fff;
		
		type = buf[0] >> 6;	/* 獲取觸摸類型 */
		

		/* 以第一個(gè)觸摸點(diǎn)為例,寄存器TOUCH1_YH(地址0X05),各位描述如下:
		 * bit7:4  Touch ID  觸摸ID,表示是哪個(gè)觸摸點(diǎn)
		 * bit3:0  Y軸觸摸點(diǎn)的11~8位。
		 */
		//id = (buf[2] >> 4) & 0x0f;
		
		if(type == FT5426_TOUCH_EVENT_DOWN || type == FT5426_TOUCH_EVENT_ON )/* 按下 	*/
		{
		} 
		else  {	/* 釋放 */		
		}
	}	
}

linux驅(qū)動(dòng)

1.介紹

  • 看到這里,我們可以得出電容觸摸屏驅(qū)動(dòng)其實(shí)大框架就是 IIC設(shè)備驅(qū)動(dòng)
  • 在此基礎(chǔ)上,介紹了觸摸屏的四個(gè)引腳,除去IIC的SCL和SDA,還有INT引腳和RST引腳.
  • INT(中斷引腳))向linux內(nèi)核上報(bào)觸摸信息,因此需要用到linux中斷驅(qū)動(dòng)框架。坐標(biāo)的上報(bào)在中斷服務(wù)函數(shù)中完成。
  • 觸摸屏的坐標(biāo)信息、屏幕按下和抬起信息都屬于 linux的 input子系統(tǒng),因此向 linux內(nèi)核上報(bào)觸摸屏坐標(biāo)信息就得使用 input子系統(tǒng)。這篇文章介紹了input子系統(tǒng)簡述
  • 在input系統(tǒng)框架上我們知道(按鍵、鼠標(biāo)、鍵盤、觸摸屏等都屬于輸入設(shè)備,linux內(nèi)核為此專門做了一個(gè)叫做input子系統(tǒng)的框架來處理輸入事件。輸入設(shè)備本質(zhì)上還是字符設(shè)備,只是在此基礎(chǔ)上套上了input框架,用戶只需要負(fù)責(zé)上報(bào)輸入事件,比如按鍵值、坐標(biāo)等信息)但是對(duì)于多點(diǎn)觸摸的上報(bào)事件我們需要引入input 子系統(tǒng)下的多點(diǎn)電容觸摸協(xié)議(MT)

1.MT協(xié)議。 MT 協(xié)議被分為兩種類型, Type A和TypeB。
1)Type A:適用于觸摸點(diǎn)不能被區(qū)分或者追蹤,此類型的設(shè)備上報(bào)原始數(shù)據(jù)
2)適用于有硬件追蹤并能區(qū)分觸摸點(diǎn)的觸摸設(shè)備,此類型設(shè)備通過 slot更新某一個(gè)觸摸點(diǎn)的信息,F(xiàn)T5426就屬于此類型,一般的多點(diǎn)電容觸摸屏 IC都有此能力。

2.我們這里使用TypeB。我們用MT協(xié)議的根本目的就是為了上報(bào)事件給內(nèi)核(這里適用于多點(diǎn)的觸摸的ABS_MT事件)

/*
@	ABS_MT 事件 
*/
 #define ABS_MT_SLOT        0x2f /* MT slot being modified ==================上 報(bào) 觸 摸 點(diǎn) ID */ 
 #define ABS_MT_TOUCH_MAJOR  0x30 /* Major axis of touching ellipse */ 
 #define ABS_MT_TOUCH_MINOR  0x31 /* Minor axis (omit if circular) */ 
 #define ABS_MT_WIDTH_MAJOR  0x32 /* Major axis of approaching ellipse 
 #define ABS_MT_WIDTH_MINOR  0x33 /* Minor axis (omit if circular) */ 
 #define ABS_MT_ORIENTATION   0x34 /* Ellipse orientation */ 
 #define ABS_MT_POSITION_X   0x35 /* Center X touch position ===========================*/ 
 #define ABS_MT_POSITION_Y   0x36 /* Center Y touch position ============================*/ 
 #define ABS_MT_TOOL_TYPE    0x37 /* Type of touching device */ 
 #define ABS_MT_BLOB_ID       0x38 /* Group a set of packets as a blob */
 #define ABS_MT_TRACKING_ID  0x39 /* Unique ID of initiated contact ==對(duì)于 Type  B 類 型 的 設(shè) 備 ==來區(qū)分觸摸點(diǎn)*/ 
 #define ABS_MT_PRESSURE     0x3a /* Pressure on contact area */ 
 #define ABS_MT_DISTANCE       0x3b /* Contact hover distance */ 
 #define ABS_MT_TOOL_X         0x3c /* Center X tool position */ 
 #define ABS_MT_TOOL_Y         0x3d /* Center Y tool position */ 



/*
@	對(duì)于Type A 類型的設(shè)備,函數(shù)來隔離不同的觸摸點(diǎn)數(shù)據(jù)信息
@	dev:用于指定具體的 input_dev設(shè)備
@ 	功能: 函數(shù)會(huì)觸發(fā) SYN_MT_REPORT 事件,此事件會(huì)通知接收者獲取當(dāng)前觸摸數(shù)據(jù),并且準(zhǔn)備接收下一個(gè)觸摸點(diǎn)數(shù)據(jù)
*/
void input_mt_sync(struct input_dev *dev) 
/*
@	對(duì)于Type B 類型的設(shè)備,上報(bào)觸摸點(diǎn)信息的時(shí)候需要通過 input_mt_slot()函數(shù)區(qū)分是哪一個(gè)觸摸點(diǎn)
@	dev:  input_dev設(shè)備
@	slot: 指定當(dāng)前上報(bào)的是哪個(gè)觸摸點(diǎn)信息 	
@	功能: 函數(shù)會(huì)觸發(fā) ABS_MT_SLOT 事件,此事件會(huì)告訴接收者當(dāng)前正在更新的是哪個(gè)觸摸點(diǎn)(slot)的數(shù)據(jù)
*/
void input_mt_slot(struct input_dev *dev, int slot) 

3.原理:Type B 設(shè)備驅(qū)動(dòng)需要給每個(gè)識(shí)別出來的觸摸點(diǎn)分配一個(gè) slot,后面使用這個(gè) slot 來上報(bào)觸摸點(diǎn)信息。(有點(diǎn)像信號(hào)和槽機(jī)制)。但是你既然多點(diǎn)觸摸,肯定每個(gè)點(diǎn)都有個(gè)先后順序,下面針對(duì)TypeB的來介紹

/*
@	Type B 觸摸點(diǎn)數(shù)據(jù)上報(bào)時(shí)序 
*/
 ABS_MT_SLOT 0 /*上報(bào)ABS_MT_SLOT事件,也就是觸摸點(diǎn)對(duì)應(yīng)的 SLOT。每次上報(bào)一個(gè)觸摸點(diǎn)坐標(biāo)之前要先使用input_mt_slot函數(shù)上報(bào)當(dāng)前觸摸點(diǎn)SLOT,觸摸點(diǎn)的SLOT其實(shí)就是觸摸點(diǎn)ID,需要由觸摸IC提供*/
 ABS_MT_TRACKING_ID 45 /*根據(jù) Type B 的要求,每個(gè) SLOT 必須關(guān)聯(lián)一個(gè)ABS_MT_TRACKING_ID,通過修改 SLOT 關(guān)聯(lián)的 ABS_MT_TRACKING_ID 來完成對(duì)觸摸點(diǎn)的添加、替換或刪除。具體用到的函數(shù)就是input_mt_report_slot_state,如果是添加一個(gè)新的觸摸點(diǎn),那么此函數(shù)的第三個(gè)參數(shù)active要設(shè)置為true,linux內(nèi)核會(huì)自動(dòng)分配一個(gè) ABS_MT_TRACKING_ID 值,不需要用戶去指定具體的ABS_MT_TRACKING_ID值*/
 ABS_MT_POSITION_X x[0] /*上報(bào)觸摸點(diǎn) 0的X 軸坐標(biāo),使用函數(shù) input_report_abs來完成*/
 ABS_MT_POSITION_Y y[0] /*上報(bào)觸摸點(diǎn) 0的Y 軸坐標(biāo),使用函數(shù) input_report_abs來完成*/
 ABS_MT_SLOT 1 
 ABS_MT_TRACKING_ID 46 
 ABS_MT_POSITION_X x[1] 
 ABS_MT_POSITION_Y y[1] 
 SYN_REPORT /*當(dāng)所有的觸摸點(diǎn)坐標(biāo)都上傳完畢以后就得發(fā)送SYN_REPORT事件,使用input_sync函數(shù)來完成*/

當(dāng)一個(gè)觸摸點(diǎn)移除以后,同樣需要通過 SLOT 關(guān)聯(lián)的ABS_MT_TRACKING_ID 來處理

/*
@	Type B 觸摸點(diǎn)移除時(shí)序 
*/
 ABS_MT_TRACKING_ID -1 /*當(dāng)一個(gè)觸摸點(diǎn)(SLOT)移除以后,需要通過 ABS_MT_TRACKING_ID 事件發(fā)送一個(gè)-1給內(nèi)核。方法很簡單,同樣使用 input_mt_report_slot_state函數(shù)來完成,只需要將此函數(shù)的第三個(gè)參數(shù)active設(shè)置為 false即可,不需要用戶手動(dòng)去設(shè)置-1。 */
 SYN_REPORT /*當(dāng)所有的觸摸點(diǎn)坐標(biāo)都上傳完畢以后就得發(fā)送 SYN_REPORT事件。 */

4.總結(jié)一下, MT協(xié)議隸屬于linux的 input 子系統(tǒng),驅(qū)動(dòng)通過大量的 ABS_MT 事件向 linux 內(nèi)核上報(bào)多點(diǎn)觸摸坐標(biāo)數(shù)據(jù)。根據(jù)觸摸 IC的不同,分為Type A和Type B兩種類型,不同的類型其上報(bào)時(shí)序不同,目前使用最多的是 Type B 類型

5.linux 下的多點(diǎn)觸摸協(xié)議其實(shí)就是通過不同的事件來上報(bào)觸摸
點(diǎn)坐標(biāo)信息,這些事件都是通過 Linux 內(nèi)核提供的對(duì)應(yīng) API 函數(shù)實(shí)現(xiàn)的

/*
@	input_mt_init_slots函數(shù)用于初始化MT的輸入slots
@	dev:  MT 設(shè)備對(duì)應(yīng)的 input_dev,因?yàn)镸T設(shè)備隸屬于input_dev。 
@	num_slots:設(shè)備要使用的SLOT數(shù)量,也就是觸摸點(diǎn)的數(shù)量
@	flags:其他一些 flags信息,可以采用‘|’運(yùn)算來同時(shí)設(shè)置多個(gè) flags標(biāo)識(shí)
@	返回值:0,成功;負(fù)值,失敗
*/
int input_mt_init_slots(  struct input_dev    *dev,  unsigned int      num_slots, unsigned int  flags) 

/*
@	定義在文件include/linux/input/mt.h中
@	此函數(shù)用于Type B 類型,此函數(shù)用于產(chǎn)生 ABS_MT_SLOT 事件,告訴內(nèi)核當(dāng)前上報(bào)的是哪個(gè)觸摸點(diǎn)的坐標(biāo)數(shù)據(jù)
@	dev:  MT 設(shè)備對(duì)應(yīng)的 input_dev
@ 	slot:當(dāng)前發(fā)送的是哪個(gè) slot的坐標(biāo)信息,也就是哪個(gè)觸摸點(diǎn)
@	返回值:無。 
*/
void input_mt_slot(struct input_dev *dev,   int  slot) 

/*
@	定義在文件drivers/input/input-mt.c 中
@	此函數(shù)用于 Type B 類型,用于產(chǎn)生 ABS_MT_TRACKING_ID 和 ABS_MT_TOOL_TYPE事件
@	dev:  MT 設(shè)備對(duì)應(yīng)的 input_dev
@	tool_type:觸摸類型,可以選擇 MT_TOOL_FINGER(手指)MT_TOOL_PEN(筆)或MT_TOOL_PALM(手掌)
@ 	active: true,連續(xù)觸摸, input子系統(tǒng)內(nèi)核會(huì)自動(dòng)分配一個(gè)ABS_MT_TRACKING_ID給slot。false,觸摸點(diǎn)抬起,表示某個(gè)觸摸點(diǎn)無效了,input 子系統(tǒng)內(nèi)核會(huì)分配一個(gè)-1 給 slot,表示觸摸點(diǎn)溢出。
@	返回值:無。 
*/
void input_mt_report_slot_state(  struct input_dev *dev, unsigned int tool_type,bool  active) 

/*
@	定義在 文件include/linux/input.h中
@	Type A和Type B 類型都使用此函數(shù)上報(bào)觸摸點(diǎn)坐標(biāo)信息
@	dev:  MT 設(shè)備對(duì)應(yīng)的 input_dev。
@	code:要上報(bào)的是什么數(shù)據(jù),可以設(shè)置為ABS_MT_POSITION_X或ABS_MT_POSITION_Y,也就是X 軸或者Y軸坐標(biāo)數(shù)據(jù)
@	value:具體的X 軸或Y軸坐標(biāo)數(shù)據(jù)值
*/
void input_report_abs(  struct input_dev *dev,unsigned int      code,   int  value) 

/*
@	定義在文件drivers/input/input-mt.c中
@	函數(shù)會(huì)獲取到具體的觸摸點(diǎn)數(shù)量,不需要用戶給出
@	dev:  MT 設(shè)備對(duì)應(yīng)的 input_dev
@	use_count:true,有效的觸摸點(diǎn)數(shù)量;false,追蹤到的觸摸點(diǎn)數(shù)量多于當(dāng)前上報(bào)的數(shù)量
@	返回值:無
*/
void input_mt_report_pointer_emulation(struct input_dev   *dev,   bool   use_count)

面的那么多都是整個(gè)框架中所涉及到的未知知識(shí)
多點(diǎn)電容觸摸驅(qū)動(dòng)的編寫框架用到的知識(shí)點(diǎn)和框架:
1.多點(diǎn)電容觸摸芯片的接口,一般都為I2C接口,因此驅(qū)動(dòng)主框架肯定是 I2C。
2.linux里面一般都是通過中斷來上報(bào)觸摸點(diǎn)坐標(biāo)信息,因此需要用到中斷框架
3.多點(diǎn)電容觸摸屬于 input子系統(tǒng),因此還要用到 input子系統(tǒng)框架。
4.在中斷處理程序中按照 linux的MT協(xié)議上報(bào)坐標(biāo)信息(此協(xié)議是多點(diǎn)觸摸專用)

多點(diǎn)電容觸摸驅(qū)動(dòng)編寫框架以及步驟如下:

  • 1.I2C驅(qū)動(dòng)框架(中間的probe函數(shù)里面初始化觸摸 IC,中斷和input子系統(tǒng))
    當(dāng)設(shè)備樹中觸摸 IC的設(shè)備節(jié)點(diǎn)和驅(qū)動(dòng)匹配以后probe函數(shù)會(huì)執(zhí)行
  /* 設(shè)備樹匹配表 */  
 static const struct i2c_device_id xxx_ts_id[] = { 
    { "xxx", 0, }, 
    { /* sentinel */ } 
 }; 
  
 /* 設(shè)備樹匹配表 */ 
 static const struct of_device_id xxx_of_match[] = { 
    { .compatible = "xxx", }, 
    { /* sentinel */ } 
 }; 
  
 /* i2c 驅(qū)動(dòng)結(jié)構(gòu)體 */  
 static struct i2c_driver ft5x06_ts_driver = { 
    .driver = { 
        .owner = THIS_MODULE, 
        .name = "edt_ft5x06", 
        .of_match_table = of_match_ptr(xxx_of_match), 
    }, 
    .id_table = xxx_ts_id, 
    .probe    = xxx_ts_probe, 
        .remove   = xxx_ts_remove, 
 }; 
  
 /* 
  * @description  : 驅(qū)動(dòng)入口函數(shù) 
  * @param        : 無 
  * @return       : 無 
  */ 
 static int __init xxx_init(void) 
 { 
    int ret = 0; 
    ret = i2c_add_driver(&xxx_ts_driver); 
    return ret; 
 } 
  
 /* 
  * @description  : 驅(qū)動(dòng)出口函數(shù) 
  * @param        : 無 
  * @return       : 無 
  */ 
 static void __exit xxx_exit(void) 
 { 
    i2c_del_driver(&ft5x06_ts_driver); 
 } 
  
 module_init(xxx_init); 
 module_exit(xxx_exit); 
 MODULE_LICENSE("GPL"); 
 MODULE_AUTHOR("zuozhongkai"); 
  • 2.初始化觸摸IC、中斷和 input子系統(tǒng)
static int xxx_ts_probe(struct i2c_client *client, const struct 
i2c_device_id *id) 
{ 
 	struct input_dev *input; 
    /* 1、初始化 I2C               */ 
    ...... 
    /*包括芯片的相關(guān) IO,比如復(fù)位、中斷等 IO 引腳,然后就是芯片本身的初始化,也就是配置觸摸芯片的相關(guān)寄存器*/
   
    /* 2,申請中斷, */ 
    devm_request_threaded_irq(&client->dev, client->irq, NULL, 
              xxx_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 
              client->name, &xxx); 
    ...... 
    /*因?yàn)橐话阌|摸芯片都是通過中斷來向系統(tǒng)上報(bào)觸摸點(diǎn)坐標(biāo)信息的,因此我們需要初始化中斷*/
 
    /* 3,input 設(shè)備申請與初始化   */ 
    input = devm_input_allocate_device(&client->dev); 
  
    input->name = client->name; 
    input->id.bustype = BUS_I2C; 
    input->dev.parent = &client->dev; 
    ...... 
    /*因?yàn)槎帱c(diǎn)電容觸摸屬于 input子系統(tǒng),申請到 input_dev以后還需要對(duì)其進(jìn)行初始化操作。*/
   
    /* 4,初始化 input 和 MT          */ 
    __set_bit(EV_ABS, input->evbit); 
    __set_bit(BTN_TOUCH, input->keybit); 
  
    input_set_abs_params(input, ABS_X, 0, width, 0, 0); 
    input_set_abs_params(input, ABS_Y, 0, height, 0, 0); 
    input_set_abs_params(input, ABS_MT_POSITION_X,0, width, 0, 0)
    input_set_abs_params(input, ABS_MT_POSITION_Y,0, height, 0, 0
    input_mt_init_slots(input, MAX_SUPPORT_POINTS, 0); /*初始化多點(diǎn)電容觸摸的 slots*/
    ...... 
   
    /* 5,注冊 input_dev */ 
    input_register_device(input); /*系統(tǒng)注冊前面申請到的input_dev。*/
    ...... 
 } 
  • 3.上報(bào)坐標(biāo)信息(Type B類型)
    最后就是在中斷服務(wù)程序中上報(bào)讀取到的坐標(biāo)信息
 static irqreturn_t xxx_handler(int irq, void *dev_id) 
 { 
  
    int num;              /* 觸摸點(diǎn)數(shù)量 */ 
    int x[n], y[n];       /* 保存坐標(biāo)值 */ 
   
    /* 1、從觸摸芯片獲取各個(gè)觸摸點(diǎn)坐標(biāo)值 */ 
    ...... 
   
    /* 2、上報(bào)每一個(gè)觸摸點(diǎn)坐標(biāo) */ 
    for (i = 0; i < num; i++) { 
        input_mt_slot(input, id); 
        input_mt_report_slot_state(input, MT_TOOL_FINGER, true); 
        input_report_abs(input, ABS_MT_POSITION_X, x[i]); 
        input_report_abs(input, ABS_MT_POSITION_Y, y[i]); 
    } 
    ...... 
   
    input_sync(input); 
    ...... 
   
    return IRQ_HANDLED; 
 } 

2. 實(shí)例應(yīng)用

1.修改設(shè)備樹

修改IO
4個(gè) IO,一個(gè)復(fù)位 IO、一個(gè)中斷IO、I2C2的 SCL 和SDA。復(fù)位 IO 和中斷 IO是普通的GPIO,因此這兩個(gè)IO可以放到同一個(gè)節(jié)點(diǎn)下去描述,I2C2的SCL和 SDA 屬于 I2C2,因此這兩個(gè)要放到同一個(gè)節(jié)點(diǎn)下去描述

  • 首先是復(fù)位 IO 和中斷 IO,imx6ull-alientek-emmc.dts 文件里面默認(rèn)有個(gè)名為“pinctrl_tsc”的節(jié)點(diǎn),如果被刪除了的話就自行創(chuàng)建,在此節(jié)點(diǎn)下添加觸摸屏的中斷引腳信息
/*
@	
*/
 pinctrl_tsc: tscgrp { 
   fsl,pins = < 
       MX6UL_PAD_GPIO1_IO09__GPIO1_IO09     0xF080   /* TSC_INT */ 
   >; 
 }; 

觸摸屏復(fù)位引腳使用的是 SNVS_TAMPER9,因此復(fù)位引腳信息要添加到 iomuxc_snvs 節(jié)點(diǎn)下,在 iomuxc_snvs 節(jié)點(diǎn)新建一個(gè)名為 pinctrl_tsc_reset 的子節(jié)點(diǎn)

 pinctrl_tsc_reset: tsc_reset { 
     fsl,pins = < 
       MX6ULL_PAD_SNVS_TAMPER9__GPIO5_IO09 0x10B0 
       >; 
 }; 
  • 繼續(xù)添加 I2C2 的 SCL 和 SDA 這兩個(gè) IO 信息.x6ull-alientek-emmc.dts 里面默認(rèn)就已經(jīng)添加了 I2C2 的 IO 信息,這是 NXP 官方添加的,所以不需要我們?nèi)バ薷?
 pinctrl_i2c2: i2c2grp { 
   fsl,pins = < 
       MX6UL_PAD_UART5_TX_DATA__I2C2_SCL 0x4001b8b0 
       MX6UL_PAD_UART5_RX_DATA__I2C2_SDA 0x4001b8b0 
   >; 
 }; 

注意:要防止引腳沖突

添加設(shè)備節(jié)點(diǎn)
需要向 I2C2 節(jié)點(diǎn)下添加一個(gè)子節(jié)點(diǎn),此子節(jié)點(diǎn)用于描述 FT5426,添加完成以后的 I2C2 節(jié)點(diǎn)

&i2c2 { 
   clock_frequency = <100000>; 
   pinctrl-names = "default"; 
   pinctrl-0 = <&pinctrl_i2c2>; 
   status = "okay"; 

    /* zuozhongkai FT5406/FT5426 */ 
    ft5426: ft5426@38 { 
        compatible = "edt,edt-ft5426"; 
        reg = <0x38>; /*器件地址為 0x38*/
        pinctrl-names = "default"; 
        pinctrl-0 = <&pinctrl_tsc /*復(fù)位 IO 和中斷 IO 所使用的節(jié)點(diǎn)為 pinctrl_tsc和 pinctrl_tsc_reset*/
                    &pinctrl_tsc_reset >;  
        interrupt-parent = <&gpio1>;  
        interrupts = <9 0>;  
        reset-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;/*復(fù)位IO 對(duì)應(yīng)的GPIO為GPIO5_IO09*/   
        interrupt-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;  /*中斷IO對(duì)應(yīng)的GPIO為 GPIO1_IO09。*/
    }; 
 }; 

2.編寫設(shè)備驅(qū)動(dòng)

總線驅(qū)動(dòng)官方已經(jīng)寫好過了,我們只需要寫設(shè)備驅(qū)動(dòng)。

#include <linux/module.h>
#include <linux/ratelimit.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/i2c.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#include <linux/debugfs.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
#include <linux/input/edt-ft5x06.h>
#include <linux/i2c.h>

#define MAX_SUPPORT_POINTS		5			/* 5點(diǎn)觸摸 	*/
#define TOUCH_EVENT_DOWN		0x00		/* 按下 	*/
#define TOUCH_EVENT_UP			0x01		/* 抬起 	*/
#define TOUCH_EVENT_ON			0x02		/* 接觸 	*/
#define TOUCH_EVENT_RESERVED	0x03		/* 保留 	*/

/* FT5X06寄存器相關(guān)宏定義 */
#define FT5X06_TD_STATUS_REG	0X02		/*	狀態(tài)寄存器地址 		*/
#define FT5x06_DEVICE_MODE_REG	0X00 		/* 模式寄存器 			*/
#define FT5426_IDG_MODE_REG		0XA4		/* 中斷模式				*/
#define FT5X06_READLEN			29			/* 要讀取的寄存器個(gè)數(shù) 	*/

struct ft5x06_dev {
	struct device_node	*nd; 				/* 設(shè)備節(jié)點(diǎn) 		*/
	int irq_pin,reset_pin;					/* 中斷和復(fù)位IO		*/
	int irqnum;								/* 中斷號(hào)    		*/
	void *private_data;						/* 私有數(shù)據(jù) 		*/
	struct input_dev *input;				/* input結(jié)構(gòu)體 		*/
	struct i2c_client *client;				/* I2C客戶端 		*/
};

static struct ft5x06_dev ft5x06;

/*
 * @description     : 復(fù)位FT5X06
 * @param - client 	: 要操作的i2c
 * @param - multidev: 自定義的multitouch設(shè)備
 * @return          : 0,成功;其他負(fù)值,失敗
 */
static int ft5x06_ts_reset(struct i2c_client *client, struct ft5x06_dev *dev)
{
	int ret = 0;

	if (gpio_is_valid(dev->reset_pin)) {  		/* 檢查IO是否有效 */
		/* 申請復(fù)位IO,并且默認(rèn)輸出低電平 */
		ret = devm_gpio_request_one(&client->dev,	
					dev->reset_pin, GPIOF_OUT_INIT_LOW,
					"edt-ft5x06 reset");
		if (ret) {
			return ret;
		}

		msleep(5);
		gpio_set_value(dev->reset_pin, 1);	/* 輸出高電平,停止復(fù)位 */
		msleep(300);
	}

	return 0;
}

/*
 * @description	: 從FT5X06讀取多個(gè)寄存器數(shù)據(jù)
 * @param - dev:  ft5x06設(shè)備
 * @param - reg:  要讀取的寄存器首地址
 * @param - val:  讀取到的數(shù)據(jù)
 * @param - len:  要讀取的數(shù)據(jù)長度
 * @return 		: 操作結(jié)果
 */
static int ft5x06_read_regs(struct ft5x06_dev *dev, u8 reg, void *val, int len)
{
	int ret;
	struct i2c_msg msg[2];
	struct i2c_client *client = (struct i2c_client *)dev->client;

	/* msg[0]為發(fā)送要讀取的首地址 */
	msg[0].addr = client->addr;			/* ft5x06地址 */
	msg[0].flags = 0;					/* 標(biāo)記為發(fā)送數(shù)據(jù) */
	msg[0].buf = &reg;					/* 讀取的首地址 */
	msg[0].len = 1;						/* reg長度*/

	/* msg[1]讀取數(shù)據(jù) */
	msg[1].addr = client->addr;			/* ft5x06地址 */
	msg[1].flags = I2C_M_RD;			/* 標(biāo)記為讀取數(shù)據(jù)*/
	msg[1].buf = val;					/* 讀取數(shù)據(jù)緩沖區(qū) */
	msg[1].len = len;					/* 要讀取的數(shù)據(jù)長度*/

	ret = i2c_transfer(client->adapter, msg, 2);
	if(ret == 2) {
		ret = 0;
	} else {
		ret = -EREMOTEIO;
	}
	return ret;
}

/*
 * @description	: 向ft5x06多個(gè)寄存器寫入數(shù)據(jù)
 * @param - dev:  ft5x06設(shè)備
 * @param - reg:  要寫入的寄存器首地址
 * @param - val:  要寫入的數(shù)據(jù)緩沖區(qū)
 * @param - len:  要寫入的數(shù)據(jù)長度
 * @return 	  :   操作結(jié)果
 */
static s32 ft5x06_write_regs(struct ft5x06_dev *dev, u8 reg, u8 *buf, u8 len)
{
	u8 b[256];
	struct i2c_msg msg;
	struct i2c_client *client = (struct i2c_client *)dev->client;
	
	b[0] = reg;					/* 寄存器首地址 */
	memcpy(&b[1],buf,len);		/* 將要寫入的數(shù)據(jù)拷貝到數(shù)組b里面 */
		
	msg.addr = client->addr;	/* ft5x06地址 */
	msg.flags = 0;				/* 標(biāo)記為寫數(shù)據(jù) */

	msg.buf = b;				/* 要寫入的數(shù)據(jù)緩沖區(qū) */
	msg.len = len + 1;			/* 要寫入的數(shù)據(jù)長度 */

	return i2c_transfer(client->adapter, &msg, 1);
}

/*
 * @description	: 向ft5x06指定寄存器寫入指定的值,寫一個(gè)寄存器
 * @param - dev:  ft5x06設(shè)備
 * @param - reg:  要寫的寄存器
 * @param - data: 要寫入的值
 * @return   :    無
 */
static void ft5x06_write_reg(struct ft5x06_dev *dev, u8 reg, u8 data)
{
	u8 buf = 0;
	buf = data;
	ft5x06_write_regs(dev, reg, &buf, 1);
}

/*
 * @description     : FT5X06中斷服務(wù)函數(shù)
 * @param - irq 	: 中斷號(hào) 
 * @param - dev_id	: 設(shè)備結(jié)構(gòu)。
 * @return 			: 中斷執(zhí)行結(jié)果
 */
static irqreturn_t ft5x06_handler(int irq, void *dev_id)
{
	struct ft5x06_dev *multidata = dev_id;

	u8 rdbuf[29];
	int i, type, x, y, id;
	int offset, tplen;
	int ret;
	bool down;

	offset = 1; 	/* 偏移1,也就是0X02+1=0x03,從0X03開始是觸摸值 */
	tplen = 6;		/* 一個(gè)觸摸點(diǎn)有6個(gè)寄存器來保存觸摸值 */

	memset(rdbuf, 0, sizeof(rdbuf));		/* 清除 */

	/* 讀取FT5X06觸摸點(diǎn)坐標(biāo)從0X02寄存器開始,連續(xù)讀取29個(gè)寄存器 */
	ret = ft5x06_read_regs(multidata, FT5X06_TD_STATUS_REG, rdbuf, FT5X06_READLEN);
	if (ret) {
		goto fail;
	}

	/* 上報(bào)每一個(gè)觸摸點(diǎn)坐標(biāo) */
	for (i = 0; i < MAX_SUPPORT_POINTS; i++) {
		u8 *buf = &rdbuf[i * tplen + offset];

		/* 以第一個(gè)觸摸點(diǎn)為例,寄存器TOUCH1_XH(地址0X03),各位描述如下:
		 * bit7:6  Event flag  0:按下 1:釋放 2:接觸 3:沒有事件
		 * bit5:4  保留
		 * bit3:0  X軸觸摸點(diǎn)的11~8位。
		 */
		type = buf[0] >> 6;     /* 獲取觸摸類型 */
		if (type == TOUCH_EVENT_RESERVED)
			continue;
 
		/* 我們所使用的觸摸屏和FT5X06是反過來的 */
		x = ((buf[2] << 8) | buf[3]) & 0x0fff;
		y = ((buf[0] << 8) | buf[1]) & 0x0fff;
		
		/* 以第一個(gè)觸摸點(diǎn)為例,寄存器TOUCH1_YH(地址0X05),各位描述如下:
		 * bit7:4  Touch ID  觸摸ID,表示是哪個(gè)觸摸點(diǎn)
		 * bit3:0  Y軸觸摸點(diǎn)的11~8位。
		 */
		id = (buf[2] >> 4) & 0x0f;
		down = type != TOUCH_EVENT_UP;

		input_mt_slot(multidata->input, id);
		input_mt_report_slot_state(multidata->input, MT_TOOL_FINGER, down);

		if (!down)
			continue;

		input_report_abs(multidata->input, ABS_MT_POSITION_X, x);
		input_report_abs(multidata->input, ABS_MT_POSITION_Y, y);
	}

	input_mt_report_pointer_emulation(multidata->input, true);
	input_sync(multidata->input);

fail:
	return IRQ_HANDLED;

}

/*
 * @description     : FT5x06中斷初始化
 * @param - client 	: 要操作的i2c
 * @param - multidev: 自定義的multitouch設(shè)備
 * @return          : 0,成功;其他負(fù)值,失敗
 */
static int ft5x06_ts_irq(struct i2c_client *client, struct ft5x06_dev *dev)
{
	int ret = 0;

	/* 1,申請中斷GPIO */
	if (gpio_is_valid(dev->irq_pin)) {
		ret = devm_gpio_request_one(&client->dev, dev->irq_pin,
					GPIOF_IN, "edt-ft5x06 irq");
		if (ret) {
			dev_err(&client->dev,
				"Failed to request GPIO %d, error %d\n",
				dev->irq_pin, ret);
			return ret;
		}
	}

	/* 2,申請中斷,client->irq就是IO中斷, */
	ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,
					ft5x06_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
					client->name, &ft5x06);
	if (ret) {
		dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
		return ret;
	}

	return 0;
}

 /*
  * @description     : i2c驅(qū)動(dòng)的probe函數(shù),當(dāng)驅(qū)動(dòng)與
  *                    設(shè)備匹配以后此函數(shù)就會(huì)執(zhí)行
  * @param - client  : i2c設(shè)備
  * @param - id      : i2c設(shè)備ID
  * @return          : 0,成功;其他負(fù)值,失敗
  */
static int ft5x06_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
	int ret = 0;

	ft5x06.client = client;

	/* 1,獲取設(shè)備樹中的中斷和復(fù)位引腳 */
	ft5x06.irq_pin = of_get_named_gpio(client->dev.of_node, "interrupt-gpios", 0);
	ft5x06.reset_pin = of_get_named_gpio(client->dev.of_node, "reset-gpios", 0);

	/* 2,復(fù)位FT5x06 */
	ret = ft5x06_ts_reset(client, &ft5x06);
	if(ret < 0) {
		goto fail;
	}

	/* 3,初始化中斷 */
	ret = ft5x06_ts_irq(client, &ft5x06);
	if(ret < 0) {
		goto fail;
	}

	/* 4,初始化FT5X06 */
	ft5x06_write_reg(&ft5x06, FT5x06_DEVICE_MODE_REG, 0); 	/* 進(jìn)入正常模式 	*/
	ft5x06_write_reg(&ft5x06, FT5426_IDG_MODE_REG, 1); 		/* FT5426中斷模式	*/

	/* 5,input設(shè)備注冊 */
	ft5x06.input = devm_input_allocate_device(&client->dev);
	if (!ft5x06.input) {
		ret = -ENOMEM;
		goto fail;
	}
	ft5x06.input->name = client->name;
	ft5x06.input->id.bustype = BUS_I2C;
	ft5x06.input->dev.parent = &client->dev;

	__set_bit(EV_KEY, ft5x06.input->evbit);
	__set_bit(EV_ABS, ft5x06.input->evbit);
	__set_bit(BTN_TOUCH, ft5x06.input->keybit);

	input_set_abs_params(ft5x06.input, ABS_X, 0, 1024, 0, 0);
	input_set_abs_params(ft5x06.input, ABS_Y, 0, 600, 0, 0);
	input_set_abs_params(ft5x06.input, ABS_MT_POSITION_X,0, 1024, 0, 0);
	input_set_abs_params(ft5x06.input, ABS_MT_POSITION_Y,0, 600, 0, 0);	     
	ret = input_mt_init_slots(ft5x06.input, MAX_SUPPORT_POINTS, 0);
	if (ret) {
		goto fail;
	}

	ret = input_register_device(ft5x06.input);
	if (ret)
		goto fail;

	return 0;

fail:
	return ret;
}

/*
 * @description     : i2c驅(qū)動(dòng)的remove函數(shù),移除i2c驅(qū)動(dòng)的時(shí)候此函數(shù)會(huì)執(zhí)行
 * @param - client 	: i2c設(shè)備
 * @return          : 0,成功;其他負(fù)值,失敗
 */
static int ft5x06_ts_remove(struct i2c_client *client)
{	
	/* 釋放input_dev */
	input_unregister_device(ft5x06.input);
	return 0;
}


/*
 *  傳統(tǒng)驅(qū)動(dòng)匹配表
 */ 
static const struct i2c_device_id ft5x06_ts_id[] = {
	{ "edt-ft5206", 0, },
	{ "edt-ft5426", 0, },
	{ /* sentinel */ }
};

/*
 * 設(shè)備樹匹配表 
 */
static const struct of_device_id ft5x06_of_match[] = {
	{ .compatible = "edt,edt-ft5206", },
	{ .compatible = "edt,edt-ft5426", },
	{ /* sentinel */ }
};

/* i2c驅(qū)動(dòng)結(jié)構(gòu)體 */	
static struct i2c_driver ft5x06_ts_driver = {
	.driver = {
		.owner = THIS_MODULE,
		.name = "edt_ft5x06",
		.of_match_table = of_match_ptr(ft5x06_of_match),
	},
	.id_table = ft5x06_ts_id,
	.probe    = ft5x06_ts_probe,
	.remove   = ft5x06_ts_remove,
};

/*
 * @description	: 驅(qū)動(dòng)入口函數(shù)
 * @param 		: 無
 * @return 		: 無
 */
static int __init ft5x06_init(void)
{
	int ret = 0;

	ret = i2c_add_driver(&ft5x06_ts_driver);

	return ret;
}

/*
 * @description	: 驅(qū)動(dòng)出口函數(shù)
 * @param 		: 無
 * @return 		: 無
 */
static void __exit ft5x06_exit(void)
{
	i2c_del_driver(&ft5x06_ts_driver);
}

module_init(ft5x06_init);
module_exit(ft5x06_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zuozhongkai");

3. 驅(qū)動(dòng)測試

1.手動(dòng)加載加載驅(qū)動(dòng)

  • 將上一小節(jié)編譯出來 ft5x06.ko 拷貝到
    rootfs/lib/modules/4.1.15目錄中,啟動(dòng)開發(fā)板,進(jìn)入到目錄 lib/modules/4.1.15中
depmod    /*第一次加載驅(qū)動(dòng)的時(shí)候需要運(yùn)行此命令*/

modprobe ft5x06.ko  /*加載驅(qū)動(dòng)模塊*/

hexdump /dev/input/event2    /*開始進(jìn)行接觸測試*/

2.將驅(qū)動(dòng)添加到內(nèi)核

  • 前面我們一直將觸摸驅(qū)動(dòng)編譯為模塊,每次系統(tǒng)啟動(dòng)以后在手動(dòng)加載驅(qū)動(dòng)模塊,這樣很不方便。當(dāng)我們把驅(qū)動(dòng)調(diào)試成功以后一般都會(huì)將其編譯到內(nèi)核中,這樣內(nèi)核啟動(dòng)以后就會(huì)自動(dòng)加載驅(qū)動(dòng),不需要我們再手動(dòng) modprobe 了
    1、將驅(qū)動(dòng)文件放到合適的位置,在內(nèi)核源碼中找個(gè)合適的位置將 ft5x06.c放進(jìn)去,ft5x06.c是個(gè)觸摸屏驅(qū)動(dòng),因此我們需要查找一下 linux 內(nèi)核里面觸摸屏驅(qū)動(dòng)放到了哪個(gè)目錄下。linux 內(nèi)核里面將觸摸屏驅(qū)動(dòng)放到了 drivers/input/touchscreen 目錄下,因此我們要將 ft5x06.c拷貝到此目錄下。

2.修改對(duì)應(yīng)的Makefile
電容觸摸屏驅(qū)動(dòng)(Linux驅(qū)動(dòng)開發(fā)篇)
修改完成以后重新編譯 linux 內(nèi)核,然后用新的 zImage 啟動(dòng)開發(fā)板。文章來源地址http://www.zghlxwxcb.cn/news/detail-452030.html

/*將觸摸屏驅(qū)動(dòng)添加到 linux 內(nèi)核里面以后觸摸屏對(duì)應(yīng)的是 event1,而不是前面編譯為模塊對(duì)應(yīng)的event2,這一點(diǎn)一定要注意*/

hexdump  /dev/input/event1   //查看觸摸屏原始數(shù)據(jù)上報(bào)信息==開始測試

到了這里,關(guān)于電容觸摸屏驅(qū)動(dòng)(Linux驅(qū)動(dòng)開發(fā)篇)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 全志V3S嵌入式驅(qū)動(dòng)開發(fā)(觸摸屏驅(qū)動(dòng))

    全志V3S嵌入式驅(qū)動(dòng)開發(fā)(觸摸屏驅(qū)動(dòng))

    【 聲明:版權(quán)所有,歡迎轉(zhuǎn)載,請勿用于商業(yè)用途。 聯(lián)系信箱:feixiaoxing @163.com】 ? ? ? ? 所謂的觸摸屏,其實(shí)就是在普通的lcd屏幕之上,再加一層屏而已。這個(gè)屏是透明的,這樣客戶就可以看到下面lcd屏幕的內(nèi)容,另外一方面,通過觸摸信號(hào),還可以實(shí)現(xiàn)人和機(jī)器的自然

    2024年02月08日
    瀏覽(30)
  • 嵌入式培訓(xùn)機(jī)構(gòu)四個(gè)月實(shí)訓(xùn)課程筆記(完整版)-Linux ARM驅(qū)動(dòng)編程第三天-ARM Linux ADC和觸摸屏開發(fā) (物聯(lián)技術(shù)666)

    嵌入式培訓(xùn)機(jī)構(gòu)四個(gè)月實(shí)訓(xùn)課程筆記(完整版)-Linux ARM驅(qū)動(dòng)編程第三天-ARM Linux ADC和觸摸屏開發(fā) (物聯(lián)技術(shù)666)

    鏈接:https://pan.baidu.com/s/1V0E9IHSoLbpiWJsncmFgdA?pwd=1688 提取碼:1688 ? 教學(xué)內(nèi)容: 1 、 ADC S3C2440 的 A/D 轉(zhuǎn)換器包含一個(gè) 8 通道的模擬輸入轉(zhuǎn)換器,可以將模擬輸入信號(hào)轉(zhuǎn)換成 10 位數(shù)字編碼。 在 A/D 轉(zhuǎn)換時(shí)鐘頻率為 2.5MHz 時(shí),其最大轉(zhuǎn)換率為 500KSPS ( 5 個(gè)時(shí)鐘周期完成一次轉(zhuǎn)換) 輸

    2024年02月20日
    瀏覽(26)
  • 【ChatGpt】ChatGpt解答了 “我一下午都沒解決的“ Linux觸摸屏驅(qū)動(dòng)的問題

    【ChatGpt】ChatGpt解答了 “我一下午都沒解決的“ Linux觸摸屏驅(qū)動(dòng)的問題

    現(xiàn)實(shí)問題: 有一個(gè)基于Linux4.19內(nèi)核開發(fā)了,在海思SS528芯片運(yùn)行的系統(tǒng),用鼠標(biāo)可以正常使用。 現(xiàn)在要求使用一塊公司開發(fā)的 多點(diǎn)觸控屏 連接這個(gè)系統(tǒng),能正常使用。 分析問題: 要在LInux系統(tǒng)使用觸控屏,可能需要移植 tslib 的庫,這個(gè)有以前做過,可以自己解決。 移植后

    2024年02月07日
    瀏覽(22)
  • mipi接口 1280(RGB)*720 LCD屏開發(fā)驅(qū)動(dòng)筆記帖
1、MTK8788[android 9.0]GT9XX TP觸摸屏驅(qū)動(dòng)流程分析

    mipi接口 1280(RGB)*720 LCD屏開發(fā)驅(qū)動(dòng)筆記帖 1、MTK8788[android 9.0]GT9XX TP觸摸屏驅(qū)動(dòng)流程分析

    ps:創(chuàng)業(yè)開發(fā)產(chǎn)品,自學(xué)筆記,不一定適合教材性的閱讀,零碎整理,自我總結(jié)用 材料:4.1寸lcd屏兩塊,屏自帶觸控,屏幕資料具備,rk3399和MK8788開發(fā)版上分別開發(fā)。 1】rk3399 ? ? ? ??????? 開發(fā)板:友善的rk3399v2開發(fā)版, 資料鏈接 : 處理器:RK3399 內(nèi)核: 編譯工具

    2023年04月08日
    瀏覽(125)
  • STM32 驅(qū)動(dòng)4.3寸TFT LCD 觸摸屏

    STM32 驅(qū)動(dòng)4.3寸TFT LCD 觸摸屏

    STM32的FSMC接口是并行總線接口,可以用于驅(qū)動(dòng)存儲(chǔ)芯片如FLASH/SRAM等,也可以用于驅(qū)動(dòng)并口LCD屏。觸摸屏是在顯示屏上覆蓋一層觸摸感應(yīng)的外屏,有單獨(dú)的接口輸出坐標(biāo)數(shù)據(jù)。 這里以STM32F103VET6開發(fā)板連接4.3寸TFT LCD觸摸屏,將正點(diǎn)原子的參考代碼,移植到STM32CUBEIDE開發(fā)環(huán)境,實(shí)

    2024年02月11日
    瀏覽(22)
  • 【Liux下6818開發(fā)板(ARM)】觸摸屏

    【Liux下6818開發(fā)板(ARM)】觸摸屏

    (??? ),hello我是 祐言 博客主頁:C語言基礎(chǔ),Linux基礎(chǔ),軟件配置領(lǐng)域博主?? 快上??,一起學(xué)習(xí)! 送給讀者的一句雞湯??: 集中起來的意志可以擊穿頑石! 作者水平很有限,如果發(fā)現(xiàn)錯(cuò)誤,可在評(píng)論區(qū)指正,感謝?? ? ? ? ? 在正式學(xué)習(xí)觸摸屏之前,我們先來了解一下事件

    2024年02月14日
    瀏覽(22)
  • Linux輸入設(shè)備應(yīng)用編程(鍵盤,按鍵,觸摸屏,鼠標(biāo))

    Linux輸入設(shè)備應(yīng)用編程(鍵盤,按鍵,觸摸屏,鼠標(biāo))

    目錄 一 輸入設(shè)備編程介紹 1.1?什么是輸入設(shè)備呢? ?1.2 什么是輸入設(shè)備的應(yīng)用編程?? ?1.3 input子系統(tǒng) 1.4? 數(shù)據(jù)讀取流程 1.5 應(yīng)用程序如何解析數(shù)據(jù) 1.5.1 按鍵類事件: ?1.5.2 相對(duì)位移事件? 1.5.3 絕對(duì)位移事件? 二 讀取 struct input_event數(shù)據(jù)?? 本章學(xué)習(xí)Linux輸入設(shè)備的應(yīng)用編程

    2024年02月05日
    瀏覽(38)
  • 【SA8295P 源碼分析】66 - Android 側(cè)內(nèi)核層 TouchScreen Panel(TP)觸摸屏驅(qū)動(dòng)源碼分析

    【源碼分析】 因?yàn)橐恍┰?,本文需要移除?對(duì)于已經(jīng)購買的兄弟,不用擔(dān)心,不是跑路, 我會(huì)繼續(xù)持續(xù)提供技術(shù)支持, 有什么模塊想學(xué)習(xí)的,或者有什么問題有疑問的, 請私聊我,我們 +VX 溝通技術(shù)問題,一起學(xué)習(xí),一起進(jìn)步 接下來,我一一私聊已經(jīng)購買的兄弟添加V

    2024年02月11日
    瀏覽(42)
  • linux下安裝qt、qt觸摸屏校準(zhǔn)tslib

    選擇安裝選項(xiàng):在安裝程序啟動(dòng)后,按照提示進(jìn)行操作。你可以選擇安裝路徑、安裝組件、個(gè)性化設(shè)置等。 開始安裝:在確認(rèn)安裝選項(xiàng)后,點(diǎn)擊 “安裝” 按鈕開始安裝 Qt。這個(gè)過程可能需要一些時(shí)間,取決于你選擇的組件和系統(tǒng)性能。 配置 Qt:安裝完成后,打開終端并進(jìn)入

    2024年02月09日
    瀏覽(17)
  • 【觸摸屏功能測試】昆侖通態(tài)MCGS——測試通過HJ212_TCPIP驅(qū)動(dòng)4G功能發(fā)送212報(bào)文

    【觸摸屏功能測試】昆侖通態(tài)MCGS——測試通過HJ212_TCPIP驅(qū)動(dòng)4G功能發(fā)送212報(bào)文

    型號(hào) :TPC7022Ni 測試內(nèi)容: 實(shí)現(xiàn)4G觸摸屏,通過自帶的4G卡向平臺(tái)發(fā)送HJ212報(bào)文 本驅(qū)動(dòng)構(gòu)件用于MCGS軟件,通過污染物在線監(jiān)控(監(jiān)測)系統(tǒng)數(shù)據(jù)傳輸標(biāo)準(zhǔn)協(xié)議向下位機(jī)數(shù)采儀發(fā)送各類指令; 驅(qū)動(dòng)類型 以太網(wǎng)子設(shè)備,須掛接在“通用TCPIP父設(shè)備”下才能工作 通訊協(xié)議 污染物在線監(jiān)控

    2024年02月07日
    瀏覽(95)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包