GEC210(S5PV210)裸機驅動之串列埠及串列埠中斷
主機平臺:Linux CentOS 6.5
arm平臺:粵嵌GEC210開發板(S5PV210)
這次寫一下串列埠的驅動,功能是在linux終端中鍵入並向arm傳送一個字元,arm返回這個字元將其在終端上顯示。
其中,串列埠採用串列埠0,非FIFO模式,波特率115200,8位資料為,無較檢位,接收用中斷方式,傳送用查詢方式。
既然用到中斷,那還是按就之前寫中斷的步驟進行:
8.編寫外設對應的中斷服務程式
8.1.根據標誌為判斷髮生了什麼中斷。(當多箇中斷共享一箇中斷號時通常需要做此判斷)
8.2.根據發生的中斷執行相應的任務
8.3.清除所發生中斷的中斷標誌位
8.4.清除全部VICxADDR(置0)
8.5.重新使能全域性IRQ中斷(進入中斷後,全域性IRQ中斷會被關閉)
9.設定外設暫存器初始化外設(包括清除中斷標誌位,使能中斷等操作)
9.1.關閉外設暫存器的中斷使能
9.2.清除外設中斷標誌位
9.3.初始化設定與外設相關的其它暫存器。例如I/O的功能選擇(這個容易忘記),設定輸入時鐘頻率等等。
9.4開啟外設對應中斷
10.根據外設查詢中斷源表獲得其中斷號
11.根據中斷號設定對應的中斷服務程式入口地址暫存器(VICxVECTADDRx)
12.根據中斷號使能對應中斷
下面就是針對串列埠將每個步驟具體化:
8.編寫外設對應的中斷服務程式
8.1.判斷該次中斷是否串列埠的傳送中斷、接收中斷、還是錯誤中斷
8.2.執行對應任務,此處是隻當為接收中斷時,通過查詢方式將獲得的資料傳送出去
8.3.清除對應中斷標誌位(UINTSP0和UINTP0)
8.4.清除全部VICxADDR(置0)
8.5.重新使能全域性IRQ中斷(進入中斷後,全域性IRQ中斷會被關閉)
9.設定外設暫存器初始化外設(包括清除中斷標誌位,使能中斷等操作)
9.1.關閉串列埠0中斷使能(UINTM0[3:0])
9.2.清除串列埠0中斷所有標誌位 (UINTSP0[3:0]和UINTP0[3:0])
9.3
(1)將串列埠0對應的IO引腳功能設定為UART_0_RXDGPA0CON[3:0] 和 UART_0_TXD(GPA0CON[7:4])
(2)設定波特率。波特率由PCLK時鐘、UCON[10]、UBRDIV、UDIVSLOT暫存器確定
公式:
DIV_VAL = UBRDIVn + (num of 1's in UDIVSLOTn)/16
DIV_VAL = (PCLK / (bps x 16)) −1
or
DIV_VAL = (SCLK_UART / (bps x 16)) −1
此處,時鐘源選擇PCLK(UCON[10]=0),為66M,且UDIVSLOTn=0,因此由第1、2條公式得:
UBRDIV0 = (66M/(115200*16))-1 = 35
(3)設定幀格式,包括資料位位數、停止位位數、較檢方式(ULCON0)
(4)配置UCON暫存器,裡面有很多設定,我講一些個人認為比較重要的,其它沒看懂的話就保持預設值吧
[10]:波特率時鐘源選擇位
[9:8]:Tx/Rx Interrupt Type:手冊上寫這兩位必須置1
[5]:Loop-back Mode ,即迴環測試模式,可以自發自收
[3:2]:Transmit Mode:什麼情況下允許寫串列埠傳送暫存器 00:不可寫;01:可通過中斷或查詢方式寫入;10:在DMA模式下可寫
[1:0]:Receive Mode:什麼情況下允許讀串列埠接收暫存器 00:不可寫;01:可通過中斷或查詢方式寫入;10:在DMA模式下可寫
9.4.使能串列埠中斷,這裡只使能接收中斷(UINTM0[0])
10.根據外設查詢中斷源表獲得其中斷號,可知中斷號為42
11.根據中斷號設定對應的中斷服務程式入口地址暫存器(VIC3VECTADDR10)
12.根據中斷號使能對應中斷(VIC3INTENABLE[10])
跟著再講下如何傳送和接收,這裡比較簡單
傳送:先判斷串列埠是否空閒,然後向傳送緩衝暫存器寫入資料
接收:在中斷中直接讀接收緩衝暫存器就可以了
具體實現看下面程式碼:
void uart0_int_func()
{
unsigned long temp;
if(UTRSTAT0&0x1) //判斷是否為接收中斷
{
temp=URXH0; //讀取接收暫存器
while(!(UTRSTAT0&0x2)); //等待串列埠空閒
UTXH0=temp; <span style="font-size:14px;">//</span>傳送接收到的內容
UINTSP0|=0xf; //清除中斷標誌位
UINTP0|=0xf; //清除中斷標誌位
clear_vicaddress(); <span style="font-size:14px;">/</span>/清除全部VICADDR暫存器
}
enable_global_IRQ(); //使能全域性IRQ中斷
}
void uart0_init()
{
ULCON0|=0x3; //設定幀格式
UCON0=0x305; //時鐘源、讀寫傳送接收暫存器模式
UBRDIV0=35; //設定波特率
UINTM0=0xf; //遮蔽所有串列埠中斷
GPA0CON=0x22; //設定引腳功能為串列埠收發
UINTSP0|=0xf; //清除中斷標誌
UINTP0|=0xf; //清除中斷標誌
set_int_vectaddr(42,uart0_int_func); //設定42號中斷服務程式入口地址
interrupt_enable(42); //使能中斷系統42號中斷
UINTM0=0xe; //使能串列埠接收中斷
}
好了,這就是一個簡單的串列埠程式,串列埠還有很多種模式的,例如FIFO、Infrared、DMA等模式,這些就要以後慢慢去深入學習了。