馬修才 , 溫曉輝 , 牛永紅
(1.內蒙古自治區大氣探測技術保障中心,內蒙古 呼和浩特 010051;2.內蒙古自治區氣象信息中心,內蒙古 呼和浩特 010051)
串口作為常用的通信接口,在嵌入式領域有著廣泛的應用。現如今,隨著計算機、網絡技術的發展,設備連入網絡的要求越來越迫切。目前,電子領域仍存在著大量的串口設備,對現有的串口設備進行改造使其具備聯網功能將耗費大量人力、財力。自動氣象站的氣壓傳感器[1]接口為232串口,為提高檢定/校準的效率,設計了氣壓傳感器多路采集器,將多路氣壓串口信號轉換為以太網信號傳輸,可以同時批量完成傳感器的檢定/校準任務。氣壓傳感器多路采集器在設計時,由于主控芯片自帶232串行端口數量有限,需要進行串口的擴展。串口擴展的實現方案多種多樣[2-6],本設計采用的是嵌入式微控制器+專用串口擴展芯片的方法[7-9]。本文以嵌入式設備驅動的整個開發流程為主線,從硬件電路設計、Linux下的擴展串口驅動、驅動測試等方面對本設計展開討論。
S3C2440A基于ARM920T核心,集成了強大的片上功能,多達130個復用用戶IO,4通道DMA控制器,3通道64位FIFO的UART,8通道多路復用ADC,支持IIC、IIS、SPI接口。
TL16C754B與EXAR的ST16C654管腳兼容,內置4個可獨立工作的UART單元,最高波特率可達3 Mbit/s,具有軟/硬件流控功能,可設置4路UART在不同的波特率下工作,并可選擇各種串行數據格式。對驅動程序開發人員來說,必須要了解以下引腳功能[10]:CS[A:D]為4路UART的選通信號引腳,低電平有效;A[0:2]為3位地址線;D[0:7]為8位數據線;TX/RX[A:D]為4路UART串行發送/接收引腳;INT[A:D]為4路UART的中斷信號引腳;RESET為芯片的復位信號,高電平有效;INTSEL為UART中斷屏蔽引腳,高電平時能UART中斷,低電平時需視MCR寄存器的第3位而定;CLKSEL為芯片時鐘選擇引腳,高電平時為低電平時的四倍頻;XTAL1、XTAL2為芯片外部晶振的輸入輸出引腳,外接晶振典型值為1.843 2 M、3.072 M。該器件內部共有20個8位寬的寄存器,在硬件連接正確的情況下,只要地址正確,就能像讀取MCU內部寄存器那樣讀取芯片的內部寄存器。通過A0~A2這3根地址線的8種狀態來區分20個寄存器,這20個寄存器中一定有一些是地址重疊的,這就需要通過讀寫信號及某些寄存器的特定位來進行唯一確定。S3C2440A與TL16C754B硬件連接圖,如圖1所示。

圖1 S3C2440A與TL16C754B硬件連接圖
S3C2440A的nGCS5地址譯碼芯片使能端口相連接,addr0[3:5]連接地址譯碼器的輸入,地址譯碼器的8個輸出端依次連接兩片TL16C754B的8個通道的片選信號,S3C2440A的addr[0:2]分別與TL16C754B的A[0:2]順序直連,S3C2440A讀寫控制信號與TL16C754B讀寫控制信號。兩片TL16C754B的8個通道UART寄存器的尋址范圍為:0×28000000-0×2800003F。
終端設備多種多樣,如串行終端、顯示器、telnet終端、HSS終端等。串口也屬于一種終端設備,它的驅動程序不僅僅是簡單的初始化硬件、接收/發送數據。串口驅動程序從上到下可分為四層:終端設備層、行規層、串口抽象層、串口芯片層。
終端設備層實現了用于注冊終端設備的接口函數tty_register_driver(),行規層實現了tty_disc結構體中的成員,串口抽象層的drivers/serial/serial_core.h將各類串口的共性概括出來,串口類型的識別/波特率的設置都是通過這一層來完成的。串口芯片層與具體的芯片有關,比如訪問地址和中斷號,并對芯片寄存器進行相關設置,對于標準串口,大部分驅動工作都是在這一層完成。TL16C754與8250/16550等標準串口在結構與操作方式上具有一致性,因此可以參考Linux內核中的8250/16550等標準串口驅動8250.c完成Linux下的TL16C754的驅動。
串口抽象層的serial_core.c為串口芯片層驅動提供了三個結構:uart_driver、uart_port、uart_ops以及對應的接口函數。uart_driver封裝了tty_driver,包含了串口設備的驅動名稱、設備名稱和主次設備號等信息。uart_port用來描述一個串口的地址、中斷號、端口類型等信息。uart_ops定義了針對串口的操作,如打開、關閉、線路設置等。
串口芯片層驅動程序需要完成的任務很明確:實現uart_driver、uart_port、uart_ops結構體實例并初始化它們;模塊初始化時調用uart_register_driver()和uart_add_one_port()完成串口驅動的注冊和端口的添加,模塊卸載時調用對應的“反函數”進行回收處理;根據串口芯片手冊實現uart_ops實例中的成員函數,串口芯片驅動的大部分任務是在這里完成的。
定義uart_driver實體serial_16c754,定義UART_NR個uart_port實體,本設計中UART_NR定義為8。driver_name成員代表驅動名稱,在Linux下用cat/proc/drivers命令所看到的驅動名稱;dev_name成員代表設備名稱,在Linux下用cat/proc/tty/driver/serialEX所看到的串口設備名稱,如ttysEX0;major成員代表驅動主設備號;minor成員代表驅動的起始次設備號;nr成員代表串口個數。
定義驅動的uart_ops,其中較為重要的成員函數具體實現將在2.4小節中進行介紹。除了調用uart_register_driver()和uart_add_one_port()完成串口驅動的注冊和端口的添加,Linux2.6內核中,還新增了platform驅動的結構,在內核啟動時由probe機制自動完成平臺設備結構數組和平臺驅動的匹配。在TL16C754B的驅動模塊初始化時,調用platform_device_register()和platform_driver_register()完成擴展串口平臺設備和平臺驅動的注冊。此前,需要定義擴展串口的平臺數據結構的定義和初始化。
plat_serial16c754_port結構體st16c654_data加入dmdk2410的platform_device結構體數組里,內核啟動時會將此結構體信息加載到內核中。內核將通過probe機制尋找與之匹配的驅動自動完成tl16c754串口驅動的加載。另外,模塊初始化函數中還要完成TL16C754B芯片復位和中斷申請的任務。
serial16c754_startup:應用程序的open()函數,最終會調用到serial16c754_startup,主要完成串口芯片寄存器的初始化工作。serial16c754_set_mctrl:應用程序的tcsetattr()函數,最終會調用serial16c754_set_mctrl,主要完成串行通信的通信格式的設定等功能。serial16c754_get_mctrl:應用程序的tcgetattr()函數,最終會調用serial16c754_get_mctrl,主要完成串行通信的通信格式的設定等功能。serial16c754_shutdown:應用程序的close()函數,最終會調用到serial16c754_shutdown,功能與serial16c754_startup相反。中斷處理函數static irqreturn_t serial16c754_interrupt:串口最終的數據收發都是在此完成的,當應用程序調用write()函數時,系統經過層層調用,達到驅動的serial16c754_start_tx函數,啟動串口發送中斷,驅動在中斷處理函數中將緩存中的數據發送出去,直到發送緩存為空,驅動程序調用serial16c754_stop_tx關閉串口發送中斷;當串口接收到數據,并且數據個數超過串口接收中斷觸發層級或者產生串口超時中斷,驅動在中斷處理函數中將接收到的數據寫入內核中的串口數據緩沖區中,此時如果應用程序調用了read()函數,內核會把內核中的串口數據緩沖區中的數據返回給應用程序。
驅動調試完成之后,重新編譯、下載內核,啟動新的內核后,執行“#cat/proc/tty/driver/serialEX”命令,可以查看擴展串口的內核相關信息。將8個擴展串口與安裝有串口卡(至少8個串口)的PC機相連,利用PC機下串口測試軟件和擴展串口平臺Linux下的簡單多串口應用程序完成擴展串口的驅動測試。PC串口測試軟件每秒鐘產生數據包長度為255的無符號char型隨機數據,通過串口卡串口發送到擴展串口,擴展串口平臺串口應用程序將接收到的數據通過擴展串口原樣發送回串口卡串口,由PC機串口測試軟件統計成功回送次數。在以上測試條件下運行2 330 min左右,8路串口在長時不間斷工作情況下,未產生丟包,可靠性高。
本設計為TL16C754B串口擴展的硬件系統設計和Linux下的串口驅動開發提供了一個示例,可作為設計多串口服務器時進行串口擴展的參考方案。氣壓傳感器多路采集器可以支持多路氣壓傳感器同時接入,大大提高傳感器的檢定/校準效率。