《7.串列埠通訊詳解》
《7.串列埠通訊詳解》
第一部分、章節目錄
1.7.1.通訊涉及的幾個基礎概念
1.7.2.串列埠通訊的基本概念
1.7.3.串列埠通訊的基本原理
1.7.4.S5PV210序列通訊介面詳解1
1.7.5.S5PV210序列通訊介面詳解2
1.7.6.S5PV210序列通訊介面詳解3
1.7.7.S5PV210序列通訊程式設計實戰1
1.7.8.S5PV210序列通訊程式設計實戰2
1.7.9.uart stdio的移植1
1.7.10.uart stdio的移植2
1.7.11.uart stdio的移植3
1.7.12.串列埠實驗燒錄問題總結
第二部分、章節介紹
1.7.1.通訊涉及的幾個基礎概念
本節講述通訊的發展歷史,通訊的基本原理,重點是通訊所涉及到的3對主要概念:同步和非同步、電平訊號和差分訊號、並行和序列介面。
1.7.2.串列埠通訊的基本概念
本節講述傳輸通訊涉及到的基本概念,如:波特率、起始位、資料位、奇偶校驗位、停止位、RS232電平、TTL電平等。主要學習目的是讓大家對串列埠通訊涉及到的主要概念做個瞭解,方便後續課程中使用。
1.7.3.串列埠通訊的基本原理
本節講解串列埠通訊的基本原理,讓大家明白串列埠通訊時資訊時如何在通訊線上傳播的,以及各種常見介面的通訊線定義。
1.7.4.S5PV210序列通訊介面詳解1
本節主要講述串列埠控制器的工作原理框圖,試圖讓大家明白串列埠控制器內部發送器、接收器、波特率發生器、移位器等模組的工作原理。最後簡單介紹了流控。
1.7.5.S5PV210序列通訊介面詳解2
本節詳細介紹了S5PV210這類高階SoC中串列埠的三種擴充套件模式:FIFO模式、DMA模式、IrDA模式,以及各種模式的工作原理、使用方法。
1.7.6.S5PV210序列通訊介面詳解3
本節首先講述串列埠和中斷的關係,希望向大家引入串列埠傳送/接收時的中斷模式、輪詢模式這兩個概念;然後詳細分析了串列埠控制器內部的時鐘來源、波特率計算等。
1.7.7.S5PV210序列通訊程式設計實戰1
本節開始編寫串列埠通訊的程式,首先分析了程式框架,然後重點分析了串列埠控制器的幾個主要暫存器的配置值,最後在C源程式中定義了訪問串列埠控制器暫存器的主要巨集定義。
1.7.8.S5PV210序列通訊程式設計實戰2
本節接上節繼續來編寫串列埠通訊的程式,主要包括Tx、Rx對應的GPIO的初始化,波特率的計算和設定,串列埠傳送和接收程式的編寫等。最終實現210通過串列埠向外部發送資訊。
1.7.9.uart stdio的移植1
本節開始講基於S5PV210的串列埠輸入/輸出函式來移植stdio。首先講了什麼是標準輸入輸出,然後講了移植stdio的3種途徑,最後指出我們所使用的移植方法。
1.7.10.uart stdio的移植2
本節正式開始動手移植。分析了網路下載的別人移植好的printf函式原始碼,重點講解了如何修改Makefile來使用printf函式原始碼。
1.7.11.uart stdio的移植3
本節補充講了上節課沒講到的連結指令碼的問題。然後從C語言角度分析了printf函式實現原理、C語言可變引數、vsprintf函式中的實現細節等。
1.7.12.串列埠實驗燒錄問題總結
本節為補充章節,主要針對前面章節中程式碼usb下載無法正常執行,補充講下SD卡執行上燒錄執行程式碼的實驗,並且希望大家看見實驗現象以明確程式碼無誤。
第三部分、隨堂記錄
1.7.1.通訊涉及的幾個基礎概念
1.7.1.1、通訊的發展歷史
(1)、最早通訊:烽火臺、狼煙;信件;電子通訊(電報、電話、網路訊號)
(2)、通訊中最重要的兩個方面:資訊表示、解析方法 + 資訊的傳輸方法
(3)、通訊雙方事先需要約定好資訊的表示方法和解析方法,做到一致,否則資訊不能有效傳遞
(4)、訊號的傳輸方法是指經過編碼後的通訊資訊如何在傳輸介質上傳輸的過程。
總結:通訊過程其實分為3個步驟:首先發送方先按照資訊編碼方式對有效資訊進行編碼(程式設計成可以在通訊線路上傳輸的訊號形態),然後編碼後的資訊在傳輸介質上進行傳輸,輸送給接收方;最後接收方接收到編碼資訊後進行解碼,解碼後得到可以理解的有效資訊。
1.7.1.2、電子通訊概念1:同步通訊和非同步通訊
(1)、同步和非同步的區別:首先很多地方都有同步和非同步的概念,簡單來說就是傳送方和接收方按照同一個時鐘節拍工作就叫同步,傳送方和接收方沒有統一的時鐘節拍、而各自按照自己的節拍工作就叫非同步。
(2)、同步通訊中,通訊雙方按照統一節拍工作,所以配合很好;一般需要傳送方給接收方傳送資訊同時傳送時鐘訊號,接收方根據傳送方給它的時鐘訊號來安排自己的節奏。同步通訊用在通訊雙方資訊交換頻率固定,或者經常通訊時。
(3)、非同步通訊又叫非同步通知。在雙方通訊的頻率不固定時(有時3ms收發一次,有時3天才收發一次)不適合使用同步通訊,而適合非同步通訊。非同步通訊時接收方不必一直在意傳送方,傳送方需要傳送資訊時會首先給接收方一個資訊開始的起始訊號,接收方接收到起始訊號後就認為後面緊跟著的就是有效資訊,才會開始注意接收資訊,直到收到傳送方發過來的結束標誌。
1.7.1.3、電子通訊概念2:電平訊號和差分訊號
(1)、電平訊號和差分訊號是用來描述通訊線路傳輸方式的。也就是說如何在通訊線路上表達1和0.
(2)、電平訊號的傳輸線中有一個參考電平線(一般是GND),然後訊號線上的訊號值是由訊號線電平和參考電平線的電壓差決定。
(3)、差分訊號的傳輸線中沒有參考電平,所有都是訊號線。然後1和0的表達靠訊號線之間的電壓差。
總結:電平訊號的2根通訊線之間的電平差異容易受到干擾,傳輸容易失敗;差分訊號不容易受到干擾因此傳輸質量比較穩定,現代通訊一般都使用差分訊號,電平訊號幾乎沒有了。
總結2:看起來似乎相同根數的通訊線下,電平訊號要比差分訊號要快;但是實際還是差分訊號快,因為差分訊號抗干擾能力強,因此1個傳送週期更短。
1.7.1.4、電子通訊概念3:並行介面和序列介面
(1)、序列、並行主要是考慮通訊線的根數,就是傳送方和接收方同時可以傳遞的資訊量的多少
(2)、譬如在電平訊號下,1根參考電平線+1根訊號線可以傳遞1位二進位制;如果我們有3根線(2根訊號線+1根參考線)就可以同時傳送2位二進位制;如果想同時傳送8位二進位制就需要9根線。
(3)、在差分訊號下,2根線(彼此差分)可以同時傳送1位二進位制;如果需要同時傳送8位二進位制,需要16根線。
總結:聽起來似乎並行介面比序列介面要快(序列介面一次只能傳送1位二進位制,而並行介面一次可以傳送多位二進位制)要更優秀;但是實際上序列接口才是王道,用的比較廣。因為更省訊號線,而且對傳輸線的要求更低、成本更低;而且序列時可以通過提高通訊速度來提高總體通訊效能,不一定非得要並行。
總結:其實這麼多年發展,最終勝出的是:非同步、序列、差分,譬如USB和網路通訊。
1.7.2.串列埠通訊的基本概念
1.7.2.1、串列埠通訊的特點:非同步、電平訊號、序列
(1)、非同步:串列埠通訊的傳送方和接收方之間是沒有統一的時鐘訊號的。
(2)、電平訊號:串列埠通訊出現的時間較早,速率較低,傳輸的距離較近,所以干擾還不太明顯,因此當時使用了電平訊號傳輸。後期出現的傳輸協議都改成差分訊號傳輸了。
(3)、序列通訊:串列埠通訊每次同時只能傳輸1個二進位制位。
1.7.2.2、RS232電平和TTL電平
(1)電平訊號是用訊號線電平減去參考線電平得到電壓差,這個電壓差決定了傳輸值是1還是0.
(2)在電平訊號時多少V代表1,多少V代表0不是固定的,取決於電平標準。譬如RS232電平中-3V~-15V表示1;+3~+15V表示0;TTL電平則是+5V表示1,0V表示0.
(3)不管哪種電平都是為了在傳輸線上表示1和0.區別在於適用的環境和條件不同。RS232的電平定義比較大,適合干擾大、距離遠的情況;TTL電平電壓範圍小,適合距離近且干擾小的情況。
(4)我們臺式電腦後面的串列埠插座就是RS232介面的,在工業上用串列埠時都用這個,傳輸距離小於15米;TTL電平一般用在電路板內部兩個晶片之間。
(5)對程式設計來說,RS232電平傳輸還是TTL電平是沒有差異的。所以電平標準對硬體工程師更有意義,而軟體工程師只要略懂即可。(把TTL電平和RS232電平混接是不可以的)
1.7.2.3、波特率
(1)波特率(bandrate),指的是串列埠通訊的速率,也就是串列埠通訊時每秒鐘可以傳輸多少個二進位制位。譬如每秒種可以傳輸9600個二進位制位(傳輸一個二進位制位需要的時間是1/9600秒,也就是104us),波特率就是9600.
(2)串列埠通訊的波特率不能隨意設定,而應該在一些值中去選擇。一般最常見的波特率是9600或者115200(低端微控制器如51常用9600,高階微控制器和嵌入式SoC一般用115200).為什麼波特率不可以隨便指定?主要是因為:第一,通訊雙方必須事先設定相同的波特率這樣才能成功通訊,如果傳送方和接收方按照不同的波特率通訊則根本收不到,因此波特率最好是大家熟知的而不是隨意指定的。第二,常用的波特率經過長久發展,就形成了共識,大家常用就是9600或者115200.
1.7.2.4、起始位、資料位、奇偶校驗位、停止位
(1)串列埠通訊時,收發是一個週期一個週期進行的,沒週期傳輸n個二進位制位。這一個週期就叫做一個通訊單元,一個通訊單元是由:起始位+資料位+奇偶校驗位+停止位組成的。
(2)起始位表示傳送方要開始傳送一個通訊單元;資料位是一個通訊單元中傳送的有效資訊位;奇偶校驗位是用來校驗資料位,以防止資料位出錯的;停止位是傳送方用來表示本通訊單元結束標誌的。
(3)起始位的定義是串列埠通訊標準事先指定的,是由通訊線上的電平變化來反映的。
(4)資料位是本次通訊真正要傳送的有效資料,串列埠通訊一次傳送多少位有效資料是可以設定的(一般可選的有6、7、8、9,99%情況下我們都是選擇8位資料位。因為我們一般通過串列埠傳送的文字資訊都是ASCII碼編碼的,而ASCII碼中一個字元剛好編碼為8位。)
(5)奇偶校驗位是用來給資料位進行奇偶校驗(把待校驗的有效資料逐個位的加起來,總和為奇數奇偶校驗位就為1,總和為偶數奇偶校驗位就為0)的,可以在一定程度上防止位反轉。
(6)停止位的定義是串列埠通訊標準事先指定的,是由通訊線上的電平變化來反映的。常見的有1位停止位,1.5位停止位,2位停止位等。99%情況下都是用1位停止位。
總結:串列埠通訊時因為是非同步通訊,所以通訊雙方必須事先約定好通訊引數,這些通訊引數包括:波特率、資料位、奇偶校驗位、停止位(串列埠通訊中起始位定義是唯一的,所以一般不用選擇)
1.7.3.串列埠通訊的基本原理
1.7.3.0、補充通訊概念:單工通訊和雙工通訊
(1)單工就是單方向,雙工就是雙方同時收發,同時只能但方向但是方向可以改變叫半雙工
(2)如果只能A發B收則單工,A發B收或者B發A收(兩個方向不能同時)叫半雙工,A發B收同時B發A收叫全雙工。
1.7.3.1、三根通訊線:Rx Tx GND
(1)任何通訊都要有資訊傳輸載體,或者是有線的或者是無線的。
(2)串列埠通訊是有線通訊,是通過串列埠線來通訊的。
(3)串列埠通訊線最少需要2根(GND和訊號線),可以實現單工通訊,也可以使用3根通訊線(Tx、Rx、GND)來實現全雙工。
(4)一般開發板都會引出SoC上串列埠引腳直接輸出的TTL電平的串列埠(X210開發板沒有),插座用插針式插座,每個串列埠引出的都有3個線(Tx、Rx、GND),可以用這些插座直接連線外部的TTL電平的串列埠裝置。
1.7.3.2、收發雙方事先規定好通訊引數(波特率、資料位、奇偶校驗位、停止位等)
(1)串列埠通訊屬於基層基本性的通訊規約,它自己本身不會去協商通訊引數,需要通訊前通訊雙方事先約定好通訊引數(一般4個最重要的)
(2)串列埠通訊的任何一個關鍵引數設定錯誤,都會導致通訊失敗。譬如波特率調錯了,傳送方傳送沒問題,接收方也能接收,但是接收到全是亂碼···
1.7.3.3、資訊以二進位制流的方式在通道上傳輸
(1)、串列埠通訊的傳送方每隔一定時間(時間固定為1/波特率,單位是秒)將有效資訊(1或者0)放到通訊線上去,逐個二進位制位的進行傳送。
(2)接收方通過定時(起始時間由讀到起始位標誌開始,間隔時間由波特率決定)讀取通訊線上的電平高低來區分發送給我的是1還是0。依次讀取資料位、奇偶校驗位、停止位,停止位就表示這一個通訊單元(幀)結束,然後中間是不定長短的非通訊時間(傳送方有可能緊接著就傳送第二幀,也可能半天都不發第二幀,這就叫非同步通訊),下來就是第二幀·····
總結:第一,波特率非常重要,波特率錯了整個通訊就亂套了;資料位、奇偶校驗位、停止位也很重要,否則可能認不清資料。第三,通過串列埠不管發數字、還是文字還是命令還是什麼,都要先對傳送內容進行編碼,編碼成二進位制再進行逐個位的傳送。
(3)串列埠傳送的一般都是字元,一般都是ASCII碼編碼後的字元,所以一般設定資料位都是8,方便剛好一幀傳送1個字元。
1.7.3.4、回顧:RS232電平和TTL電平的區別?序列通訊為什麼是非同步的?為什麼是序列而不是並行?
1.7.3.5、DB9介面介紹
(1)DB9介面是串列埠通訊早期比較常用的一種規範化介面。
(2)序列通訊在早期是計算機與外界通訊的主要手段,那時候的計算機都有標準配置的串列埠以實現和外部通訊。那時候就定義了一套標準的串列埠規約,DB9介面就是標準介面。
(3)DB9介面中有9根通訊線,其中3根很重要,為GND、Tx、Rx,必不可少;剩餘6根都是和流控有關的,現代我們使用串列埠都是用來做除錯一般都禁用流控,所以這6根沒用。
(4)現在一般使用串列埠時要記得把流控禁止掉,不然可能發生意想不到的問題。
1.7.4.S5PV210序列通訊介面詳解1
1.7.4.0、串列埠的名稱
(1)S5PV210的資料手冊中串列埠控制器在section8.1
(2)串列埠的官方名稱叫:universal asynchronous reciver and transmitter,通用非同步收發器
英文縮寫是uart,中文簡稱串列埠。
1.7.4.1、S5PV210的串列埠控制器工作原理框圖
(1)整個串列埠控制器包含transmitter和receiver兩部分,兩部分功能彼此獨立,transmitter負責210向外部發送資訊,receiver負責從外部接收資訊到210內部。
(2)匯流排角度來講,串列埠控制器是接在APB總線上的。對我們程式設計有影響的是:將來計算串列埠控制器的源時鐘時是以APB匯流排來計算的。
(3)transmitter由傳送緩衝區和傳送移位器構成。我們要傳送資訊時,首先將資訊進行編碼(一般用ASCII碼)成二進位制流,然後將一幀資料(一般是8位)寫入傳送緩衝區(從這裡以後程式就不用管了,剩下的傳送部分是硬體自動的),傳送移位器會自動從傳送緩衝區中讀取一幀資料,然後自動移位(移位的目的是將一幀資料的各個位分別拿出來)將其傳送到Tx通訊線上。
(4)receiver由接收緩衝區和接收移位器構成。當有人通過串列埠線向我傳送資訊時,資訊通過Rx通訊線進入我的接收移位器,然後接收移位器自動移位將該二進位制位儲存入我的接收緩衝區,接收完一幀資料後receiver會產生一箇中斷給CPU,CPU收到中斷後即可知道receiver接收滿了一幀資料,就會來讀取這幀資料。
總結:傳送緩衝區和接收緩衝區是關鍵。傳送移位器和接收移位器的工作都是自動的,不用程式設計控制的,所以我們寫串列埠的程式碼就是:首先初始化(初始化的實質是讀寫暫存器)好串列埠控制器(包括髮送控制器和接收控制器),然後要傳送資訊時直接寫入傳送緩衝區,要接收資訊時直接去接收緩衝區讀取即可。可見,串列埠底層的工作(譬如怎麼移位的、譬如起始位怎麼定義的、譬如TTL電平還是RS232電平等)對程式設計師是隱藏的,程式設計師不用去管。軟體工程師對串列埠操作的介面就是傳送/接收緩衝區(實質就是暫存器,操作方式就是讀寫記憶體)
(5)串列埠控制器中有一個波特率發生器,作用是產生串列埠傳送/接收的節拍時鐘。波特率發生器其實就是個時鐘分頻器,它的工作需要源時鐘(APB匯流排來),然後內部將源時鐘進行分頻(軟體設定暫存器來配置)得到目標時鐘,然後再用這個目標時鐘產生波特率(硬體自動的)。
1.7.4.2、自動流控(AFC:Auto flow control)
(1)為什麼需要流控?流控的目的是讓串列埠通訊非常可靠,在傳送方速率比接收方快的時候流控可以保證傳送和接收不會漏掉東西。
(2)現在為什麼不用流控?現在計算機之間有更好更高階(usb、internet)的通訊方式,串列埠已經基本被廢棄了。現在串列埠的用途更多是SoC用來輸出除錯資訊的。由於除錯資訊不是關鍵性資訊、而且由於硬體發展串列埠本身速度已經相對慢的要死了,所以硬體都能協調發送和接收速率,因此流控已經失去意義了,所以現在基本都廢棄了。
1.7.5.S5PV210序列通訊介面詳解2
1.7.5.0、本來串列埠的功能就是上節講過的部分,但是後來的技術發展給串列埠疊加了一些高階功能,在像210這類的高階SoC的串列埠控制器中,都有這類高階功能。
1.7.5.1、FIFO模式及其作用
(1)典型的串列埠設計,傳送/接收緩衝區只有1位元組,每次傳送/接收只能處理1幀資料。這樣在微控制器中沒什麼問題,但是到複雜SoC中(一般有作業系統的)就會有問題,會導致效率低下,因為CPU需要不斷切換上下文。
(2)解決方案就是想辦法擴充套件串列埠控制器的傳送/接收緩衝區,譬如將傳送/接收緩衝器設定為64位元組,CPU一次過來直接給傳送緩衝區64位元組的待發送資料,然後transmitter慢慢發,發完再找CPU再要64位元組。但是串列埠控制器本來的傳送/接收緩衝區是固定的1位元組長度的,所以做了個變相的擴充套件,就是FIFO。
(3)FIFO就是first in first out,先進先出。fifo其實是一種資料結構,這裡這個大的緩衝區叫FIFO是因為這個緩衝區的工作方式類似於FIFO這種資料結構。
1.7.5.2、DMA模式及其作用
(1)DMA direct memory access,直接記憶體訪問。DMA本來是DSP中的一種技術,DMA技術的核心就是在交換資料時不需要CPU參與,模組可以自己完成。
(2)DMA模式要解決的問題和上面FIFO模式是同一個問題,就是串列埠傳送/接收要頻繁的折騰CPU造成CPU反覆切換上下文導致系統效率低下。
(3)傳統的串列埠工作方式(無FIFO無DMA)效率是最低的,適合低端微控制器;高階微控制器上CPU事物繁忙所以都需要串列埠能夠自己完成大量資料傳送/接收。這時候就需要FIFO或者DMA模式。FIFO模式是一種輕量級的解決方案,DMA模式適合大量資料迸發式的傳送/接收時。
1.7.5.3、IrDA模式及其用法
(1)IrDA其實就是紅外,紅外就是紅外線通訊(電視機、空調遙控器就是紅外通訊的)。
(2)紅外通訊的原理是傳送方固定間隔時間向接收方傳送紅外訊號(表示1或0)或者不傳送紅外訊號(表示0或者1),接收方每隔固定時間去判斷有無紅外線訊號來接收1和0.
(3)分析可知,紅外通訊和串列埠通訊非常像,都是每隔固定時間傳送1或者0(判斷1或0的物理方式不同)給接收方來通訊。因此210就利用串列埠通訊來實現了紅外發送和接收。
(4)210的某個串列埠支援IrDA模式,開啟紅外模式後,我們只需要向串列埠寫資料,這些資料就會以紅外光的方式向外發射出去(當然是需要一些外部硬體支援的),然後接收方接收這些紅外資料即可解碼得到我們的傳送資訊。
1.7.6.S5PV210序列通訊介面詳解3
1.7.6.1、序列通訊與中斷的關係
(1)串列埠通訊分為傳送/接收2部分。傳送方一般不需要(也可以使用)中斷即可完成傳送,接收方必須(一般來說必須,也可以輪詢方式接收)使用中斷來接收。
(2)傳送方可以選擇使用中斷,也可以選擇不使用中斷。使用中斷的工作情景是:傳送方先設定好中斷並繫結一箇中斷處理程式,然後傳送方丟一幀資料給transmitter,transmitter傳送耗費一段時間來發送這一幀資料,這段時間內傳送方CPU可以去做別的事情,等transmitter傳送完成後會產生一個TXD中斷,該中斷會導致事先繫結的中斷處理程式執行,在中斷處理程式中CPU會切換回來繼續給transmitter放一幀資料,然後CPU切換離開;不使用中斷的工作情景是:傳送方事先禁止TXD中斷(當然也不需要給相應的中斷處理程式了),傳送方CPU給一幀資料到transmitter,然後transmitter耗費一段時間來發送這幀資料,這段時間CPU在這等著(CPU沒有切換去做別的事情),待發送方傳送完成後CPU再給它一幀資料繼續傳送直到所有資料發完。CPU是怎麼知道transmitter已經發送完了?原來是有個狀態暫存器,狀態暫存器中有一個位叫傳送緩衝區空標誌,transmitter傳送完成(傳送緩衝區空了)就會給這個標誌位置位,CPU就是通過不斷查詢這個標誌位為1還是0來指導傳送是否已經完成的。
(3)因為串列埠通訊是非同步的,非同步的意思就是說傳送方佔主導權。也就是說傳送方隨時想發就能發,但是接收方只有時刻等待才不會丟失資料。所以這個差異就導致傳送方可以不用中斷,而接收方不得不使用中斷模式。
1.7.6.2、210序列通訊介面的時鐘設計
(1)串列埠通訊為什麼需要時鐘?因為串列埠通訊需要一個固定的波特率,所以transmitter和receiver都需要一個時鐘訊號。
(2)時鐘訊號從哪裡來?源時鐘訊號是外部APB匯流排(PCLK_PSYS,66MHz)提供給串列埠模組的(這就是為什麼我們說串列埠是掛在APB總線上的),然後進到串列埠控制器內部後給波特率發生器(實質上是一個分頻器),在波特率發生器中進行分頻,分頻後得到一個低頻時鐘,這個時鐘就是給transmitter和receiver使用的。
(3)串列埠通訊中時鐘的設定主要看暫存器設定。重點的有:暫存器源設定(為串列埠控制器選擇源時鐘,一般選擇為PCLK_PSYS,也可以是SCLK_UART),還有波特率發生器的2個暫存器。
(4)波特率發生器有2個重要暫存器:UBRDIVn和UDIVSLOTn,其中UBRDIVn是主要的設定波特率的暫存器,UDIVSLOTn是用來輔助設定的,目的是為了校準波特率的。
1.7.7.S5PV210序列通訊程式設計實戰1
1.7.7.1、整個程式流程分析
(1)整個串列埠通訊相關程式包含2部分:uart_init負責初始化串列埠,uart_putc負責傳送一個位元組
1.7.7.2、串列埠控制器初始化關鍵步驟
(1)初始化串列埠的Tx和Rx引腳所對應的GPIO(查原理圖可知Rx和Rx分別對應GPA0_1和GPA0_0)
(2)GPA0CON(0xE0200000),bit[3:0] = 0b0010 bit[7:4] = 0b0010
(3)初始化這幾個關鍵暫存器UCON0 ULCON0 UMCON0 UFCON0 UBRDIV0 UDIVSLOT0
1.7.7.3、主要的幾個暫存器
(1)ULCON0 = 0x3 // 0校驗位、8資料位、1停止位
(2)UCON = 0x5 // 傳送和接收都是polling mode
(3)UMCON0 = 0x0 // 禁止modem、afc
(4)UFCON0 = 0x0 // 禁止FIFO模式
(5)UBRDIV0和UDIVSLOT0和波特率有關,要根據公式去算的
1.7.7.4、在C原始檔中定義訪問暫存器的巨集
定義好了訪問暫存器的巨集之後,將來寫程式碼時直接使用即可。
1.7.8.S5PV210序列通訊程式設計實戰2
1.7.8.1、串列埠Tx、Rx對應的GPIO的初始化
給GPA0CON的相應bit位賦值為相應值,用C語言位操作來完成。
1.7.8.2、UCON、ULCON、UMCON、UFCON等主要控制暫存器
依據上節中分析的值進行依次設定即可。
1.7.8.3、波特率的計算和設定
(1)第一步,用PCLK_PSYS和目標波特率去計算DIV_VAL: DIV_VAL = (PCLK / (bps x 16)) ?1
(2)第二步,UBRDIV0暫存器中寫入DIV_VAL的整數部分
(3)第三步,用小數部分*16得到1個個數,查表得uBDIVSLOT0暫存器的設定值
1.7.8.4、串列埠傳送和接收函式的編寫
(1)寫傳送函式,主要傳送前要用while迴圈等待發送緩衝區為空才能傳送。
1.7.8.5、綜合除錯
注意Makefile的修改。
1.7.8.6、擴充套件練習-更改波特率後再除錯
自己練習。注意程式中改了波特率後,SecureCRT也要相應修改,不然收不到東西。
1.7.9.uart stdio的移植1
1.7.9.1、什麼是stdio
(1)#include <stdio.h>
(2)stdio:standard input output,標準輸入輸出
(3)標準輸入輸出就是作業系統定義的預設的輸入和輸出通道。一般在PC機的情況下,標準輸入指的是鍵盤,標準輸出指的是螢幕。
(4)printf函式和scanf函式可以和底層輸入/輸出函式繫結,然後這兩個函式就可以和stdio繫結起來。也就是說我們直接呼叫printf函式輸出,內容就會被從標準輸出輸出出去。
(5)在我們這裡,標準輸出當然不是螢幕了,而是串列埠。標準輸出也不是鍵盤,而是串列埠。
1.7.9.2、printf函式的工作原理
(1)printf函式工作時內部實際呼叫了2個關鍵函式:一個是vsprintf函式(主要功能是格式化列印資訊,最終得到純字串格式的列印資訊等待輸出),另一個就是真正的輸出函式putc(操控標準輸出的硬體,將資訊傳送出去)
1.7.9.3、移植printf函式的三種思路
(1)我們希望在我們的開發板上使用printf函式進行(串列埠)輸出,使用scanf函式進行(串列埠)輸入,就像在PC機上用鍵盤和螢幕進行輸入輸出一樣。因此需要移植printf函式/scanf函式
(2)我們說的移植而不是編寫,我們不希望自己完全從新編寫而是想盡量借用也有的程式碼(叫移植)
(3)一般移植printf函式可以有3個途徑獲取printf的實現原始碼:最原始最原本的來源就是linux核心中的printk。難度較大、關鍵是麻煩;稍微簡單些的方法是從uboot中移植printf;更簡單的方法就是直接使用別人移植好的。
(3)我們課程中使用第三種方法,別人移植好的printf函式來自於友善之臂的Tiny210的裸機教程中提供的。
1.7.9.4、移植好的printf介紹
參考視訊中講解。
1.7.10.uart stdio的移植2
1.7.10.1、修改Makefile進行printf移植
1.7.10.2、Makefile及gcc的庫檔案介紹
1.7.10.3、多資料夾裸機工程的結構解析
1.7.10.4、編譯執行及測試
1.7.11.uart stdio的移植3
1.7.11.1、在移植後的uart stdio專案中新增link.lds連結指令碼,指定連線地址到0xd0020010
1.7.11.2、gcc可變引數及va_arg介紹
(1)printf函式中首先使用了C語言的可變引數va_start/va_arg/va_end;
(2)建議大家先去baidu“C語言可變引數”,然後按照別人的教程、部落格實際寫幾個簡單的變參的使用示例,先明白可變引數怎麼工作,然後再來分析這裡。
1.7.11.3、vsprintf函式詳解
printf
vsprintf
vsnprintf
number
vsprintf函式的作用是按照我們的printf傳進去的格式化標本,對變參進行處理,然後將之格式化後快取在一個事先分配好的緩衝區中。
printf後半段呼叫putc函式將緩衝區中格式化好的字串直接輸出到標準輸出。
1.7.12.串列埠實驗燒錄問題總結
1.7.12.1、usb下載的問題
(1)USB下載時在Win7 X64系統下,下載前面章節的小程式碼時沒問題,下載串列埠通訊的小程式碼時也沒問題,下載uart stdio的移植就有問題了。有時候下載不動、有時候能下載但是不執行、有時候又正常下載執行。我已經試過下載其他的dnw或dnw驅動更新,都無法解決。
1.7.12.2、SD卡映象燒錄
(1)SD卡燒錄映象做裸機實驗,在第四部分1.4.2節中有講過。
(2)本次我們在Windows下燒錄(linux下的燒錄參考以前的)
(3)Windows下燒錄映象是使用九鼎提供的工具(X210光碟資料\A盤\tools\x210_Fusing_Tool.exe),注意執行時右鍵“以管理員身份執行”。
1.7.12.3、啟動方式設定
(1)X210開發板的啟動方式的選擇,請參考1.2.11節。其實就是OM5的問題,OM5設定為VCC則從USB啟動,OM5設定成GND,則從iNand/SD卡啟動。
(2)開發板選擇從iNand啟動後,還要確保iNand中uboot是被擦除的。
(3)關於如何破壞uboot的問題,大家可以參考之前課程中講的在linux/android系統中破壞uboot的方法。我之前講過在uboot中破壞uboot的方法:movi write u-boot 0x30000000。很多同學反映擦除後錯亂,進不了系統也從SD卡啟動不了,只能通過USB刷機來解決。後來又分析,改為:mw 0x30000000 0x0 0x100000,然後再movi write u-boot 0x30000000
。但是反饋結果有人說可以了,有人說還是不行·······
(4)不管怎麼擦除uboot,總之首先確保你的板子SD卡啟動是成功的。怎麼確保?先用SD卡燒錄啟動之前的LED閃爍的專案,確保看到現象就證明燒錄SD卡方法和啟動SD卡都成功了,再做本節課的實驗。
1.7.12.4、連結指令碼的影響
1.7.12.5、bin檔案大於16KB怎麼辦?
通過USB下載最多也只能下載96KB大小的bin,如果bin大於96KB肯定SRAM放不下會出錯。如果用SD卡啟動,那麼mkv210_image.c決定了bin檔案最大不能超過16KB。
超過了怎麼辦?2種解法:
第一,在USB下載時,可以先下載一個x210_usb.bin,然後再將裸機程式連線到0x23E00000,然後再修改dnw中下載地址,將裸機程式碼下載到0x23E00000執行。(這時不需要重定位了)
第二,在SD卡啟動時,將整個裸機工程分為2部分;第一部分大小16KB以內,第二部分放剩下的(放在SD卡的後面的某個扇區開始的位置,譬如放在第50個扇區開始的位置),然後在裸機程式碼中進行重定位(SD卡中重定位)。這個暫時沒講,以後如果有用到就講。