• <noscript id="e0iig"><kbd id="e0iig"></kbd></noscript>
  • <td id="e0iig"></td>
  • <option id="e0iig"></option>
  • <noscript id="e0iig"><source id="e0iig"></source></noscript>
  • PCI串口編程

    標簽: vxworks  Linux PCI

    一、硬件環境

    硬件開發環境是PCI9054+FPGA,16串口或8串口。

    軟件開發平臺則是linux、VxWorks。

    主要是運用在工控領域,在一般商用平臺可能用不到這玩意。

    二、PCI相關知識

    PCI相關知識主要是參考了網上一些前輩寫的博文,這里將其貼出來,以免后來人繼續收集。

    PCI 總線學習筆記-PCI9054  http://blog.csdn.net/lg2lh/article/details/8042008

    PCI設備的地址空間               http://www.cnblogs.com/zszmhd/archive/2012/05/08/2490105.html

    另外《linux設備驅動開發詳解》(宋寶華)也有附帶講一些PCI驅動的編程,可以去瞄一瞄。

    第一篇博文主要是介紹PCI9054的相關信息,知道這個片子是怎么做的,以及其是如何將FPGA和PC機連接起來,熟悉硬件原理。在實際的編程中,我們可能根本感覺不到這個片子,作為一個“橋片”,操作系統其實都已經將廠商的驅動給集成了,并不會說還需要我們來進行過多的編程。

    第二篇博文具體內容很重要,是PCI設備的特性屬性,但作為使用者,其實我們用到的只是PCI的地址空間,其他的暫時不用理會,PCI地址空間即是系統在啟動時,PCI設備向CPU大佬申請的一段獨有的地址空間以供自己使用,這段地址的相關信息也就存儲在PCI配置空間的BAR(Base Address Registers)中。

                                                                               

    在linux中,需要調用相關的API函數就能將BAR的信息取出進行使用了。

    三、編程相關信息

    Linux中,PCI設備的編程其實和普通設備的編程很相似,沒有什么特別不同,主要的不同應該是映射PCI設備的地址空間。

    UART設備,在編程中使用uart_register_driver注冊tty設備,同時使用platform_driver_register注冊平臺總線。PCI-UART則是一實際總線,所以在注冊時,我們選擇注冊為實際的總線——pci_register_driver。(參考Linux xr17v35x.c)

                                                                   image

                                                                       image

                                                                       image

    xr_uart_driver為驅動特殊的信息,xrserial_pci_driver為驅動匹配提供操作方法,在probe方法中,對串口相關資源進行初始化(還未對硬件進行相關設置),為該設備關聯文件操作方法(uart_ops)。

    先來看看probe中主要做的事情。

    image

    在一個pci設備可以被使用之前,必須調用pci_enable_device進行**,該函數會調用底層代碼**PCI設備上的I/O和內存,使之可用。而pci_disable_device所做的事情剛好相反,告訴系統該PCI設備不再使用,同時,禁用相關的一些資源。

    經過一系列調用進入函數setup_port。

    image

    圖中的bar是在xrpciserial_boards數組中flags指定,此處是BAR0。(根據實際產品來,比如,我這里是BAR2)

    image

    若是我們的硬件沒有預先跟軟件這邊說,那軟件這邊有能力得到這個信息嗎?答案肯定是可以的。可以使用pci_select_bars來確定該PCI設備是否有申請到地址空間。(若沒有肯定是有錯誤了)

    bars = pci_select_bars(pdev, IORESOURCE_MEM);

    返回值若是0x5,則是代表BAR0,BAR2滿足select條件的,其條件就是函數的第二個參數IORESOURCE_MEM,因為PCI設備申請的地址空間有兩種訪問方式,一個是MEM,另一個是以IO方式訪問,(第二篇博文中有介紹)。

    這個時候我們可以使用這個返回值來映射這些BAR,若PCI設備使用了BAR0,那軟件就使用BAR0去操作特定的內存地址(寄存器)就可以了,一個PCI設備一般不會使用很多BAR的,最多一兩個就不得了了,要那么多,FPGA那邊也受不了。

    當然,有一些是強制性的就指定了該設備是使用哪一個BAR作為內存映射的基址,其他的BAR則是用于自定義用途,那軟件這邊強制性映射BAR0就好了。

    看圖片上,其實還調用了一個ioremap,BAR中的基址是屬于物理地址的,軟件想直接訪問物理地址是做不到,那么,就需要使用ioremap將物理地址轉化為虛擬地址,以供軟件來使用。映射完后,使用priv->remapped_bar[bar]就可以來操作設備上的寄存器了。

     

    分析完setup后(其實上面主要的工作是內存映射,其他的代碼比較繁瑣,在實際編程中可以適當簡潔)。

    進入serialxr_register_port。

    填充 uart_port 結構體。

    image 

    填充ops操作方法,也就是在應用層在使用open、write等,底層驅動最終會被調用的方法。使用uart_add_one_port將驅動與串口鏈接到一起,這樣,在應用層操作/dev/tty*時,相應的ops就會被調用了。

    image 

    到這里,probe函數大體就完成了,再之后的工作就是對ops的接口進行實現了,這里其實就可以參考一般串口設備到底在干嘛了,例如參考S3C2440的串口驅動。

    參考至http://blog.csdn.net/lizuobin2/article/details/51773305

    struct uart_ops {
    	unsigned int	(*tx_empty)(struct uart_port *);	 /* 串口的Tx FIFO緩存是否為空 */
    	void		(*set_mctrl)(struct uart_port *, unsigned int mctrl);	/* 設置串口modem控制 */
    	unsigned int	(*get_mctrl)(struct uart_port *);	/* 獲取串口modem控制 */
    	void		(*stop_tx)(struct uart_port *);		/* 禁止串口發送數據 */
    	void		(*start_tx)(struct uart_port *);	/* 使能串口發送數據 */	
    	void		(*send_xchar)(struct uart_port *, char ch);	/* 發送xChar */
    	void		(*stop_rx)(struct uart_port *);		/* 禁止串口接收數據 */
    	void		(*enable_ms)(struct uart_port *);	/* 使能modem的狀態信號 */
    	void		(*break_ctl)(struct uart_port *, int ctl);	/* 設置break信號 */
    	int			(*startup)(struct uart_port *);		/* 啟動串口,應用程序打開串口設備文件時,該函數會被調用 */
    	void		(*shutdown)(struct uart_port *);/* 關閉串口,應用程序關閉串口設備文件時,該函數會被調用 */
    	void		(*flush_buffer)(struct uart_port *);
    	void		(*set_termios)(struct uart_port *, struct ktermios *new,
    				       struct ktermios *old);	/* 設置串口參數 */
    	void		(*set_ldisc)(struct uart_port *);/* 設置線路規程 */
    	void		(*pm)(struct uart_port *, unsigned int state,
    			      unsigned int oldstate);	/* 串口電源管理 */
    	int		(*set_wake)(struct uart_port *, unsigned int state);
    
    	/*
    	 * Return a string describing the type of the port
    	 */
    	const char *(*type)(struct uart_port *);
    
    	/*
    	 * Release IO and memory resources used by the port.
    	 * This includes iounmap if necessary.
    	 */
    	void		(*release_port)(struct uart_port *);
    
    	/*
    	 * Request IO and memory resources used by the port.
    	 * This includes iomapping the port if necessary.
    	 */
    	int		(*request_port)(struct uart_port *);	/* 申請必要的IO端口/IO內存資源,必要時還可以重新映射串口端口 */
    	void		(*config_port)(struct uart_port *, int); /* 執行串口所需的自動配置 */
    	int		(*verify_port)(struct uart_port *, struct serial_struct *); /* 核實新串口的信息 */
    	int		(*ioctl)(struct uart_port *, unsigned int, unsigned long);
    #ifdef CONFIG_CONSOLE_POLL
    	void	(*poll_put_char)(struct uart_port *, unsigned char);
    	int		(*poll_get_char)(struct uart_port *);
    #endif
    };

    特別說明下,其中set_termios,與串口數據,流控開關,以及波特率設置相關。應用層若需要操控這些格式或者是打開流控等,需要使用tcgetattr函數得到對應串口的termios結構體。通過tcsetattr函數將設置后termios結構體傳遞給對應的串口。

    startup則與open函數相關,在串口進行open操作時,上層會調用uart_open(serial_core.c),然后調用打開的設備的文件操作函數方法的startup。shutdown則與之相對。

    ioctl則是支持一些該串口特殊的操作(若沒有,則不設置就可以了)。

    image

    config_port是在驅動調用uart_add_one_port,鏈接驅動和串口端口時就被調用的一個函數,這個函數調用的真是早啊,主要的作用也是做一些在串口還沒打開時需要處理的一些事,例如,設置串口的模式(232\485\422)。

    大概就是這些了,其實VxWorks的驅動與之類似,可以參考vxbTemplateSio.c或者是templateSio.c,應該不會遇到啥比較可怕的大坑 。


    另外需要注意的是VxWorks映射PCI BAR空間的問題,這些個代碼網上有很多,可以去直接搜索下,不必去從源碼上扣,別人已經整理出來了,我們就不必要花這個功夫了唄!


    分析的參考代碼地址。

    http://download.csdn.net/download/qq_30103483/10143170

    版權聲明:本文為qq_30103483原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
    本文鏈接:https://blog.csdn.net/qq_30103483/article/details/78702759

    智能推薦

    比特說串口編程

    要說一種植物,從種子發芽開始.要說計算機,從源頭開始.   在1.X系列的文章中,我們從最開始的燈泡的例子開始,一步步深入,知道了CPU是怎么工作的,配合內存可以自動工作。   前面的內容基本上是CPU工作原理的完整輪廓了。   我們知道現在使用的各種形態的計算機除了CPU還有很多別的設備,這些所有的設備都不在CPU里面,都是外部設備,簡稱:外設。常見外設有:鍵盤,鼠...

    七、Linux串口編程

    Linux下的串口編程過程如下(我就不給大家再講串口是什么了,不懂得朋友自行補上串口相關知識): 目錄 一、打開串口 二、初始化串口 1、 串口的初始化結構介紹 2、串口的初始化常用函數介紹  函數 tcgetattr 波特率相關的函數 cfsetispeed 和 cfsetospeed、cfgetispeed 、cfgetospeed 函數 tcflush 函數 tcseta...

    樹莓派串口編程

    串口通信通常用在多機通信中 比如樹莓派和語言模塊的通信 數據在T和R之間通信,這時全雙工的 全雙工:兩個人互相罵 半雙工: 講話的時候另一個人閉嘴 通信要求:1、語言相通 ——》數據格式 2、語速正常 ——》波特率 比如用串口使用樹莓派時,選擇了115200。 數據位,停止位,奇偶校驗位就是數據格式 如果不寫驅動,就要用到wiringPi 參考如下 ...

    HTML中常用操作關于:頁面跳轉,空格

    1.頁面跳轉 2.空格的代替符...

    freemarker + ItextRender 根據模板生成PDF文件

    1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...

    猜你喜歡

    電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!

    Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...

    requests實現全自動PPT模板

    http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...

    Linux C系統編程-線程互斥鎖(四)

    互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...

    統計學習方法 - 樸素貝葉斯

    引入問題:一機器在良好狀態生產合格產品幾率是 90%,在故障狀態生產合格產品幾率是 30%,機器良好的概率是 75%。若一日第一件產品是合格品,那么此日機器良好的概率是多少。 貝葉斯模型 生成模型與判別模型 判別模型,即要判斷這個東西到底是哪一類,也就是要求y,那就用給定的x去預測。 生成模型,是要生成一個模型,那就是誰根據什么生成了模型,誰就是類別y,根據的內容就是x 以上述例子,判斷一個生產出...

    精品国产乱码久久久久久蜜桃不卡