📄 lib_emac.c
字号:
//* 清除接收状态寄存器
AT91C_BASE_EMAC->EMAC_RSR = AT91C_EMAC_OVR | AT91C_EMAC_REC | AT91C_EMAC_BNA;
//* 复制所有有效帧到接收缓冲区,不接收广播帧,不复制FCS字段
AT91C_BASE_EMAC->EMAC_NCFGR |= AT91C_EMAC_CAF | AT91C_EMAC_NBC | AT91C_EMAC_DRFCS;
//* 设置EMAC地址
AT91C_BASE_EMAC->EMAC_SA1L = MAC_ADDR_0 | ((ULONG)(MAC_ADDR_1 << 8)) | ((ULONG)(MAC_ADDR_2 << 16)) | ((ULONG)(MAC_ADDR_3 << 24));
AT91C_BASE_EMAC->EMAC_SA1H = MAC_ADDR_4 | ((ULONG)(MAC_ADDR_5 << 8));
//* 设置EMAC中断
OS_ENTER_CRITICAL()
{
//* 发送和接收结束中断使能
AT91C_BASE_EMAC->EMAC_IER = AT91C_EMAC_RCOMP | AT91C_EMAC_TCOMP;
/* Enable the interrupts in the AIC. */
AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_EMAC, EMAC_INT_PRIOR, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, irqEMACISR);
AT91C_BASE_AIC->AIC_IECR = 0x1 << AT91C_ID_EMAC;
}
OS_EXIT_CRITICAL()
//* 最后,接收、发送使能并允许统计寄存器(用于测试)
AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_TE | AT91C_EMAC_RE | AT91C_EMAC_WESTAT;
}
//*------------------------------------------------------------------------------------------------
//* 函数名称 : __HandlePHY
//* 功能描述 : 对PHY进行读写操作
//* 入口参数 : <ubRegAddr>[in] 指定对PHY的哪个寄存器进行读写
//* : <puwData>[in][out] 指向操作数据的指针。对于读,这个地址保存读取的数据;对于写则是要写入
//* : 寄存器的数据
//* : <blIsRead>[in] 是否是读操作,如果不是则是写操作
//* 出口参数 : 无
//*------------------------------------------------------------------------------------------------
static void __HandlePHY(UBYTE ubRegAddr, UWORD *puwData, BOOLEAN blIsRead)
{
ULONG __ulHandleVal;
if(blIsRead)
{
__ulHandleVal = (0x01 << 30)
| (0x02 << 28)
| (PHY_ADDR << 23)
| (ubRegAddr << 18)
| (0x02 << 16);
}
else
{
__ulHandleVal = (0x01 << 30)
| (0x01 << 28)
| (PHY_ADDR << 23)
| (ubRegAddr << 18)
| (0x02 << 16)
| (*puwData & 0xFFFF);
}
AT91C_BASE_EMAC->EMAC_MAN = __ulHandleVal;
while(!(AT91C_BASE_EMAC->EMAC_NSR & AT91C_EMAC_IDLE));
if(blIsRead)
*puwData = AT91C_BASE_EMAC->EMAC_MAN & 0x0000FFFF;
}
//*------------------------------------------------------------------------------------------------
//* 函数名称 : __ResetPHY
//* 功能描述 : 设置PHY芯片为UTP模式并复位PHY芯片
//* 入口参数 : 无
//* 出口参数 : 无
//*------------------------------------------------------------------------------------------------
static void __ResetPHY(void)
{
#if __DEBUG__ == 0
//* PHY在上电或复位期间需要根据RXER/FXEN引脚(24脚)的锁存输入状态来选择是UTP模式还是光纤模式。每个PIO
//* 口线都被内置了一个上拉电阻,所以整机上电后该引脚的逻辑电平为高,这样就会使得PHY进入了光纤模式。我们
//* 需要UTP模式,也就是PHY上电或复位期间的锁存输入状态为低,所以在这里必须禁止该口线的内部上拉电阻,然后
//* 再复位PHY芯片,使其进入UTP模式
AT91C_BASE_PIOB->PIO_PPUDR = AT91C_PB7_ERXER;
//* 复位PHY芯片,RTL8201BL的数据手册要求必须维持至少10ms的低电平,这里设置为2的(8 + 1)次方个SCK周期,
//* 时间为15.621ms
AT91C_BASE_RSTC->RSTC_RMR = 0xA5000000 | (0x08 << 8);
AT91C_BASE_RSTC->RSTC_RCR = 0xA5000000 | AT91C_RSTC_EXTRST;
//* 等待NRST引脚恢复为高电平
while(!(AT91C_BASE_RSTC->RSTC_RSR & AT91C_RSTC_NRSTL));
#endif
}
//*------------------------------------------------------------------------------------------------
//* 函数名称 : __CheckPHYID
//* 功能描述 : 检查PHY ID是否为0x82010000,如果不是则表明PHY还没有就绪或者出现故障,函数将一直查询直至正确
//* 入口参数 : 无
//* 出口参数 : 无
//*------------------------------------------------------------------------------------------------
static void __CheckPHYID(void)
{
ULONG __ulPHYID;
UBYTE __ubDelaySeconds = 0;
EnableMDI()
{
while(TRUE)
{
__HandlePHY(PHY_REG_ID1, (UWORD*)&__ulPHYID, TRUE);
__HandlePHY(PHY_REG_ID2, ((UWORD*)&__ulPHYID)+1, TRUE);
if(__ulPHYID == PHY_ID_RTL8201)
break;
else
{
__ResetPHY();
if(__ubDelaySeconds < 15)
__ubDelaySeconds++;
OSTimeDlyHMSM(0, 0, __ubDelaySeconds, 0);
}
}
}
DisableMDI()
}
//*------------------------------------------------------------------------------------------------
//* 函数名称 : __ilWaitLinkEstablished
//* 功能描述 : 等待PHY建立链路
//* 入口参数 : 无
//* 出口参数 : 无
//*------------------------------------------------------------------------------------------------
__inline void __ilWaitLinkEstablished(void)
{
UWORD __uwHandleData;
UBYTE __ubDelaySeconds = 0;
while(TRUE)
{
__HandlePHY(PHY_REG_BMSR, &__uwHandleData, TRUE);
if(__uwHandleData & PHY_BMSR_LINKESTABLISHED)
break;
else
{
__ResetPHY();
if(__ubDelaySeconds < 15)
__ubDelaySeconds++;
OSTimeDlyHMSM(0, 0, __ubDelaySeconds, 0);
}
}
}
//*------------------------------------------------------------------------------------------------
//* 函数名称 : __ilWaitAutoNegEnd
//* 功能描述 : 等待PHY自动协商结束
//* 入口参数 : 无
//* 出口参数 : 无
//*------------------------------------------------------------------------------------------------
__inline void __ilWaitAutoNegEnd(void)
{
UWORD __uwHandleData;
UBYTE __ubDelaySeconds = 0;
do{
if(__uwHandleData & PHY_BMSR_AUTONEGEND)
break;
else
{
__HandlePHY(PHY_REG_BMSR, &__uwHandleData, TRUE);
OSTimeDlyHMSM(0, 0, 1, 0);
}
}while(TRUE);
}
//*------------------------------------------------------------------------------------------------
//* 函数名称 : __SetupLinkSpeedAndDuplex
//* 功能描述 : 从PHY获取自动协商的结果,设置EMAC自身的链路速度和单双工方式。注意,该函数会阻塞所在任务的正
//* : 常执行直至设置成功
//* 入口参数 : 无
//* 出口参数 : 无
//*------------------------------------------------------------------------------------------------
static void __SetupLinkSpeedAndDuplex(void)
{
UWORD __uwHandleData;
ULONG __ulSpdAndFD = 0x00000000;
EnableMDI()
{
__ilWaitLinkEstablished();
__ilWaitAutoNegEnd();
//* 获得协商的结果
__HandlePHY(PHY_REG_ANLPAR, &__uwHandleData, TRUE);
//* 决定线速
if((__uwHandleData & PHY_ANLPAR_100TX) || (__uwHandleData & PHY_ANLPAR_100TXFD))
__ulSpdAndFD = AT91C_EMAC_SPD;
//* 决定单双工方式
if((__uwHandleData & PHY_ANLPAR_100TXFD) || (__uwHandleData & PHY_ANLPAR_10TFD))
__ulSpdAndFD |= AT91C_EMAC_FD;
//* 将链路速度和单双工方式设置进EMAC的网络配置寄存器
AT91C_BASE_EMAC->EMAC_NCFGR = (AT91C_BASE_EMAC->EMAC_NCFGR & EMAC_NCFGR_SPD_FD_MASK) | __ulSpdAndFD;
}
DisableMDI()
}
//*------------------------------------------------------------------------------------------------
//* 函数名称 : __InitDescriptorsForRxBAndTxB
//* 功能描述 : 初始化接收和发送缓冲区描述符,使每个描述符指向正确的缓冲区地址,然后将描述符首地址写入队列指
//* : 针指针寄存器
//* 入口参数 : 无
//* 出口参数 : 无
//*------------------------------------------------------------------------------------------------
static void __InitDescriptorsForRxBAndTxB(void)
{
LONG i;
//* 将接收缓冲区地址填充到缓冲区描述符
for(i=0; i<NB_RX_BUFS; i++)
__staRxBDescriptors[i].ulRxBAddrAndFlag = (int)baRxBufs[i];
//* 置位最后一个缓冲区描述符的Wrap位
__staRxBDescriptors[NB_RX_BUFS - 1].ulRxBAddrAndFlag |= RxDESC_FLAG_WARP;
//* 将发送缓冲区地址填充到缓冲区描述符
for(i=0; i<NB_TX_BUFS; i++)
{
__staTxBDescriptors[i].ulTxBAddr = (int)baTxBufs[i];
//* 标记这个缓冲区为程序所有,根据数据手册,该位为0表示这个缓冲区为EMAC所有
__staTxBDescriptors[i].uStatus.bstStatus.bitIsUsed = 1;
}
//* 置位发送缓冲区的结束位(Wrap)
__staTxBDescriptors[NB_TX_BUFS - 1].uStatus.bstStatus.bitIsWrap = 1;
//* 将描述符队列首地址写入接收和发送队列指针寄存器
AT91C_BASE_EMAC->EMAC_RBQP = (int)__staRxBDescriptors;
AT91C_BASE_EMAC->EMAC_TBQP = (int)__staTxBDescriptors;
}
//*------------------------------------------------------------------------------------------------
//* 函数名称 : __ilResetTxBDescriptors
//* 功能描述 : 复位发送缓冲区描述符的Used位,使其能够继续被使用
//* 入口参数 : 无
//* 出口参数 : 无
//*------------------------------------------------------------------------------------------------
__inline void __ilResetTxBDescriptors(void)
{
static LONG __lIdxToReset = 0;
//* 根据EMAC数据手册,EMAC在发送完毕后会置位帧的第一个缓冲区描述符的Used位,所以在这里只需置位其它描
//* 述符即可
if(__staTxBDescriptors[__lIdxToReset].uStatus.bstStatus.bitIsUsed)
{
while(!__staTxBDescriptors[__lIdxToReset].uStatus.bstStatus.bitIsLastBuf)
{
__lIdxToReset++;
if(__lIdxToReset >= NB_TX_BUFS)
__lIdxToReset = 0;
__staTxBDescriptors[__lIdxToReset].uStatus.bstStatus.bitIsUsed = 1;
}
__lIdxToReset++;
if(__lIdxToReset >= NB_TX_BUFS)
__lIdxToReset = 0;
}
else;
}
//*------------------------------------------------------------------------------------------------
//* 函数名称 : GetInputPacketLen
//* 功能描述 : 获取到达的信息包的长度
//* 入口参数 : 无
//* 出口参数 : 无
//*------------------------------------------------------------------------------------------------
UWORD GetInputPacketLen(void)
{
UWORD __uwIdx, __uwLen = 0;
//* 跳过碎片帧,判断依据是帧头位未被置位
while((__staRxBDescriptors[__uwCurRxBIdx].ulRxBAddrAndFlag & RxDESC_FLAG_OWNSHIP)
&& !__staRxBDescriptors[__uwCurRxBIdx].uStatus.bstStatus.bitStartOfFrm)
{
//* 释放这个缓冲区
__staRxBDescriptors[__uwCurRxBIdx].ulRxBAddrAndFlag &= (~RxDESC_FLAG_OWNSHIP);
__uwCurRxBIdx++;
if(__uwCurRxBIdx >= NB_RX_BUFS )
{
__uwCurRxBIdx = 0;
}
}
__uwIdx = __uwCurRxBIdx;
//* 只有最后一个缓冲区才保存帧的长度,其它均为0
while((__staRxBDescriptors[__uwIdx].ulRxBAddrAndFlag & RxDESC_FLAG_OWNSHIP))
{
__uwLen = __staRxBDescriptors[__uwIdx].uStatus.bstStatus.bitLen;
if(__uwLen > 0)
break;
__uwIdx++;
if(__uwIdx >= NB_RX_BUFS)
__uwIdx = 0;
}
//* 保存信息包读取位置
__pbFrom = (BYTE*)(__staRxBDescriptors[__uwCurRxBIdx].ulRxBAddrAndFlag & EMAC_RxB_ADDR_MASK);
return __uwLen;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -