1. 程式人生 > >Imx8串列埠故障案例分析

Imx8串列埠故障案例分析

        最近解決一故障——在imx8qxp單板按“上下鍵”或者貼上較長命令均會導致系統宕機。最後查出來是驅動移植問題。在此做下記錄,免得以後忘記,也對以後有類似串列埠問題提供一個參考。

        故障描述已經比較清楚,只出現在imx8qxp單板,所以跟單板是有關係的。只在“上下鍵”或其他功能鍵如“HOME、END”等以及貼上較長命令情況下出現,而其他普通輸入按鍵沒有問題,可以從這幾個功能鍵的差異入手。

        網上查閱資料發現這幾個按鍵都是由一連串字元組成的,不單單是一個ASCII鍵值,程式段例項如下:

case KEY_CURSOR_UP:       hit |= add("\033[A"); break;

case KEY_CURSOR_DOWN:   hit |= add("\033[B"); break;

case KEY_CURSOR_LEFT:     hit |= add("\033[D"); break;

case KEY_CURSOR_RIGHT:    hit |= add("\033[C"); break;

case KEY_CURSOR_HOME:    hit |= add("\033[1~"); break;

case KEY_CURSOR_END:      hit |= add("\033[4~"); break;

case KEY_PAGE_UP:          hit |= add("\033[5~"); break;

case KEY_PAGE_DOWN:       hit |= add("\033[6~"); break;

case KEY_INSERT:            hit |= add("\033[2~"); break;

case KEY_DELETE:           hit |= add("\033[3~"); break;

case KEY_F1:                hit |= add("\033OP"); break;

       其中‘\033’就是ESC,所以“UP鍵”就由ESC、[、A三個字元組成,也就是你在串列埠終端敲擊一個“UP鍵”,實際上是同時送給串列埠三個字元‘ESC’、‘[’、‘A’。

        在程式中打點除錯,發現每當按下“UP鍵”時,串列埠驅動程式只能收到‘ESC’、‘[’字元,第三個字元怎麼也收不到,更糟糕的是後續所有按鍵都會丟失。整個串列埠模組處於“假死”狀態。為什麼說“假死”,是因為我的整個功能模組是正常執行的,列印這些都是正常的,只是按鍵沒有反應,也就是讀不到鍵值,串列埠中斷都可以正常的收到。

        對比linux驅動,發現imx8系列都用同一個驅動程式,路徑在drivers/tty/serial/fsl_lpuart.c。在初始化流程中會對串列埠的讀寫中斷、FIFO、DMA以及WATERMASK等功能進行設定。我們的系統中為簡單起見並沒有使能FIFO、DMA及WATERMASK等功能,只用其來實現簡單的按鍵收發而已。我們的初始化流程也並沒有問題。

        無賴只能將串列埠所涉及的暫存器打出來對比,看正常情況和“假死”情況狀態暫存器能不能給出一些提示。果然,打暫存器才是發現硬體故障的核心手段。“假死”情況狀態暫存器中設定了一個“OR”標誌位。手冊中對這個標誌位是這樣描述的:

       注意其中高亮顯示的那句話——當ORflag被置位時,即使資料快取中有足夠的空間,也不會有資料往裡面存。

       難怪後面的按鍵都沒有反應,原來是OR這個標誌被置位了。那什麼情況下,OR標誌位會被置位呢?上圖中也給出了描述,就是接收資料的暫存器溢位了。

       回想下故障現象,“UP鍵”會同時給出3個字元、貼上較長命令也相當於同時傳送了較多字元,這讓預設只有一個字元的資料暫存器怎麼來得急接收。

       找到問題之後,果斷將linux中的使能FIFO功能的程式段copy過來,驗證一下,OK,問題得到解決。本來還想在OR標誌被置位後,來個清除處理的,後來看linux貌似也沒有處理,只是將overrun計數器進行了++操作,也就作罷。本來一旦出現OR標誌,即使清楚了對後續串列埠輸入不會有影響,但丟失的資料還是找不回來,而且還會隱藏故障現象。那就這麼地吧。