Linux-2.6 16c550 串口驱动移植

本文中将要说道的是Linux驱动移植中最为初级最为简单的一种,就是通用性很强的UART设备驱动的移植,当然这还不能完全满足博主我这可怜的智商。

我所移植的这个驱动不是别的就是可以使用已有驱动8250.c来驱动的16c550, 千万别笑话我,谁叫这是第一次呢。

其实说到底我也没干什么,就是配置了一些参数而已,剩下的就都交给platform和8250了。

下面就是重要的结构体的配置具体情况:

static struct plat_serial8250_port sc16550_data[] = {
.mapbase  = sc16550_UART_BASE, //flags使用IOREMAP,8250驱动会自动映射mapbase
.irq = sc16550_UART_IRQ,
.uartclk  = sc16550_UART_BAUD * 16,
.iotype  = UPIO_MEM,
.flags  = UPF_BOOT_AUTOCONF | 
                          UPF_SKIP_TEST | UPF_IOREMAP,
        .regshift       = 0,
};


static struct platform_device sc16550_device = {
.name = "serial8250",
.id = PLAT8250_DEV_PLATFORM,
.dev = { .platform_data = sc16550_data, },
};

这个platform_device对象的私有数据指成员向一个plat_serial8250_port类型的数组。在这里该数组描述了一个串口接口的基本信息。当8250驱动检测到这个platform_device对象后,就分析该对象的私有数据成员指向的那个plat_serial8250_port类型的数组。然后根据该数组的每个成员描述的信息生成一个串口对象设备。

实现了这个platform_device结构体后,把这个对象注册即可。但这个对象的name必须是serial8250。否则8250驱动检测不到这个样的设备。

下面详细介绍plat_serial8250_port这个对象。我们看一段代码:

  1. {
  2.             .membase = (void *) io_p2v(UART5_BASE),
  3.             .mapbase = UART5_BASE,
  4.             .irq = IRQ_UART_IIR5,
  5.             .uartclk = MAIN_OSC_FREQ,
  6.             .regshift = 2,
  7.             .iotype = UPIO_MEM32,
  8.             .flags = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART | UPF_IOREMAP,
  9. },
    membase: 
        
该成员描述的该串口接口寄存器虚拟地址的基地址。在初始化该成员时,需要自己把该串口接口寄存器的物理地址映射到虚拟地址空间。并且该映射工作需要在内核的板级初始化阶段完成。
    mapbase:
        
该成员描述的该串口接口寄存器物理地址的基地址。其实只要初始化了mapbase成员,上面的membase成员就可以不必初始化了。因为8250驱动如果检测到只初始化了mapbase成员而membaseNULL,flags使用IOREMAP,8250驱动会自动映射mapbase,即自动把该串口接口寄存器的物理地址空间映射到虚拟地址空间。
    irq:
        
该成员描述的是该串口接口使用的中断号。
    uartclk:
        
该成员描述了该串口接口使用的时钟频率。
    regshift:
        
该成员表示:在访问该串口接口的某个寄存器时,需把该寄存器的号左移多少位然后加基地址(不管是物理或虚拟地址)才能得能到
        
这个寄存器的址址。
    iotype:
        
该成员表示该串口接口寄存器的地址类型,可以取值以下的其中一个:

  1.         UPIO_PORT 端口地址,8位
  2.         UPIO_HUB6 
  3.         UPIO_MEM 8位的内存地址 
  4.         UPIO_MEM32 32位的内存地址 
  5.         UPIO_AU 
  6.         UPIO_TSI 
  7.         UPIO_DWAPB 
  8.         UPIO_RM9000
        一般来说,如果该成员初始化为UPIO_MEMUPIO_PORT,那么regshift成员应该为0;如果该成员初始化为UPIO_MEM32,那么regshift成员应该为2. 
    flags:
        UPF_BOOT_AUTOCONF   
表示自动探测串口类型,这个一般是需要的

        UPF_SKIP_TEST       表示在探测串口类型时,是否测试地址的可访问性。这在调试阶段是需要的。

        UPF_FIXED_TYPE: which specifies that the UART type is known and should not be probed.

        

    
除了flags,上面的各个成员都必须严格设置正确才能保证串口接口被正确探测和初始化。
    
如果串口接口类型没有被探测出来,或者FIFO长度不对,这需要考虑寄存器的访问是否正确,这包括:基地址是否正确,regshiftiotype是否正确,时钟频率是否正确。
    
如果探测信息也没有,或者接口数量不对。那么请在mem menuconfig中,在

  1. Device Drivers ---> 
  2.         Character devices ---> 
  3.             Serial drivers --->
  4.                    (8) Maximum number of 8250/16550 serial ports 
  5.                               (8) Number of 8250/16550 serial ports to register at runtime

    这两项的数字等于在8250注册串口接口的总数。

開發嵌入式系統時的 UART 設定
南港 IC 設計育成中心(Nankang IC Design Incubation Center)
E-mail:stc_nk@itri.org.tw
1.
在傳送與接受的兩端都需依循著相同的資料
格式,在 RS-232 中使用的是非同步起停
(Asynchronous Start Stop)編碼格式。
前言
本篇報告以 Linux 作業系統上的 UART
為例,介紹在進行 Linux 核心編譯時,與
UART 控制有關的部分,使得運行在 FPGA
上的 Linux 作業系統能透過 UART 傳送訊息
到 Console 上,協助開發者進行驗證與除錯。
在底下分為三部分來說明,依次是「UART
簡介」「Linux 對 UART 的控制」及「實作

範例」

2.
其編碼格式是以 1 個起始位元後面緊跟
著 5 到 8 個資料位元,接著是 1 個同位元檢
查碼,最後則是 1 或 2 個停止位元。其中,
起始位元一定為低電位的信號,而停止位元
則是高電位的信號,同位元檢查可以是奇同
位元(Odd Parity Bit)、偶同位元(Even Parity
Bit)或是不含同位元檢查碼。Fig. 1是一個串
列傳輸的資料格式範例,其資料位元為 8,
不具同位元檢查碼,含 2 個停止位元。
UART 簡介
UART(Universal Asynchronous Receiver /
Transmitter)[1]為非同步收發傳輸器,具有將
資料在串列傳輸與平行傳輸間作傳輸轉換的
功能。由於 UART 在傳輸上會利用到 RS-232
通訊協定來進行串列信號傳輸,因此,底下
先介紹 RS-232 通訊協定,再來則是介紹在
FPGA 開發板上所使用的 UART 裝置之輸出
入信號,最後,則是說明該裝置進行傳輸時,
必要的暫存器設定。
Fig. 1 串列傳輸的資料格式
UART 輸出入信號
RS-232 通訊協定
本 文 中 之 UART 的 硬 體 實 現 是 利 用
OpenCores[3] 所 提 供 的 RTL Code 合 成 到
FPGA上。因該Code為OpenRISC Platform的
一部分,為了配合該平台所採用的
WISHBONE匯流排系統[5],其輸出入信號還
包括了WISHBONE的相關控制信號 如Fig. 2
,
RS-232[2]是美國電子工業聯盟所制定
的串列數據通信介面標準,在此標準中,字
元是以序列的方式,一個接一個位元進行串
列傳輸。與並列傳輸的方式相較,其優點是
傳輸線少,配線簡單,傳送距離較遠。資料
在傳輸時,為了確保能正確的傳送與接受,
所示。在Table. 1中為與UART相關的輸出入
信號說明。
1
Bit
Function Description
0 Select number of bits in each character。
1 00 – 5 bits。01 – 6 bits。10 – 7 bits。11 – 8 bits。
Specify the number of generated stop bits。
2
0 – 1 stop bit。1 – 1.5 stop bits when 5-bit
character length selected and 2 bits otherwise。
Parity Enable。0 – No parity。1 – Parity bit is
Fig. 2 UART 的輸出入接腳
3
generated on each outgoing character and is
checked on each incoming one.
Port
Function Description
Even Parity select。0 – Odd number of 1 is
srx_pad_i The serial input signal。 stx_pad_o The serial output signal。 number of 1 is transmitted in each word。
cts_pad_i Clear To Send。 Stick Parity bit。0 – Stick Parity disabled。1 – If
dsr_pad_i Data Set Ready。 bits 3 and 4 are logic 1,the parity bit is
dcd_pad_i Data Carrier Detect。 ri_pad_i Ring Indicator。 rts_pad_o Request To Send。 
4
5
transmitted and checked in each word。1 – Even
transmitted and checked as logic 0。If bit 3 is 1
and bit 4 is 0 then the parity bit is transmitted
dtr_pad_o 
Break Control bit。1 – the serial out is forced into
6
Data Terminal Ready。
int_o 
and checked as 1。
Interrupt output。
logic 0 (break state)。0 – break is disabled。
Divisor Latch Access bit。1 – The divisor latches
7
Table. 1 UART 輸出入接腳
can be accessed。0 – The normal registers are
accessed。
Table. 2 LCR 暫存器說明
UART 傳輸暫存器的設定
DL 暫存器共 16 位元,主要用來調整
UART 的傳輸速率,其單位為 bps,表每秒傳
輸的位元數。在此 UART 的設計上,每個位
元需維持週期信號(uartclk)的 16 倍,以完成
輸入信號的取樣。因此,將輸入的週期信號
除 16 後,便可得到該 UART 的最大傳輸速
率,稱為 Base_Baud。只要傳輸速率小於最
大傳輸速率,便可藉由 DL 暫存器存入需除
頻的值,完成調整的動作。
如前所述,利用 UART 進行傳輸時,需
依循固定的編碼格式,因此,需將這些設定
存 妥 在 UART 的 內 部 暫 存 器 LCR (Line
Control Register) 及 DL (Divisor Latch)中,才
能讓 UART 正常工作。
LCR暫存器為 8 位元,主要用來控制
UART信號傳輸的格式,Table. 2便針對LCR
暫存器內的每一個控制位元做說明。
如在週期信號為 20MHz,每秒傳輸位元
2
為 9600 bps 的情況下,DL 需儲存的值為
(0x0082)。計算方式如下:
段的「Boot Command Line」參數設定。
menuconfig 設定
Base _ Baud
=
Bit _ Rate(bps)
frequency _ input
1
×
=
Bit _ Rate(bps)
16
20000000
= 130.20...(0x0082)
16 × 9600
Divisor _ Latch =
在 Linux 作業系統中,依照核心與裝置
間的傳輸形式區分,可分為字元裝置
(Character Device)、區塊裝置(Block Device)
及網路裝置(Network)三大類。字元裝置指需
以串列順序依序進行存取的裝置,如觸控式
螢幕、磁帶驅動程式、滑鼠等。區塊裝置則
是可任意順序以區塊為單位進行存取,如硬
碟、軟碟機等。至於網路裝置之所以獨立於
這兩者之外,主要在於網路裝置是針對封包
的接放和發送所設計,有別於上述兩者。
當使用 Linux 2.6.19 來控制 UART 時,
不需手動填入 LCR 及 DL 的值,只要在編譯
核心 (Kernel) ,設定好編碼格式及傳輸的速
率,在核心啟動時,Linux 便會自動寫入這些
暫存器。若是需對 UART 進行測試,或是遇
到 Linux 啟動後 UART 無法顯出訊息時,可
以將這些暫存器的值取出,用來協助除錯。
由於 UART 屬於字元裝置 以 linux2.6.19
,
為例,在開啟 menuconfig 後,依底下的路徑
可找到與 UART 相關驅動程式選項: Device

Drivers 」→「 Character devices 」→「 Serial
drivers」
。在「Serial drivers」選單中,共有五
個設定項目,分別如下:
本文僅介紹 UART 的重要部分,進一步
的資訊,可參考 OpenCores 的「UART 16550
compatible project」[6]。
3.
Linux 對 UART 的控制
「 8250/16550 and compatible serial
support」
:選擇是否使用 8250/16550 及與其
在嵌入式系統中,需有一個作業系統以
便能進行軟硬體間工作的分配與協調,目前
的 嵌 入 式 作 業 系 統 有 Linux 、 WinCE 、
VxWorks、Nucleus 等。因 Linux 作業系統穩
定,且為開放原始碼等優勢條件下,已成為
系統開發常採用的嵌入式作業系統之一。
相 容 的 驅 動 程 式 。 8250 為 早 期 National
Semiconductor[4] 所設計的 UART 裝置,因
OpenCores 的 UART 設計上與 8250 相容,可
直接利用 Linux 已有的 8250 驅動程式。
「Console on 8250/16550 and compatible
serial port」
:決定是否由序列埠傳送訊息。
在開發嵌入式系統時,開機測試可分三
個階段完成。首先需將 Linux 原始碼透過交
叉編譯器編譯成映像檔(IMAGE),接著則是
將之儲放到記憶裝置裡,最後透過開機載入
器(Bootloader),設定 Boot Command Line 參
「Maximum number of 8250/16550 serial
ports」
:最大的 UART 連接埠個數。
數,完成作業系統的開機。底下所討論的內
容,涵蓋第一階段需留意的「menuconfig 設
定」「UART 硬體資訊」兩部分,及第三階

「Number of 8250/16550 serial ports to
register at runtime」
:在 Linux 啟動時,預先
3
啟動好的 UART 連接埠個數;該數不可大於
「最大的 UART 連接埠個數」

「Console Options」主要用來設定核心
的主控台,使得 Linux 能顯示訊息。其語法
為 console=parameters,parameters 由使用者
指定,可為底下所說明的項目之一。
「 Extended 8250/16550 serial driver
options 」 開 啟 一 些 延 伸 功 能 的 支 援 。 如
:
Sharing serial interrupt、Auto detect IRQ、RSA
serial port 等。
ttyn:指定主控台為虛擬終端。(n 為編號)
ttySn[,options]:指定主控台為序列埠終
端,其後的選項是傳輸速率及編碼格式,預
設是「9600n8」
,表示傳輸速率為 9600bps,
沒有同位元檢查,資料為 8 位元。
UART 硬體資訊
UART 硬 體 資 訊 主 要 寫 在 原 始 碼
(arch/or32/board/config.c)中,其內需要記錄的
資訊陳列如下:
uart,<io|mmio>,addr[,options]:指定主控
台為核心啟動初期以輪詢模式在 8250/16550
UART 上所啟動的主控台。<io|mmio>需擇一
填入,表示 I/O 映射狀況為隔離式或記憶體
映射式,addr 為該 UART 裝置對映的位址,
options 的格式則如 ttySn 中所介紹。由於在
核心完全啟動後,會將輪詢模式轉換中斷模
式,
因此該選項只適用於核心啟動初期除錯。
static struct plat_serial8250_port
serial_platform_data[] = {
.mapbase = ,//UART 硬體基底位址
.irq = ,//UART 中斷向量。
.uartclk = ,//UART 的時鐘週期。
.regshift = ,//UART 暫存器位移。
.iotype = ,//UART 位址對映方式。
.flags = ,//UART 的控制旗標。共 32 位元,有
4.
實作範例介紹
//19 個,所有旗標定義於下底標頭檔
本篇報告中,使用的硬體平台是 Altera
EP1S10 的 FPGA 開發板,在該板子上除了
FPGA晶片外,另具有記憶體晶片及RS232 的
接頭。FPGA晶片內實現的RTL Codes,除了
記憶體控制器為Altera所提供外,其它皆來自
OpenCores 。 作 業 系 統 為 取 自 於
www.kernel.org ,並做適當PATCH後的Linux
2.6.19 作業系統。開發工具則是使用GNU所
提供的工具集。底下陳列便是這次實作中所
選用的軟硬體的項目:
//include/linux/serial_core.h
}
在上述這些資訊中,都需依規格填入適
當的數值,以便讓 Linux 啟動後能得知該裝
置的硬體資訊。
Boot Command Line
Boot Command Line 主要用來設定核心
的 初 始 化 狀 態 , 其 選 項 包 括 「 Console
Options 」 「 Memory Options 」 「 Ramdisk


Options 」 「 Root Disk Options 」 「 PCI


Options 」 ... 等 , 在 此 只 會 針 對 「 Console
Options」中與 UART 相關的部分來做說明。
中央處理器:OpenRISC1200(10MHz)
記憶體晶片:Micron SDRAM-16MB
週邊裝置:UART、JTAG
開機載入器:None
4
作業系統:Linux 2.6.19-or32
交叉編譯器:gcc 3.4.4。
述於這次實作中所做的設定。
menuconfig設定:
Fig. 3顯示的是整個系統的架構圖,在FPGA
內部主要的硬體元件除了負責整個系統運作
的CPU-OpenRISC1200 外,還有SDRAM控
制器,用以對板子上的SDRAM晶片進行讀寫
資料的操作;DBG_top內含JTAG控制器,主
要的任務是將編譯好的映像檔載入到
SDRAM 中,使得 CPU 一啟動時,能馬上在
SDRAM上存取到資料;至於UART_top,則
用來傳送和接收串列傳輸的資料,以提供
Linux啟動後與開發者互動的介面。這些裝置
元件皆透過 WISHBONE 匯流排來相互連接
著。
Fig. 4 所示是在實作中 menuconfig 的設定內
容。
Fig. 4 menuconfig 的設定
UART硬體資訊:
UART 設備的資訊記錄在原始檔位置
(arch/or32/board/config.c) 中,填寫的資訊如
下:
static struct plat_serial8250_port
serial_platform_data[] = {
//UART 硬體基底位址為 0x90000000
.mapbase
= 0x90000000,
//UART 中斷向量編號為 2
.irq
= 2,
//UART 的操作時鐘週期為 10MHz
Fig. 3 系統架構圖
.uartclk
= 10000000,
//UART 暫存器無位移
在此實作中,所採用的 UART 傳輸速率
及編碼格式內容如下:
.regshift
= 0,
//UART 為 Memory Mapping IO
.iotype
= UPIO_MEM,
每秒傳輸位元:9600 bps //「UPF_IOREMAP」
              資料位元:8 bits :將實體記憶體位址轉換成核心的虛
                        同位檢查:None 
                                  停止位元:1 bit 
流量控制:None .flags=UPF_IOREMAP| UPF_BOOT_AUTOCONF,
//擬位址。
//「UPF_BOOT_AUTOCONF」
:讓 Linux 在開機啟動時會
//自動對該裝置進行初始化設定。
};
如第3節所述,在編譯Linux時,有三個
地方會影響到UART裝置的啟動 底下分別闡
,
5
下,如何設定 Boot Command Line,完成作
業系統的啟動。希望透過本文的說明,對想
瞭解開發嵌入式系統時 UART 設定的讀者,
有個基本認識,對往後嵌入式系統的設計與
開發有所幫助。
Boot Command Line:
在開發中的嵌入式 Linux 系統,一般可
透過開機載入器來設定 Boot Command Line
的 參 數 , 本 次 實 驗 則 是 直 接 將 Boot
Command Line 的 內 容 寫 在 原 始 檔
(arch/or32/kernel/setup.c)中。其優點在於省去
開機載入器的啟動時間及所佔用的空間。設
定的內容為:
References
1.
2.
3.
4.
5.
http://en.wikipedia.org/wiki/UART
http://en.wikipedia.org/wiki/RS-232
http://www.opencores.org/
http://www.national.com/analog
http://en.wikipedia.org/wiki/Wishbone_(co
mputer_bus)
6. http://www.opencores.org/websvn/?project
=uart16550
7. http://www.kernel.org
8. http://www.embecosm.com/
9. http://www.meansoffreedom.com/index.ht
ml
10. http://www.zubira.com/openrisc/or1k_suse
_uclinux.html
11. OpenRISC 1200 IP Core Specification
12. OpenRISC 1000 Architecture Manual
13. WISHBONE System-on-Chip (SoC)
Interconnection Architecture for Portable IP
Cores Revision: B.3
14. John Catsoulis,” Designing Embedded
Hardware”.
15. Christopher Hallinan,” Embedded Linux
Primer: A Practical, Real-World Approach”.
16. Greg Kroah-Hartman,”Linux Kernel in a
Nutshell”.
17. P.Raghavan,Amol Lad,Sriram
Neelakandan,” Embedded Linux System
Design and Development”
static char command_line[COMMAND_LINE_SIZE]
= "root=/dev/ram console=ttyS0,9600n8";
Fig. 5 為經上述設定後,將映像檔下載至
SDRAM完成開機的畫面。
Fig. 5 開機完成的畫面
5.
結論
在本文中,闡述使用 UART 時所需具備
的相關知識,包括資料傳輸格式、輸出入接
腳及暫存器的設定,及編譯 Linux 映像檔時,
所需注意到的地方,如開啟 menuconfig 時需
留意的設定,原始碼中需視硬體情況來填入
的資料,及在沒有使用開機載入器的情況
南港 IC 設計育成中心 2009/4
6


 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值