)
前陣子把一塊 7 寸串口觸摸屏接到 ARM Linux 主板上時我以為這個活半小時就能搞定。畢竟板子內核里已經帶了 8250 串口驅動屏幕模塊自己也有觸摸功能接上 UART 之后無非就是在應用層發(fā)指令、讀坐標。結果真正調起來才發(fā)現(xiàn)Linux 下做串口屏和單片機上完全是兩碼事。設備樹里串口引腳的 pinctrl 沒配好觸摸坐標上報到 Linux 輸入子系統(tǒng)之后的映射關系也是錯的跑一會兒還會丟字節(jié)。折騰了兩三天最后問題基本都在內核配置和輸入子系統(tǒng)接入方式上反而屏幕本身沒出什么幺蛾子。這次就把我做 Linux 串口觸摸屏的完整設計和排錯過程總結一下給后面要做類似方案的朋友一個參考。主題圍繞 Linux 內核如何正確支持串口屏、串口觸摸數(shù)據(jù)怎么變成標準 Linux 輸入事件以及這個過程中容易踩到的各種坑。1. 串口屏項目的技術邊界Linux下不是“接上就能用”1.1 串口屏與普通LCD的本質差異很多人剛接觸串口屏時會有一個思維慣性覺得屏幕就是顯示設備要么走 HDMI、要么走 RGB/MIPI最多再加個 I2C 觸摸芯片。但串口屏的原理完全不同。它本身就是一塊帶 MCU 的獨立顯示模組內部有自己的顯存、字庫和控件庫主控只需要通過串口發(fā)一條“顯示一張圖”“設置某個文本控件”之類的指令剩下的渲染工作全部在屏幕內部完成。這帶來一個非常大的好處Linux 側不需要維護 framebuffer也不需要關心分辨率、刷新率、圖層疊加這些復雜功能。整個過程看起來就是“打開一個串口設備往里寫指令再讀取返回”。但也正因為如此Linux 內核側的工作邊界變得很微妙。你不需要去寫一個 LCD 控制器驅動但你必須保證串口設備穩(wěn)定可用、數(shù)據(jù)不丟、觸摸事件能進入 Linux 標準的輸入子系統(tǒng)。否則就會出現(xiàn)“屏幕顯示正常但觸摸點了沒反應”這種最尷尬的局面。1.2 Linux側要解決的三層問題接串口屏時我習慣把問題拆成三層來看。第一層是硬件載體層。串口屏一般走 TTL 電平的 UART少數(shù)工業(yè)場景會轉 RS232 或者 RS485。這一層要做的事情包括確認 SoC 的 UART 引腳是否被其他外設占用、設備樹里的串口節(jié)點是否使能、波特率和校驗位是否和屏幕一致。內核側主要涉及 pinctrl、串口驅動、設備樹 aliases。第二層是數(shù)據(jù)通道層。串口屏的通訊協(xié)議通常是一幀一幀的里面可能有幀頭、命令字、長度、負載、校驗和、幀尾。Linux 的read()是流式讀取不保證一次拿到完整的一幀所以需要一個狀態(tài)機或者緩沖機制來拼包。這一層可以在用戶態(tài)做也可以寫一個內核模塊做 line discipline。第三層是輸入事件層。這是 Linux 串口屏和單片機串口屏最大的區(qū)別。單片機可以直接把觸摸坐標拿去用但 Linux 下各種圖形框架Qt、GTK、Flutter默認從/dev/input/eventX讀取輸入事件所以串口屏上報的觸摸數(shù)據(jù)必須轉換成標準的input_event結構。要么通過 uinput 從用戶態(tài)注入要么在內核里注冊一個 input device 驅動。這三層只要有一層沒做對整個系統(tǒng)用起來就會很別扭。2. 內核側支持串口屏UART設備樹、驅動與DMA配置2.1 先讓tty節(jié)點穩(wěn)定可用的關鍵配置內核對串口屏的支持核心其實就是“把串口這個基礎外設整利索”。以 ARM Linux 上常用的設備樹為例一個串口節(jié)點往往要打開兩樣東西status okay和對應的pinctrl。uart3 { pinctrl-0 uart3_tx_pins uart3_rx_pins; pinctrl-names default; status okay; };看起來簡單但實際板卡上會有很多隱性沖突。最常見的是這個串口被內核 console 占用了。很多 BSP 默認把consolettyS0,115200寫在內核啟動參數(shù)里而ttyS0恰好就是要接串口屏的串口。這時候即使你的應用能打開/dev/ttyS0內核日志也會時不時地往這個串口上吐數(shù)據(jù)屏幕就會間歇性亂碼。解決方式有三個換一個不沖突的串口節(jié)點比如把串口屏接到ttyS1。修改console啟動參數(shù)讓內核日志輸出到別的串口。用earlycon或者獨立調試串口把普通串口完全釋放給業(yè)務。另一個我踩過的坑是設備樹里串口的時鐘和別名。有些平臺需要配置clocks屬性否則串口波特率計算會偏差很大例如 115200 實際跑出來是 110000 左右屏幕端就會一直亂碼。調試時可以先在內核 dmesg 里看串口驅動的初始化信息確認最終的波特率分頻系數(shù)是否符合預期。2.2 串口驅動選型與調度依賴Linux 下最常見的串口驅動是 8250 系列和 PL011 系列。8250 通常對應兼容 16550A 的 UART很多 x86 板卡和部分 ARM SoC 都走這一套PL011 則是 ARM 平臺常見的驅動比如樹莓派和一些基于 AMBA 總線的 SoC。這兩個驅動在內核 config 里的選項不一樣CONFIG_SERIAL_8250y CONFIG_SERIAL_8250_CONSOLEy CONFIG_SERIAL_AMBA_PL011y CONFIG_SERIAL_AMBA_PL011_CONSOLEy如果裁剪內核的時候漏掉了對應選項系統(tǒng)可能連/dev/ttyS0或/dev/ttyAMA0都不會出現(xiàn)。檢查的時候不要光看有沒有這個設備節(jié)點還要確認驅動有沒有真正 probe 成功。串口屏對實時性的要求其實不高但觸摸體驗對“連續(xù)上報”很敏感。如果系統(tǒng)負載高用戶態(tài)讀串口的線程被調度器長時間掛起觸摸事件就會一陣一陣地卡。比較好的做法是把讀取線程設置成高優(yōu)先級實時線程或者用poll/select加超時的阻塞式讀取不要用忙等循環(huán)。Linux 的串口驅動內部有等待隊列機制poll會在數(shù)據(jù)到達時喚醒進程這對觸摸讀取已經足夠。2.3 DMA/FIFO的取舍與實測效果內核里的串口驅動為了降低中斷頻率一般都會打開 FIFO常見 16550A 的 FIFO 是 64 字節(jié)。但串口屏的數(shù)據(jù)量其實很小觸摸坐標動靜也就幾十個字節(jié)顯示指令一般也不會超過幾百字節(jié)所以 FIFO 溢出風險并不高。另外很多 BSP 會默認給串口打開 DMA 支持。DMA 能夠把數(shù)據(jù)從 UART FIFO 搬到內存減少 CPU 中斷但在某些平臺上反而會帶來問題DMA 描述符分配失敗、緩存一致性問題、或者 DMA 通道和別的驅動沖突。實際測試下來如果只是接一塊串口觸摸屏關閉 DMA 讓數(shù)據(jù)走傳統(tǒng)中斷FIFO系統(tǒng)更穩(wěn)。關閉方式因平臺而異有一些是在設備樹里配置dmas屬性為空或去掉dma-names有些是內核 config 里關閉CONFIG_SERIAL_8250_DMA。關鍵判斷依據(jù)是看實測是否丟字節(jié)。我曾經遇到一個平臺開著 DMA 時串口屏的觸摸坐標偶爾多出幾個 FF 字節(jié)關了 DMA 之后連續(xù)點了半個小時都沒出現(xiàn)異常。這種問題排查起來很耗費時間不如一開始就按“數(shù)據(jù)量小就關 DMA”的原則處理。3. 串口協(xié)議解析策略內核處理還是用戶態(tài)處理3.1 串口屏通信數(shù)據(jù)幀的基本模樣串口屏品牌很多協(xié)議也各不相同但常見協(xié)議的結構往往差不太多。拿市面上主流的幾類串口屏來說發(fā)送指令一般是“幀頭 命令 參數(shù) 幀尾”觸摸上報則是“幀頭 觸摸狀態(tài) X坐標 Y坐標 幀尾”。假設某串口屏的觸摸包格式是這樣0xAA 0x01 0x00 0x80 0x01 0x2C 0x00 0xFF 0xFF 0xFF其中0xAA是幀頭0x01表示觸摸按下后面0x0080是 X 坐標大端0x012C是 Y 坐標0xFF 0xFF 0xFF是結束標志。不同品牌會有不同設計有的用長度字段有的用 CRC16 校驗有的用累加和校驗。解析時務必先看明白兩個問題這條協(xié)議是定長的還是變長的有沒有校驗字段定長協(xié)議解析最簡單每次讀到固定字節(jié)數(shù)就能處理變長協(xié)議需要根據(jù)長度字段來循環(huán)讀。校驗字段也不能忽略工業(yè)環(huán)境下的串口線經常會受干擾沒有校驗的協(xié)議很容易出現(xiàn)“觸摸亂跳”。3.2 兩種解析路線的對比這里有一個經常被問到的選擇串口協(xié)議解析到底放在內核里還是用戶態(tài)我的回答是默認放用戶態(tài)。理由有三個調試方便。用戶態(tài)程序可以隨便printf可以用腳本模擬串口屏回包不用反復重新編譯內核。協(xié)議迭代快。串口屏廠商偶爾會出固件升級波協(xié)議微調用戶態(tài)改起來成本低。內核社區(qū)不建議在驅動里維護業(yè)務協(xié)議。內核自帶的大量串口驅動只負責數(shù)據(jù)搬運不解析業(yè)務幀。但有一種情況我會考慮寫內核模塊屏幕觸摸事件需要參與系統(tǒng)的休眠喚醒策略。比如系統(tǒng)休眠后串口屏來觸摸事件要喚醒系統(tǒng)這時候用戶態(tài)進程已經被凍結無法及時處理就必須在中斷/驅動層做事件檢測。另一個場景是觸摸數(shù)據(jù)量極大用戶態(tài) read 已經成了性能瓶頸雖然這種情況在串口屏項目里很少出現(xiàn)。同時也要提醒一點有一些想“玩得高級”的人會試圖動態(tài) hook tty 設備的file_operations攔截read和write來實現(xiàn)串口數(shù)據(jù)過濾甚至透明加密。這種思路確實能解決問題但風險很高。內核里隨便替換file_operations很容易造成引用計數(shù)混亂而且不同內核版本的tty_operations結構體定義不一致升級一次內核就要重新適配。與其這樣還不如正兒八經注冊一個 line discipline把串口數(shù)據(jù)流在鏈路層做自定義處理。3.3 粘包、斷包與狀態(tài)機解析串口本身是字節(jié)流不是“一包一包”的。用戶態(tài)調用read()時有可能一次拿到半包數(shù)據(jù)也有可能一次拿到兩包數(shù)據(jù)。這就叫斷包和粘包。很多初次做串口屏的人吃了這個虧——以為read()返回多少字節(jié)就是完整的一幀結果發(fā)現(xiàn)坐標偶爾錯亂。正確做法是引入一個簡單的狀態(tài)機逐字節(jié)處理enum parse_state { ST_IDLE, ST_HEAD, ST_CMD, ST_LEN, ST_DATA, ST_TAIL }; for (size_t i 0; i len; i) { switch (state) { case ST_IDLE: if (buf[i] FRAME_HEAD) state ST_HEAD; break; case ST_HEAD: if (buf[i] FRAME_HEAD) // 連續(xù)兩個幀頭按協(xié)議處理 continue; cmd buf[i]; state ST_CMD; break; // ... 其余狀態(tài)處理 } }另外還需要一個超時機制。如果收到半個包之后就再也沒有后續(xù)字節(jié)一定要在超時后復位狀態(tài)機否則下一個幀頭到來之前會一直卡在中間狀態(tài)。這個超時的經驗值一般取“若干個字節(jié)間隔”串口波特率 115200 時5~10ms 超時就已經足夠。解析完成之后還可以順便在/proc或/sys下導出一些統(tǒng)計信息比如收了多少幀、校驗錯誤多少次、解析成功多少次。這樣在客戶現(xiàn)場出了問題時能快速判斷是協(xié)議解析問題還是電磁干擾問題。4. 從觸摸數(shù)據(jù)到標準input事件串口觸摸屏接入Linux輸入子系統(tǒng)4.1 evdev/input子系統(tǒng)的基礎Linux 下幾乎所有輸入設備——鍵盤、鼠標、觸摸屏、遙控器——最終都會通過 input 子系統(tǒng)向上層報事件。用戶空間的圖形庫經常監(jiān)聽/dev/input/eventXevdev就是這一層的內核驅動。串口屏的觸摸功能要跟 Linux 生態(tài)無縫配合就得把坐標上報到 evdev。接入方式有兩種用戶態(tài)通過 uinput 模擬輸入設備或者內核態(tài)寫一個 input driver。uinput 的優(yōu)點是極其靈活int fd open(/dev/uinput, O_WRONLY | O_NONBLOCK); ioctl(fd, UI_SET_EVBIT, EV_KEY); ioctl(fd, UI_SET_KEYBIT, BTN_TOUCH); ioctl(fd, UI_SET_EVBIT, EV_ABS); ioctl(fd, UI_SET_ABSBIT, ABS_X); ioctl(fd, UI_SET_ABSBIT, ABS_Y); ioctl(fd, UI_DEV_CREATE); struct input_event ev {0}; ev.type EV_ABS; ev.code ABS_X; ev.value x; write(fd, ev, sizeof(ev)); ev.type EV_SYN; ev.code SYN_REPORT; ev.value 0; write(fd, ev, sizeof(ev));用 uinput 時核心邏輯就是解析串口幀 → 算出真實坐標 → 寫一個input_event→ 發(fā)送SYN_REPORT。這個鏈路非常清晰而且不用改內核、不用重新編譯設備樹適合大多數(shù)商業(yè)項目。內核態(tài)的 input driver 適合對延遲極其敏感、或者需要深度休眠喚醒的場景。實現(xiàn)上大致是注冊一個input_allocate_device()創(chuàng)建的設備設置好ABS_X/ABS_Y的最小值和最大值然后在一個內核線程或中斷上下文里調input_report_abs()和input_sync()。這種方法要求你對內核模塊開發(fā)有足夠的把握否則一個空指針就能讓整個系統(tǒng) panic。4.2 坐標換算與校準串口屏返回的坐標值取決于屏幕內部觸摸面板的 ADC 采樣范圍。有些屏幕的 X 范圍是 0~4095有些是 0~1023Y 范圍也可能和屏幕分辨率不是嚴格對應。但 Linux 輸入子系統(tǒng)上報的坐標范圍必須是設備描述里聲明的absmax否則用戶態(tài)拿到之后還要二次換算。通常做法是把串口屏上報的原始值線性映射到屏幕的實際分辨率linux_x (raw_x - x_min) * (screen_width - 1) / (x_max - x_min) linux_y (raw_y - y_min) * (screen_height - 1) / (y_max - y_min)這里最容易忽略的一點是觸摸面板的零點方向。有些屏幕的 X 坐標從左往右增加有些卻是反的Y 軸也是一樣。如果映射之后觸摸點和顯示點仍然是鏡像的就要對坐標做反轉。校準也不能只做一次。實際項目里屏幕可能被更換、屏幕玻璃面板存在裝配誤差、或者貼了不同厚度的保護膜都會導致觸摸坐標漂移。Linux 桌面環(huán)境一般用 libinput 的校準矩陣嵌入式 Qt 環(huán)境可以用 tslib 的ts_calibrate生成校準參數(shù)按映射公式寫進應用配置即可。經驗上在顯示畫面正確的前提下先用evtest查看上報值再用一個小畫布程序驗證“按下位置和光標位置”是否一致是最快的校準方法。4.3 多點觸摸和按鍵組合上報常見串口屏里帶多點觸摸的型號也不在少數(shù)。Linux 內部對多點觸摸使用 MT 協(xié)議Type B 是比較主流的實現(xiàn)方式需要用到input_mt_slot和input_mt_report_slot_state。假設屏幕支持兩個觸摸點上報邏輯大概是input_mt_slot(dev, 0); input_mt_report_slot_state(dev, MT_TOOL_FINGER, true); input_report_abs(dev, ABS_MT_POSITION_X, x0); input_report_abs(dev, ABS_MT_POSITION_Y, y0); input_mt_slot(dev, 1); input_mt_report_slot_state(dev, MT_TOOL_FINGER, true); input_report_abs(dev, ABS_MT_POSITION_X, x1); input_report_abs(dev, ABS_MT_POSITION_Y, y1); input_mt_report_slot_state(dev, MT_TOOL_FINGER, false); input_sync(dev);注意協(xié)議解析層要怎么區(qū)分“多點”與“單點”。很多串口屏的觸摸協(xié)議在單點觸摸和多點觸摸下走的是不同的命令字不能混用。如果協(xié)議文檔不夠詳細可以在屏幕上放兩個手指慢慢移動直接打印收到的十六進制原始數(shù)據(jù)來反推。還有一類串口屏是做“控件跳轉”的屏幕上的按鈕會主動上報“按鍵編號”而不是絕對坐標。這種場景下更簡單——直接把按鍵編號映射成EV_KEY事件交給上層應用處理。但要注意區(qū)分觸摸類是單擊還是長按否則上層會收到一大批重復按鍵事件。5. 實測中的問題清單亂碼、丟幀、漂移與開機時序5.1 亂碼和串口參數(shù)不一致亂碼是最容易定位、也最常見的問題。大部分串口屏出廠默認波特率是 9600 或者 115200如果你的應用stty設置成了 57600或者內核 console 啟動參數(shù)里用了別的串口參數(shù)就會出現(xiàn)一堆亂碼。排錯時先做三件事stty -F /dev/ttyS3 115200 raw -echo cat /dev/ttyS3第一確認內核啟動階段沒有往這個串口打印日志第二確認上位機的波特率和屏幕固件一致第三確認串口電平匹配。TTL 串口屏接 RS232 電平轉換器或者在相反方向接板載 RS232 口都會出現(xiàn)不穩(wěn)定亂碼。這里再順便提一個容易忽略的校驗位問題。很多串口屏默認是8N1也就是 8 個數(shù)據(jù)位、無校驗、1 個停止位。但用老款迪文屏或某些工業(yè)屏時可能會是8E1或8O1。如果應用層一直用 8N1 去讀偶校驗的屏幕偶爾能收到正確數(shù)據(jù)但整體上是隔三差五亂碼。5.2 丟幀與緩沖區(qū)配置“丟幀”從表面看是觸摸卡頓、指令沒反應但底層原因往往在 Linux 的數(shù)據(jù)鏈路里。一個常見原因是用戶態(tài)讀取線程被高負載任務拖住串口接收緩沖區(qū)溢出后新來的數(shù)據(jù)被丟棄。Linux tty 驅動本身有接收緩沖區(qū)但默認大小有限。如果你確定某路串口數(shù)據(jù)量比較大或者讀取線程確實響應不及時可以嘗試調大 tty 的 flip buffer 或者使用TIOCVHANGUP清理緩沖。更常見的做法是提高讀取線程優(yōu)先級struct sched_param param { .sched_priority 50 }; pthread_setschedparam(thread_id, SCHED_FIFO, param);如果平臺支持把當前線程綁到和 UART 中斷親和性一致的 CPU 核上也能減少調度延遲。另外一個容易造成“數(shù)據(jù)看起來丟了”的原因是 DMA 未配置好卻開著 DMA。DMA 描述符不夠時UART 收到的數(shù)據(jù)沒有及時搬到內存硬件 FIFO 一旦溢出就會丟字節(jié)。遇到這種情況直接看/proc/interrupts里對應串口的中斷計數(shù)增長是否正常和dmesg里有沒有報DMA timeout之類的錯誤。5.3 觸摸漂移與坐標零點錯誤觸摸漂移最典型的癥狀是“點擊屏幕右上角光標卻出現(xiàn)在左上角附近”。除了第 4 章說的坐標映射和零點方向問題之外還有一種漂移是“越往邊緣越偏”這通常說明屏幕觸摸面板本身不是線性的。很多串口屏支持在屏幕內部做觸摸校準你可以在屏的工程配置里手動校準一次之后再往 Linux 側輸出坐標。這種二次校準的效果往往比純線性映射更準因為屏幕內部的校準固件能修正非線性誤差。如果換了不同批次、不同尺寸的串口屏校準參數(shù)務必要重新做一遍。不要為了圖省事把上一塊屏的校準文件直接拷貝到新設備里尤其是從老型號屏幕換到新型號屏幕時坐標范圍可能完全不一樣。5.4 上電時序與串口屏的“假故障”最后說一下上電時序。很多工控板是 Linux 系統(tǒng)和串口屏同時上電串口屏內部 MCU 啟動可能需要幾百毫秒甚至一秒而 Linux 用戶態(tài)程序可能更早地嘗試向串口屏發(fā)初始化指令。這時候屏幕還沒就緒程序等不到應答就會誤判為“串口屏壞了”。解決方式是加一個初始化握手機制。程序打開串口節(jié)點后不急著發(fā)業(yè)務數(shù)據(jù)先發(fā)送一條查詢指令等待屏幕返回確定應答連續(xù)重試幾次都失敗才報錯。同樣如果系統(tǒng)里有獨立看門狗喂狗線程應該和串口讀取線程分開。因為讀串口偶爾會阻塞如果讓同一個線程既讀串口又喂狗一旦串口屏瞬時無響應看門狗可能先超時復位整個系統(tǒng)造成更嚴重的問題。6. 選型與工程落地建議從STM32到Linux的遷移經驗6.1 串口屏品牌選型時的內核視角市面上常見的串口屏品牌比如淘晶馳、迪文、大彩都有各自的開發(fā)生態(tài)。選型時除了看屏幕分辨率、色深、UI 組態(tài)軟件好不好用之外還要特別關注兩點。第一串口協(xié)議是否公開、文檔是否完整。有的屏幕協(xié)議只在廠商的組態(tài)軟件里封裝不提供公開指令表這種就很難在 Linux 下穩(wěn)定擴展。第二觸摸上報是否走同一路串口。有些屏幕支持觸摸數(shù)據(jù)通過單獨引腳輸出有些必須和顯示指令共用同一路 UART這會直接影響你的串口資源配置。另外新舊型號切換也要留個心眼。某些品牌的老型號屏幕固件和新型號使用不同的協(xié)議格式代碼里最好不要把協(xié)議解析寫死在業(yè)務邏輯里而是單獨抽象一層方便后面換屏時只改協(xié)議適配。6.2 內核裁剪與系統(tǒng)打包時的注意事項如果產品要量產內核裁剪是繞不開的一步。裁剪時最容易犯的錯誤就是把“看起來沒用”的輸入子系統(tǒng)給裁掉了。串口屏雖然不走 I2C 觸摸芯片但它一旦通過 uinput 注入輸入事件就需要CONFIG_INPUT_UINPUT上層圖形庫讀取觸摸點則需要CONFIG_INPUT_EVDEV。CONFIG_INPUTy CONFIG_INPUT_EVDEVy CONFIG_INPUT_UINPUTy CONFIG_SERIAL_8250y CONFIG_SERIAL_COREy這幾個選項建議直接編進內核而不是編譯成模塊否則系統(tǒng)啟動時如果沒有提前insmod/dev/input目錄下就會少設備節(jié)點。同時還要注意 udev 規(guī)則。串口屏設備節(jié)點權限如果不做處理普通用戶態(tài)程序可能打不開/dev/ttySx。在開發(fā)板階段直接跑 root 可能沒感覺到了產品要做降權運行時節(jié)點權限就會變成一個問題。KERNELttyS[0-9]*, MODE0660, GROUPdialout KERNELuinput, MODE0660, GROUPinput6.3 和裸機開發(fā)不同的幾個思維轉變從 STM32 裸機方案遷移到 Linux最大的差異是多任務環(huán)境。裸機里你可以寫一個while(1)循環(huán)原地等待串口數(shù)據(jù)完全可控但在 Linux 里會有藍牙、WiFi、看門狗、業(yè)務線程等一大堆進程搶 CPU 和中斷資源串口讀取線程必須用阻塞式 IO 加超時而不是忙等。另一個差異是調試方式。裸機可以直接用 JTAG 打斷點看寄存器Linux 下判斷串口問題就應該先用evtest、stty、dmesg、/proc/tty/driver/serial這些工具和接口做快速定位而不是一上來就改內核代碼。串口屏項目里絕大多數(shù)問題都出在配置不在驅動本身。最后分享一個小經驗如果串口屏在開發(fā)板上工作正常換到量產主板上出現(xiàn)觸摸漂移或亂碼先別急著懷疑代碼優(yōu)先檢查主板串口電平參考電壓和信號完整性。很多小批量主板會把 UART 走線拉得太長又沒加 ESD 防護和上拉電阻干擾引起的丟幀比軟件問題更難查。在硬件端正、協(xié)議解析正確的基礎上內核和用戶態(tài)的配置只要按我前面說的幾個原則去處理這套方案基本能穩(wěn)定跑很久。