ARM中基于DMA的高效UART通訊及其應用
在以S3C44B0X為核心組成的移動機器人中,采用3路PWM定時器驅動3個直流電機,通用的GPIO口和A/D口連接外部的紅外和超聲以及激光傳感器,使用UART0完成與上位機(PC)的數據交換,這些數據是單向的(從上位機發送給S3c44b0x),主要是上位機傳給機器人控制器的各種命令信息,但是命令信息的發送時間上是不具有規律性的,即間隔時間不定。為了充分的利用CPU,減少數據丟失的風險,我們利用UART的DMA模式來完成數據的接收。軟件部分主要是針對具體的應用,對DMA控制器以及UART作適當的初始化。UART的初始化比較簡單,主要是通訊數據格式、波特率等的設置,這些與其他控制器相同,只要設置相關的寄存器即可。注意UART設置成不使用自動流控制,不使用紅外線傳輸模式,關鍵要注意UART0設置成DMA模式而不是中斷模式,并且要使能FIFO緩沖區(根據需要,使用16字節的接收緩沖區),這樣在接收緩沖區滿時,會產生DMA請求而不是中斷請求。限于篇幅,具體的寄存器定義以及串行口的初始化不做詳悉介紹,可以參考文獻[1][2]。
DMA控制器的初始化也比較簡單,主要是相關寄存器的設置。與BDMA0相關的在本系統中用到的寄存器以及相關定義見表1,具體寄存器的名稱定義以及物理地址見參考文獻[1][2]。
表1 S3c44b0x的BDMA相關寄存器的定義
在初始化時要正確設置目標(緩沖區的)首地址、數據傳輸的方向、源寄存器的首地址、地址指針是否遞增以及遞增方向、DMA計數器等等。相關代碼以及注釋如下:
#define RAM_ADDRESS 0xc200000 //定義接收數據的緩沖區,根據硬件而定。在我們的系統中擴展的SDRAM 存儲空間從0x0C00000~0x0C7fffff,占用S3c44b0x的bank 6。
#define size 16 //定義DMA的計數器,根據需要設定,可以選擇的選項是4、8、2和16
char *Buf;
Buf=(unsigned char*) RAM_ADDRESS; //指針指向起始地址
BDISRC0=(1128)+(int)(rURxH0); /*以字節為單位傳送;因為DMA操作時是將UART的寄存器中的數據讀出放置到設定的緩沖區,所以源寄存器的地址應該是固定到;UART的接收保存寄存器rURxH0,同時位[29:28]應該設置成 0b11。*/
BDIDES0=(1030)+(0128)+ Buf); /*傳輸方向模式設定為從內部設備(UART口)到外部存儲器(SDRAM),目標存儲器(SDRAM)使用地址遞增的方向,將數據順次放置到緩沖區中*/
BDICNT0=(1030)+(126)+(322)+(121)+(0 lt;20)+size;/*設置UART0使用BDMA0通道,在DMA計數到0時自動重載和自動啟動,計數結束產生中斷,每次DMA操作移動 16字節數據到設定地緩沖區*/
BDICNT0 |= (120);//使能DMA
BDCON0 = 0x02;//允許外部DMA請求
數據接收:這一部分工作由初始化好后的DMA控制器依靠硬件來完成。接收數據不定時,初始化UART0的接收緩沖區為16字節,當接收緩沖區滿時,會產生DMA請求,然后在DMA控制器的控制下,將UART的接收FIFO中的16字節的數據轉移到指定的緩沖區中(SRAM),當數據轉移完畢(DMA 計數到0)后,要做兩件事情:一是自動重載和自動啟動,即自動重新設置好目標(緩沖區)首地址和源地址(UART接收寄存器)以及DMA計數器,準備好下次DMA請求;另外產生DMA中斷。DMA中斷服務程序要做的工作很簡單,只要對全局標志RECEIVE_FLAG置位,通知主程序有新的命令需要處理。這樣主程序可以直接處理RAM中的數據,而不需要花費時間去讀取UART的接收緩沖區。
數據處理:當主程序通過查詢全局標志RECEIVE_FLAG,如果為1,則知道有新的命令,可以直接讀取命令緩沖區,同時對RECEIVE_FLAG清零。然后按照一定的算法對接收的數據做出解析,這部分內容不做重點討論。
評論