基于LPC2210的RTL8019AS以太網(wǎng)驅(qū)動系統(tǒng)設(shè)計(三)
六.接收數(shù)據(jù)包模塊
RTL8019AS接收數(shù)據(jù)有中斷模式和查詢模式兩種。
?采用中斷模式時,需要在初始化程序中配置中斷。當(dāng)有一個正確的數(shù)據(jù)包到達(dá)時,RTL8019AS會產(chǎn)生一個中斷信號,在中斷處理程序中進(jìn)行接收數(shù)據(jù)處理。
?采用查詢模式時,由主程序定時對接收緩沖區(qū)進(jìn)行查詢,當(dāng)檢測到有新的數(shù)據(jù)時,通過遠(yuǎn)程DMA方式將數(shù)據(jù)從RTL8019AS的RAM空間讀出進(jìn)行處理。
本驅(qū)動系統(tǒng)采用查詢方式實現(xiàn)數(shù)據(jù)包的接收
6.1接收數(shù)據(jù)包模塊的功能
在接收數(shù)據(jù)時,接收緩沖區(qū)構(gòu)成一個循環(huán)FIFO隊列。PSTART,PSTOP兩個寄存器限定了循環(huán)隊列的開始頁和結(jié)束頁,CURR為寫入指針,受RTL8019芯片控制,BNRY為讀出指針,有主機(jī)程序控制。根據(jù)CURR是否等于BNRY+1,來判斷是否收到新的數(shù)據(jù)包,新收到的數(shù)據(jù)包存于CURR指定地址的RAM中。當(dāng)CURR=BNRY時,RTL8019芯片停止接收數(shù)據(jù)包,反之,CURR按模增加。
6.2接收數(shù)據(jù)包模塊的數(shù)據(jù)結(jié)構(gòu)
?REC_BUFF_UNION:定義共用體REC_BUFF_UNION來存儲接收到的以太網(wǎng)幀,因為一個最大以太網(wǎng)幀長度為1518bit,所以定義公用體容量為1536bit。
?unionREC_BUFF_UNIONREC_BUFF[MAX_REC_BUFF];
REC_BUFF數(shù)組用來存儲以太網(wǎng)幀,此系統(tǒng)定義最多可以接收5條最大以太網(wǎng)幀。
1>實現(xiàn)形式
#define MAX_REC_BUFF5
unionREC_BUFF_UNION
{
uint32Dwords[384];
uint16words[768];
uint8bytes[1536];
};
REC_BUFF_UNIONREC_BUFF[MAX_REC_BUFF];
2>定義uint16*REC_BUFF_PTR_WORDS,
uint8* REC_BUFF_PTR_BYTES,
用REC_BUF_PTR_WORDS來接收2字節(jié)數(shù)據(jù),用REC_BUFF_PTR_BYTES來接收1字節(jié)數(shù)據(jù)。
3>以太以太網(wǎng)幀格式
6.3接收數(shù)據(jù)包模塊的組成
第一步:RTL8019AS以太網(wǎng)芯片從以太網(wǎng)讀數(shù)據(jù)
該過程涉及的寄存器如下:
?PSTART,PSTOP:以太網(wǎng)芯片接收數(shù)據(jù)緩沖區(qū)的起始,末頁地址。形成一個接收緩沖區(qū),每頁256字節(jié)。
?CURR:接收緩沖區(qū)寫頁指針
?BNRY:接收緩沖區(qū)讀指針
這四個寄存器在芯片初始化模塊中被設(shè)置。
在初始化TPSR,BNRY,PSTART,PSTOP寄存器后,就定義了接收緩沖區(qū)和發(fā)送緩沖的容量和起始地址:
當(dāng)有新數(shù)據(jù)包到來時,網(wǎng)絡(luò)芯片會自動判斷是否發(fā)送給本機(jī);若是有新數(shù)據(jù)到來,則用本地DMA存入接收緩沖區(qū),并自動修改寫指針。
1>接收數(shù)據(jù)包操作之前,先關(guān)中斷
2>判斷是否發(fā)生溢出和復(fù)位。若發(fā)生,則初始化芯片,結(jié)束程序。
3>獲取讀頁指針bnry和寫頁指針curr。
4>判斷寫頁指針是否讀取正確。若錯誤,則開中斷,結(jié)束程序
5>判斷bnry+1是超過接收緩沖區(qū)末地址,若超過,則從接收緩沖區(qū)首地址開始讀。
第二步:ARM LPC2210從網(wǎng)絡(luò)芯片RTL8019AS中讀數(shù)據(jù)
該過程涉及的寄存器同上,當(dāng)對寄存器的具體賦值不同。
?遠(yuǎn)程DMA起始地址的高字節(jié)位,賦為最后一次已經(jīng)讀取頁的地址。低地址為0.
?遠(yuǎn)程DMA的字節(jié)計數(shù)寄存器為待讀的數(shù)據(jù)長度。
?設(shè)置CR為0XA發(fā)送數(shù)據(jù)包
1>判斷curr是否等于bnry+1,若不等于則有新的數(shù)據(jù)包到來,CURR按模增加。當(dāng)CURR=BNRY時,RTL8019芯片停止接收數(shù)據(jù)包。
2>接收數(shù)據(jù)包之前,先判斷接收緩沖環(huán)區(qū)是否達(dá)到最大(此系統(tǒng),限定接收緩沖區(qū)最大為5)。若達(dá)到最大,則重第一個緩沖區(qū)開始存。
3>設(shè)定遠(yuǎn)程DMA起始地址和遠(yuǎn)程DMA數(shù)據(jù)字節(jié)計數(shù)器啟動DMA讀取以太網(wǎng)幀頭部前4個字節(jié)存入程序數(shù)組。
4>清零遠(yuǎn)程DMA字節(jié)計數(shù)器并中止DMA讀操作
5>根據(jù)接收到的以太網(wǎng)幀頭判斷接收幀是否錯誤,若有錯誤則進(jìn)行錯誤處理,然后程序結(jié)束。
錯誤類型有:
?接收狀態(tài)是否錯誤
?下一頁指針是否正確
?幀的長度是否大于1536
6>若數(shù)據(jù)包是完成的,讀取剩下的數(shù)據(jù)
?把bnry+4的地址賦值給遠(yuǎn)程DMA起始地址寄存器(RASR1,RSAR0)
?把幀的長度賦值給遠(yuǎn)程DMA計算寄存器(RBCR0,RBCR1)
?啟動遠(yuǎn)程DMA讀
7>從0x10遠(yuǎn)程DMA端口處,讀取數(shù)據(jù)存放到緩沖區(qū)中
8>清零遠(yuǎn)程DMA字節(jié)計數(shù)器寄存器(RSCR1,RSCR0),并終止DMA操作。
9>讀完一個幀后,修改讀頁bnry指針
10>修改完頁指針后,判讀讀頁指針是否到接收緩沖區(qū)首地址,若小于0X4C,則將binry恢復(fù)到接收緩沖區(qū)末地址處。
11>把修改過的讀頁指針寫入BNRY處
12>清除所有中斷標(biāo)志
13>判斷以太網(wǎng)中的下一條協(xié)議字段值是否是ARP數(shù)據(jù)報或IP數(shù)據(jù)報,如果是則調(diào)用上層程序進(jìn)行處理。如果不是則不處理。
?判斷是ARP或IP協(xié)議時,則REC_BUFF_NUM+1,在下一個緩沖區(qū)接收新的以太網(wǎng)幀。
?開中斷
?調(diào)用以太網(wǎng)報處理函數(shù)
?循環(huán)判斷是否有新的數(shù)據(jù)包到來
6.4接收數(shù)據(jù)包模塊接口
接收包模塊調(diào)用了寫數(shù)據(jù)子模塊,讀數(shù)據(jù)子模塊和頁面切換子模塊
?讀數(shù)據(jù)子模塊:從RTL8019AS中把數(shù)據(jù)讀出。
?寫數(shù)據(jù)子模塊:將數(shù)據(jù)寫入RTL2019AS芯片中
?頁面切換子模塊:可選擇Page0,Page1,Page3三個頁面
6.5接收數(shù)據(jù)包模塊程序
/****************************Copyright(c)********************
**西安郵電學(xué)院
**graduate school
**XNMS實驗室
**Author:冀博
**Time:2011年2月21日
**http://blog.csdn.net/tigerjb
**
**--------------FileInfo---------------------------------------------------------------------
****************************Copyright(c)******************** /
/**********************************************************
**函數(shù)原型:unsigned char * Rec_Packet()
**入口參數(shù):無
**返回值:程序正確返回0
**說明:查詢是否有新數(shù)據(jù)包并接收進(jìn)緩沖區(qū)
**********************************************************/
uint8 Rec_Packet()
{void Send_Packet(struct _pkst *TxdData)//
{
static uint8 REC_BUFF_NUM=0;
//定義讀頁號bnry和寫頁號curr
static uint8 bnry,curr;
//存放以太網(wǎng)幀報頭
static uint16 tmp[2];
uint16 * REC_BUFF_PTR_WORDS;
uint8 * REC_BUFF_PTR_BYTES;
uint8 i;
uint16 ii,length;
OS_ENTER_CRITICAL();
rea1:
page(0);
i=ReadFromNet(0X07);
//如果復(fù)位或益出就重新初試化
if((i&0x90)!=0)
{
InitNic(0);
O