1、硬件
1>復位引腳:GPIO19__TP_RESET,
復位方法: 原來的復位是把復位引腳=“高->低->高”操作;
現在:“拉高->拉低”操作;
Register Descriptions (base: 0x1000_0600)
GPIO23_00_DATA: PIO Pin Data (offset: 0x0020)
GPIO23_00_SET: Set PIO Pin Data Bit (offset: 0x002C)
GPIO23_00_RESET: Clear PIO Pin Data Bit (offset: 0x0030)
測試R418左引腳電平:
未操作:3.256V,高電平
reg s 0
reg r 0x620 //0x320780或0x100780,GPIO19_bit[19]=0;
測試:3.256V,高電平
reg w 0x62c 0x00080000 //GPIO19_SET拉高; 3.256V;
reg w 0x630 0x00080000 //GPIO19_RESET拉低; 3.256V;
測試:3.254V,reg r 0x620=<4>0x100780,bit[19]=0;
# reg r 0x624
<4>0xef87ff,bit[19]=1=輸出引腳;
GPIO19: ____|————|____
TP_RESET: ————|____|————3.3V
還是?
GPIO19: ————|____
TP_RESET: ____|————3.3V
Register Descriptions (base: 0x1000_0600)
GPIO39_24_DATA: PIO Pin Data (offset: 0x0048)
GPIO39_24_SET: Set PIO Pin Data Bit (offset: 0x0054)
GPIO39_24_RESET: Clear PIO Pin Data Bit (offset: 0x0058)
測試R418左引腳電平:
未操作:3.256V,高電平
reg r 0x648 //0x1000,bit[14]=0;
reg w 0x654 0x4000 //3.256V,
reg w 0x658 0x4000 //3.256V,
2>內核打印
#cat proc/kmsg & //打開內核打印開關;
問題1:觸摸屏的原理:觸摸屏->AT24CXX->I2C->芯片MT7620?
答:不是,觸摸屏->ILI2117A芯片->I2C->芯片MT7620。
設備地址問題:
2K、4K和8K EEPROM設備都需要一個8位的設備地址字,在啟動條件下,為讀取或寫入操作啟用芯片(參見圖1)。
該設備地址詞由一個強制的一個,零序列組成,第四個最重要的位顯示。這是所有EEPROM設備的共同點。
接下來的3位是A2、A1和A0設備地址位,用於2K EEPROM。這3位必須與它們對應的硬連線輸入引腳相比。
4K EEPROM只使用A2和A1設備地址位,第三位是內存頁面地址位。這兩個設備地址比特必須與它們對應的硬連線輸入引腳相比。A0 pin沒有連接。
8K EEPROM只使用A2設備地址比特與接下來的2位用於內存頁面尋址。A2bit必須與相應的硬連線輸入pin相比。
A1和A0別針沒有連接。
第8位設備地址是read / write操作選擇位。如果這個比特是高的,如果這個比特很低,則啟動了讀操作。
在設備地址的比較中,EEPROM將輸出一個零。如果沒有進行比較,芯片將返回到備用狀態。
STATUS: I2C Status Register (offset: 0x0018)
I2C確認錯誤檢測
0:表示固件正在寫入STARTXFR register。
1:表示在發送設備地址、地址或數據之后,主機控制器沒有從I2C從設備接收到正確的確認。
問題:I2C設備是否有片選引腳?
主控器件通過地址碼建立多機通信的機制,因此I2C總線省去了外圍器件的片選線,這樣無論總線上掛接多少個器件,其系統仍然為簡約的二線結構。
=============================================
i2c通信:
問題1:MT7620A的I2C讀字節的操作流程是什么?
答: Start信號->虛寫(dev_addr和word_addr)->讀數據;
問題2:開始信號怎么發送?
答:單片機是用通過先后配置SDA/SCL的電平狀態來實現,如:
void init(void) //總線初始化 將總線都拉高一釋放總線 發送啟動信號前,要先初始化總線。
即總有檢測到總線空閑才開始發送啟動信號
{
sda = 1;
delay();
scl = 1;
delay();
}
void start(void) //開始信號,SCL在高電平期間,SDA一個下降沿則表示啟動信號;
{
sda = 1; //釋放SDA總線;
delay();
scl = 1;
delay();
sda = 0;
delay();
}
MT7620等直接用配置寄存器實現,如:??
ra_outl(RALINK_I2C_STARTXFR_REG, WRITE_CMD); /* I2C_Start */
問題3:應答是怎么回事兒?為什么會報錯?
問題4:
============================
觸摸屏2:
問題0:MT7620DA的設備地址是怎么處理的?和arm的區別?
答:MT7620DA的7bit設備地址(不包含讀寫位)存入寄存器RALINK_I2C_DEVADDR_REG(DEVADDR: I2C Device Address Register (offset: 0x0008))
問題1:觸摸板是從-主模式還是主-從模式?ALC5621呢?寄存器初始化需要修改嗎?
答:應該都是主-從模式;
1月4日-周六最后測試:
源碼:
#if 1
printf("\nEnter i2c_test read:\n");
regdat = read_ft5x0x_i2c(FT5x0x_REG_FW_VER);
printf("FT5x0x_REG_FW_VER = 0x%x\n", regdat);
regdat = read_ft5x0x_i2c(FT5x0x_REG_POINT_RATE);
printf("FT5x0x_REG_POINT_RATE = 0x%x\n", regdat);
regdat = read_ft5x0x_i2c(FT5X0X_REG_THGROUP);
printf("FT5X0X_REG_THGROUP = 0x%x\n", regdat);
printf("\nEnter i2c_test read:\n");
regdat = read_ft5x0x_i2c(FT5x0x_REG_FW_VER + 3);
printf("FT5x0x_REG_FW_VER = 0x%x\n", regdat);
regdat = read_ft5x0x_i2c(FT5x0x_REG_POINT_RATE + 3);
printf("FT5x0x_REG_POINT_RATE = 0x%x\n", regdat);
regdat = read_ft5x0x_i2c(FT5X0X_REG_THGROUP + 3);
printf("FT5X0X_REG_THGROUP = 0x%x\n", regdat);
regdat = read_ft5x0x_i2c(0x0);
printf("[0x0] = 0x%x\n", regdat);
regdat = read_ft5x0x_i2c(0x1);
printf("[0x1] = 0x%x\n", regdat);
regdat = read_ft5x0x_i2c(0x2);
printf("[0x2] = 0x%x\n", regdat);
regdat = read_ft5x0x_i2c(0x3);
printf("[0x3] = 0x%x\n", regdat);
regdat = read_ft5x0x_i2c(0x4);
printf("[0x4] = 0x%x\n", regdat);
regdat = read_ft5x0x_i2c(0x5); /* 得到: 0x31cc */
printf("[0x5] = 0x%x\n", regdat);
#else
6: System coming VPT testing!!!!.
i2c_master_init
RALINK_REG_CLKCFG1=0x75AFFFC0
RALINK_REG_PIODATA = 0xb0000620
RALINK_REG_PIODATA = 0xb0000620
RALINK_REG_PIODATA = 0xb0000620
IIC is ready now
Enter i2c_test read:
FT5x0x_REG_FW_VER = 0x0
FT5x0x_REG_POINT_RATE = 0x0
FT5X0X_REG_THGROUP = 0x0
Enter i2c_test read:
FT5x0x_REG_FW_VER = 0x0
FT5x0x_REG_POINT_RATE = 0x0
FT5X0X_REG_THGROUP = 0x0
[0x0] = 0x0
[0x1] = 0x8100
[0x2] = 0x0
[0x3] = 0x100
[0x4] = 0x5630
[0x5] = 0x31cc
=====i2c_test over.=====
問題2:ILI2117的地址線A0沒有接嗎?為什么讀出來的值都是2字節?
答:
問題3:ILI設備設備信息存儲在哪些寄存器中?讀取的方式?
答:是否是
TP_VENDER //=1; //地址=0x3-> [0x1]高位字節;
FW_TEST_VERSION //=0; //地址=0x5->[0x2]高位字節, 0x6->[0x3]低位字節;
???
==================================================
TS驅動:
1.修改驅動,通過編譯;
1.1當驅動與設備系統有較大出入時,使用設備系統的自有接口驅動,如:I2C驅動;
若仍使用系統自帶的I2C將需要對系統I2C接口初始化做一定的處理;
2.編寫測試程序;
3.實驗測試;
Register Descriptions (base: 0x1000_0600)
GPIO71_40_INT: PIO Pin Interrupt Status (offset: 0x0060)
/*
* Simple, straightforward mutexes with strict semantics:簡單,直接的互斥體與嚴格的語義:
*
* - only one task can hold the mutex at a time
* - only the owner can unlock the mutex
* - multiple unlocks are not permitted
* - recursive locking is not permitted
* - a mutex object must be initialized via the API
* - a mutex object must not be initialized via memset or copying
* - task may not exit with mutex held
* - memory areas where held locks reside must not be freed
* - held mutexes must not be reinitialized
* - mutexes may not be used in hardware or software interrupt
* contexts such as tasklets and timers
*
* These semantics are fully enforced when DEBUG_MUTEXES is
* enabled. Furthermore, besides enforcing the above rules, the mutex
* debugging code also implements a number of additional features
* that make lock debugging easier and faster:
*
* - uses symbolic names of mutexes, whenever they are printed in debug output
* - point-of-acquire tracking, symbolic lookup of function names
* - list of all locks held in the system, printout of them
* - owner tracking
* - detects self-recursing locks and prints out all relevant info
* - detects multi-task circular deadlocks and prints out all affected
* locks and tasks (and only those tasks)
*/
/*簡單,直接的互斥體與嚴格的語義:
*一次只能有一個任務持有互斥鎖
* -只有擁有者可以解鎖互斥鎖
* -不允許多次解鎖
* -不允許遞歸鎖定
* -互斥對象必須通過API初始化
* -互斥對象不能通過memset或復制來初始化
* -任務可能不退出互斥鎖持有
* -持有鎖所在的內存區域不能被釋放
* -不能重新初始化被持有的互斥對象互斥體不能用於硬件或軟件中斷
*上下文,如微線程和計時器**當DEBUG_MUTEXES被執行時,這些語義將被完全執行*
啟用。此外,除了執行上述規則外,互斥鎖還可以執行*調試代碼還實現了許多附加功能*使鎖調試更容易和更快:*
* -在調試輸出中打印互斥對象時,使用它們的符號名
* -獲取點跟蹤,函數名的符號查找
* -系統中所有鎖的清單,打印出來
* -業主追蹤檢測自遞歸鎖並打印出所有相關信息檢測多任務循環死鎖並打印出所有受影響的鎖和任務(僅限那些任務)
* /
struct mutex {
/* 1: unlocked, 0: locked, negative: locked, possible waiters */
atomic_t count;
spinlock_t wait_lock;
struct list_head wait_list;
#if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP)
struct thread_info *owner;
#endif
#ifdef CONFIG_DEBUG_MUTEXES
const char *name;
void *magic;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lockdep_map dep_map;
#endif
};
Linux的GPIO子系統解析 ( 一 )
/*
* Some platforms don't support the GPIO programming interface.
*
* In case some driver uses it anyway (it should normally have
* depended on GENERIC_GPIO), these routines help the compiler
* optimize out much GPIO-related code ... or trigger a runtime
* warning when something is wrongly called.
*/
/*
*有些平台不支持GPIO編程接口。
*如果一些驅動程序使用它(它通常應該依賴於GENERIC_GPIO),這些例程幫助編譯器優化出很多gpio相關的代碼…或者在錯誤調用某個東西時觸發運行時警告。
*/
static inline int gpio_is_valid(int number)
static inline int gpio_request(unsigned gpio, const char *label)
static inline void gpio_free(unsigned gpio)
static inline int gpio_direction_input(unsigned gpio)
static inline int gpio_direction_output(unsigned gpio, int value)
static inline int gpio_set_debounce(unsigned gpio, unsigned debounce)
static inline int gpio_get_value(unsigned gpio)
static inline void gpio_set_value(unsigned gpio, int value)
static inline int gpio_cansleep(unsigned gpio)
static inline int gpio_get_value_cansleep(unsigned gpio)
static inline void gpio_set_value_cansleep(unsigned gpio, int value)
static inline int gpio_export(unsigned gpio, bool direction_may_change)
static inline int gpio_export_link(struct device *dev, const char *name, unsigned gpio)
static inline int gpio_sysfs_set_active_low(unsigned gpio, int value)
static inline void gpio_unexport(unsigned gpio)
static inline int gpio_to_irq(unsigned gpio)
static inline int irq_to_gpio(unsigned irq)
/**
* wait_event_interruptible -在條件變為真之前休眠
* @wq:等待的隊列
* @condition:要等待的事件的C表達式
* 進程進入休眠狀態(TASK_INTERRUPTIBLE),直到@condition的計算結果為true或收到信號。
* 每次喚醒@wq等待隊列時都會檢查@condition。
* wake_up()必須在更改任何可能更改等待條件結果的變量之后調用。
* 如果被一個信號打斷,函數將返回-ERESTARTSYS;如果@condition被賦值為true,則返回0。
*/
#define wait_event_interruptible(wq, condition)
在amlogic芯片的I2C是在drivers/amlogic/i2c/aml_i2c.c中,不過名字為aml_i2c_xfer()。如下:
static const struct i2c_algorithm aml_i2c_algorithm = {
.master_xfer = aml_i2c_xfer,
.functionality = aml_i2c_func,
};
/*General i2c master transfer*/
static int mt7620_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
{
struct aml_i2c *i2c = &aml_i2c_ddata;
struct i2c_msg * p;
unsigned int i;
unsigned int ret=0;
spin_lock(&i2c->lock);
i2c->ops->xfer_prepare(i2c);
for (i = 0; !ret && i < num; i++)
{
p = &msgs[i];
i2c->msg_flags = p->flags;
ret = i2c->ops->do_address(i2c, p->addr, p->buf, p->flags & I2C_M_RD, p->len);
if (ret || !p->len)
continue;
if (p->flags & I2C_M_RD)
ret = i2c->ops->read(i2c, p->buf, p->len);
else
ret = i2c->ops->write(i2c, p->buf, p->len);
}
i2c->ops->stop(i2c);
spin_unlock(&i2c->lock);
if (p->flags & I2C_M_RD)
{
AML_I2C_DBG("read ");
}
else
{
AML_I2C_DBG("write ");
}
for(i=0;i<p->len;i++)
{
AML_I2C_DBG("%x-",*(p->buf)++);
}
AML_I2C_DBG("\n");
/* Return the number of messages processed, or the error code*/ ?
if (ret == 0)
return num;
else
{
printk("[aml_i2c_xfer] error ret = %d \t", ret);
printk( "i2c master %s current slave addr is 0x%x\n", i2c->master_no?"a":"b", i2c->cur_slave_addr);
return ret;
}
}
#(1)編譯子目錄
# 進入工程的根目錄,在shell中運行export TOPDIR=$(pwd)
# 然后直接make appl或者進入子目錄運行make
#(2)清除
# make clean 清除.o文件
# make distclean 清除.o和.d文件
問題1:函數的參數在傳輸過程中會出問題嗎?為什么總是出現Segmentation fault?
答:段錯誤,一般是出現野指針或對空指針的調用而出現的?。
所謂的段錯誤就是指訪問的內存超過了系統所給這個程序的內存空間,通常這個值是由gdtr來保存的,他是一個48位的寄存器,其中的32位是保存由它指向的gdt表,
后13位保存相應於gdt的下標,最后3位包括了程序是否在內存中以及程序的在cpu中的運行級別,指向的gdt是由以64位為一個單位的表,在這張表中就保存着程序運
行的代碼段以及數據段的起始地址以及相應的斷限和頁面交換還有程序運行級別和內存粒度等信息,一旦一個程序發生了越界訪問,CPU就會產生相應的異常保護,
於是segmentation fault就出現了。
即“當程序試圖訪問不被允許訪問的內存區域(比如,嘗試寫一塊屬於操作系統的內存),或以錯誤的類型訪問內存區域(比如,嘗試寫一塊只讀內存)。這個描述
是准確的。為了加深理解,我們再更加詳細的概括一下SIGSEGV。段錯誤應該就是訪問了不可訪問的內存,這個內存要么是不存在的,要么是受系統保護的。
Ø SIGSEGV是在訪問內存時發生的錯誤,它屬於內存管理的范疇
Ø SIGSEGV是一個用戶態的概念,是操作系統在用戶態程序錯誤訪問內存時所做出的處理。
Ø 當用戶態程序訪問(訪問表示讀、寫或執行)不允許訪問的內存時,產生SIGSEGV。
Ø 當用戶態程序以錯誤的方式訪問允許訪問的內存時,產生SIGSEGV。
用戶態程序地址空間,特指程序可以訪問的地址空間范圍。如果廣義的說,一個進程的地址空間應該包括內核空間部分,只是它不能訪問而已。
————————————————
版權聲明:本文為CSDN博主「喜歡戀着風」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/u010150046/article/details/77775114
問題2:明明在i2c.c中已經定義了mt7620_i2c_xfer()函數,且EXPORT_SYMBOL(mt7620_i2c_xfer)修飾,但是在執行ili2117.ko模塊時仍發生錯誤:
ili2117: Unknown symbol mt7620_i2c_xfer (err 0)
insmod: cannot insert 'ili2117.ko': Success
答:原因找到了,加載ili2117.ko模塊之前卸載了板子的所有驅動(包括i2c所在的ramips_mt7620模塊),因此必然出現“Unknown symbol mt7620_i2c_xfer”
錯誤。
問題3:目前的內核是否使用了Linux內核自帶的I2C/input子系統、設備樹?如何和奕力TP原廠的ILI2117_TP驅動對接起來?
答:都沒有,目前公司的系統里面,自定義了i2c驅動,且直接編譯進內核了,不過這個i2c功能比較簡單,只有i2c_read/i2c_write(),沒有比較豐富的
i2c操作函數(尤其i2c子系統常用的內核i2c-core.c中的一些函數,例如:i2c_transfer())。ILI2117_TP驅動的最底層是內核i2c_transfer()函數,而我們的
i2c驅動最底層是i2c_read/i2c_write(),通過查驗i2c_transfer()函數可知其到底是調用某CPU的master_i2c_xfer()函數。因此,在i2c.c文件中定義
mt7620_i2c_xfer()函數並實現其內部讀寫函數:
if (msgs[i].flags & I2C_M_RD) /* 2.讀數據 */
{
ret = do_master_read(&msgs[i]);
}
else /* 3.寫數據 */
{
ret = do_master_write(&msgs[i]);
}
的定義與實現。
備注:關於內核的I2C/input子系統、設備樹可以通過make menuconfig配置選項進系統。
問題4:為什么mt7620_i2c_xfer()函數名字改成i2c_transfer()時,且內部實現一致時,編譯時總是發生一些未知/莫名的錯誤?
答:不要定義和內核函數同名的函數,否則由於頭文件包含的原因,極易因調用混亂而產生錯誤。
問題5:ILI2117_TP持續修改測試方法
答:前言:由於TP和keys_leds的GPIO沖突,執行fv_drv.sh腳本,卸載所有驅動,然后重新加載fvdd/ramips_mt7620,在公司的i2c平台上實現i2c操作,
然后再加載ili2117.ko驅動並調試。
①每次修改前,先把之前的代碼復制一份(名字不用改動),然后再修改;
②用D:\shared_dir\driver_ts_20191230\fip11c\build目錄下的keys_leds.ko復制到D:\shared_dir\driver_tp_20200116\fip15\build目錄下;
③保持fv_drv.sh不變,不要刪除該文件(xx_OK.sh是目前可以滿足要求的腳本);
④下載fv_drv.sh到/tmp目錄,chmod 777 fv_drv.sh;
⑤./fv_drv.sh
⑥insmod fv_drv.sh
問題6:加載ili2117.ko之后,執行期間發生錯誤:
<4>*** ilitek_get_customer_firmware_version ***
<1>CPU 0 Unable to handle kernel paging request at virtual address 00000000, epc == 80013240, ra == 80013018
原因何在?
答:互斥鎖的原因,暫時關閉即可。
//mutex_lock(&ilitek_data->ilitek_mutex);
ret = ilitek_i2c_write_and_read(data, 1, 5, data, 4);
p_customer_fw_ver = kzalloc(sizeof(u8) * 11, GFP_KERNEL);
//mutex_unlock(&ilitek_data->ilitek_mutex);
找到原因了,互斥鎖沒有初始化。
=============
2020.02.16:
問題7:不管是報點協議A還是協議B,當發生觸點中斷時,從ILI2117上報SOC的報文格式是一樣的嗎?
或者說報文格式是什么樣的呢?
答:查看數據手冊《I2C Programming Guide(ILI2117A/ILI2118A )》——4.3. Data Report;
報點協議與獲得從從機ILI2117發送給SOC的報文沒有關系,與input上報給應用層的機制有關系。
問題8:坐標數據在報文中的什么位置?如何提取?可以完全繞開輸入子系統嗎?
坐標怎么計算?
答:
如果只是單純的得到觸點的數據坐標,那么只需要ilitek_i2c_read(buf, read_packet_len)之后讀取buf[]的數據即可,
ilitek_touch_down()和ilitek_touch_release()及其他input數據加工上報的函數,
將失去存在的意義。
坐標計算:
int X0= ((buf[1]>>4) & 0xf)<<8 + buf[2];
int Y0= ((buf[1]>>0) & 0xf)<<8 + buf[3];
int X1= ((buf[5]>>4) & 0xf)<<8 + buf[6];
int Y1= ((buf[5]>>0) & 0xf)<<8 + buf[7];
int X2= ((buf[9]>>4) & 0xf)<<8 + buf[10];
int Y2= ((buf[9]>>0) & 0xf)<<8 + buf[11];
#define TOUCH_SCREEN_X_MAX (480) /*LCD_WIDTH,默認值:1080*/
#define TOUCH_SCREEN_Y_MAX (272) /*LCD_HEIGHT,默認值:1920*/
問題9:TP中斷添加
答:
(0)復制最新修改的ilitek_mian.c文件為ilitek_mian_2020216.c
(1)查看上次編譯的ili2117.ko的時間,查出ilitek_main.c的源碼版本,重新編譯並查看TP信息讀取是否正確;
ili2117.ko:2月4日15:31; 選取ilitek_mian.c
(2)在上次編譯的基礎上添加中斷,並重新編譯;
問題10:關於中斷程序,是合並到ilitek_main.c文件中好還是仍保留到ilitek_touch_screen.c文件,是否具有可行性?優劣勢?
答:合並:可行,優勢:邏輯簡單;劣勢:文件更大了,程序可移植性變差了;
不合並:
問題:兩個文件的某些函數將相互調用,關於中斷的處理,將變得復雜;
問題11:已經基本實現中斷和報點,接下來需要做什么修改?
答:(1)報點函數,逐漸恢復其原來的功能;
(2)開啟線程;
(3)中斷多次上報問題; 也即上升/下降沿問題;
(4)如何與APP交接數據;
(5)文檔;(提前)
(6)4個虛擬鍵,沒有搞啊。
問題12:若在中斷處理中有調用I2C,則中斷中需要屏蔽中斷嗎?還用信號量可以嗎?
答:(1)應該不需要。
(2)不可以用信號量,否則可能造成休眠,且無法喚醒。
注:
①在中斷處理過程中,必須屏蔽中斷,否則系統運行會出現錯誤,這種說法正確嗎?
正確答案:B-不正確
解析:
CPU通過指令限制某些設備發出中斷請求,稱為屏蔽中斷。
從CPU要不要接收中斷即能不能限制某些中斷發生的角度 ,中斷可分為
可屏蔽中斷 :可被CPU通過指令限制某些設備發出中斷請求的中斷
不可屏蔽中斷:不允許屏蔽的中斷如電源掉電
②屏蔽中斷和關中斷的概念不一樣,屏蔽中斷是指不允許發生中斷,而關中斷是為了避免中斷寄存器的值被其他的中斷發生更改。
采用中斷屏蔽技術,會封鎖(與中斷屏蔽標志相對應的事件 )的響應;
③在中斷處理過程中,中斷屏蔽功能可以起______的作用。
A.設置中斷優先級
B.改變中斷優先級
C.增加中斷優先級
D.撤銷中斷優先級
正確答案:B
問題13:請教linux irq 中斷能使用mutex互斥鎖嗎?
答:spin lock 可以用在中斷處理程序用, 其他的 如信號量等是不行的,可能引起睡眠的函數都不能用在中斷里.
在中斷上下文中不能采用同步原語(信號量,管程、同步變量等)和長期互斥原語(這會導致進程睡眠), 而只能
采用短期互斥原語(例如自旋鎖)。
解析:在執行臨界區代碼(非中斷環境),獲取自旋鎖前,先屏蔽本地中斷,如此執行臨界區代碼時將不會有中斷發生。
否則,中斷響應后,處理函數執行到自旋鎖處時將自旋,等待該鎖重新可用,但是鎖的持有者在該中斷處理程序執行
完畢之前不可能運行,這就成為了雙重請求死鎖。
例:
spinlock_t i2c_lock=SPIN_LOCK_UNLOCKED; //或者DEFINE_SPINLOCK(i2c_lock);(include/linux/spinlock_types.h)
unsigned long flags;
spin_lock_irqsave(&i2c_lock, flags);
/*臨界區*/
spin_unlock_irqrestore(&i2c_lock, flags);
函數spin_lock_irqsave():保存中斷的當前狀態,禁止本地中斷,然后獲取指定的鎖。
函數spin_unlock_reqrestore():對指定的鎖解鎖,讓中斷恢復到加鎖前的狀態。所以即使中斷最初是被禁止的,代碼也不會錯誤地激活它們。
問題14:互斥量定義成全局還是靜態?
答:暫時全局吧。
問題15:read_proc的功能類似字符操作read函數,用什么方法傳輸信息到應用層?
對坐標數據以什么格式傳輸到應用層?
答:
方案1:用/proc節點文件保存觸點數據
(1)參考《linux設備驅動程序》第三版的第四章“調試技術”的‘/proc文件’一節:
(2)與伊工溝通,是直接把I2C傳輸過來的數據直接拷過去,還是重新處理之后再傳過去,如果處理該怎么處理?
答:方案1:ilitek_read_data_and_report()仍保留坐標和虛擬鍵的處理,並同時保存從ILI2117傳輸過來的數據
到全局靜態緩沖區report_buf[50];
方案2:研究網上的坐標上報案例;
問題16:問伊工,有沒有虛擬鍵,坐標范圍(即起始坐標和長寬);
答:有,坐標范圍未知。
問題17:cat /proc/ks_tp_report 命令問什么會造成多次proc_read操作?
答:proc_read函數:static int ilitek_tp_report_proc_read(char * buf, char **start, off_t offset, int count, int *eof, void *data);
proc_read函數的問題,若函數處理中,調用函數形參offset、count,則函數處理會出問題,造成無限打印。具體根本原因,尚未知。
例1:簡單led的/proc_read處理:
static int led_proc_read(char * buf, char **start, off_t offset, int count, int *eof, void *data)
{
if (count > 4)
count = 4;
memcpy(buf, "test", count);
*eof = 1;
return count;
}
例2:
static int temp = 0;
static ssize_t proc_read(char *buffer, char **buffer_location,off_t offset, int buffer_length, int *eof, void *data)
{
sprintf(buffer,"read ,demo temp is %d",temp);
printk(KERN_NOTICE "read ,demo temp is %d\n",temp);
return 0;
}
操作:
# insmod ili2117.ko
(進行觸摸屏點擊操作...)
# ls /proc/
... ks_tp_report
# cat /proc/ks_tp_report
<4>ilitek_tp_report_proc_read is here!
<4>--- start read ---
<4>--- read over ---
注:對於/proc節點文件,echo就是寫,cat就是讀操作。
問題18:ILI2117發給SOC的43字節報文中,那個手指觸點ID的排位規則是什么?按照時間嗎?
如果觸摸滑動只要手指不離開屏幕,無論做什么動作(橫向滑動/圓周滑動等),該手指的ID
是不是都不會變化?
答:ID0的資料只會放在byte1-byte3,ID1的資料只會放在byte5-byte7,不是按時間先后的,
你一直按着,ID是不會跳動的。
如果byte1-byte3都為0xff,ID0就為release,以此類推。
每個觸摸點都有一個ID,它是按照該觸摸點加入到觸摸動作中的順序來分配的。觸摸點的ID從用戶接觸觸摸屏開始到接觸釋放期間會保持不變。
當接觸點釋放時,與之關聯的觸摸點就不再屬於該觸摸動作的一部分了。
例如,如果使用兩根手指觸摸屏幕,分配給第一個觸摸點的ID就是1,分配給第二個接觸點的ID就是2。
如果第二根手指從觸摸屏離開,則只有觸摸點1仍然是該觸摸動作的一部分。
如果又有另外一根手指加入到該觸摸動作中,分配給新的觸摸點的ID是3,該觸摸動作此時有1和3兩個觸摸點。(存疑,實驗現象顯示,當第二個手指
離開后,該ID釋放,再有手指按下時,將仍分配ID2。若第三手指在第二手指未離開時按下,則分配ID3,即使手指2離開仍保持ID不變)
check_sum = p_msg[0] + ... + p_msg[41];
check_sum = (uint8_t) ((-check_sum) & 0xFF);
if (check_sum != buf[42]){ERROR!}
測試1:
動作:先放第一個手指Pnt[0],再放第二個手指Pnt[1],Pnt[1]水平向左滑動,
然后再放第三個手指Pnt[2],然后放開第二個手指Pnt[1]。
打印:
①先放第一個手指Pnt[0]
<4>Data Report: Pnt[0]=(228, 120)
<4> Data Report: release point counter = 9
②再放第二個手指Pnt[1],第二個手指Pnt[1]水平向左滑動
<4>Data Report: Pnt[0]=(227, 118)
<4> Data Report: Pnt[1]=(116, 130)
<4> Data Report: release point counter = 8
<4>Data Report: Pnt[0]=(226, 114)
<4> Data Report: Pnt[1]=(110, 135)
<4> Data Report: release point counter = 8
<4>Data Report: Pnt[0]=(225, 110)
<4> Data Report: Pnt[1]=(90, 147)
<4> Data Report: release point counter = 8
<4>Data Report: Pnt[0]=(225, 111)
<4> Data Report: Pnt[1]=(82, 151)
<4> Data Report: release point counter = 8
<4>Data Report: Pnt[0]=(225, 111)
<4> Data Report: Pnt[1]=(80, 153)
<4> Data Report: release point counter = 8
<4>Data Report: Pnt[0]=(225, 111)
<4> Data Report: Pnt[1]=(73, 158)
<4> Data Report: release point counter = 8
<4>Data Report: Pnt[0]=(225, 112)
<4> Data Report: Pnt[1]=(70, 159)
③再放第三個手指Pnt[2]
<4>Data Report: Pnt[0]=(224, 115)
<4> Data Report: Pnt[1]=(70, 159)
<4> Data Report: Pnt[2]=(368, 170)
<4> Data Report: release point counter = 7
④放開第二個手指Pnt[1]
<4>Data Report: Pnt[0]=(224, 117)
<4> Data Report: release point id = 1
<4>Data Report: Pnt[2]=(368, 170)
<4> Data Report: release point counter = 8
<4>Data Report: Pnt[0]=(224, 118)
<4> Data Report: Pnt[2]=(368, 170)
<4> Data Report: release point counter = 8
<4>*** ilitek_read_data_and_report ***
<4>Data Report: Pnt[0]=(224, 119)
<4> Data Report: release point id = 2
<4>Data Report: release point counter = 9
<4>*** ilitek_read_data_and_report ***
<4>Data Report: Pnt[0]=(223, 119)
<4> Data Report: release point counter = 9
測試2:手指1按下不動,手指2按下然后抬起,再然后手指3按下並抬起:
<4>Data Report: Pnt[0]=(368, 68)
<4> Data Report: release point counter = 9
<4>Data Report: Pnt[0]=(368, 68)
<4> Data Report: Pnt[1]=(115, 61)
<4> Data Report: release point counter = 8
<4>Data Report: Pnt[0]=(368, 68)
<4> Data Report: release point id = 1
<4>Data Report: release point counter = 9
...
<4>Data Report: Pnt[0]=(368, 68)
<4> Data Report: release point counter = 9
<4>Data Report: Pnt[0]=(368, 68)
<4> Data Report: Pnt[1]=(95, 253)
<4> Data Report: release point counter = 8
<4>Data Report: Pnt[0]=(368, 68)
<4> Data Report: release point id = 1
<4>Data Report: release point counter = 9
<4>Data Report: release point id = 0
<4>Data Report: release point counter = 10
問題19:觸摸屏支持的手勢和產生的事件類型
手勢 描述 產生的事件
旋轉 兩根手指做旋轉動作,一根手指繞另一根手指做順時針運動來讓該對象順時針旋轉,反之亦然。 · ROTATION_STARTED· ROTATE· ROTATION_FINISHED
滾動 滑動動作,向上或向下滑動來做豎直滾動,向左或向右滑動來做水平滾動 · SCROLL_STARTED· SCROLL· SCROLL_FINISHED如果用鼠標的滾輪來滾動,則只會產生SCROLL事件
輕掃 通過屏幕或者觸摸板向上、下、左、右方向的輕掃動作。對角線運動不會被識別為輕掃動作。 · SWIPE_LEFT· SWIPE_RIGHT· SWIPE_UP· SWIPE_DOWN
每個輕掃手勢只會生成一個輕掃事件,但也會生成SCROLL_STARTED、SCROLL和SCROLL_FINISHED事件。
縮放 兩支手指做捏的動作,捏合在一起表示縮小,分開表示放大。 · ZOOM_STARTED· ZOOM· ZOOM_FINISHED
測試:
cat /proc/kmsg &
voip.sh stop
rmmod alc5621d
rmmod ramips_mt7620
rmmod fvdd
rmmod keys_leds
rmmod nand_lcd_notdma_fip11c
cd /tmp
tftp -g -l ili2117.ko 192.168.1.88
或者
cat /proc/kmsg &
voip.sh stop
cd /tmp
tftp -g -l fv_drv.sh 192.168.1.88
chmod 777 fv_drv.sh
tftp -g -l ili2117.ko 192.168.1.88
./fv_drv.sh
insmod ili2117.ko
打印如下:
<4>Enter ilitek_i2c_transfer: @@@@@@@
<4>mt7620_i2c_xfer:@@@@@@@
<4>do_master_write:@@@@@@@
<4>do_master_write: msgs->addr = 62
<6> ILITEK INFO line = 1150 ilitek_get_chip_type : ----------------------ILI Chip Type=0x2117-------------------------
<4>Enter ilitek_i2c_write_and_read: delay>0:*****
<4>Enter ilitek_i2c_transfer: @@@@@@@
<4>mt7620_i2c_xfer:@@@@@@@
<4>do_master_write:@@@@@@@
<4>do_master_write: msgs->addr = 62
<4>Enter ilitek_i2c_transfer: @@@@@@@
<4>mt7620_i2c_xfer:@@@@@@@
<4>do_master_read:@@@@@@@
<4>do_master_write: msgs->addr = 62
<6> ILITEK INFO line = 1153 ilitek_get_chip_type : ----------------------ILI Chip Type=0xbf-------------------------
<4>Enter ilitek_i2c_transfer: @@@@@@@
<4>mt7620_i2c_xfer:@@@@@@@
<4>do_master_write:@@@@@@@
<4>do_master_write: msgs->addr = 62
<4>Enter ilitek_i2c_transfer: @@@@@@@
<4>mt7620_i2c_xfer:@@@@@@@
<4>do_master_write:@@@@@@@
<4>do_master_write: msgs->addr = 62
<4>Enter ilitek_i2c_transfer: @@@@@@@
<4>mt7620_i2c_xfer:@@@@@@@
<4>do_master_write:@@@@@@@
<4>do_master_write: msgs->addr = 62
<4>*** ilitek_reset ***
<6> ILITEK INFO line = 275 ilitek_reset : delay = 150
<4>ilitek_reset: RALINK_REG_PIODATA = 0x1a0780
<4>ilitek_reset: RALINK_REG_PIODATA = 0x120780
<4>*** ilitek_get_platform_firmware_version ***
<4>*** ilitek_i2c_write_and_read ***
<4>Enter ilitek_i2c_write_and_read: delay>0:*****
<4>Enter ilitek_i2c_transfer: @@@@@@@
<4>mt7620_i2c_xfer:@@@@@@@
<4>do_master_write:@@@@@@@
<4>do_master_write: msgs->addr = 0x26
<4>Enter ilitek_i2c_transfer: @@@@@@@
<4>mt7620_i2c_xfer:@@@@@@@
<4>do_master_read:@@@@@@@
<4>do_master_write: msgs->addr = 0x26
<4>*** ilitek_get_platform_firmware_version ***after lock
<6> ILITEK INFO line = 1193 ilitek_get_platform_firmware_version : platform_firmware 0x56.0x30.0x31.0x2e.0x30.0x31.0x32.0x2e.0x30.0x34
<6> ILITEK INFO line = 1194 ilitek_get_platform_firmware_version : Platform_firmware = V01.012.04
<4>*** ilitek_get_customer_firmware_version ***
<4>*** ilitek_i2c_write_and_read ***
<4>Enter ilitek_i2c_write_and_read: delay>0:*****
<4>Enter ilitek_i2c_transfer: @@@@@@@
<4>mt7620_i2c_xfer:@@@@@@@
<4>do_master_write:@@@@@@@
<4>do_master_write: msgs->addr = 0x26
<4>Enter ilitek_i2c_transfer: @@@@@@@
<4>mt7620_i2c_xfer:@@@@@@@
<4>do_master_read:@@@@@@@
<4>do_master_write: msgs->addr = 0x26
<6> ILITEK INFO line = 1235 ilitek_get_customer_firmware_version : Customer_ver Major = 1, Minor = 0.0, _gFwVersion = 00000.00000
<4>*** ilitek_get_pannel_info ***
<4>*** ilitek_i2c_write_and_read ***
<4>Enter ilitek_i2c_write_and_read: delay>0:*****
<4>Enter ilitek_i2c_transfer: @@@@@@@
<4>mt7620_i2c_xfer:@@@@@@@
<4>do_master_write:@@@@@@@
<4>do_master_write: msgs->addr = 0x26
<4>Enter ilitek_i2c_transfer: @@@@@@@
<4>mt7620_i2c_xfer:@@@@@@@
<4>do_master_read:@@@@@@@
<4>do_master_write: msgs->addr = 0x26
<6> ILITEK INFO line = 1279 ilitek_get_pannel_info : Resolution(2048, 2048)
<6> ILITEK INFO line = 224 ilitek_touch_driver_init : add touch device driver i2c driver.
#
------------------------------------在FIP15固件基礎上調試------------------------------------
ili2117.ko加載失敗原因
1.原來的加載環境是FIP13/14的固件環境:
16M固件:FIP13_FVUI_V0.2.2_201912231525_T_v1.1.16M
固件:C:\Users\whwuh\Desktop\工作-個人\4.LCD\7__觸摸屏驅動設計\FVUI_V0.2.2_202001141610_T.bin
2.現在是FIP15.bin的環境
上報打印格式:
tpevent=point:%d,pressure:%d,x:%d,y:%d
測試:
1.讀點坐標是否准確, 是
2.坐標數據是否及時更新, 是
3.多點觸摸上報
答:未解決,打算用二維字符數組buf[10][]存儲一次上報的多點數據;
4.抬起狀態打印
答:正在解決;
5.觸摸屏分辨率的問題
答:
6.觸屏的隊列/線程?
二、問題
問題1:手指狀態檢測 與 按下/抬起上報和打印
加載ili2117.ko驅動,打印:
<4>[ 1774.768000] *** ilitek_get_pannel_info ***
<4>[ 1774.772000] use LCM resolution(480, 272)
<4>[ 1774.776000] Data Report: Pnt[0]=(0, 0)
<4>[ 1774.776000] Data Report: Pnt[1]=(0, 0)
<4>[ 1774.776000] Data Report: Pnt[2]=(0, 0)
<4>[ 1774.776000] Data Report: Pnt[3]=(0, 0)
<4>[ 1774.776000] Data Report: Pnt[4]=(0, 0)
<4>[ 1774.776000] Data Report: Pnt[5]=(0, 0)
<4>[ 1774.776000] Data Report: Pnt[6]=(0, 0)
<4>[ 1774.776000] Data Report: Pnt[7]=(0, 0)
<4>[ 1774.776000] Data Report: Pnt[8]=(0, 0)
<4>[ 1774.776000] Data Report: Pnt[9]=(0, 0)
由此可以判定,
ilitek_read_data_and_report()
static int ilitek_touch_release(int id)
if (ilitek_data->touch_flag[id] == 1)
DBG("Data Report: release point id = %d\n", id);
復位TP之后,所有觸點的ilitek_data->touch_flag[id]的初值都是1!
但是對於經過“4.1 該手指抬起”檢測后,所有已經抬起手指的touch_flag[i]都將歸0:
if ((buf[(point_len * i) + data_shift] == 0xFF) && (buf[(point_len * i) + data_shift + 1] == 0xFF)
&& (buf[(point_len * i) + data_shift + 2] == 0xFF))
{
release_point++; /*沒有按下,則表明這個手指已經抬起*/
#ifdef ILITEK_TOUCH_PROTOCOL_B
ilitek_touch_release(i); /*報告手指抬起*/
#endif
continue;
}
因此,后面的“所有手指抬起”檢測程序,由於touch_flag[i]都將歸0,將沒有任何打印:
if (release_point == report_max_point)
{
if (ilitek_data->touch_before_suspend == 0)
{
if (ilitek_data->is_touched){
ilitek_touch_release_all_point();
}
ilitek_check_key_release(x, y, 0);
ilitek_data->is_touched = false;
問題2:出現一次,點擊一次觸屏后,屏幕連續刷幾十條消息,原因未知;
<4>[ 2592.484000] Data Report: Pnt[0]=(271, 58)
<4>[ 2592.500000] Data Report: Pnt[1]=(344, 47)
<4>[ 2592.500000] Data Report: Pnt[2]=(111, 27)
<4>[ 2592.500000] Data Report: Pnt[0]=(267, 49)
<4>[ 2592.516000] Data Report: Pnt[1]=(344, 47)
<4>[ 2592.516000] Data Report: Pnt[2]=(111, 27)
答:廠家說,你是靠中斷觸發還是單純的polling?如果中斷觸發,那你可以能要設旗標等報點處理完才能
繼續處理中斷觸發,旗標沒有舉起來以前都不要處理中斷觸發。
問題2:對於/proc/ks_tp_report接口文件,
(1)如果在執行cat /proc/ks_tp_report命令前,連續進行多次觸摸操作,則接口上報的坐標,
也即,ilitek_tp_report_proc_read()函數執行,
將是多行多觸點上報還是僅是最后一次觸點的上報?
(2)如果xx_proc_read()是由線程自動執行,如TP中斷喚醒該線程,則在執行cat /proc/ks_tp_report
命令前,
注:對/proc/ks_xx接口文件的讀/寫操作:
寫:
命令>
echo bmp_file_begin > /proc/ks_lcd_bmp
cat /tmp/bg0_dark.bmp > /proc/ks_lcd_bmp
echo bmp_file_end > /proc/ks_lcd_bmp
執行函數>
xx_proc_write();
讀:
命令>
cat /proc/ks_tp_report
執行函數:
ilitek_tp_report_proc_read();
也就是說,執行一次echo/cat命令,將執行一次xx_proc_write()/xx_proc_read()函數?
答1:應該是最后一次觸點上報。