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

📄 emac.c

📁 基于atmel公司的at91rm9200的以太网驱动
💻 C
字号:
//*----------------------------------------------------------------------------
//*         ATMEL Microcontroller Software Support  -  ROUSSET  -
//*----------------------------------------------------------------------------
//* The software is delivered "AS IS" without warranty or condition of any
//* kind, either express, implied or statutory. This includes without
//* limitation any warranty or condition with respect to merchantability or
//* fitness for any particular purpose, or against the infringements of
//* intellectual property rights of others.
//*----------------------------------------------------------------------------
//* File Name           : main.c
//* Object              : main application written in C
//* Creation            : Hi   11/18/2002
//*
//*----------------------------------------------------------------------------
#include "AT91RM9200.h"
#include "lib_AT91RM9200.h"
#include "Emac.h"
#include <string.h>

extern unsigned int AT91F_GetTickCount(void);

// Our Ethernet MAC address and IP address
char OurEmacAddr[6] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
unsigned char OurIpAddr[4]  = {192, 168, 0, 11}; // {0x0A, 0xD7, 0xF5, 0xAC}

//Buffer descriptor address must be word aligned
#define AT91C_EMAC_TDLIST_BASE	0x20010000

char RxPacket[NB_ETH_RX_PACKETS*ETH_PACKET_SIZE];
AT91PS_TdDescriptor tdList = (AT91PS_TdDescriptor)AT91C_EMAC_TDLIST_BASE;



// ****************************************************************************************************
// ** EMAC lowlevel functions 
// ****************************************************************************************************
//*----------------------------------------------------------------------------
//* \fn    AT91F_MII_ReadPhy
//* \brief This function return the MII phy register
//*----------------------------------------------------------------------------
unsigned short AT91F_MII_ReadPhy(
	AT91PS_EMAC pEmac,     // \arg Pointer to AT91PS_EMAC service
	unsigned char addr) 
{
	unsigned int Wait = AT91F_GetTickCount() + 10;
	unsigned int value = 0x60020000 | (addr << 18);

	pEmac->EMAC_MAN = value;
  	while(AT91F_GetTickCount() < Wait);
	return (pEmac->EMAC_MAN & 0x0000ffff);
}



//*----------------------------------------------------------------------------
//* \fn    AT91F_MII_GetLinkSpeed
//* \brief This function configure the link speed
//*----------------------------------------------------------------------------
int MII_GetLinkSpeed(AT91PS_EMAC pEmac)     // \arg Pointer to AT91PS_EMAC service
{
  unsigned short stat1, stat2; 
  
	stat1 = AT91F_MII_ReadPhy(pEmac, MII_STS_REG);
	stat1 = AT91F_MII_ReadPhy(pEmac, MII_STS_REG);

	stat2 = AT91F_MII_ReadPhy(pEmac, MII_STS2_REG);
    
    //set MII for 100BaseTX and Full Duplex
	if ((stat1 & 0x4000) && (stat2 & 0x8000) )
    	pEmac->EMAC_CFG |= (AT91C_EMAC_SPD| AT91C_EMAC_FD);    
    //set MII for 10BaseT and Full Duplex 
	else if ((stat1 & 0x1000) && (stat2 & 0x2000))
    	pEmac->EMAC_CFG = (pEmac->EMAC_CFG & AT91C_EMAC_SPD) | AT91C_EMAC_FD;
    //set MII for 100BaseTX and Half Duplex 
	else if ((stat1 & 0x2000) && (stat2 & 0x4000))
    	pEmac->EMAC_CFG = (pEmac->EMAC_CFG | AT91C_EMAC_SPD ) & ~AT91C_EMAC_FD;
    //set MII for 10BaseT and Half Duplex 
	else if ((stat1 & 0x0800) && (stat2 & 0x1000))
    	pEmac->EMAC_CFG = pEmac->EMAC_CFG & ~AT91C_EMAC_SPD & ~AT91C_EMAC_FD;

	return 0;
}

//*----------------------------------------------------------------------------
//* \fn    AT91F_MDIO_StartupPhy
//* \brief This function start the phy
//*----------------------------------------------------------------------------
int AT91F_MDIO_StartupPhy(AT91PS_EMAC pEmac)     // \arg Pointer to AT91PS_EMAC service
{
	int ret;
	if(pEmac->EMAC_SR & AT91C_EMAC_LINK)
		return 0;

	pEmac->EMAC_CTL |= AT91C_EMAC_MPE;

	ret = MII_GetLinkSpeed(pEmac);

	pEmac->EMAC_CTL &= ~AT91C_EMAC_MPE;
  
	return 0;
}


//*----------------------------------------------------------------------------
//* \fn    AT91F_EMACInit
//* \brief This function initialise the ethernet
//*----------------------------------------------------------------------------
int AT91F_EMACInit( // \return Status ( Success = 0)
		AT91PS_EMAC pEmac,     // \arg Pointer to AT91PS_EMAC service
		unsigned int pTdList)
{
	int status;
	
	AT91F_EMAC_CfgPMC();
	AT91F_EMAC_CfgPIO();

	status = AT91F_MDIO_StartupPhy(pEmac);
	if ( status )
		return status;

	// the sequence write EMAC_SA1L and write EMAC_SA1H must be respected
	pEmac->EMAC_SA1L = ((int)OurEmacAddr[2] << 24) | ((int)OurEmacAddr[3] << 16) | ((int)OurEmacAddr[4] << 8) | OurEmacAddr[5];
	pEmac->EMAC_SA1H = ((int)OurEmacAddr[0] << 8) | OurEmacAddr[1];

	pEmac->EMAC_RBQP = pTdList;
	pEmac->EMAC_RSR  &= ~(AT91C_EMAC_OVR | AT91C_EMAC_REC | AT91C_EMAC_BNA);
	pEmac->EMAC_CFG  |= (AT91C_EMAC_CAF | AT91C_EMAC_NBC | AT91C_EMAC_RMII);
	pEmac->EMAC_CFG  &= ~(AT91C_EMAC_CLK);
	pEmac->EMAC_CTL  |= (AT91C_EMAC_TE | AT91C_EMAC_RE);

 	return 0;
}

//*----------------------------------------------------------------------------
//* \fn    AT91F_EmacEntry
//* \brief Initialise Emac to receive packets
//*----------------------------------------------------------------------------
int AT91F_EmacEntry(void)
{
	unsigned int i;
	char *pRxPacket;
	
	pRxPacket = (char *)RxPacket;

	// Initialise tdList descriptor. This descriptor must be WORD aligned
	for (i = 0; i < NB_ETH_RX_PACKETS; ++i) 
	{
		tdList[i].addr = ((unsigned int) (pRxPacket + (i * ETH_PACKET_SIZE))) & 0xFFFFFFFC;
		tdList[i].size = 0;
	}
	
	// Set the WRAP bit at the end of the list descriptor
	tdList[NB_ETH_RX_PACKETS-1].addr |= 0x02;
	
	return(AT91F_EMACInit(AT91C_BASE_EMAC, (unsigned int) tdList));
}	



//*----------------------------------------------------------------------------
//* \fn    AT91F_IcmpChksum
//* \brief Process ICMP Checksum...
//*----------------------------------------------------------------------------
unsigned short AT91F_IcmpChksum(unsigned short *p, int len) 
{
	int i, t;
	
	for (i=0,t=0; i<len; i++, p++)
		t += SWAP16(*p);
	t = (t & 0xffff) + (t >> 16);
	return (~t);									
}



//*----------------------------------------------------------------------------
//* \fn    AT91F_ProcessEmacPacket
//* \brief Process ARP and ICMP packets...
//*----------------------------------------------------------------------------
int AT91F_ProcessEmacPacket(AT91PS_IPheader pHeader)
{
	unsigned short *pFrameType, *pArpOp;
	unsigned int i, icmp_len;
	char *pData;
	int status = AT91C_NO_IPPACKET;
	
	AT91PS_IPheader pIpHeader;
	AT91PS_IcmpEchoHdr pIcmpEcho;
	int process = 0;
	

	// Receive one packet		
	process = 0;	
	status = 0;
	for (i = 0; i < NB_ETH_RX_PACKETS; ++i) {				
		if(tdList[i].addr & 0x1) {
			if (*AT91C_EMAC_RSR & AT91C_EMAC_REC)
				(*AT91C_EMAC_RSR) |= AT91C_EMAC_REC;
			process = 1;	
			break;				
		}
	}
		
	if (!process)
		return AT91C_NO_IPPACKET;
						
	process = i;
		
	// Process this packet
	pFrameType = (unsigned short *) ((tdList[i].addr & 0xFFFFFFFC) + 12);
	pData      = (char *)(tdList[i].addr & 0xFFFFFFFC);

	switch (SWAP16(*pFrameType)) {
	case PROT_ARP: // ARP Packet format
		pArpOp = (unsigned short *) (pData + 20);

		if (SWAP16(*pArpOp) == ARP_REQUEST) {
		       // ARP REPLY operation
			*pArpOp =  SWAP16(ARP_REPLY);				
			// Fill the dest address and src address
			for (i = 0; i <6; i++) {
				// swap ethernet dest address and ethernet src address
				pData[i] = pData[i+6];
				pData[i+6] = OurEmacAddr[i];
				// swap sender ethernet address and target ethernet address
				pData[i+22] = OurEmacAddr[i];
				pData[i+32] = pData[i+6];
			}									
				// swap sender IP address and target IP address
			for (i = 0; i<4; i++) {				
				pData[i+38] = pData[i+28];
				pData[i+28] = OurIpAddr[i];
			}
				
			if (!(*AT91C_EMAC_TSR & AT91C_EMAC_BNQ))
				return AT91C_NO_IPPACKET;
		  	*AT91C_EMAC_TSR |= AT91C_EMAC_COMP;
			*AT91C_EMAC_TAR = (unsigned int)pData;
 			*AT91C_EMAC_TCR = 0x40;
		}			
	break; // case PROT_ARP
		
	case PROT_IP:	// IP protocol frame
		pIpHeader = (AT91PS_IPheader)(pData + 14);			
		pIcmpEcho = (AT91PS_IcmpEchoHdr)((char *)pIpHeader + 20);
		memcpy(pHeader, pIpHeader,sizeof(AT91S_IPheader));

#if AT91C_DISPLAY_ALL_IPHEADER
		status = AT91C_IPPACKET;
#endif		
		
		switch(pIpHeader->ip_p) {
		case PROT_ICMP:		
			// set the status variable to display in main.c only ICMP packets
			status = AT91C_IPPACKET;
				
			// if ICMP_ECHO_REQUEST ==> resp = ICMP_ECHO_REPLY
			if(pIcmpEcho->type == ICMP_ECHO_REQUEST) {
				pIcmpEcho->type = ICMP_ECHO_REPLY;
				pIcmpEcho->code = 0;
				pIcmpEcho->cksum = 0;

				// Checksum of the ICMP Message				
				icmp_len = (SWAP16(pIpHeader->ip_len) - 20)/(sizeof(unsigned short));
			    pIcmpEcho->cksum = SWAP16(AT91F_IcmpChksum((unsigned short *) pIcmpEcho, icmp_len));
					
				// Swap IP Dest address and IP Source address
				for(i = 0; i <4; i++) {
					pIpHeader->ip_dst[i] = pIpHeader->ip_src[i];
					pIpHeader->ip_src[i] = OurIpAddr[i];
				}

				// Swap Eth Dest address and Eth Source address
				for(i = 0; i <6; i++) {
					pData[i] = pData[i + 6];
					pData[i+6] = OurEmacAddr[i];
				}
					// send the echo_reply
			  	*AT91C_EMAC_TSR |= AT91C_EMAC_COMP;
				*AT91C_EMAC_TAR = (unsigned int)pData;
				*AT91C_EMAC_TCR = SWAP16(pIpHeader->ip_len)+ 14;
			}
		break; // case PROT_ICMP

		default:
			break;
		}
	break; // case PROT_IP
						
	default:
		break;
	}// switch (SWAP16(*pFrameType))
	// process the packet
	tdList[process].addr &= ~0x01;
	return status;
}

⌨️ 快捷键说明

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