RS485 串行通信調試:工具鏈挑戰與 POSIX 兼容性問題
起初只是關于 linux-serial-test(一款用于通過發送和接收數據流對串行端口進行壓力測試的開源工具)的一份簡單問題報告,卻演變成了一個涉及回歸分析、交叉編譯的差異、glibc 版本不兼容以及更底層的 POSIX 合規性問題等多層面的調試挑戰。該工具被用于我們的持續集成(CI)管道中,以驗證 Toradex 模塊上的 UART 功能;但在多臺設備上報告出現故障后,這促使我們對整個工具鏈展開了更廣泛的調查。
這是一個關于我們 master build 中突發故障(起初懷疑是內核回歸)的故事:它將我們引入了優化迷局,然后遭遇了工具鏈問題,最終發現了一個顯而易見卻被忽視的POSIX合規性違規問題。
問題 由于多個設備上都出現了故障,最初懷疑是最近的一次上游提交。上游提交 77320571e63c (“檢查端口上是否已配置 RS485”)引入了一項出于良好意圖的更改:優先使用通過設備樹在端口上已配置的 RS485 設置。 然而,它卻違背了一個基本假設: 應始終尊重用戶的命令行意圖.
if (rs485.flags & SER_RS485_ENABLED) {
printf("RS485 already enabled on port, ignoring delays if set\n");
} else {
// Configure RS485 based on user flags
}為什么會出問題 用戶無法實現下面操作:
如果 RS485 此前已被啟用,則將其禁用
更改延遲設置
運行 UART 環回測試(此操作需要禁用 RS485)
正確測試流量控制
教訓一:優先考慮用戶意圖,而非設備配置。
if (_cl_rs485) {
/* User explicitly wants RS485 */
if ((_cl_rs485_after_delay < 0) && (rs485.flags & SER_RS485_ENABLED)) {
printf("RS485 already enabled on port\n");
} else {
/* Configure RS485 with user settings */
// ... configuration code ...
}
} else {
/* User wants RS485 disabled - ALWAYS disable */
rs485.flags &= ~(SER_RS485_ENABLED | ...);
// ... disable code ...
}這效果非常理想。測試全部通過。一切都很順利。
但接著出現了 第二個問題.
相同的源代碼,在本地使用 aarch64-none-linux-gnu-gcc 編譯時運行正常。但在通過 OpenEmbedded(OE)構建時,-c 標志(RTS/CTS 流程控制) 在無提示的情況下失效了:
tx=272, rx=0 ← Data sent but not received!誤區一:加固標志
-D_FORTIFY_SOURCE=2
-fstack-protector-strong
-mbranch-protection=standard我們已將其禁用,但仍然失敗了。
誤區二:編譯優化級別
OE: -O2
Local: default我們改成了 -O0,但仍然失敗。
誤區三:PIE(Position Independent Executable)
Local: "executable" (no PIE)
OE: "pie executable" (PIE enabled)我們通過以下方式禁用了 PIE: -fno-pie -no-pie. 還是失敗了。
教訓: 不要只治癥狀,而要找出根本原因。
最后,我們對比了正常運行和無法運行的二進制文件中的實際符號:
nm ./linux-serial-test-local | sort > local.sym
nm ./linux-serial-test-oe | sort > oe.sym
diff local.sym oe.sym太棒了!發現區別:
Local (works):
- strtol (C99)
- cxa_finalize@GLIBC_2.17
OE (fails):
- __isoc23_strtol (ISO C23!)
- __wrap_main
- Missing cxa_finalizeOE 工具鏈在編譯的開啟了 支持 ISO C23,從而改變了運行時的基本行為。
我們在本地構建了 OE SDK,以重現 CI 環境:
bitbake -c populate_sdk core-image-minimal
source /opt/sdk/environment-setup-aarch64-oe-linux現在我們能夠重現該故障了, 本地 使用相同的工具鏈。這一點至關重要,它證明了問題出在工具鏈上,而非 OE 構建基礎設施中。
由于符號分析指向了 glibc 方面的問題,我們需要了解運行時究竟發生了什么。此時,strace 就顯得尤為重要。
strace linux-serial-test -o2 -i3 -b 115200 -p /dev/verdin-uart1 -c -a10 -w16我們的發現:
ioctl(3, TCSETS2,
{c_iflag=, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|,
c_cflag=B115200|B115200<
提交
Toradex 在 elexcon 2026 深圳國際電子展暨嵌入式展等待您光臨
韜睿丨誠邀參與:Verdin RK3568J 核心板 Early Access計劃
Toradex Verdin iMX8M Plus 上使用 Bao Hypervisor
基于 NXP i.MX8M Plus 測試 Zephyr RTOS
Verdin iMX8M Plus 實現上電亮屏的無閃爍啟動




投訴建議