PC 机 UART(NS8250)详解
PC 機 UART(NS8250)詳解
異步串行通信原理
兩臺計算機/設備進行數據交換,即通信,必須像人們對話一樣使用同一種語言。在計算機通信術語中,我們把計算機/設備與計算機/設備之間的“語言”稱為通信協議。通信協議規定了傳送一個有效數據長度單位的格式。通常我們使用術語“幀”來形容這種格式。為了能讓通信雙方確定收/發的順序和進行一些錯誤檢測操作,除了必要的數據以外,在傳輸的一幀信息中還包含用于同步和錯誤檢測的其它信息,例如在開始傳輸數據信息之前先發送起始/同步或通信控制信息,并且在發送完需要的數據信息之后再傳輸一些校驗信息等。
串行通信是指在線路上以比特流一次一個比特進行傳輸的通信方式。串行通信可分為異步和同步串行通信兩種類型。它們之間的主要區別在于傳輸時同步的通信單位或幀的長度不同。異步串行通信以一個字符作為一幀進行傳輸,而同步串行通信則以多個字符或字節組成的序列作為一幀數據進行傳輸。若再以人們之間的對話作比喻,那么異步通信如同對話雙方講話速度很慢,說話時一個字一個字地 “蹦”出來,在說出每個字后可以停頓任意長時間。而同步通信則如同通信雙方以連貫的一句話作為對話單位。可以看出,實際上如果我們把傳輸單位縮小到一個比特位時(對話時用一個個拼音字母),那么以一個字符進行傳輸的異步串行通信也可以看作是一種同步傳輸通信方式。因此異步和同步通信的區分主要是一種習慣或慣例上的劃分。
異步串行傳輸格式
異步串行通信傳輸的幀格式如下圖所示。傳輸一個字符由起始位、數據位、奇偶校驗位和停止位構成。其中起始位起同步作用,值恒為0。數據位是傳輸的實際數據,即一個字符的代碼。其長度可以是5到8個比特。奇偶校驗位可有可無,由軟件編程設定。停止位恒為1,可由軟件設定為1、1.5 或 2 個比特位。在通信開始發送信息之前,雙方必須設置成相同的格式。在異步通信規范中,把傳送 1 稱為傳號(MARK),傳送 0 稱為空號(SPACE)。
當無數據傳輸時,發送方處于傳號(MARK) 狀態,持續發送 1。若需要發送數據,則發送方需要先發送一個持續時間為1比特位的空號,作為起始位。接收方收到空號后,就開始與發送方同步,然后接收隨后的數據。若程序中設置了奇偶校驗位,那么在數據傳輸完之后還需要接收奇偶校驗位。最后是停止位。在一幀發送完后可以立刻發送下一幀,也可以先發送傳號,過一段時間再發下一幀。
在接收一字符幀時,接收方可能會檢測到三種錯誤之一:
- 奇偶校驗錯誤。此時程序應該要求對方重新發送該字符;
- 過速錯誤。當程序取字符速度小于接收速度,就會發生這種錯誤。此時應該修改程序,加大取字符的頻率;
- 幀格式錯誤。當接收到的格式信息不正確時會發生這種錯誤。例如在應該收到停止位時卻收到了空號。通常造成這種錯誤的情況除了線路干擾以外,很可能是通信雙方設置的幀格式不同。
通用異步接收/發送控制器(UART)
為實現串行通信,IBM PC/XT 機(下文簡稱 PC 機)上通常都帶有 2 個符合 RS-232C 標準的串行接口,并使用通用異步接收/發送器控制芯片 UART(Universal Asynchronous Receiver-Transmitter) 組成的串行控制器來處理串行數據的收發工作。PC 機上的串行接口通常使用 25 芯的 DB-25 或 9 芯的 DB-9 連接器,主要用來連接 MODEM 設備,因此 RS-232C 標準規定了很多 MODEM 專用接口引線。
以前的 PC 機都使用國家半導體公司的 NS8250 或 NS16450 UART 芯片,現在的PC機則使用了 16650A 及其兼容芯片,但都與 NS8250/NS16450 芯片兼容。 NS8250/NS16450 與 16650A 芯片的主要區別在于16650A 芯片還支持 FIFO 傳輸方式。在這種方式下,UART 可以在接收或發送了最多16個字符后才引發一次中斷,從而可以減輕系統和 CPU 的負擔。
當 PC 機上電啟動時,系統 RESET 信號通過 NS8250 的 MR 引腳使得 UART 內部寄存器和控制邏輯復位。此后若要使用 UART 就需要對其進行初始化編程操作,以設置 UART 的波特率、數據位數以及工作方式等。
UART 硬件邏輯
PC 機中使用 UART 的異步串行口硬件邏輯如下圖所示。其中可分成 3 部分。
第一部分主要包括數據總線緩沖 D7~D0 、 內部寄存器選擇引腳A0~A2 、 CPU 讀/寫數據選通引腳 DISTR 和 DOSTR、芯片復位引腳 MR、中斷請求輸出引腳 INTRPT 以及用戶自定義的用于禁止/允許中斷的引腳 OUT2。 當 OUT2 為 1 時可禁止 UART 發出中斷請求信號。
第二部分主要包括 UART與 RS-232 接口的引腳部分。這些引腳主要用于接收/發送串行數據和產生或接收 MODEM 控制信號。串行輸出數據引腳(SOUT)向線路上發送比特數據流;輸入數據引腳(SIN)接收線路上傳來的比特數據流;數據設備就緒引腳(DSR)用于通信設備(MODEM)通知 UART 已準備好接收數據;數據終端就緒引腳(DTR)則用于計算機通知 MODEM 已準備好接收數據…由于這部分和編程關系不大,所以略去。
第三部分是 UART 芯片時鐘輸入電路部分。UART 的工作時鐘可以通過在引腳 XTAL1 和 XTAL2 之間連接一個晶體振蕩器來產生,也可以通過 XTAL1 直接從外部引入。PC 機則使用了后一種辦法,在 XTAL1 引腳上直接輸入 1.8432MHz 的時鐘信號。UART 發送波特率的 16 倍由引腳 BAUDOUT 輸出,而引腳 RCLK 是接收數據的波特率。由于這兩者連接在一起,因此 PC 機上發送和接收數據波特率相同。
NS8250 的寄存器
與中斷控制芯片 8259A 一樣,UART 也是一個可編程的控制芯片。UART 的內部組成框圖如下。
NS8250 中 CPU 能夠訪問的寄存器有 9 個,但是用于選擇這些寄存器的地址線 A2~A0 最多能夠選擇 8 個寄存器。因此 NS8250 就在線路控制寄存器(LCR)中拿出一位(位 7)用作選擇除數鎖存(divisor latch)寄存器(b7=1時選中) 。位 7 被稱作除數鎖存訪問位(DLAB,Divisor Latch Access Bit)。
因為端口 0x3F8 和 0x3F9是復用的,所以一共有 7 個端口地址。端口地址及寄存器的用途見下表。
| COM1 | 0x3F8 - 0x3FF | IRQ4 |
| COM2 | 0x2F8 - 0x2FF | IRQ3 |
NS8250 設計有2個中斷寄存器(IER-中斷允許寄存器, IIR-中斷識別寄存器)和4級中斷。4級中斷的優先權,是按照串行通信過程中事件的緊迫程度安排的,是固定不變的。中斷允許寄存器(IER)的低4位控制這4級中斷是否被允許:某位為1,則對應的中斷被允許;否則,被禁止。
(下表的端口一列,括號里的是COM2的端口地址)
| 0x3F8 (0x2F8) | 寫 | DLAB=0 | 寫發送保持寄存器 THR,THR 會把寫入的字符發送出去。 |
| 讀 | DLAB=0 | 讀接收緩存寄存器 RBR , RBR 內含有收到的字符。 | |
| 讀/寫 | DLAB=1 | 讀/寫波特率因子的低字節 (LSB ) | |
| 0x3F9 (0x2F9) | 讀/寫 | DLAB=1 | 讀/寫波特率因子的高字節 (MSB ) |
| 讀/寫 | DLAB=0 | IER(Interrupt enable register),中斷允許寄存器 [7:4] 全 0 保留不用; [3] = 1 允許modem狀態中斷; [2] = 1 允許接收器線路狀態中斷; [1] = 1 允許發送保持寄存器空中斷; [0] = 1 允許接收到數據中斷; | |
| 0x3FA (0x2FA) | 讀 | IIR(Interrupt identification register),中斷識別寄存器。 中斷處理程序以此判斷此次中斷是 4 種中的那一種。 [7:3]全 0 保留不用; [2:1] = 11 線路狀態改變中斷,優先級最高,讀線路狀態可復位; = 10 己接收到數據中斷, 讀接收數據可復位; = 01 發送保持寄存器空中斷,讀 IIR 或寫發送保持寄存器可復位; = 00 MODEM 狀態改變中斷,讀 MODEM狀態可復位 。 [0] =0,有待處理的中斷;=1,無中斷 | |
| 0x3FB (0x2FB) | 寫 | LCR,線路控制寄存器 具體內容見下文。 | |
| 0x3FC (0x3FC) | 寫 | MCR,MODEM 控制寄存器 [7:5] 全 0 保留 ; [4] = 1,芯片處于循環反饋診斷操作模式;在這種方式下UART芯片內部自動把輸入(SIN) 和輸出 (SOUT) 引腳 “短接”,若此時發送的數據和接收到的數據相等,那么就說明 UART 芯片工作正常。注意:但該方式僅用于診斷測試UART芯片的好壞,不能作為一種實際的通信方式使用。 [3] = 1, 輔助用戶指定輸出2(Auxiliary output 2,OUT2), 允 許 INTRPT 到系統; [2] = 1, 輔助用戶指定輸出1(Auxiliary output 1,OUT1), PC 機未用; [1] = 1, 使請求發送 RTS( Request to send) 有效,可以理解為使能發送; [0] = 1, 使數據終端就緒DTR( Data terminal ready)有效,可以理解為使能接收; | |
| 0x3FD (0x2FD) | 讀 | LSR,線路狀態寄存器 [7] = 0, 保留; [6] = 1, 發送移位寄存器為空; [5] = 1, 發送保持寄存器為空,可以取字符發送; [4] = 1, 接收到滿足間斷條件的位序列; [3] = 1, 幀格式錯誤; [2] = 1, 奇偶校驗錯誤; [1] = 1, 超越覆蓋錯誤; [0] = 1, 接收器數據準備好,系統可讀取。 | |
| 0x3FE (0x2FE) | 讀 | MSR,MODEM狀態寄存器。δδ 表示信號或條件發生變化。 [7] = 1, 載波檢測(CD)有效; [6] = 1, 響鈴指示(RI)有效; [5] = 1, 數據設備就緒(DSR)有效; [4] = 1, 清除發送 (CTS) 有效; [3] = 1, 檢測到 δδ 載波 ; [2] = 1, 檢測到響鈴信號邊沿; [1] = 1, δδ 數據設備就緒(DSR); [0] = 1, δδ 清除發送(CTS)。 |
LCR:線路控制寄存器
| [1:0] | 數據位長度。 00:5位數據位; 01 : 6位數據位; 10 : 7位數據位; 11 : 8位數據位 |
| [2] | 停止位長度。 =1:此時停止位長度依賴于數據位長度:若數據位長度是5位 ,則停止位為 1.5 位 ;若數據位長度是 6、7 或 8 位 ,則停止位為 2 位 ; =0:停止位是1位 |
| [3] | =1:允許奇偶校驗 =0:無奇偶校驗 |
| [4] | =1:偶校驗; =0:奇校驗 |
| [5] | 奇偶校驗選擇附加標志位。 = 0: 不附加。 = 1: 在校驗位和停止位之間附加1位奇偶標志位。若采用偶校驗,則這個標志為邏輯0;若采用奇校驗,則這個標志為邏輯1。選用這一附加標志位的作用是發送設備把采用何種奇偶校驗方式也通過數據流告訴接收設備。顯然,在收發雙方已經約定奇偶校驗方式的情況下,不需要這一附加位。 |
| [6] | 中止控制位。指定發送正常信號還是連續發送空號(中止符,邏輯0)。 =0:發送正常信號; =1:發送端會連續發送空號。若發空號的時間超過一個完整的數據字傳送時間,接收端就視發送設備已中止發送。此時,若允許中斷,則接收設備向CPU產生中斷請求。 |
| [7] | =1:除數鎖存訪問位; =0:表示訪問發送保持寄存器/接收緩存寄存器/中斷允許寄存器 |
看了上面的表格,或許你覺得暈:這么多寄存器,到底怎么配呢?別擔心,下文會介紹。
UART 初始化編程方法
當 PC 機上電啟動時,系統 RESET 信號通過 NS8250 的 MR 引腳使得 UART 內部寄存器和控制邏輯復位。此后若要使用 UART 就需要對其進行初始化編程操作,比如說設置 UART 的波特率、數據位數以及工作方式等。下面以 PC 上的串行端口 COM1 為例說明對其初始化的步驟。該串口的端口基地址是port = 0x3f8。 UART 芯片中斷引腳 INTRPT 被連接至中斷控制芯片引腳 IRQ4 上。當然,在初始化之前應該首先在 IDT 表中設置好串行中斷處理過程的中斷描述符。
設置通信傳輸波特率
設置通信傳輸波特率就是設置兩個除數鎖存寄存器 LSB 和 MSB 的值,即 16 位的波特率因子。由上表可知,若要訪問這兩個除數鎖存寄存器,必須首先設置線路控制寄存器 LCR 的第 8 位 DLAB = 1,即向端口 port+3 (0x3fb) 寫入 0x80 。 然后對端口 port (0x3f8) 和 port+1 (0x3f9) 執行寫操作。
對于指定的波特率,波特率因子的計算公式為:
波特率因子=UART時鐘頻率波特率?16波特率因子=UART時鐘頻率波特率?16
例如:波特率為2400 Baud,則
波特率因子=UART時鐘頻率波特率?16=1.8432MHz2400?16=18432002400?16=48波特率因子=UART時鐘頻率波特率?16=1.8432MHz2400?16=18432002400?16=48
48=0x0030,我們需要在 LSB 中寫入0x30 , 在 MSB 中寫入0x00 。 波特率設置好后,最好復位線路控制寄存器的 DLAB 位。
設置通信傳輸格式
串行通信傳輸格式由線路控制寄存器 LCR 中的各個位來定義。其中每位的含義見上表所示。如果我們需要把傳輸格式設置成無奇偶校驗位、8 位數據位和 1 位停止位,那么就需要向LCR 寫入值 0x03。
設置 MODEM 控制寄存器
對該寄存器進行寫入操作可以設置 UART 的操作方式和控制 MODEM。 UART操作方式有中斷和查詢兩種。還有一種循環反饋方式,但該方式僅用于診斷測試 UART 芯片的好壞,不能作為一種實際的通信方式使用。在 PC 機 ROM BIOS 中使用的是查詢方式,但本文是為了搞清楚 Linux-0.11系統而寫的,由于 Linux-0.11 采用的是高效率的中斷方式,因此我們只介紹中斷方式下 UART 的編程方法。
中斷方式是指當 MODEM 狀態發生變化時、接收出錯時、發送保持寄存器空時、或者接收到一個字符時允許UART 通 過 INTRPT 引腳向 CPU 發出中斷請求信號。至于允許哪些中斷請求則由中斷允許寄存器 IER 來確定。但是若要讓 UART 的中斷請求信號能夠送到 8259A 中斷控制器,就需要把 MODEM 控制寄存器 MCR 的位3(OUT2) 置位。因為在PC 機中,該位控制著 INTRPT 引腳到 8259A 的電路。
查詢方式是指 MODEM 控制寄存器 MCR 位3(OUT2)復位的條件下,程序通過循環查詢 UART 寄存器的內容來接收/發送串行數據。當 MCR的位3 = 0 時,雖然在 MODEM 狀態發生變化等條件下 UART 仍然能使 INTRPT 引腳產生中斷請求信號,并且能根據產生中斷的條件設置中斷標識寄存器 IIR 的內容,但是中斷請求信號并不能被送到8259A 中。因此程序只能通過查詢線路狀態寄存器 LSR 和中斷標識寄存器 IIR 的內容來判斷 UART 的當前工作狀態并進行數據的接收和發送操作。
MCR的位 1 和位 0 分別用于控制 MODEM , 當這兩位置位時,UART的數據終端就緒引腳(DTR)和請求發送引腳(RTS)輸出有效。
若要把 UART 設置成中斷方式,并且使 DTR 和 RTS 有效,那么就需要向 MODEM 控制寄存器寫入0x0b , 即1011b 。
初始化中斷允許寄存器
中斷允許寄存器 IER 用來設置可產生中斷的條件,即中斷來源類型。共有 4 種中斷源類型可供選擇,對應比特位置1 表示允許該條件產生中斷,否則禁止。當中斷產生時,具體是哪個中斷源產生的中斷由中斷標識寄存器 IIR 中的 [2:1] 指明,并且讀寫特定寄存器的內容可以復位 UART 的中斷。IER 的位 0 用于確定當前是否有中斷,位0=0表示有待處理的中斷。
在 Linux 0.11 串行端口初始化函數中,設置允許 3 種中斷源產生中斷(寫入0x0d),即在 MODEM 狀態發生變化時、接收有錯時、接收器收到字符時都允許產生中斷,但不允許發送保持寄存器空產生中斷。因為我們此時還沒有數據要發送。當對應串行終端的寫隊列有數據要發送時,tty_write()函數會調用rs_write()函數來置位發送保持寄存器空中斷允許標志,從而在該中斷源引發的串行中斷處理過程中,內核程序就可以開始取出寫隊列中的字符發送輸出到發送保持寄存器中,以讓 UART 發送出去。一旦 UART 把該字符發送了出去,發送保持寄存器又會變空而引發中斷請求。于是只要寫隊列中還有字符,系統就會重復這個處理過程,把字符一個一個地發送出去。當寫隊列中所有字符都發送出去后,寫隊列變空了,中斷處理程序就會把中斷允許寄存器中的發送保持寄存器空中斷允許標志復位掉,從而再次禁止發送保持寄存器空引發中斷請求。此次“循環”發送操作也隨之結束。
UART 中斷處理程序編程方法
由上文可知,UART 可由 4 種不同的中斷源類型產生中斷。因此當串行中斷處理程序剛開始執行時,僅知道發生了中斷,但不知道是哪種情況引起了中斷。所以串行中斷處理程序的第一個任務就是確定產生中斷的具體條件。這需要借助于中斷標識寄存器 IIR 來確定產生當前中斷的源類型。因此串行中斷處理程序可以根據產生中斷的源類型使用子程序地址跳轉表jmp_table[]來分別處理,其偽代碼如下:
rep_int:inb %dx,%al // 讀中斷標識寄存器 IIR 到 ALtestb $1,%al // 判斷有無待處理的中斷(位0==0說明有中斷)jne end // 若沒有待處理的中斷,則跳轉到end// 根據IIR[2:1]的值調用對應的處理函數call *jmp_table(,%eax,2) /* NOTE! not *4, bit0 is 0 already */jmp rep_int // 跳轉,繼續判斷有無待處理中斷 end: movb $0x20,%al //中斷退出處理。向中斷控制器發送結束中斷指令E0I 。outb %al,$0x20 /* EOI */...iretjmp_table:.long modem_status,write_char,read_char,line_status//edx中是串口基地址0x3F8 modem_status: addl $6,%edx /* clear intr by reading modem status reg */inb %dx,%al // 讀Modem狀態寄存器retline_status:addl $5,%edx /* clear intr by reading line status reg. */inb %dx,%al // 讀線路狀態寄存器retread_char:inb %dx,%al // 讀取接收緩沖寄存器中的字符...retwrite_char:// 由于設置了發送保持寄存器允許中斷標志而引起此次中斷,// 說明對應串行終端的寫字符緩沖隊列中有字符需要發送。寫字符隊列出隊-->al;outb %al,%dx //寫到發送保持寄存器中if(寫字符隊列為空){屏蔽發送保持寄存器空中斷;}ret在取出 IIR 的內容后,首先根據位 0 判斷是否有待處理的中斷。若位 0 = 0,則表示有需要處理的中斷。再根據位[2:1]使用指針跳轉表調用相應的子處理程序。在每個子程序中,會在處理完后復位 UART 的相應中斷源。當子處理程序返回后,主處理程序會循環判斷是否還有其他中斷源([0] ==0 ? ) 。如果本次中斷還有其他中斷源,那么 IIR 的位 0 仍然是0。于是中斷處理程序會再調用相應中斷源的子處理程序……直到引起本次中斷的所有中斷源都被處理并復位,此時 UART 會自動設置 IIR 的位 0 = 1 ,表示已無待處理的中斷,于是中斷處理程序即可退出。
參考資料
[ 1 ] 《微型計算機接口技術》(清華大學出版社,鄧亞平,陳昌志)
[ 2 ] 《Linux內核完全剖析》(趙炯,機械工業出版社,2006)
總結
以上是生活随笔為你收集整理的PC 机 UART(NS8250)详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 波特与比特率
- 下一篇: 家用工具套装_家居工具一:成为家居维修达