- [[Linux_BSP] Week1。Linux架構、 Boot、kernel、driver、device tree 筆記](https://hackmd.io/@YungHuiHsu/ryZ1i45dT) - [[Linux_BSP] Week2。UART與GPIO控制](https://hackmd.io/@YungHuiHsu/B1e_heHt6) - [[Linux_BSP] Week3_1。I2C 通訊、GMSL2 Camera](https://hackmd.io/@YungHuiHsu/HkaQBH0K6) - [[Linux_BSP] Week3_2。GMSL2 Camera](https://hackmd.io/@YungHuiHsu/Hyjmb5V96) - [[Linux_BSP] Week4。HPC Debug](https://hackmd.io/@YungHuiHsu/HknGTEw9p) --- ## BSP Week2任務 1. 學習 C programming 於Linux - Task: :::success 1. 使用 C 語言撰寫兩支程式,分別是`hello_world.c` 與 `hello_wistron.c`,功能是在Nvidia Xavier 上,被執行時,分別輸出Hello World、Hello Wistron 到 Shell Console 2. 使用 Makefile 進行程式的編譯,需要可以單獨 編譯特定程式,舉例: (1) 指令: `make all` -- 編譯全部 (2) 指令: `make world` -- 編譯hello_world.c (3) 指令: `make Wistron` -- 編譯hello_wistron.c (4) 指令: `make clean` -- 清除編譯產出之所有檔案及物件 ::: 2. 學習 UART 控制 - Task: :::success 1. 使用 C 語言撰寫程式,用於監聽 Nvidia Xavier的 UART port,且程式需要在系統開機完成後,自動啟動 2. 當 PC 透過 UART 連接於 Xavier 時,該程式需要具有以下能力 (1) 當 PC 輸入 Hi/hi 或 Hello/hello,程式回傳 Hi 或 Hello (2) 當 PC 輸入上述以外的訊息,程式將所收到的訊息存入某 log 檔案 (3) 接收到的訊息以換行符號當作結束 ::: 3. 學習 GPIO 控制 - Task: :::success 1. 啟用一根 GPIO 腳位,將其設定為 GPIO output可控 2. 於 Shell Console 動態設定為 output high 或output low,並以電錶量測驗證 ::: 4. 評核驗收 - Task: :::success 1. 啟用一根 GPIO 腳位,將其設定為 GPIO output可控 2. 於 Shell Console 動態設定為 output high 或output low,並以電錶量測驗證 3. 控制 GPIO 的動作(output high/low),除了可以經由 Shell Console,也能透過 UART 通訊控制以及讀取 GPIO 當前狀態 ::: --- # 1. 使用 C 語言撰寫程式 - [[Compilation] make與cmake指令筆記](https://hackmd.io/@YungHuiHsu/rJyCf2vYp) ```bash= $ tree . ├── hello_wistron.c ├── hello_world.c └── Makefile ``` - hello_world.c ```c= #include <stdio.h> int main() { printf("Hello, World!\n"); return 0; } ``` - Makefile ```text= CC=gcc CFLAGS=-Wall -g EXECUTABLES=hello_world hello_wistron .PHONY: all clean all: $(EXECUTABLES) hello_world: hello_world.c $(CC) -o $@ $< $(CFLAGS) hello_wistron: hello_wistron.c $(CC) -o $@ $< $(CFLAGS) clean: -rm -f $(EXECUTABLES) ``` - Makefile指令解釋 1. `CC=gcc` - 這行設定了`CC`變量,表示編譯器(Compiler),這裡使用的是`gcc`,也就是GNU編譯器。 2. `CFLAGS=-I -Wall -g` - 設定了`CFLAGS`變量,表示編譯器的選項(Compiler Flags)。 - `-Wall` 啟用所有的警告信息,幫助開發者發現潛在的錯誤。 - `-g` 生成適合於gdb調試器的調試信息。 3. `EXECUTABLES=hello_world hello_wistron` - 定義了一個變量`EXECUTABLES`,它包含了所有需要編譯的目標執行文件。 4. `.PHONY: all clean` - 定義了偽目標`all`和`clean`,即這些目標不對應具體的文件。 5. `all: $(EXECUTABLES)` - 定義了一個目標`all`,它依賴於`$(EXECUTABLES)`,即`hello_world`和`hello_wistron`。 - 運行`make`或`make all`時,會編譯`hello_world`和`hello_wistron`這兩個程序。 6. `hello_world: hello_world.c` - 定義了一個目標`hello_world`,它依賴於源文件`hello_world.c`。 - 當`hello_world.c`比`hello_world`新,或者`hello_world`不存在時,會執行下一行的命令。 7. `$(CC) -o $@ $< $(CFLAGS)` - 使用`gcc`編譯`hello_world.c`,生成執行文件`hello_world`。 - `$@`代表目標名稱,這裡是`hello_world`。 - `$<`代表第一個依賴,這裡是`hello_world.c`。 - `$(CFLAGS)`引入之前定義的編譯選項。 8. `hello_wistron: hello_wistron.c` - 同`hello_world`類似 9. `clean:` - 定義了一個目標`clean`,用於清理編譯生成的文件。 - 執行Makefile,可用`make`或`make all` - 可執行檔製作出來了 ```bash= $ make gcc -o hello_world hello_world.c -I -Wall -g gcc -o hello_wistron hello_wistron.c -I -Wall -g $ tree . ├── hello_wistron ├── hello_wistron.c ├── hello_world ├── hello_world.c └── Makefile ``` - 執行`make clean` terminal 跳出`rm -f hello_world hello_wistron`訊息,刪除編譯過的可執行檔 --- # 2. "學習 UART 控制"筆記 ### 任務拆解: 1. 理解 UART 的基本概念,包括它如何在兩個設備間提提供通信能力。 - UART(Universal Asynchronous Receiver/Transmitter,通用非同步收發傳輸器)是用於非同步串行通信的硬件裝置。 - 熟悉 Nvidia Xavier 平台的 UART 接口。這可能包括硬件接口的位置、PIN 腳的配置以及任何必要的硬件設置。 - 學習如何在 PC 端設置串行通信。這包括安裝和配置串行通信軟件,如 Putty 或 minicom,以及理解如何配置串行端口的參數(如波特率、數據位、停止位和奇偶校驗)。 - 進行實際的通信測試。這涉及 - 從 PC 端發送數據到 Xavier,並確認 Xavier 能夠接收數據並做出適當的響應。具體來說,這需要編寫或使用現成的腳本或程序來在 PC 端發送命令,然後在 Xavier 端接收和處理這些命令。可能還需要在 Xavier 端配置 UART 服務來處理接收到的數據。 - 實施 UART 雙向通信的測試案例。這意味著要從 Xavier 端發送資料回 PC 端,並確認數據正確無誤。 - 具體操作步驟如下: - [x] **連接設備**:使用適當的串行纜線或 USB 轉 UART 轉換器連接 PC 和 Xavier。 - [x] **配置 PC 端**:打開串行通信軟件,設置正確的串行端口參數,如波特率等。 - [x] **發送數據**:從 PC 端發送測試命令,如文字訊息 "Hi" 或 "See Hello"。 - [x] **檢查回應** - 在 Xavier 端監控 UART 接收到的數據,確認是否如預期收到了來自 PC 的訊息,並確認 Xavier 是否發回了正確的回應,如 "Hello"。 - [ ] **回傳數據**:從 Xavier 端發送數據至 PC,並在 PC 端確認是否正確接收。 - [ ] **執行控制指令**:如果測試包括發送控制指令以觸發 Xavier 端的特定行為,則在 PC 端發送這些指令並在 Xavier 端確認行為執行和日誌輸出是否符合預期。 ## 通用非同步收發傳輸器 UART 的基本概念 UART(Universal Asynchronous Receiver/Transmitter,非同步收發傳輸器)是一種廣泛使用的串行通信協議。它主要用於電子設備之間的點對點通信。以下是UART的簡單介紹和功能: ![image](https://hackmd.io/_uploads/BkzRDZUt6.png =400x) ![image](https://hackmd.io/_uploads/BJ19DZ8K6.png =500x) 1. **基本功能**: - UART允許兩個設備之間進行串行數據傳輸。它將數據包裝成串行形式,以便在只有一對傳輸線(發送線和接收線)的情況下進行通信。 2. **異步通信**: - UART是異步的,意味著它在傳輸數據時不需要發送和接收兩端的時鐘同步。每個字節的開始和結束由起始位和停止位標記,這樣接收方就可以正確地識別數據的邊界。 3. **配置參數**: - UART通信可以通過設置不同的參數來配置,包括波特率(Baud Rate)、數據位(Data Bits)、停止位(Stop Bits)和奇偶校驗位(Parity Bits)。這些參數必須在通信的兩端設置一致。 :::info - Byte - 位元組/字节: - 位元組是計算數據儲存或傳輸的基本單位之一,通常由8個位元組成。每個位元組都可以表示256個不同的值(從0到255),並用於儲存單個字符(如字母、數字或符號)。 - Bit - 位元/: - 位元是數字信息的最小單位,它只能表示兩個值,通常是0和1。位元是計算機數據處理和儲存的基礎,它們用於表示二進制數字和在計算機中執行邏輯運算。 ::: - :pencil2:資料訊框 ![image](https://hackmd.io/_uploads/B1xpwb8F6.png =500x) ![image](https://hackmd.io/_uploads/r118_bLFT.png =700x) 1. **數據位(Data Bits)**: - 數據位定義了每個數據包中實際數據的大小。常見的設置包括7位或8位。例如,設置為8位數據位時,每個數據包可以傳輸8位二進制數據,這等於一個位元組(Byte)。數據位的數量直接影響你可以傳輸的數據的類型和大小。 2. **停止位(Stop Bits)**: - 停止位用於標記每個數據包的結束,讓接收方知道一個數據包已經傳輸完畢。常見的設置有1位、1.5位或2位停止位。增加停止位的數量可以提高通信的可靠性,但也會稍微減少數據傳輸的效率,因為它增加了每個數據包的總位數。 3. **奇偶校驗位(Parity Bits)**: - 奇偶校驗位是一種錯誤檢測機制,用於檢查數據在傳輸過程中是否出現了錯誤。它通過在數據位之後添加一個額外的位來工作,這個位被設置為使得整個數據包(包括數據位和奇偶校驗位)的位數為奇數或偶數。 - **無校驗(None)**:不進行奇偶校驗。 - **奇校驗(Odd)**:設置校驗位,使得數據位加上校驗位的總和為奇數。 - **偶校驗(Even)**:設置校驗位,使得數據位加上校驗位的總和為偶數。 - 奇偶校驗可以幫助檢測單個位的錯誤,但它不是一種非常可靠的錯誤檢測方法。對於更高級的錯誤檢測和糾正,可能需要使用其他通信協議或錯誤檢測和糾正算法。 - :pencil2: Baud Rate 鮑率(繁體慣用語)/波特率(簡體慣用語) :::info 波特率(英文原名:Baud Rate)是衡量數據傳輸速率的單位,特別是在串行通信中使用。它表示每秒可以傳輸多少個信號單位。在串行通信中,每個信號單位可以包含一個或多個位(二進制數字0或1)。 波特率的定義與每秒傳輸的位數(比特率)有所不同。在一些情況下,每個信號單位可能只代表一個位的變化,這時波特率等於比特率。然而,在其他情況下,一個信號單位可能代表多個位的變化(例如通過使用多級編碼技術),這時波特率會低於比特率。 在設定串行通信設備時,正確的波特率設定非常重要,因為通信的兩端必須以相同的速率發送和接收信號,才能正確地傳輸數據。常見的波特率包括9600、14400、19200、38400、57600 和 115200 等。 ![image](https://hackmd.io/_uploads/ByCcwZUYT.png =300x) ::: 4. **應用範圍**: - UART廣泛應用於各種電子設備,如微控制器、感測器、電腦和其他通信設備。它特別適用於距離較近、數據傳輸速率不是特別高的應用場景。 5. **簡單和可靠**: - UART通信由於其簡單性和可靠性,被廣泛應用於工業控制系統、嵌入式系統和消費電子產品中。 UART提供了一種簡單而有效的方式,用於在不同的電子設備之間進行數據交換。由於其設計的簡潔性和實現的易用性,UART在電子通信領域中一直占有重要的地位。 :::success - 本次任務中的雙向 UART 控制 1. 使用 PC 端透過串行端口向 Nvidia Xavier 的 UART port 發送命令,確認數據能夠正確發送和接收,以確保 UART 功能正常。 2. PC 端通過 UART 接口與 Xavier 設備連接,執行以下測試以保證通信無誤: (1) 從 PC 發送文字訊息如 "Hi" 或 "See Hello" 等,並確認 Xavier 端是否能夠正確回應 "Hello"。 (2) 從 PC 發送控制指令,觀察 Xavier 是否能夠按照指令正確執行,並且回傳相應的 log 資訊。 (3) 從 Xavier 端發送資料到 PC 端,並確認 PC 端是否能夠接收到正確的資料。 ::: ## Nvidia AGX Xavier 平台的 UART接口 參考硬體規格配置文件 - [Jetson Xavier Developer Kit Carrier Board Specification](chrome-extension://mhnlakgilnojmhinhkckjpncpbhabphi/pages/pdf/web/viewer.html?file=https%3A%2F%2Fstatic5.arrow.com%2Fpdfs%2F2018%2F12%2F12%2F12%2F23%2F1%2F848262%2Fnvda_%2Fmanual%2Fjetson_xavier_developer_kit_carrier_board_specification.pdf) 需要找出版上的UART接口 #### 錯誤紀錄 :::spoiler 1. 透過j501這個 Micro USB B 接口連結到筆電 2. 使用PuTTY、minicom或圖形介面的cutecom等Serial terminal來跟UART port 溝通(設置連接) 3. 用C 語言撰寫程式,用於監聽 Nvidia Xavier的 UART port(j501) - Frank 240117 14:56 > 關於 UART 理解,這樣算是合理的,至於 terminal 工具,我沒有推薦,要看你如何規劃你的程式去做選擇 > - 假設 UART 通訊是規劃走 raw data,那可能很難找到現成合用的,自己寫一個可能會比較快 > - 假設通訊是規劃 ASCII 訊號,那就看哪一種工具與你的規劃合用 - Hermes Wu 240117 15:14 > - J501預設是Xavier的Debug UART, 我想Frank指的UART應該不會是這一組UART > - Windows上的Terminal可以用putty or teraterm - [Agx xavier UART1(ttyTHS0)](https://forums.developer.nvidia.com/t/agx-xavier-uart1-ttyths0/217839) > The debug uart is through the micro-B port on Xavier developer kit. Please connect it to a host PC through USB type-A to micro-B adapter and run minocom or picocom on the host. You shall see the log. - 丟去詢問Frank得到回覆: '我覺得會影響'。 > 再研究規格書看看有哪個端口可以拿來連接使用 ::: ### 接線設置 使用版上的Expansion Header (J30) 上的 UART1可以來連接筆電 需要使用"USB 轉 TTL 序列傳輸線",將轉換器的 TX、RX 和 GND 針腳連接到擴展頭上, 相對應的 UART_TX、UART_RX 和 GND 針腳,要使用跳線來完成這些連接 ![image](https://hackmd.io/_uploads/HJ1tVxIFa.png =500x) > - 可以看到 Micro USB B Connector (J501) 被指定為 UART 控制台。這意味著可以通過這個 Micro USB 接口連接到開發板並獲取串行控制台訪問。**但"J501預設是Xavier的Debug UART"會影響通信,因此不使用J501(見錯誤紀錄)** > - 擴展頭 (J30) 提供了 GPIO 以及額外的 UART 通道,這取決於針腳的配置。在實際使用時,擴展頭允許開發者連接多種外部設備,包括串行通信設備。 ![image](https://hackmd.io/_uploads/Sy3ILg8tT.png =500x) ![image](https://hackmd.io/_uploads/rys0wlUFa.png =500x) ![image](https://hackmd.io/_uploads/B14xYxIta.png =500x) ![image](https://hackmd.io/_uploads/r1jIfol5p.png =200x) > Jetson AGX Xavier Pin 1([source: 2018。 JetsonHacks。JETSON AGX XAVIER J30 GPIO EXPANSION HEADER PINOUT](https://jetsonhacks.com/nvidia-jetson-agx-xavier-gpio-header-pinout/)) > :warning: 注意:top是左邊,不然針腳會插反 > :warning: 轉接器的TX要連接到針腳的RX | 正確接線 | 接錯的樣子 | | -------- | -------- | |![image](https://hackmd.io/_uploads/SJo4JUPYT.png =300x) | ![image](https://hackmd.io/_uploads/Hk--Ng8F6.png =300x) | > J30 擴展頭包含 UART1_TX (發送) 和 UART1_RX (接收) 針腳,它們分別對應於針腳 8 和 10。 > 使用以下設備和步驟來完成連接: > > 1. **線材規格**:需要一條具有適當接頭的線材,能夠從 J30 連接到電腦上的串行端口或 USB 轉接器。如果電腦沒有原生的串行端口,將需要一個 TTL 到 USB 轉換器,這樣的轉換器通常具有一個接頭,可以直接連接到擴展頭上的 UART 針腳。 > 2. **3.3V 電平兼容性**:根據註記,使用擴展頭上的 CAN 針腳時要特別小心,因為它們在系統啟動時會因為 SoC 內部的 3.3V 上拉電阻而被拉高到 3.3V。然而,UART 針腳應該是安全的,只要確保轉換器也是 3.3V 兼容的。如果需要,可以在系統啟動後通過軟體切換電壓軌並禁用內部上拉電阻。 > 3. **TTL 到 USB 轉換器**:需要一個 TTL 到 USB 轉換器,以便將 UART 信號轉換為電腦可以通過 USB 端口識別的信號。這種轉換器通常支持 3.3V 和 5V 電平,應該選擇一個與 AGX Xavier 的 3.3V 信號電平兼容的轉換器。 > 4. **連接方式**:將轉換器的 TX、RX 和 GND 針腳連接到擴展頭上相對應的 UART_TX、UART_RX 和 GND 針腳。可以使用跳線來完成這些連接。 > > 在進行任何連接之前,要關閉 AGX Xavier 的電源,以避免造成損害。 :::info 在大多數情況下,UART 通信只需要連接 UART 的傳輸線(TX)和接收線(RX)。 UART #1 Request to Send (UART1_RTS) 和 Clear to Send (UART1_CTS)這兩個硬體流控制(使用 RTS 和 CTS),通常在更複雜的應用中使用,比如當通信的兩個設備都支持硬體流控制,並且需要在高速或者不穩定環境下保證數據傳輸的可靠性時,以防止緩衝區溢出。如果只是進行基本的串行通信,並且不需要硬體流控制功能,那麼通常不需要連接 RTS 和 CTS 信號。 對於以下簡單任務: - 啟動後自動運行的程式監聽 - 簡單的命令回應 - 將接收的資料記錄到日誌文件 只需要確保 UART TX 和 RX 正確連接到 PC 的對應接口,並且 Jetson 和 PC 都設定了匹配的串行通信參數(例如Baud Rate),這樣的設置就已經足夠了 至於地線(GND),一般來說在進行串行通信連接時,只需要連接一個 GND 針腳。選擇哪一個 GND 針腳並不是非常關鍵,因為它們在電氣上都是互相連通的。但為了方便起見,可以選擇靠近 UART TX 和 RX 針腳的 GND 針腳進行連接。 在連接時,使用以下方式: - TX:連接到轉接器或 PC 的 RX 端。 - RX:連接到轉接器或 PC 的 TX 端。 - GND:選擇一個靠近 TX 和 RX 針腳的 GND 進行連接。 ::: ### 接線後的通信確認 :::success 當用minicom 來測試 UART 連接時,必須確認兩邊的環境設置完全一樣,所以必須分別找出兩邊的tty裝置名稱 :warning:雖然筆電Linux系統驅動有抓到`ttyUSB0`,但還是需要確認兩邊環境一致可以通訊,後面在撰寫c語言監聽程式時才能排除環境問題 ::: 在已經將線連接到 AGX Xavier 和筆電之後,可以按照以下步驟來檢查連接並確認其功能: 1. **開機 AGX Xavier**: - 確保所有連接都正確無誤後,開機 AGX Xavier連結筆電。 2. **檢查設備識別**: - 檢查設備識別步驟1:**在筆電Linux輸入`dmesg | grep tty`查找UART端口** - `dmesg | grep tty` 命令來查看是否有新的串行設備(tty)被識別。 - ttyS4 和 ttyS5 是內建的串行端口。 - ttyACM0 是一個 USB 通訊設備類(ACM)串行裝置,這通常與某些類型的 USB 轉串行設備或內嵌式板相關。 - **ttyUSB0** 是由 FTDI USB 轉串行裝置轉換器連接的串行端口,這就是連接到AGX Xavier的端口 ```bash= [ 0.176989] printk: console [tty0] enabled [ 0.501626] 0000:00:16.3: ttyS4 at I/O 0x5080 (irq = 19, base_baud = 115200) is a 16550A [ 6.697202] cdc_acm 1-1:1.2: ttyACM0: USB ACM device [ 6.991188] dw-apb-uart.0: ttyS5 at MMIO 0xd564e000 (irq = 20, base_baud = 115200) is a 16550A [445630.057129] usb 1-3: FTDI USB Serial Device converter now attached to ttyUSB0 ``` - 檢查設備識別步驟2:**在AGX Xavier`dmesg | grep tty`查找UART端口** - 發現有ttyTHS0、ttyTHS1、ttyTHS4,不知哪個對應到"Expansion Header (J30) 上的UART1_TX (發送) 針腳 8 和 UART1_RX (接收) 針腳10" ```bash= yh@AGX-Xavier:~$ sudo dmesg | grep tty [ 0.000000] Kernel command line: root=/dev/mmcblk0p1 rw rootwait rootfstype=ext4 mminit_loglevel=4 console=ttyTCU0,115200n8 console=tty0 fbcon=map:0 net.ifnames=0 rootfstype=ext4 video=efifb:off [ 0.001891] printk: console [tty0] enabled [ 1.130465] printk: console [ttyTCU0] enabled [ 7.650929] 3100000.serial: ttyTHS0 at MMIO 0x3100000 (irq = 35, base_baud = 0) is a TEGRA_UART [ 7.665870] 3110000.serial: ttyTHS1 at MMIO 0x3110000 (irq = 36, base_baud = 0) is a TEGRA_UART [ 7.680734] 3140000.serial: ttyTHS4 at MMIO 0x3140000 (irq = 37, base_baud = 0) is a TEGRA_UART [ 10.249216] systemd[1]: Created slice system-serial\x2dgetty.slice. ``` #### 使用 minicom 來測試 UART 連接、確認兩邊環境設置一致 ##### 測試 UART 連接Step1:安裝 Minicom: - 如果電腦尚未安裝 minicom,可以使用套件管理器來安裝。例如,在 Ubuntu 上,可以使用以下命令: ``` sudo apt-get install minicom ``` ##### 測試 UART 連接Step2:配置 Minicom: - 在電腦上打開終端。 - 使用設置選項運行 minicom: ``` minicom -s ``` - 在配置菜單中,選擇 "Serial port setup"(串行端口設置)。 - 將 Serial Device 設置為 `/dev/your_device`(或系統上的串行端口名稱)。 - :warning:在Host(筆電)與Target(AGX Xavier)都要設 - Host(筆電)Serial Device 設置為 `/dev/ttyUSB0` (根據) `dmesg |grep tty`抓到的結果 - Target(AGX Xavier)抓到的為`/dev/THS0`、`/dev/THS1`、`/dev/THS4`三個,由於不知哪個對應到我插上的針腳(Expansion Header (J30) 上的UART1_TX (發送) 針腳 8 和 UART1_RX (接收) 針腳10"),因使全部都設,參數同步之後透過訊號發送就能在target端使用`cat /dev/ttyTHS0`指令確認了 - 將波特率設置為 115200,其餘設置為 8N1(8 個數據位,無奇偶校驗,1 個停止位)。 - Hardware Flow Control: No - 如果提示,將配置保存為默認設置。 ![image](https://hackmd.io/_uploads/H13jNqwY6.png) ##### 測試 UART 連接Step3:UART通信測試 - 接著參考這篇做簡單的測試[Quick Test of UART in Linux](https://tkcheng.wordpress.com/2018/12/11/quick-test-of-uart-in-linux/) - Host端 ```bash= USER:# sudo su root:# echo Hello_World >> /dev/ttyUSB0 ``` - Target端 ```bash= sudo cat /dev/${your_ttydevice}| hexdump #eg sudo cat /dev/ttyTHS0 | hexdump ``` 原則上就是輪流把預設的Serieal Device(${your_ttydevice})依序設定為`/dev/THS0`、`/dev/THS1`、`/dev/THS4`,進入 `sudo cat /dev/ttyTHS0 | hexdump`指令狀態,看哪個對host端發送的訊號有反應 - 結果 - :100: 找出是ttyTHS0 ![image](https://hackmd.io/_uploads/rJvQKrvYp.png) #### 確認target system(AGX Xavier)的UART端口位置與名稱 透過"測試 UART 連接Step3:UART通信測試" 找出是ttyTHS0 因此下面的排查方法可以跳過了 #### 確認過程記錄 :::spoiler - 問題: 在"檢查設備識別步驟2:**在AGX Xavier`dmesg | grep tty`查找UART端口**"發現有3個ttyTHS設備,但不知哪個對應到 "Expansion Header (J30) 上的UART1_TX (發送) 針腳 8 和 UART1_RX (接收) 針腳10" 接下來的步驟為確認此問題 - 對策 :::success 有兩種方式可以去查詢確認: - 1. 從官方的[Jetson AGX Xavier Series Pinmux](https://developer.nvidia.com/embedded/downloads)文件查詢(Nvidia Jetson Download Center) - 2. 從source code的device tree的.dtsi文件(module level)查詢 - :warning:device tree 文件通常只在源代碼或開發環境中可用。在一個運行中的系統上,device tree 的編譯版本(.dtb 文件)會被加載 - 在建立source code的host system(例如筆電)而非target system(AGX Xavier)查找 ::: - 結果 - 1. 從官方的[Jetson AGX Xavier Series Pinmux](https://developer.nvidia.com/embedded/downloads)文件查詢(Nvidia Jetson Download Center)文件比對結果 ![image](https://hackmd.io/_uploads/HyuwULLFp.png =800x) - 根據pinmux文件,`UART1_TX` 信號位於 K53 引腳,並且在 GPIO 方面被映射為 `GPIO3_PR.02`,同時被標記為 `UA3_TXD`。 - 這意味著該引腳被用作 UART3 的發送(TX)信號。 - 為了在 device tree 文件中找到相對應的 `ttyTHS` 裝置,需要查找那些引用到 `GPIO3_PR.02` 或 `UA3_TXD` 的部分。這通常會在 `.dts` 或 `.dtsi` 文件中以某種形式引用到,例如 GPIO 的定義或是 UART 控制器的配置。 - 2. 從source code的device tree的.dtsi文件(module level)查詢結果 - 在 AGX Xavier 的 Linux source code目錄中運行以下命令: - 解壓縮以下檔案 ![image](https://hackmd.io/_uploads/SyJYOLUtp.png =400x) - 搜尋device tree文件中的關鍵字`GPIO3_PR.02` 或 `UA3_TXD` ```bash=! cd ~/Linux_for_Tegra/source/public/hardware/nvidia/ # 在當前目錄及其所有子目錄中的 .dts 或 .dtsi 文件中搜尋包含 GPIO3_PR.02 或 UA3_TXD 的行 grep -rnw --include=\*.dts --include=\*.dtsi '.' -e 'GPIO3_PR.02' -e 'UA3_TXD' # 使用正則表達式 grep -rnw --include=\*.dts --include=\*.dtsi '.' -e 'GPIO3_PR.02\|UA3_TXD' ``` 這些命令會在當前目錄及其子目錄中搜尋所有 `.dts` 和 `.dtsi` 文件,以找出包含 `GPIO3_PR.02` 或 `UA3_TXD` 的行。找到後,您應該可以看到這些引腳是如何在 device tree 中被配置,以及它們對應到哪個 `ttyTHS` 裝置。 :lock_with_ink_pen: 注意,`GPIO3_PR.02` 是對 GPIO 方面的引用,而 `UA3_TXD` 是對 UART 功能的引用。 - 硬件配置和設備樹(DTS)文件目錄 NVIDIA Tegra 平台的 Linux source codee tree ,特別是針對 T19x 系列(Tegra 194,即 AGX Xavier)。在這個源碼樹中,包含了硬件配置和設備樹(DTS)文件,這些文件用於定義和配置硬件資源和接口 ```bash= (base) yh@wsl2:~/Linux_for_Tegra$ tree -L 3 . ├── platform │ ├── t19x │ │ ├── common │ │ ├── galen │ │ ├── galen-industrial │ │ ├── jakku │ │ └── mccoy │ ├── t23x │ │ ├── common │ │ ├── concord │ │ ├── mandalore │ │ ├── p3768 │ │ └── prometheus │ └── tegra │ └── common └── soc ├── t19x │ ├── kernel-dts │ ├── kernel-include │ └── optee-dts ├── t23x │ ├── kernel-dts │ ├── kernel-include │ └── optee-dts └── tegra └── kernel-include ``` - 查找結果 `grep -rnw --include=\*.dts --include=\*.dtsi '.' -e 'ttyTHS\|uart\|GPIO3\|UA3_TXD'` - 完全找不到與`GPIO3`、`UA3_TXD`有關的關鍵字 ```bash= ./platform/t19x/galen/kernel-dts/common/tegra194-p2888-0000-a00.dtsi:36: combined-uart { ./platform/t19x/galen/kernel-dts/common/tegra194-p2888-0000-a00.dtsi:38: combined-uart; ./platform/t19x/jakku/kernel-dts/common/tegra194-p3668-common.dtsi:300: combined-uart { ./platform/t19x/jakku/kernel-dts/common/tegra194-p3668-common.dtsi:302: combined-uart; ./soc/t19x/kernel-dts/tegra194-soc/tegra194-soc-uart.dtsi:18: * tegra194-soc-uart.dtsi: Tegra194 soc dtsi file for UART instances ./soc/t19x/kernel-dts/tegra194-soc/tegra194-soc-uart.dtsi:205: combined-uart { ./soc/t19x/kernel-dts/tegra194-soc/tegra194-soc-uart.dtsi:206: compatible = "nvidia,tegra194-tcu", "nvidia,tegra186-combined-uart"; ./soc/t19x/kernel-dts/tegra194-soc/tegra194-soc-virt.dtsi:66: combined-uart { ./soc/t19x/kernel-dts/tegra194-soc/tegra194-soc-base.dtsi:40:#include "tegra194-soc-uart.dtsi" ``` ::: --- ## 編寫C程式來開啟並監聽 UART 連接 在 Linux 中,要使用標準的 POSIX 系統調用,如 `open()`, `read()`, `write()`, 和 `close()`,以及設置串行端口屬性(例如使用 `termios` 結構)。 - **配置系統服務**: - 為了使程式在系統開機後自動啟動,需要將其配置為一個系統服務。在基於 systemd 的系統中,這涉及創建一個新的服務文件(例如 `/etc/systemd/system/uart-listener.service`),並使用 `systemctl enable` 命令來啟用它。 - **處理 PC 輸入**: - 程式需要解析從 PC 端通過 UART 接收到的數據,並根據收到的訊息內容做出適當回應或執行動作。這可能涉及到簡單的字符串比 較,例如使用 `strcmp()` 函數來檢查是否收到了 "Hi"、"hi"、"Hello" 或 "hello"。 - **回傳訊息**: - 根據接收到的訊息,程式將回傳 "Hi" 或 "Hello"。這涉及到使用 `write()` 系統調用來發送回應。 - **記錄非標準訊息**: - 如果收到的訊息不是 "Hi"、"hi"、"Hello" 或 "hello",則需要將該訊息寫入一個日誌文件。這可能涉及到使用如 `fopen()`、`fprintf()` 和 `fclose()` 的文件操作函數。 - **處理訊息結束**: - 程式還需要能夠識別訊息的結束,這通常由換行符號 (`\n`) 表示。在讀取串行數據時,程式需要正確處理這個結束符。 - **錯誤處理**: - 需要在程式中添加適當的錯誤處理機制,以應對串行通信過程中可能出現的任何錯誤情況。 - **測試**: - 在將程式部署到 Xavier 上之前,應在開發環境中進行徹底測試,以確保所有功能按預期工作。 完成這些步驟後,程式應該能夠在 AGX Xavier 上執行,並在開機後自動啟動,正確地與通過 Micro USB B Connector (J501) 接口連接的 PC 進行交互。確保在 AGX Xavier 上進行端到端的測試,包括程序的自動啟動、正確解析 PC 端發送的指令,以及將收到的非預設指令記錄到日誌文件中 ## 參考資料與補充 #### [成大資工 Wiki。Universal Asynchronous Receiver/Transmitter (USART)](https://wiki.csie.ncku.edu.tw/embedded/USART) #### :pencil2:tty :::info 在計算機術語中,`tty` 是 "teletypewriter"(電傳打字機)的縮寫,歷史上用於指代早期的終端設備。在現代作業系統中,`tty` 通常用來指代終端介面,這是用戶與計算機系統交互的一個介面。 在 Unix 和類 Unix 系統(如 Linux 和 macOS)中,`tty` 有特定的含義: 1. **`tty` 設備**: - `tty` 設備代表一個文本輸入/輸出環境。這可以是實體設備,如連接到計算機的鍵盤和顯示器,也可以是虛擬的,如遠程終端會話(通過SSH等)或圖形介面中的終端仿真器。 2. **`/dev/tty` 文件**: - 在這些系統中,`tty` 設備通常在 `/dev` 目錄下有對應的設備文件。例如,實體串行端口可能被表示為 `/dev/ttyS0`(在 Linux 中),而虛擬終端(如終端仿真器)可能被表示為 `/dev/tty1`、`/dev/tty2` 等。 3. **`dmesg | grep tty` 命令**: - 在描述中,`dmesg | grep tty` 命令用於檢查系統消息緩衝區中與 `tty` 相關的消息。`dmesg` 命令顯示內核相關的消息(如硬件驅動加載信息),而 `grep tty` 用於篩選出包含 "tty" 的行。這在檢查新連接的串行設備(如通過 UART 介面的設備)時特別有用,因為當這些設備連接到系統時,內核會記錄相關信息,並且這些信息通常包含設備文件的名稱(如 `/dev/ttyUSB0`)。 在 Windows 系統中,串行端口通常表示為 “COM” 端口,如 COM1, COM2 等,這與 Unix 系統中的 `tty` 設備概念相似,但命名和管理方式有所不同。在 Windows 中,可以通過設備管理器查看和管理這些串行端口設備。 :::