天天看點

Linux驅動開發篇-RS232/485/GPS驅動實驗1.Linux下UART驅動架構2.RS232驅動編寫3.移植minicom4.RS232驅動測試

目錄

1.Linux下UART驅動架構

    1)uart_driver注冊與登出

    2)uart_port的添加與移除

    3)uart_ops實作

2.RS232驅動編寫

    1)UART3 IO節點建立

    2)添加uart3節點

3.移植minicom

    1)移植ncurses

    2)移植minicom

4.RS232驅動測試

    1)RS232連接配接設定

    2)minicom設定

    3)RS232收發測試

      序列槽是很常用的一個外設,在Linux下通常通過序列槽和其他裝置或傳感器進行通信,根據電平的

      不同,序列槽分為TTL和RS232。不管是什麼樣的接口電平,其驅動程式都是一樣的,通過外接

      RS485這樣的晶片就可以将序列槽轉換為RS485信号,正點原子的I.MX6U-ALPHA開發闆就是這

      麼做的。對于正點原子的I.MX6U-ALPHA開發闆而言,RS232、RS485以及GPS子產品接口通通

      連接配接到了I.MX6U的UART3接口上,是以這些外設最終都歸結為UART3的序列槽驅動。本章我們

      就來學習一下如何驅動I.MX6U-ALPHA開發闆上的UART3序列槽,進而實作RS232、RS485以及

      GSP驅動。

1.Linux下UART驅動架構

    1)uart_driver注冊與登出

              同I2C、SPI一樣,Linux也提供了序列槽驅動架構,我們隻需要按照相應的序列槽架構編寫驅

              動程式即可。序列槽驅動沒有什麼主機端和裝置端之分,就隻有一個序列槽驅動,而且這個驅

              動也已經由NXP官方已經編寫好了,我們真正要做的就是在裝置樹中添加所要使用的序列槽

              節點資訊。當系統啟動以後序列槽驅動和裝置比對成功,相應的序列槽就會被驅動起來,生

              成/dev/ttymxcX(X=0….n)檔案。

              雖然序列槽驅動不需要我們去寫,但是序列槽驅動架構我們還是需要了解的,uart_driver結構

              體表示UART驅動,uart_driver定義在include/linux/serial_core.h檔案中,内容如下:

295 struct uart_driver {
296 	struct module *owner; /* 子產品所屬者 */
297 	const char *driver_name; /* 驅動名字 */
298 	const char *dev_name; /* 裝置名字 */
299 	int major; /* 主裝置号 */
300 	int minor; /* 次裝置号 */
301 	int nr; /* 裝置數 */
302 	struct console *cons; /* 控制台 */
303
304 	/*
305 	* these are private; the low level driver should not
306 	* touch these; they should be initialised to NULL
307 	*/
308 	struct uart_state *state;
309 	struct tty_driver *tty_driver;
310 };
           

              每個序列槽驅動都需要定義一個uart_driver,加載驅動的時候通過uart_register_driver函數

              向系統注冊這個uart_driver,此函數原型如下:

int uart_register_driver(struct uart_driver *drv)
           

              函數參數和傳回值含義如下:

              drv:要注冊的uart_driver。

              傳回值:0,成功;負值,失敗。

              登出驅動的時候也需要登出掉前面注冊的uart_driver,需要用到uart_unregister_driver

              函數,函數原型如下:

void uart_unregister_driver(struct uart_driver *drv)
           

              函數參數和傳回值含義如下:

              drv:要登出的uart_driver。

               傳回值:無。

    2)uart_port的添加與移除

              uart_port表示一個具體的port,uart_port定義在include/linux/serial_core.h檔案,内容如下

              (有省略):

117 struct uart_port {
118 	spinlock_t lock; /* port lock */
119 	unsigned long iobase; /* in/out[bwl] */
120 	unsigned char __iomem *membase; /* read/write[bwl] */
......
235 	const struct uart_ops *ops;
236 	unsigned int custom_divisor;
237 	unsigned int line; /* port index */
238 	unsigned int minor;
239 	resource_size_t mapbase; /* for ioremap */
240 	resource_size_t mapsize;
241 	struct device *dev; /* parent device */
......
250 };
           

              uart_port中最主要的就是第235行的ops,ops包含了序列槽的具體驅動函數,這個我們稍後

              再看。每個UART都有一個uart_port,那麼uart_port是怎麼和uart_driver結合起來的呢?

              這裡要用到uart_add_one_port函數,函數原型如下:

int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
           

              函數參數和傳回值含義如下:

              drv:此port對應的uart_driver。

              uport:要添加到uart_driver中的port。

              傳回值:0,成功;負值,失敗。

              解除安裝UART驅動的時候也需要将uart_port從相應的uart_driver中移除,需要用到

              uart_remove_one_port函數,函數原型如下:

int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
           

              函數參數和傳回值含義如下:

              drv:要解除安裝的port所對應的uart_driver。

              uport:要解除安裝的uart_port。

              傳回值:0,成功;負值,失敗。

    3)uart_ops實作

             在上面講解uart_port的時候說過,uart_port中的ops成員變量很重要,因為ops包含了針對

             UART具體的驅動函數,Linux系統收發資料最終調用的都是ops中的函數。ops是uart_ops

             類型的結構體指針變量,uart_ops定義在include/linux/serial_core.h檔案中,内容如下:

49 struct uart_ops {
50 	unsigned int (*tx_empty)(struct uart_port *);
51 	void (*set_mctrl)(struct uart_port *, unsigned int mctrl);
52 	unsigned int (*get_mctrl)(struct uart_port *);
53 	void (*stop_tx)(struct uart_port *);
54 	void (*start_tx)(struct uart_port *);
55 	void (*throttle)(struct uart_port *);
56 	void (*unthrottle)(struct uart_port *);
57 	void (*send_xchar)(struct uart_port *, char ch);
58 	void (*stop_rx)(struct uart_port *);
59 	void (*enable_ms)(struct uart_port *);
60 	void (*break_ctl)(struct uart_port *, int ctl);
61 	int (*startup)(struct uart_port *);
62 	void (*shutdown)(struct uart_port *);
63 	void (*flush_buffer)(struct uart_port *);
64 	void (*set_termios)(struct uart_port *, struct ktermios *new,
65 						struct ktermios *old);
66 	void (*set_ldisc)(struct uart_port *, struct ktermios *);
67 	void (*pm)(struct uart_port *, unsigned int state,
68 				unsigned int oldstate);
69
70 	/*
71 	* Return a string describing the type of the port
72 	*/
73 	const char *(*type)(struct uart_port *);
74
75 	/*
76 	* Release IO and memory resources used by the port.
77 	* This includes iounmap if necessary.
78 	*/
79 	void (*release_port)(struct uart_port *);
80
81 	/*
82 	* Request IO and memory resources used by the port.
83 	* This includes iomapping the port if necessary.
84 	*/
85 	int (*request_port)(struct uart_port *);
86 	void (*config_port)(struct uart_port *, int);
87 	int (*verify_port)(struct uart_port *, struct serial_struct *);
88 	int (*ioctl)(struct uart_port *, unsigned int, unsigned long);
89 	#ifdef CONFIG_CONSOLE_POLL
90 	int (*poll_init)(struct uart_port *);
91 	void (*poll_put_char)(struct uart_port *, unsigned char);
92 	int (*poll_get_char)(struct uart_port *);
93 	#endif
94 };
           

              UART驅動編寫人員需要實作uart_ops,因為uart_ops是最底層的UART驅動接口,是實實

              在在的和UART寄存器打交道的。關于uart_ops結構體中的這些函數的具體含義請參考

              Documentation/serial/driver這個文檔。UART驅動架構大概就是這些,接下來我們理論聯

              系實際,看一下NXP官方的UART驅動檔案是如何編寫的。

2.RS232驅動編寫

      前面我們已經說過了,I.MX6U的UART驅動NXP已經編寫好了,是以不需要我們編寫。我們要

      做的就是在裝置樹中添加UART3對應的裝置節點即可。打開imx6ull-alientek-emmc.dts檔案,

      在此檔案中隻有UART1對應的uart1節點,并沒有UART3對應的節點,是以我們可以參考uart1

      節點建立uart3節點。

    1)UART3 IO節點建立

              UART3用到了UART3_TXD和UART3_RXD這兩個IO,是以要先在iomuxc中建立UART3

              對應的pinctrl子節點,在iomuxc中添加如下内容:

1 pinctrl_uart3: uart3grp {
2     fsl,pins = <
3         MX6UL_PAD_UART3_TX_DATA__UART3_DCE_TX 0X1b0b1
4         MX6UL_PAD_UART3_RX_DATA__UART3_DCE_RX 0X1b0b1
5     >;
6 };
           

               最後檢查一下UART3_TX和UART3_RX這兩個引腳有沒有被用作其他功能,如果有的話

               要将其屏蔽掉,保證這兩個IO隻用作UART3,切記!!!

    2)添加uart3節點

              預設情況下imx6ull-alientek-emmc.dts中隻有uart1和uart2這兩個節點,如圖1所示:

Linux驅動開發篇-RS232/485/GPS驅動實驗1.Linux下UART驅動架構2.RS232驅動編寫3.移植minicom4.RS232驅動測試

圖1 uart1和 uart2節點 

              uart1是UART1的,在正點原子的I.MX6U-ALPHA開發闆上沒有用到UART2,而且UART2

              預設用到了UART3的IO,是以需要将uart2這個節點删除掉,然後加上UART3對應的

              uart3,uart3節點内容如下: 

1 &uart3 {
2 	pinctrl-names = "default";
3 	pinctrl-0 = <&pinctrl_uart3>;
4 	status = "okay";
5 };
           

              完成以後重新編譯裝置樹并使用新的裝置樹啟動Linux,如果裝置樹修改成功的話,系統

              啟動以後就會生成一個名為“/dev/ttymxc2”的裝置檔案,ttymxc2就是UART3對應的裝置

              檔案,應用程式可以通過通路ttymxc2來實作對UART3的操作。

3.移植minicom

      minicom類似我們常用的序列槽調試助手,是Linux下很常用的一個序列槽工具,将minicom移植到

      我們的開發闆中,這樣我們就可以借助minicom對序列槽進行讀寫操作。

    1)移植ncurses

              minicom需要用到ncurses,依次需要先移植ncurses,如果前面已經移植好了ncurses,那

              麼這裡就不需要再次移植了,隻需要在編譯minicom的時候指定ncurses庫和頭檔案目錄即

              可。

              首先在ubuntu中建立一個目錄來存放我們要移植的檔案,比如我

              在/home/zuozhongkai/linux/IMX6ULL目錄下建立了一個名為“tool”的目錄來存放所有的移

              植檔案。然後下載下傳ncurses源碼,将ncurses-6.0.tar.gz拷貝到Ubuntu中建立的tool目錄

              下,然後進行解壓,解壓指令如下:

tar -vxzf ncurses-6.0.tar.gz
           

              解壓完成以後就會生成一個名為“ncurses-6.0”的檔案夾,此檔案夾就是ncurese的源碼文

              件夾。在tool目錄下建立名為“ncurses”目錄,用于儲存ncurses編譯結果,一切準備就緒

              以後就可以編譯ncureses庫了。進入到ncureses源碼目錄下,也就是剛剛解壓出來的

              ncurses-6.0目錄中,首先是配置ncureses,輸入如下指令:

./configure --prefix=/home/zuozhongkai/linux/IMX6ULL/tool/ncurses --host=arm-linux-

gnueabihf --target=arm-linux-gnueabihf --with-shared --without-profile --disable-stripping --without-progs --with-manpages --without-tests

              configure就是配置腳本,--prefix用于指定編譯結果的儲存目錄,這裡肯定将編譯結果儲存

              到我們前面建立的“ncurses”目錄中。--host用于指定編譯器字首,這裡設定為“arm-linux-

              gnueabihf”,--target用于指定目标,這裡也設定為“arm-linux-gnueabihf”。配置指令寫好

              以後點選Enter鍵,等待配置完成,配置成功以後如圖2所示:

Linux驅動開發篇-RS232/485/GPS驅動實驗1.Linux下UART驅動架構2.RS232驅動編寫3.移植minicom4.RS232驅動測試

圖2 配置成功

              配置成功以後輸入“make”指令開始編譯,編譯成功以後如圖3所示:

Linux驅動開發篇-RS232/485/GPS驅動實驗1.Linux下UART驅動架構2.RS232驅動編寫3.移植minicom4.RS232驅動測試

 圖3 編譯成功

              編譯成功以後輸入“makeinstall”指令安裝,安裝的意思就是将編譯出來的結果拷貝到--

              pfefix指定的目錄裡面去。安裝成功以後如圖4所示: 

Linux驅動開發篇-RS232/485/GPS驅動實驗1.Linux下UART驅動架構2.RS232驅動編寫3.移植minicom4.RS232驅動測試

圖4 安裝成功

              安裝成功以後檢視一下前面建立的“ncurses”檔案夾,會發現裡面多了一些東西,如圖5所

              示:

Linux驅動開發篇-RS232/485/GPS驅動實驗1.Linux下UART驅動架構2.RS232驅動編寫3.移植minicom4.RS232驅動測試

圖5 編譯出來的結果

              我們需要将圖5中include、lib和share這三個目錄中存放的檔案分别拷貝到開發闆根檔案系

              統中的/usr/include、/usr/lib和/usr/share這三個目錄中,如果哪個目錄不存在的話請自行

              建立!!拷貝指令如下:

sudo cp lib/* /home/zuozhongkai/linux/nfs/rootfs/usr/lib/ -rfa

sudo cp share/* /home/zuozhongkai/linux/nfs/rootfs/usr/share/ -rfa

sudo cp include/* /home/zuozhongkai/linux/nfs/rootfs/usr/include/ -rfa

              然後在開發闆根目錄的/etc/profile(沒有的話自己建立一個)檔案中添加如下所示内容:

1 #!/bin/sh
2 LD_LIBRARY_PATH=/lib:/usr/lib:$LD_LIBRARY_PATH
3 export LD_LIBRARY_PATH
4
5 export TERM=vt100
6 export TERMINFO=/usr/share/terminfo
           

    2)移植minicom

              繼續移植minicom,擷取minicom源碼,将minicom-2.7.1.tar.gz拷貝到ubuntu中

              的/home/zuozhongkai/linux/IMX6ULL/tool目錄下,然後在tool目錄下建立一個名為

              “minicom”的子目錄,用于存放minicom編譯結果。一切準備好以後就可以編譯minicom

              了,先解壓minicom,指令如下:

tar -vxzf minicom-2.7.1.tar.gz
           

              解壓完成以後會生成一個叫做minicom-2.7.1的檔案夾,這個就是minicom的源碼,進入到

              此目錄中,然後配置minicom,配置指令如下:

cd minicom-2.7.1/ //進入 minicom 源碼目錄

./configure CC=arm-linux-gnueabihf-gcc --prefix=/home/zuozhongkai/linux/IMX6ULL/tool/

minicom --host=arm-linux-gnueabihf CPPFLAGS=-I/home/zuozhongkai/linux/IMX6ULL/tool/

ncurses/include LDFLAGS=-L/home/zuozhongkai/linux/IMX6ULL/tool/ncurses/lib -enable-cfg-dir=/etc/minicom //配置

              CC表示要使用的gcc交叉編譯器,--prefix指定編譯出來的檔案存放目錄,肯定要存放到我

              們前面建立的minicom目錄中。--host指定交叉編譯器字首,CPPFLAGS指定ncurses的頭

              檔案路徑,LDFLAGS指定ncurses的庫路徑。配置成功的話如圖6所示:

Linux驅動開發篇-RS232/485/GPS驅動實驗1.Linux下UART驅動架構2.RS232驅動編寫3.移植minicom4.RS232驅動測試

圖6 配置成功

              配置成功以後執行如下指令編譯并安裝:

make
make install
           

              編譯安裝完成以後,前面建立的minicom目錄内容如圖7所示:

Linux驅動開發篇-RS232/485/GPS驅動實驗1.Linux下UART驅動架構2.RS232驅動編寫3.移植minicom4.RS232驅動測試

 圖7 minicom安裝編譯結果

              将minicom目錄中bin子目錄下的所有檔案拷貝到開發闆根目錄中的/usr/bin目錄下,指令

              如下:

sudo cp bin/* /home/zuozhongkai/linux/nfs/rootfs/usr/bin/
           

              完成以後在開發闆中輸入“minicom -v”來檢視minicom工作是否正常,結果如圖8所示:

Linux驅動開發篇-RS232/485/GPS驅動實驗1.Linux下UART驅動架構2.RS232驅動編寫3.移植minicom4.RS232驅動測試

圖8 minicom版本号

              從圖8可以看出,此時minicom版本号為2.7.1,minicom版本号檢視正常。輸入如下指令打

              開minicom配置界面:

minicom -s
           

              結果是打不開minicom配置界面,提示如圖9所示資訊:

Linux驅動開發篇-RS232/485/GPS驅動實驗1.Linux下UART驅動架構2.RS232驅動編寫3.移植minicom4.RS232驅動測試

 圖9 minicom打開失敗

              從圖9可以看出,minicom異常嚣張,竟然讓我們“Go away”,這能容忍?!必須要治一

              下。解決方法很簡單,建立/etc/passwd檔案,然後在passwd檔案裡面輸入如下所示内

               容: 

root:x:0:0:root:/root:/bin/sh
           

              完成以後重新開機開發闆!

              開發闆重新開機以後再執行“minicom -s”指令,此時minicom配置界面就可以打開了,如圖10

              所示:

Linux驅動開發篇-RS232/485/GPS驅動實驗1.Linux下UART驅動架構2.RS232驅動編寫3.移植minicom4.RS232驅動測試

圖10 mincom 配置界面

              如果能出現圖10所示界面,那麼就說明mincom工作正常了。

4.RS232驅動測試

    1)RS232連接配接設定

              在測試之前要先将I.MX6U-ALPHA開發闆的RS232與電腦連接配接起來,首先設定JP1跳線

              帽,如圖11所示:

Linux驅動開發篇-RS232/485/GPS驅動實驗1.Linux下UART驅動架構2.RS232驅動編寫3.移植minicom4.RS232驅動測試

 圖11 UART3 跳線帽設定

              跳線帽設定好以後使用RS232線将開發闆與電腦連接配接起來,這裡建議使用USB轉

              DB9(RS232)資料線,比如正點原子售賣的CH340方案的USB轉公頭DB9資料線,如圖12

              所示: 

Linux驅動開發篇-RS232/485/GPS驅動實驗1.Linux下UART驅動架構2.RS232驅動編寫3.移植minicom4.RS232驅動測試

圖12 USB 轉 DB9資料線

              圖12中所示的資料線是帶有CH340晶片的,是以當連接配接到電腦以後就會出現一個COM

              口,這個COM口就是我們要使用的COM口。比如在我的電腦上就是COM9,在

              SecureCRT上建立一個連接配接,序列槽為COM9,波特率為115200。

    2)minicom設定

              在開發闆中輸入“minicom -s”,打開minicom配置界面,然後選中“Serial port setup”,如圖

              13所示:

Linux驅動開發篇-RS232/485/GPS驅動實驗1.Linux下UART驅動架構2.RS232驅動編寫3.移植minicom4.RS232驅動測試

圖13 選中序列槽設定項

             選中“Serial port setup”以後點選回車,進入設定菜單,如圖14所示: 

Linux驅動開發篇-RS232/485/GPS驅動實驗1.Linux下UART驅動架構2.RS232驅動編寫3.移植minicom4.RS232驅動測試

圖14 序列槽設定項

              圖14中有7個設定項目,分别對應A、B……G,比如第一個是選中序列槽,UART3的序列槽文

              件為/dev/ttymxc2,是以序列槽設定要設定為/dev/ttymxc2。設定方法就是按下鍵盤上

              的‘A’,然後輸入“/dev/ttymxc2”即可,如圖14所示: 

Linux驅動開發篇-RS232/485/GPS驅動實驗1.Linux下UART驅動架構2.RS232驅動編寫3.移植minicom4.RS232驅動測試

圖14 序列槽裝置檔案設定

              設定完以後按下Enter鍵确認,确認完以後就可以設定其他的配置項。比如E設定波特率、

              資料位和停止位的、F設定硬體流控的,設定方法都一樣,設定完以後如圖15所示: 

Linux驅動開發篇-RS232/485/GPS驅動實驗1.Linux下UART驅動架構2.RS232驅動編寫3.移植minicom4.RS232驅動測試

 圖15 UART3設定

              都設定完成以後按下Enter鍵确認并退出,這時候會退回到如圖13所示的界面,按下ESC鍵

              退出圖13所示的配置界面,退出以後如圖16所示: 

Linux驅動開發篇-RS232/485/GPS驅動實驗1.Linux下UART驅動架構2.RS232驅動編寫3.移植minicom4.RS232驅動測試

圖16 minicom序列槽界面

              圖14就是我們的序列槽調試界面,可以看出目前的序列槽檔案為/dev/ttymxc2,按下CTRL-

              A,然後再按下Z就可以打開minicom幫助資訊界面,如圖17所示:

Linux驅動開發篇-RS232/485/GPS驅動實驗1.Linux下UART驅動架構2.RS232驅動編寫3.移植minicom4.RS232驅動測試

 圖17  minicom幫助資訊界面

              從圖17可以看出,minicom有很多快捷鍵,本實驗我們打開minicom的回顯功能,回顯功

               能配置項為“localEchoon/off..E”,是以按下E即可打開/關閉回顯功能。

    3)RS232收發測試

              1、發送測試

                   首先測試開發闆通過UART3向電腦發送資料的功能,需要打開minicom的回顯功能(不

                   打開也可以,但是在minicom中看不到自己輸入的内容),回顯功能打開以後輸入

                    “AAAA”,如圖18所示:

Linux驅動開發篇-RS232/485/GPS驅動實驗1.Linux下UART驅動架構2.RS232驅動編寫3.移植minicom4.RS232驅動測試

圖18 通過UART3向電腦發送“AAAA”

                   圖18中的“AAAA”相當于開發闆通過UART3向電腦發送“AAAA”,那麼COM9就會接收

                   到“AAAA”,SecureCRT中COM9收到的資料如圖19所示: 

Linux驅動開發篇-RS232/485/GPS驅動實驗1.Linux下UART驅動架構2.RS232驅動編寫3.移植minicom4.RS232驅動測試

 圖19 電腦接收到開發闆發送過來的資料

                   可以看出,開發闆通過UART3向電腦發送資料正常,那麼接下來就測試開發闆資料接

                   收功能。

             2、接收測試

                   接下來測試開發闆的UART3接收功能,同樣的,要先打開SecureCRT上COM9的本地

                   回顯,否則的話你在COM9上輸出的内容會看不到,但是實際上是已經發送給了開發

                   闆。選中SecureCRT的Options->SessionOptions->Adavnced,打開回話配置界面,

                   然後選中“Localecho”,如圖20所示: 

Linux驅動開發篇-RS232/485/GPS驅動實驗1.Linux下UART驅動架構2.RS232驅動編寫3.移植minicom4.RS232驅動測試

圖20 電腦向開發闆發送“BBBB”

                   SecureCRT設定好以後向開發闆發送一個“BBBB”,在SecureCRT的COM9上輸入

                   “BBBB”,如圖21所示:

Linux驅動開發篇-RS232/485/GPS驅動實驗1.Linux下UART驅動架構2.RS232驅動編寫3.移植minicom4.RS232驅動測試

圖21 電腦向開發闆發送“BBBB”  

                   此時開發闆的minicom就會接收到發送過來的“BBBB”,如圖22所示:

Linux驅動開發篇-RS232/485/GPS驅動實驗1.Linux下UART驅動架構2.RS232驅動編寫3.移植minicom4.RS232驅動測試

 圖22 開發闆接收到發送過來的資料

                   UART3收發測試都沒有問題,說明我們的UART3驅動工作正常。如果要退出minicom

                   的話,在minicom通信界面按下CRTL+A,然後按下X來關閉minicom。關于minicom的

                   使用我們這裡講的很簡單,大家可以在網上查找更加詳細的minicom使用教程。

繼續閱讀