⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lib_emac.c

📁 基于AT91SAM7x256的硬件平台的WEB服务器源码(A&shy DS版本, ucOS_II+LWIP+自己编写的DNS查询工具)
💻 C
📖 第 1 页 / 共 2 页
字号:
	
	//* 清除接收状态寄存器
	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 + -