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

📄 lib_emac.c

📁 《嵌入式网络系统设计-基于Atmel ARM7 系列》这个本书的光盘资料
💻 C
📖 第 1 页 / 共 2 页
字号:
	if((__u32IntStatus & AT91C_EMAC_RCOMP) || (__u32ReceiveStatus & AT91C_EMAC_REC))
	{
		//* 向EMAC接收线程发送信号
		OSSemPost(hEthernetInput);
			
		//* 清除REC(Frame Received)位
		AT91C_BASE_EMAC->EMAC_RSR = AT91C_EMAC_REC;
	}

	if(__u32IntStatus & AT91C_EMAC_TCOMP)
	{
		//* 复位发送缓冲区描述符的Used位使其为程序所有
		__ilResetTxBDescriptors();
		AT91C_BASE_EMAC->EMAC_TSR = AT91C_EMAC_COMP;
	}
}
//*------------------------------------------------------------------------------------------------
//* 函数名称 : EMACInit
//* 功能描述 : 初始化EMAC:对PHY、MII口线、EMAC操作模式进行配置,设置接收和发送缓冲区描述符。设置
//*			 : EMAC接收和发送中断
//* 入口参数 : 无
//* 出口参数 : 无
//*------------------------------------------------------------------------------------------------
void EMACInit(void)
{
	extern HANDLER hEthernetInput;
	
#if OS_CRITICAL_METHOD == 3                     
    OS_CPU_SR  		cpu_sr = 0;
#endif	

	//* 复位PHY芯片,使其进入UTP模式
	__ResetPHY();
	
	//* 等待一段指定的时间,使PHY就绪
	OSTimeDlyHMSM(0, 0, 3, 0);

	//* 设置PIOB引脚为外设A引脚(即EMAC引脚),禁止PIOB控制,改为外设控制
	AT91C_BASE_PIOB->PIO_ASR = EMAC_MII_PINS;
	AT91C_BASE_PIOB->PIO_PDR = EMAC_MII_PINS;
	
	//* 因为没有使用ETXER,所以这里将其配置为由PIO控制
	AT91C_BASE_PIOB->PIO_PER = AT91C_PB12_ETXER;
	AT91C_BASE_PIOB->PIO_ODR = AT91C_PB12_ETXER;
	
	//* 设置MDC时钟分频数
	AT91C_BASE_EMAC->EMAC_NCFGR |= AT91C_EMAC_CLK_HCLK_32;
	
	//* 检查PHY ID是否为0x82010000,如果不是则表明PHY还没有就绪或者出现故障,函数将一直查询直至正确
	__CheckPHYID();
	
	//* 从PHY获取自动协商的结果,设置EMAC自身的链路速度和单双工方式。注意,该函数会阻塞所在任务的正常执行
	//* 直至设置成功
	__SetupLinkSpeedAndDuplex();
	
	//* 建立接收任务使用的信号量,对uCOS的配置保证信号量在软件逻辑上能够百分百建立成功
	hEthernetInput = OSSemCreate(0);
	
	//* 初始化接收和发送缓冲区描述符,使每个描述符指向正确的缓冲区地址
	__InitDescriptorsForRxBAndTxB();
	
	//* 设置EMAC为MII模式,使能EMAC时钟
	AT91C_BASE_EMAC->EMAC_USRIO = AT91C_EMAC_CLKEN;
	
	//* 清除接收状态寄存器
	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 = 0xBC | ((INT32U)(0x20 << 8)) | ((INT32U)(0x06 << 16)) | ((INT32U)(0x09 << 24));
	AT91C_BASE_EMAC->EMAC_SA1H = 0x30 | ((INT32U)(0x11 << 8));
	
	//* 设置EMAC中断
	OS_ENTER_CRITICAL()
	{
		//* 发送和接收结束中断使能
		AT91C_BASE_EMAC->EMAC_IER = AT91C_EMAC_RCOMP | AT91C_EMAC_TCOMP;
		
		AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_EMAC, AT91C_AIC_PRIOR_HIGHEST, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, irqEMACISR);
	    AT91C_BASE_AIC->AIC_IECR = 0x01 << AT91C_ID_EMAC;
	}
	OS_EXIT_CRITICAL()
	
	//* 最后,接收、发送使能
	AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_TE | AT91C_EMAC_RE;
}
//*------------------------------------------------------------------------------------------------
//* 函数名称 : GetInputPacketLen
//* 功能描述 : 获取到达的信息包的长度
//* 入口参数 : 无
//* 出口参数 : 无
//*------------------------------------------------------------------------------------------------
INT16U GetInputPacketLen(void)
{
	INT16U		__u16Idx, __u16Len = 0;
	
	//* 跳过碎片帧,判断依据是帧头位未被置位
	while((__staRxBDescriptors[__u16CurRxBIdx].u32RxBAddrAndFlag & RxDESC_FLAG_OWNSHIP) 
			&& !__staRxBDescriptors[__u16CurRxBIdx].uStatus.bstStatus.bitStartOfFrm)
	{
		//* 释放这个缓冲区
		__staRxBDescriptors[__u16CurRxBIdx].u32RxBAddrAndFlag &= (~RxDESC_FLAG_OWNSHIP);		
		__u16CurRxBIdx++;
		if(__u16CurRxBIdx >= NB_RX_BUFS)
		{
			__u16CurRxBIdx = 0;
		}
	}
	
	__u16Idx = __u16CurRxBIdx;
	
	//* 只有最后一个缓冲区才保存帧的长度,其它均为0
	while((__staRxBDescriptors[__u16Idx].u32RxBAddrAndFlag & RxDESC_FLAG_OWNSHIP))
	{
		__u16Len = __staRxBDescriptors[__u16Idx].uStatus.bstStatus.bitLen;
		if(__u16Len > 0)
			break;
			
		__u16Idx++;
		if(__u16Idx >= NB_RX_BUFS)
			__u16Idx = 0;
	}
	
	//* 保存信息包读取位置
	__pbFrom = (INT8S*)(__staRxBDescriptors[__u16CurRxBIdx].u32RxBAddrAndFlag & EMAC_RxB_ADDR_MASK);
	
	return __u16Len;
}
//*------------------------------------------------------------------------------------------------
//* 函数名称 : EMACReadPacket
//* 功能描述 : 从EMAC读取信息包到申请的pbuf链,该函数要求PBUF_POOL_BUFSIZE大于或等于接收缓冲区,最好是整
//*			 : 数倍,这样函数处理最简单。注意,在调用该函数之前必须先调用GetInputPacketLen()函数,这样才
//*			 : 能获取正确的读取位置
//* 入口参数 :          <pbTo>[in] 指向pbuf的指针
//*			 : <u16SegmentLen>[in] pbuf中需要存储的实际数据长度,因为在申请pbuf时,pbuf_alloc()已经根据
//*			 :                     实际的帧长将其分割进了多个pbuf组成的pbuf链中,而pstPbuf->len则保存了
//*			 :                     每个pbuf需要存储的数据。换句话说pbuf链中的最后一个pbuf的len字段长度应
//*			 :                     该小于或等于PBUF_POOL_BUFSIZE,而前面的pbuf则等于PBUF_POOL_BUFSIZE
//*			 :  <blIsLastPbuf>[in] 是否是最后一个Pbuf
//* 出口参数 : 无
//*------------------------------------------------------------------------------------------------
void EMACReadPacket(INT8S *pbTo, INT16U u16SegmentLen, BOOLEAN blIsLastPbuf)
{		
	INT16U			__u16TotalLenToRead = 0, 					//* 已经读取到pbuf的总字节数
					__u16RemainLenToRead,						//* 还剩多少字节没有读取到pbuf中
					__u16RemainLenInRxBToRead;					//* EMAC接收缓冲区中还剩下多少字节没有读取					
	BOOLEAN			__blIsNotRelease;							//* 是否已经主动释放给EMAC
	
	
	/* 注意,必须保证PBUF_POOL_BUFSIZE大于或等于接收缓冲区 */
	
	while(__u16TotalLenToRead < u16SegmentLen)
	{
		__u16RemainLenInRxBToRead = ETH_RX_BUF_SIZE - __u16TotalLenInRxBToRead;
		__u16RemainLenToRead = u16SegmentLen - __u16TotalLenToRead;
		if(__u16RemainLenToRead >= __u16RemainLenInRxBToRead)
		{
			memcpy(pbTo + __u16TotalLenToRead, __pbFrom, __u16RemainLenInRxBToRead);
			__u16TotalLenToRead += __u16RemainLenInRxBToRead;
			__u16TotalLenInRxBToRead = 0;
			
			//* 将接收缓冲区归还给EMAC
			__staRxBDescriptors[__u16CurRxBIdx].u32RxBAddrAndFlag &= (~RxDESC_FLAG_OWNSHIP);
			__blIsNotRelease = OS_FALSE;
			
			//* 调整描述符索引与读取指针
			__u16CurRxBIdx++;
			if(__u16CurRxBIdx >= NB_RX_BUFS)
				__u16CurRxBIdx = 0;
				
			__pbFrom = (INT8S*)(__staRxBDescriptors[__u16CurRxBIdx].u32RxBAddrAndFlag & EMAC_RxB_ADDR_MASK);
		}
		else
		{
			memcpy(pbTo + __u16TotalLenToRead, __pbFrom, __u16RemainLenToRead);
			__u16TotalLenToRead += __u16RemainLenToRead;
			__u16TotalLenInRxBToRead += __u16RemainLenToRead;
			
			__pbFrom = __pbFrom + __u16TotalLenInRxBToRead;						
			__blIsNotRelease = OS_TRUE;
		}					
	}
	
	if(blIsLastPbuf)
	{
		//* 将接收缓冲区归还给EMAC,如果存在恰好是PBUF_POOL_BUFSIZE的整数倍的数据包,则没有必要再一次释放,因为它已经在
		//* 上面被释放
		if(__blIsNotRelease)
		{
			__staRxBDescriptors[__u16CurRxBIdx].u32RxBAddrAndFlag &= (~RxDESC_FLAG_OWNSHIP);
			__u16CurRxBIdx++;
			if(__u16CurRxBIdx >= NB_RX_BUFS)
				__u16CurRxBIdx = 0;
		}
			
		__u16TotalLenInRxBToRead = 0;
	}		
}
//*------------------------------------------------------------------------------------------------
//* 函数名称 : EMACSendPacket
//* 功能描述 : 由low_level_output()函数调用,完成实际的数据发送。
//* 入口参数 :         <pbFrom>[in] 指向pbuf中数据的指针
//*			 :      <u32Length>[in] pbuf中的数据长度
//*			 : <blIsEndOfFrame>[in] 是否是pbuf链中的最后一个,也就是帧尾
//* 出口参数 : 如果无法申请下内存则返回ERR_MEM,成功则返回ERR_OK
//*------------------------------------------------------------------------------------------------
BOOLEAN EMACSendPacket(INT8S *pbFrom, INT32U u32Length, BOOLEAN blIsEndOfFrame)
{
	INT32U 			__u32TotalLenToWrite = 0, __u32CurLenToWrite, __u32LenRemainToWrite, __u32IsLastBuf;
	
	INT32S 			i;
	INT8S			*__pbBuf;
	
#if OS_CRITICAL_METHOD == 3                     
    OS_CPU_SR  		cpu_sr = 0;
#endif	

	//* 如果要发送的数据长度大于一个发送缓冲区,则需要将这些数据分割进多个缓冲区进行发送
	while(__u32TotalLenToWrite < u32Length)
	{
		//* 等待缓冲区可用,最长等待3秒钟
		i = 0;
		while(!__staTxBDescriptors[__u16TxBIndex].uStatus.bstStatus.bitIsUsed)
		{
			//* 如果已经到达等待时间仍然没有可用缓冲区,则立即返回
			if(i > 300)
				return OS_FALSE;
			
			OSTimeDly(1);
			i++;
		}
	
		OS_ENTER_CRITICAL()
		{
			//* 从描述符中获得缓冲区地址,然后把数据复制到缓冲区
			__pbBuf = (INT8S*)__staTxBDescriptors[__u16TxBIndex].u32TxBAddr;
			
			//* 计算向缓冲区写入的数据长度
			__u32LenRemainToWrite = u32Length - __u32TotalLenToWrite;
			if(__u32LenRemainToWrite > ETH_TX_BUF_SIZE)
				__u32CurLenToWrite = ETH_TX_BUF_SIZE;
			else
				__u32CurLenToWrite = __u32LenRemainToWrite;
			
			//* 将pbuf中的数据复制到发送缓冲区
			memcpy(__pbBuf, &(pbFrom[__u32TotalLenToWrite]), __u32CurLenToWrite);
			__u32TotalLenToWrite += __u32CurLenToWrite;
			
			//* 看看是否是已经到达pbuf链的末尾,如果是则标记当前使用的缓冲区为最后一个缓冲区
			if(blIsEndOfFrame && (__u32TotalLenToWrite >= u32Length))
			{
				__u32IsLastBuf = TxDESC_STATUS_LAST_BUF;
			}
			else
				__u32IsLastBuf = 0;
	
			//* 填充当前的描述符:缓冲区中的数据实际长度、最后一个缓冲区标记、WRAP位(如果确实是最后一个描述符)
			if(__u16TxBIndex >= (NB_TX_BUFS-1))
			{				
				__staTxBDescriptors[__u16TxBIndex].uStatus.u32Status = (__u32CurLenToWrite & TxDESC_STATUS_BUF_SIZE)
																		| __u32IsLastBuf
																		| TxDESC_STATUS_WRAP;
				__u16TxBIndex = 0;
			}
			else
			{
				__staTxBDescriptors[__u16TxBIndex].uStatus.u32Status = (__u32CurLenToWrite & TxDESC_STATUS_BUF_SIZE)
																		| __u32IsLastBuf;
				__u16TxBIndex++;
			}
	
			//* 如果已经到达pbuf链的末尾则立即发送
			if(__u32IsLastBuf)
				AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_TSTART;
		}
		OS_EXIT_CRITICAL()
	}

	return OS_TRUE;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -