?? lib_emac.c
字號(hào):
//*------------------------------------------------------------------------------------------------
//* 文件名 : lib_emac.c
//* 功能描述 : EMAC外設(shè)的函數(shù)庫
//* 作者 : 焦海波
//* 版本 : 0.1
//* 建立日期、時(shí)間 : 2006/10/08 10:25
//* 最近修改日期、時(shí)間 :
//* 修改原因 :
//*------------------------------------------------------------------------------------------------
//*------------------------------------------ 頭文件 ----------------------------------------------
#include "/uCOS_II/includes.h"
#include "/at91sam7x256/include/AT91SAM7X256.h"
#include "/at91sam7x256/include/lib_AT91SAM7X256.h"
#include "/LwIP/include/lwip/opt.h"
#include "lib_emac.h"
//*------------------------------------- 常量、變量、宏 -------------------------------------------
//* 因?yàn)榻邮站彌_區(qū)描述符字0的2到31位保存緩沖區(qū)地址,最低兩位有其它用處,所以指定4字節(jié)對(duì)齊,以保證緩沖區(qū)地址
//* 的最低兩位為0
__align(4) static volatile BYTE baRxBufs[NB_RX_BUFS][ETH_RX_BUF_SIZE]; //* 接收緩沖區(qū)
static BYTE baTxBufs[NB_TX_BUFS][ETH_TX_BUF_SIZE]; //* 發(fā)送緩沖區(qū)
/* 因?yàn)榫彌_區(qū)描述符長度為雙字,正好8個(gè)字節(jié),所以指定雙字對(duì)齊 */
__align(8) static volatile AT91S_RxBDescriptor __staRxBDescriptors[NB_RX_BUFS]; //* 接收緩沖區(qū)描述符數(shù)組
__align(8) static volatile AT91S_TxBDescriptor __staTxBDescriptors[NB_TX_BUFS]; //* 發(fā)送緩沖區(qū)描述符數(shù)組
//* 保存要讀取的接收緩沖區(qū)的索引位置
static UWORD __uwCurRxBIdx = 0;
static BYTE *__pbFrom;
//*-------------------------------------- 函數(shù)原型聲明 --------------------------------------------
static void __HandlePHY(UBYTE ubRegAddr, UWORD *puwData, BOOLEAN blIsRead);
static void __ResetPHY(void);
static void __CheckPHYID(void);
static void __SetupLinkSpeedAndDuplex(void);
static void __InitDescriptorsForRxBAndTxB(void);
__inline void __ilResetTxBDescriptors(void);
//*================================================================================================
//* 函 數(shù) 區(qū)
//*================================================================================================
//*------------------------------------------------------------------------------------------------
//* 函數(shù)名稱 : irqEMACISR
//* 功能描述 : EMAC發(fā)送和接收結(jié)束中斷處理函數(shù)
//* 入口參數(shù) : 無
//* 出口參數(shù) : 無
//*------------------------------------------------------------------------------------------------
__irq void irqEMACISR(void)
{
extern HANDLER hEthernetInput;
ULONG __ulIntStatus, __ulReceiveStatus;
OSIntEnter();
{
//* 在讀取時(shí)中斷狀態(tài)寄存器位會(huì)被清除
__ulIntStatus = AT91C_BASE_EMAC->EMAC_ISR;
//* 這個(gè)是容易忽略的地方,只有讀取RSR寄存器,EMAC中斷處理才能在寫EOICR寄存器之后真正結(jié)束
__ulReceiveStatus = AT91C_BASE_EMAC->EMAC_RSR;
if((__ulIntStatus & AT91C_EMAC_RCOMP) || (__ulReceiveStatus & AT91C_EMAC_REC))
{
//* 向EMAC接收任務(wù)發(fā)送信號(hào)
OSAPISemSend(hEthernetInput);
//* 清除REC(Frame Received)位
AT91C_BASE_EMAC->EMAC_RSR = AT91C_EMAC_REC;
}
if(__ulIntStatus & AT91C_EMAC_TCOMP)
{
//* 復(fù)位發(fā)送緩沖區(qū)描述符的Used位使其為程序所有
__ilResetTxBDescriptors();
AT91C_BASE_EMAC->EMAC_TSR = AT91C_EMAC_COMP;
}
//* 清除中斷標(biāo)志,結(jié)束中斷處理
AT91C_BASE_AIC->AIC_EOICR = 0;
}
OSIntExit();
}
//*------------------------------------------------------------------------------------------------
//* 函數(shù)名稱 : EMACSendPacket
//* 功能描述 : 由__low_level_output()函數(shù)調(diào)用,完成實(shí)際的數(shù)據(jù)發(fā)送。
//* 入口參數(shù) : <pbFrom>[in] 指向pbuf中數(shù)據(jù)的指針
//* : <ulLength>[in] pbuf中的數(shù)據(jù)長度
//* : <blIsEndOfFrame>[in] 是否是pbuf鏈中的最后一個(gè),也就是幀尾
//* 出口參數(shù) : 如果無法申請(qǐng)下內(nèi)存則返回ERR_MEM,成功則返回ERR_OK
//*------------------------------------------------------------------------------------------------
BOOLEAN EMACSendPacket(BYTE *pbFrom, ULONG ulLength, BOOLEAN blIsEndOfFrame)
{
ULONG __ulTotalLenToWrite = 0, __ulCurLenToWrite, __ulLenRemainToWrite, __ulIsLastBuf;
//* 注意這是一個(gè)私有的靜態(tài)變量
static UWORD __uwTxBIndex = 0;
LONG i;
BYTE *__pbBuf;
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr = 0;
#endif
//* 如果要發(fā)送的數(shù)據(jù)長度大于一個(gè)發(fā)送緩沖區(qū),則需要將這些數(shù)據(jù)分割進(jìn)多個(gè)緩沖區(qū)進(jìn)行發(fā)送
while(__ulTotalLenToWrite < ulLength)
{
//* 等待緩沖區(qū)可用,最長等待3秒鐘
i = 0;
while(!__staTxBDescriptors[__uwTxBIndex].uStatus.bstStatus.bitIsUsed)
{
//* 如果已經(jīng)到達(dá)等待時(shí)間仍然沒有可用緩沖區(qū),則立即返回
if(i > 300)
return FALSE;
OSTimeDly(1);
i++;
}
OS_ENTER_CRITICAL()
{
//* 從描述符中獲得緩沖區(qū)地址,然后把數(shù)據(jù)復(fù)制到緩沖區(qū)
__pbBuf = (BYTE*)__staTxBDescriptors[__uwTxBIndex].ulTxBAddr;
//* 計(jì)算向緩沖區(qū)寫入的數(shù)據(jù)長度
__ulLenRemainToWrite = ulLength - __ulTotalLenToWrite;
if(__ulLenRemainToWrite > ETH_TX_BUF_SIZE)
__ulCurLenToWrite = ETH_TX_BUF_SIZE;
else
__ulCurLenToWrite = __ulLenRemainToWrite;
//* 將pbuf中的數(shù)據(jù)復(fù)制到發(fā)送緩沖區(qū)
memcpy(__pbBuf, &(pbFrom[__ulTotalLenToWrite]), __ulCurLenToWrite);
__ulTotalLenToWrite += __ulCurLenToWrite;
//* 看看是否是已經(jīng)到達(dá)pbuf鏈的末尾,如果是則標(biāo)記當(dāng)前使用的緩沖區(qū)為最后一個(gè)緩沖區(qū)
if(blIsEndOfFrame && (__ulTotalLenToWrite >= ulLength))
{
__ulIsLastBuf = TxDESC_STATUS_LAST_BUF;
}
else
__ulIsLastBuf = 0;
//* 填充當(dāng)前的描述符:緩沖區(qū)中的數(shù)據(jù)實(shí)際長度、最后一個(gè)緩沖區(qū)標(biāo)記、WRAP位(如果確實(shí)是最后一個(gè)描述符)
if(__uwTxBIndex >= (NB_TX_BUFS-1))
{
__staTxBDescriptors[__uwTxBIndex].uStatus.ulStatus = (__ulCurLenToWrite & TxDESC_STATUS_BUF_SIZE)
| __ulIsLastBuf
| TxDESC_STATUS_WRAP;
__uwTxBIndex = 0;
}
else
{
__staTxBDescriptors[__uwTxBIndex].uStatus.ulStatus = (__ulCurLenToWrite & TxDESC_STATUS_BUF_SIZE)
| __ulIsLastBuf;
__uwTxBIndex++;
}
//* 如果已經(jīng)到達(dá)pbuf鏈的末尾則立即發(fā)送
if(__ulIsLastBuf)
AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_TSTART;
}
OS_EXIT_CRITICAL()
}
return TRUE;
}
//*------------------------------------------------------------------------------------------------
//* 函數(shù)名稱 : EMACReadPacket
//* 功能描述 : 從EMAC讀取信息包到申請(qǐng)的pbuf鏈,該函數(shù)要求PBUF_POOL_BUFSIZE大于或等于接收緩沖區(qū),最好是整
//* : 數(shù)倍,這樣函數(shù)處理最簡單。注意,在調(diào)用該函數(shù)之前必須先調(diào)用GetInputPacketLen()函數(shù),這樣才
//* : 能獲取正確的讀取位置
//* 入口參數(shù) : <pbTo>[in] 指向pbuf的指針
//* : <uwSegmentLen>[in] pbuf中需要存儲(chǔ)的實(shí)際數(shù)據(jù)長度,因?yàn)樵谏暾?qǐng)pbuf時(shí),pbuf_alloc()已經(jīng)根據(jù)
//* : 實(shí)際的幀長將其分割進(jìn)了多個(gè)pbuf組成的pbuf鏈中,而pstPbuf->len則保存了
//* : 每個(gè)pbuf需要存儲(chǔ)的數(shù)據(jù)。換句話說pbuf鏈中的最后一個(gè)pbuf的len字段長度應(yīng)
//* : 該小于或等于PBUF_POOL_BUFSIZE,而前面的pbuf則等于PBUF_POOL_BUFSIZE
//* : <blIsLastPbuf>[in] 是否是最后一個(gè)Pbuf
//* 出口參數(shù) : 無
//*------------------------------------------------------------------------------------------------
void EMACReadPacket(BYTE *pbTo, UWORD uwSegmentLen, BOOLEAN blIsLastPbuf)
{
UWORD __uwTotalLenToRead = 0, //* 已經(jīng)讀取到pbuf的總字節(jié)數(shù)
__uwRemainLenToRead, //* 還剩多少字節(jié)沒有讀取到pbuf中
__uwRemainLenInRxBToRead; //* EMAC接收緩沖區(qū)中還剩下多少字節(jié)沒有讀取
static UWORD __uwTotalLenInRxBToRead = 0; //* EMAC接收緩沖區(qū)中已經(jīng)讀了多少字節(jié)的數(shù)據(jù)
BOOLEAN __blIsNotRelease; //* 是否已經(jīng)主動(dòng)釋放給EMAC
/* 注意,必須保證PBUF_POOL_BUFSIZE大于或等于接收緩沖區(qū) */
while(__uwTotalLenToRead < uwSegmentLen)
{
__uwRemainLenInRxBToRead = ETH_RX_BUF_SIZE - __uwTotalLenInRxBToRead;
__uwRemainLenToRead = uwSegmentLen - __uwTotalLenToRead;
if(__uwRemainLenToRead >= __uwRemainLenInRxBToRead)
{
memcpy(pbTo + __uwTotalLenToRead, __pbFrom, __uwRemainLenInRxBToRead);
__uwTotalLenToRead += __uwRemainLenInRxBToRead;
__uwTotalLenInRxBToRead = 0;
//* 將接收緩沖區(qū)歸還給EMAC
__staRxBDescriptors[__uwCurRxBIdx].ulRxBAddrAndFlag &= (~RxDESC_FLAG_OWNSHIP);
__blIsNotRelease = FALSE;
//* 調(diào)整描述符索引與讀取指針
__uwCurRxBIdx++;
if(__uwCurRxBIdx >= NB_RX_BUFS)
__uwCurRxBIdx = 0;
__pbFrom = (BYTE*)(__staRxBDescriptors[__uwCurRxBIdx].ulRxBAddrAndFlag & EMAC_RxB_ADDR_MASK);
}
else
{
memcpy(pbTo + __uwTotalLenToRead, __pbFrom, __uwRemainLenToRead);
__uwTotalLenToRead += __uwRemainLenToRead;
__uwTotalLenInRxBToRead += __uwRemainLenToRead;
__pbFrom = __pbFrom + __uwTotalLenInRxBToRead;
__blIsNotRelease = TRUE;
}
}
if(blIsLastPbuf)
{
//* 將接收緩沖區(qū)歸還給EMAC,如果存在恰好是PBUF_POOL_BUFSIZE的整數(shù)倍的數(shù)據(jù)包,則沒有必要再一次釋放,因?yàn)樗呀?jīng)在
//* 上面被釋放
if(__blIsNotRelease)
{
__staRxBDescriptors[__uwCurRxBIdx].ulRxBAddrAndFlag &= (~RxDESC_FLAG_OWNSHIP);
__uwCurRxBIdx++;
if(__uwCurRxBIdx >= NB_RX_BUFS)
__uwCurRxBIdx = 0;
}
__uwTotalLenInRxBToRead = 0;
}
}
//*------------------------------------------------------------------------------------------------
//* 函數(shù)名稱 : EMACInit
//* 功能描述 : 初始化EMAC:對(duì)PHY、MII口線、EMAC操作模式進(jìn)行配置,設(shè)置接收和發(fā)送緩沖區(qū)描述符。設(shè)置
//* : EMAC接收和發(fā)送中斷
//* 入口參數(shù) : 無
//* 出口參數(shù) : 無
//*------------------------------------------------------------------------------------------------
void EMACInit(void)
{
extern HANDLER hEthernetInput;
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr = 0;
#endif
//* 復(fù)位PHY芯片,使其進(jìn)入U(xiǎn)TP模式
__ResetPHY();
//* 等待一段指定的時(shí)間,使PHY就緒
OSTimeDlyHMSM(0, 0, 3, 0);
//* 設(shè)置PIOB引腳為外設(shè)A引腳(即EMAC引腳),禁止PIOB控制,改為外設(shè)控制
AT91C_BASE_PIOB->PIO_ASR = EMAC_MII_PINS;
AT91C_BASE_PIOB->PIO_PDR = EMAC_MII_PINS;
//* 因?yàn)闆]有使用ETXER,所以這里將其配置為由PIO控制
AT91C_BASE_PIOB->PIO_PER = AT91C_PB12_ETXER;
AT91C_BASE_PIOB->PIO_ODR = AT91C_PB12_ETXER;
//* 設(shè)置MDC時(shí)鐘分頻數(shù)
AT91C_BASE_EMAC->EMAC_NCFGR |= AT91C_EMAC_CLK_HCLK_32;
//* 檢查PHY ID是否為0x82010000,如果不是則表明PHY還沒有就緒或者出現(xiàn)故障,函數(shù)將一直查詢直至正確
__CheckPHYID();
//* 從PHY獲取自動(dòng)協(xié)商的結(jié)果,設(shè)置EMAC自身的鏈路速度和單雙工方式。注意,該函數(shù)會(huì)阻塞所在任務(wù)的正常執(zhí)行
//* 直至設(shè)置成功
__SetupLinkSpeedAndDuplex();
//* 建立接收任務(wù)使用的信號(hào)量,對(duì)uCOS的配置保證信號(hào)量在軟件邏輯上能夠百分百建立成功
hEthernetInput = OSAPISemNew(0);
//* 初始化接收和發(fā)送緩沖區(qū)描述符,使每個(gè)描述符指向正確的緩沖區(qū)地址
__InitDescriptorsForRxBAndTxB();
//* 設(shè)置EMAC為MII模式,使能EMAC時(shí)鐘
AT91C_BASE_EMAC->EMAC_USRIO = AT91C_EMAC_CLKEN;
//* 清除接收狀態(tài)寄存器
AT91C_BASE_EMAC->EMAC_RSR = AT91C_EMAC_OVR | AT91C_EMAC_REC | AT91C_EMAC_BNA;
//* 復(fù)制所有有效幀到接收緩沖區(qū),不接收廣播幀,不復(fù)制FCS字段
AT91C_BASE_EMAC->EMAC_NCFGR |= AT91C_EMAC_CAF | AT91C_EMAC_NBC | AT91C_EMAC_DRFCS;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -