----------- 使 串口在進入idle后繼續輸出log ------------
默認是不能的, 只要下面的, 就能不斷的輸出串口log:
adb shell
setprop persist.uartconsole.enable 1
串口線標准不一樣, 有一根串口線能打出 feature phone的串口數據。 但6795的數據就打不出來。 有1.8伏的,和2.8伏的。要確定串口線用的對不對。 里面是轉換芯片的。
--------------------------- 串口芯片, 配置, 使用 ---------------
串口芯片集成到了主芯片內部, 串口芯片一般包括, 接收緩沖區, 發送緩沖區. 這是硬件緩沖區. 主芯片一般有三條串口線, 就像可以有多條i2c總線.
相應的gpio可以選擇配置成串口, 並不是每個gpio都能配置成串口, 從gpio配置表dws文件, 可以看到gpio是否支持串口模式.
從feature phone調試來看, 串口只能被一個模塊使用, 可以用setowner函數來切換被哪個模塊使用. 有一個nv項會決定, 串口給哪個模塊用.
每次串口在接收到數據時, 都會發送串口消息, 在feature phone中, 消息中都會指定發給哪個task. task中都會有一個循環, 來接收task. 循環中會相應的receive函數, 接收消息, 如果沒消息過來, 則會阻塞.
實際中遇到的問題:
1. 在打開串口時, 本來要打開串口1, 而打開了串口3, 結果Task循環中, 一直沒收到消息.
2. 配置串口時, 沒調setowner, 導致open串口時指定的模塊, 與串口的owner不一致, 導致電流一直在巨大跳變. 一插上usb, 電腦的services進程占用40%
3. uart_getbytes函數的指定的軟件緩沖區length大小為0, 導致硬件緩沖區的數據沒有被接收, 串口驅動的接收標志沒有被置位,
導致下一次串口接收數據時, 沒有發串口消息. 把length改大即可.
4. 串口的owner切換, 默認配置的是給at模塊用. 為了給2502傳送數據, 添加一個at命令, 完成模塊切換. 即將串口由at模塊轉給自定義的task模塊.
5. task 配置, 在hal_task_config.h配置, 編譯不過. 要在app_task_config.h配置, task所做的事情, 應該都屬於mmi層. 對應linux, 應該是串口用戶空間編程.
6. 因持續收到的串口消息沒有釋放, 導致收到第600個左右的字節時, 系統掛掉.
先說一下消息的一般機制:
java, c, c++, 消息架構都是, 消息對象里都會指定消息的接收者, 消息的接收者, 一般都是一個循環,
循環里有個函數會等待消息, 如果消息沒來, 就會阻塞在那, 如果消息過來, 才會繼續執行.
mtk Task接收uart消息, 就是使用這個機制.
串口有數據發來, 就會有個串口消息發出來, 通過對串口設置owner, 即該task的mod id, 這樣對消息體里id就指定這個task. 消息發送這個task.
task while 循環接收到消息, 實際接收的消息的對象, 一般的機制都是由接收者來釋放這個消息在內存中申請的空間.
若沒有釋放, 這里碰到一個問題, 由於空間不斷泄漏, 到收到第600多個字節, 消息對象數量不斷增多, 泄漏的內存不斷增大, 導致系統掛住.
串口工具有時at命令無響應, 串口工具重新打開就好
------------------ cts rts配置 -----------------
解釋cts/rts流控,要從接收緩沖區說起. 當初遇到了什么問題, 而想出了這個東西.
流控是為了接收緩沖區沒有准備好, 發送方還在發數據的問題, 數據丟失的問題.
解決的辦法, 就是多連一條線, 接收方通過控制這根線的高低電平, 來告訴發送方, 接收緩沖區是否准備好.
接收緩沖區如果沒准備好, 會把這根線拉高, 如果准備好, 就把這根線拉低.
從術語上講, 這根線在rx這邊, 對應引腳是rts, 在tx那邊, 接引腳cts. 在數據沒准備好時, rts拉低. 默認rts配置成內部拉高.
接線:
rx要接到對方的tx, tx要接到對方的rx. 在調ble與2502通訊時, ble要配成與2502相反.
rts要接到對方的cts. rts電位由接收方控制.
通過控制電平, 通知對方:
當接收方還沒准備好, 接收方會把rts拉高, 即發送方的cts被拉高, 這樣發送方就知道接收發沒有准備好, 就不發送了.
當接收方准備好時, 接收方會把rts拉低, 即發送方的cts被拉低, 這樣發送方就知道接收發准備好, 就發送數據.
gpio配置:
從Datashee可確認, 打開dws, 可看到支持硬件流控的gpio. 2502只有兩個gpio支持硬件流控, 從gpio選項中可確認.
測試硬件是否起作用:
對於ble與2502, 因為2502給ble發送大數據, ble是接收方, 所以rts信號由接收方控制, 這就是ble支持硬件流控. 而2502的cts收到這個信號, 能不發送數據, 說明2502也支持硬件流控.
分包大小要受對方緩沖區限制, 最大不能超過對方接收緩沖區.
-------------------- 反接, 看另一方數據 --------------------
uart , 串口線的白線接到板子上的Tx, 即接到板子的發she點, 即看板子的串口輸出信息.
ble到2502的串口總線, 引出的tx, rx測試點, 是以2502來命名的,
如果想接收2502的串口發出信息, 就接點tx點.
如果想看ble的串口發出發出信息, 就接到rx點.
調試時經常要看ble的發出信息. 所以uart反接一下.
一語擊中要點, 又不賣nong.
可以從插頭, 直接引出針來.
修行需要積點滴以成大海的yi力
----- 串口速率 ---------
串口傳輸速率, 50K, 20K分別對應哪個檔. 115200 對應多少. 除以8, 得14402, 即15K. 是吧
串口傳輸速率有兩種表示方法, 一種bps, 如115200. 一種是KBps, 一般一個數據占8位. 所以115200對應的是14.4KBps. 理論上每秒傳14K. 傳輸速率是否受接收方的限制.
---------- 協調串口數據傳輸的信號線 ----------------
uart可以有18根信號線, unix環境只用了6根.
GND - Logic Ground 地線, 提供了一個參考電壓, 基於這個參考電壓, 有兩種電壓, space電壓, mark電壓.
TXD - Transmitted Data發送信號線
RXD - Received Data接收信號線
DCD - Data Carrier Detect表示另一端已經連接好的信號線, space電壓表示另一端已經連接, mark電壓表示沒准備好
DTR - Data Terminal Ready表示另一端是否已經准備好的信號線, space電壓表示已經准備好
CTS - Clear To Send space電壓表示本地這端可以送出更多數據
RTS - Request To Send space電壓表示本地已經准備好了數據可以傳送.
以后再看到這些字母就不犯迷糊了. 這些信號線都是來協調數據傳送的, 就是為了給你百分之百的保證. 才有了這么多信號線.
芯片從串行總線接到數據, 數據都是一個字節一個字節傳送的, 必須知道字節的開始位置, 與結束位置.
串行線在沒有數據傳送時, 都是mark電壓.
在變到space電壓, 說明有數據來了,
每個字節前都有一個space電壓的start位, 表示字節的開始
在每個字節的最后都一個parity校驗位, 和一個停止位.
數據一般表示為8N1, 表示8個數據位, 無校驗位, 有一個停止位.
7E1 表示7個數據位, Even偶數校驗位, 和一個停止位.
-------------
雙工之雙字,就表示雙向, 接收與發送兩個方向
全雙工, 就是同一時刻, 可以同時接收與發送數據, 一個發送線, 一個接收線
半雙工, 在同一時刻, 只能發送, 或只能接收.
----------------
為了協調串行數據流, 有軟件和硬件兩種方法,
軟件方式即是用特殊字符來開始或結束數據流, 這些特殊字符有: 開始的有XON, DC1, 結束的有XOFF, DC3.
硬件方式, 接收方准備好時, 將CTS置為space電壓, 沒有准備好就置為mark電壓. 這樣發送方就知道可以發送數據了. CLEAR to send, 即告訴發送方可以發送了.
發送方准備好時, 將RTS置為space電壓, 這樣接收方就知道可以接收數據了. Request to send, 即發送請求發送數據, 讓接收方接收.
這就是CTS/RTS通知機制.
有數據正在傳輸時, 接收信號線和發送信號線, 都會保持在mark電壓. 如果傳着傳着, 從mark電壓掉到space電壓, 並且持續了1/4秒, 說明傳輸break了, 這時break條件就存在了.
break一般被用來重置數據線.
--------------- 串口線 -------------
串口線的地線是必須連接的, 若只看log, 則只連tx和地線, tx對應白線. 若要通過串口發at命令, 則要tx, rx, 地線三根線.
電源引出的線有可能燒掉, 用萬用表量一下電阻, 正常的會有一個值.
2502引出的uart1, 與藍牙通信, 接收藍牙發來的At命令, (應該是字節), 然后2502向藍牙通過串返回數據.
-------------- 串口log --------------------
串口線的發送或接收, 都是基於板子命名的, 串口數據從板子出去的, 就叫發送。 串口線里面,有一條線專門是發送的, 這條線叫發送線, 原理圖上的焊點叫tx。
t (transmit)表示發送,從板子到電腦,
r (receive)接收,從電腦到板子,接收電腦發來的命令。
原理圖上有注釋,uar1 for ap log, 從原理圖對應的pcb圖上找到測試的uart點。
串口線里有個轉喚器, 白色線表示發送, 綠色線表示接收,黑線表示接地。 一般看串口log, 只用發送,即只連白線與黑線。 如果黑線接到了rx上,即接收點,串口log就是亂碼。
lk傳過disable_uart參數決定了,串口是否吐log. 如果lk后面的階段,如kernel, recover模式,如果不吐log. 就要檢查這個參數。
串口如果想吐android log, 就必須在命令行下,輸入logcat。 如果沒有這個命令, 串口是不會吐android log 的。
串口可以看到初始化log, preloader, lk, 內核的,串口日志是非常需要的。usb無法看到初始化日志。
pcb一般只選pads, vias兩項, 從sch對應找到pcb鍾的測試點
需要一個usb轉串口驅動的軟件,如果環境變量有修改,這個軟件就安裝失敗。
用secureCRT看串口log輸出:
從設備管理器上,找到端口,這里10
連接速率選最大,其它默認
如果有光標,說明連上了,可以看串口log了。
------------- 將串口注冊為一個終端 ------------
tty_io.c 注冊tty設備
uart0:ap 側log
uart1: modem側log
如果不接rx拿掉,則無此問題
終端是與外部與計算機交互的一個窗口
------------------------
pty是虛擬終端,
pts, ptmx是pty的實現
每打開一個終端, /dev/pts/ 下就有一個文件
先從外部特性認識一下
一個串口(串行端口),就是一個終端,對應/dev/ttySn
在圖形界面下,打開終端實際是打開依終端,對應/dev/pts/ 下面的一個文件,可以打開終端,看一下pts目錄下多了一個文件。
用echo "1" > /dev/pts/n 可以看到終端下面出現相應字符。
查看當前終端, 用tty, 如可看到/dev/pts/2
對於/dev/console, 只有單用戶模式下,才可登錄到控制台
用who, 可看到打開了多少個虛擬終端。
/dev/tty始終代表當前終端,如果當前終端為/dev/pts/2, 則/dev/tty/就代表/dev/pts/2
echo "1" > /dev/tty等同於 echo "1" > /dev/pts/2
ps -aux 的TTY列,顯示在哪個終端上運行
再從代碼上分析實現:
從上層到驅動層:
tty_io.c read
線路層:tty_ldisc.c read 等待隊列機制進入睡眠
驅動層:以串口為例,則應為 serial_core.c
fs_initcall與module_initcall, 都是define_initcall宏函數,被放在vmlinux.lds.s鏈接腳本的INIT_CALLS宏指定的init段中,該宏在vmlinux.lds.h中定義。
調用過程: start_kernel-> init-> init線程函數調用do_initcalls來調用這些init函數。
字符設備初始化(drivers/char/mem.c)主要就是tty初始化,chr_dev_init->tty_init,完成tty設備初始化,總算看到字符設備的應用示例了, 設備初始化一定會創建設備模型,
--------------------
串口線中:白線為tx, 即發送線。 綠線為rx. 即接收線。
接上rx線,不會有機器掛掉的問題,把軟件重新firmware upgrade一下,就解決休眠后掛掉的問題,
用rx,向機器發送命令,需要機器亮屏,可使用tab鍵,在usb線不夠用,或usb口不能用時,用rx串口, 一樣看到adb shell所能看到的文件信息,調用otg,usb被占用,這時用串最合適。
若想看log, 可以直接aee -k 6就顯示log.
選中后,可以直接查找
control+f 進入debug模式, 這個模式能看到arm各寄存器的值,中斷號信息,
開機初始化log只能看串口,因為adb shell就內核完全啟動后的用戶空間的一個進程,所以adb shell 看不到內核初始化的log, 這包括各個驅動的probe初始化log. mtk log建立在文件系統上,所以也沒有內核初始化log.
preloader lk 內核初始化log都可通過串口看到。
有亂碼時,重啟secure uart就好了。
----------- 串行總線基本原理 -------------
RS-232是串行總線標准.該總線按位傳送.
串行總線由發送線tx,接收線rx,地線組成.
發送線在發送的同時,接收線可以接收,即異步通信
波特率是每秒傳送的位數.單位是bps. 一般一個字符有10位,1個起始位.1個結束位,8個數據位. 每秒字符數(即信息包數,一個信息包含一個字符)乘上字符的位數,即是波特率.
數據位,一個信息包有一個開始位,一個結束位.數據位有的7位,有的是8位.這個要根據協議確定.
停止位一方面表示一個信息包的結束,一方面提供校正同步時鍾
校驗用奇偶校驗.如果是偶校驗,數據1的個數為偶數,校驗位就為0. 可以判斷是否有噪聲干擾了信號.
uart連接的串行設備, i2c連接的並行設備.
uart一般用於計算機與外部設備的通信,如鍵盤等. i2c一般用於內部模塊通信.sensor都是用i2c. gps, 藍牙等射頻相關的都走串口.
顯示器也用串口,有9針串口, 也有25針串口.
所謂協議,接收方與發送方確定,一個信息包的每個位表示的含義.雙方對此的理解必須是一致的.
接收過程:由波特率和接收時鍾,確定每一位的時間長度.
當信號線從1跳到0,表示開始接收.
一偵一幀的接收. 在一幀之內,用時鍾確定接收特定的位.
每隔8個時鍾,來接收一位.
把數據放到寄存器中,在發送時鍾的控制下,將寄存器的數據移位輸出.
在接收端,在接收上升沿的那個時刻,對數據采樣,把數據放到移位寄存器中,組成並行數據取出.
波特率是一秒鍾發送的位數.波特率因子發送或接收一個數據位需要的時鍾數.
顯示屏25針的串口有4條數據線,11條控制線,其余備用線.
-----------------------------
串口也可以同步通訊, 這時需要多出一個時鍾線, 因為同步通訊需要硬件上額外支持, 一般不用同步通訊.
訪問串口設備文件的方法:
改變串口設備文件的權限, 以讓一般程序可以訪問
一切皆是文件, 打開串口設備, 就中打開這個文件, 即
open("/dev/ttyS0", );
進程打開一個串口設備, 默認,進程就是這個串口設備的終端, 控制終端, 串口設備上的信號都會影響這個進程, 如ctrl+C這個信號就會終止這個進程.
如果不想接收這個串口的信號, 使進程不成為這個串口的終端, 就不會收到串口的信號了. 用O_NOCTTY.
如果進程不關心另一端是否連接, 即不關心dcd信號的狀態, 就用O_NODELAY.
向串口可以寫入數據, 發at命令就是寫數據, 用write系統調用.
從串口讀數據, 就是從串口緩沖區上讀數據, 如果得不到數據, read就不返回.
如果想讓read立即返回, 就要用fcntl設置一下, fcntl(fd, F_SETFL, FNDELAY);
關閉串口, 直接關閉這個設備文件即可, 就會將dtr信號拉低.
CLOCAL與CREAD, 保證程序不會成為端口的所有者, 所有者必須處理各種信號.
options.c_cflag |= (CLOCAL | CREAD);
控制選項還可設置奇偶校驗.
沒有奇偶校驗:
options.c_cflag &= ~PARENB
options.c_cflag &= ~CSTOPB
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
奇數校驗:
options.c_cflag |= PARENB // 使能校驗位 options.c_cflag &= ~PARODD options.c_cflag &= ~CSTOPB options.c_cflag &= ~CSIZE; options.c_cflag |= CS7;
即c_cflag設置成7E1
偶數校驗:
options.c_cflag |= PARENB
options.c_cflag |= PARODD
options.c_cflag &= ~CSTOPB
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS7;
即c_cflag設置成7O1
控制選項中設置了奇偶校驗, 在輸入選項就要把奇偶項剝去, 設置為:
options.c_iflag |= (INPCK | ISTRIP);
如果發生了奇偶校驗錯誤, DEL字符和NUL字符和出錯的字符一起發出.
如果打開了使能了奇偶校驗, 又要做一些特別試驗, 如在發生奇偶校驗錯誤, 也要忽略, 放行數據, 可用
options.c_iflag |=IGNPAR;
這時只有NUL字符送出
如果硬件上支持cts/rts, 就要設置:
options.c_cflag |= CNEW_RTSCTS
如果不支持:
options.c_cflag &= ~CNEW_RTSCTS;
舊的接口沒有c_ispeed,和c_ospeed兩個成員. 所以就用了CBAUD,B9600等波特率常數
常量TCSANOW標志所有改變必須立刻生效而不用等到數據傳輸結束
tcsetattr 可以設置的有:
TCSANOW標志所有改變必須立刻生效而不用等到數據傳輸結束
TCSADRAIN 等待傳輸完之后再生效.
串口連接兩台機器, 波特率應為兩個中較小的那個.
設置一個字符大小:
options.c_flag &= ~CSIZE;
options.c_flag |= CS8; 也可以CS8.
--------------------------
------------------------
