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

📄 ethernet_lpc23xx.c

📁 This program contains program realization EMAC for LPC23xx
💻 C
📖 第 1 页 / 共 2 页
字号:


	// remove reset conditions
	ETH_MAC1	= 0x00;
	ETH_MIICFG  = 0x00;
	ETH_COMMAND = 0x00;


	// Initialize DMA Interface

	prvInitDMAEngine();


   	/* Set reduced MII interface */
#ifdef RMII_INTERFACE

   	ETH_COMMAND = CR_RMII;
	ETH_PHYSUPP = 0;

	/* Reset Reduced MII Logic. */
	ETH_PHYSUPP = SUPP_RES_RMII;
	/* wait until reset done */
	for (Timeout = 200; Timeout; Timeout--)
		;

#else
   	ETH_COMMAND &= ~CR_RMII;
	ETH_PHYSUPP = 0;

	/* reset the MII management */
	ETH_MIICFG = 0x8000;
	/* wait until reset done */
	for (Timeout = 200; Timeout; Timeout--)
		;
#endif


	/* pass frames which are too short, but with valid CRC */
	ETH_COMMAND |= CR_PASS_RUNT_FRM;		


	/* configure PHY	*/
	aPhyStatus = prvConfigurePHY(PHY_DEVICE_NO_1);

	
	/* configure MAC control registers						*/

	ETH_MAC1 = 0x00; // MAC1_PASS_ALL;
	ETH_MAC2 = MAC2_CRC_EN | MAC2_PAD_EN;
	ETH_MAXF = ETH_MAX_FLEN;
	ETH_CLRT = CLRT_RETRANSMAX | CLRT_COLLWINDOW;
	ETH_IPGR = IPGR_DEF;

	/* Configure MAC 2 register depends on PHY extended Status */
	if (aPhyStatus & PHY_EXST_FDX)
	{
		ETH_MAC2    |= MAC2_FDPX_ENA;		/* Full duplex is enabled. */
		ETH_COMMAND |= CR_FULL_DUP;
		ETH_IPGT     = IPGT_FULL_DUP;
	}
	else 
		ETH_IPGT = IPGT_HALF_DUP;			/* Half duplex interpacket gap */


	/* Configure speed */
	if (aPhyStatus & PHY_EXST_SPEED_10M)
		ETH_PHYSUPP = 0;					/* 10MBit mode. */
	else
		ETH_PHYSUPP = SUPP_SPEED_100;		/* 100 MBit supported */
   

	/*
	* configure station address
	*
	* normally the MAC address is not derived from config.h. It should be 
	* read out of a serial EEPROM, Flash configuration or something else  */ 

	aMACAddress[0] = 0xA5;
	aMACAddress[1] = 0x91;
	aMACAddress[2] = 0x89;
	aMACAddress[3] = 0x03;
	aMACAddress[4] = 0x04;
	aMACAddress[5] = 0x09;

	vEthSetStationAddress( aMACAddress);

	
	/* configure receive filters	*/

	prvConfigureRxFilters();


	ETH_INTENABLE = INT_RX_DONE | INT_TX_DONE;	/* Enable RXdone & TXdone interrupts. */
	ETH_INTCLEAR  = 0xFFFF;					/* Reset all interrupts */

	ETH_COMMAND  |= (CR_RX_EN | CR_TX_EN);	/* Enable rx and tx mode of MAC Ethernet core */
	ETH_MAC1     |= MAC1_REC_EN;

	/* enable VIC for Ethernet interrupt. */
	if( INT_PRIORITY > 15 )
	   return( FALSE );
	   
    prvSetupInt(INT_SOURCE_ETH, (uint32_t)vEthIntService, INT_PRIORITY); 
    prvEnableEthInterrupt();   
  
    return(TRUE);
}

/****************************************************************************
* Name:			ulReadFrame
*                  	
* Description:	read a received frame from driver 
*				note: it is in response to the caller that 
*				there is enough memory allocated for the given 
*				frame pointer.  
*				
*						
* Parameters:	pointer to a Buffer which has enough space for 
*				the received frame data. 
*					
* Return value:	length of received data in bytes
*				0x00: --> nothing available
*
****************************************************************************
*/
uint32_t	ulReadFrame(uint8_t* aFrameBuffer)
{
	uint32_t	i;
	uint32_t	recLength = 0x00;
	uint8_t*	pRec = 0x00;
	bool		frameReceived;

	/* no frame buffer, then return with 0x00 */
	if( aFrameBuffer == 0x00 )	
		return( 0x00 );

	/* check readIndex */
	if( readIndex > NUMBER_REC_FRAGMENTS )
	{
		/* reset readIndex */
		readIndex = 0x00;
		for( i=0; i < (NUMBER_REC_FRAGMENTS -1); i++ )
		{
			if( (uxRxFrame[i].Length == 0x00) && (uxRxFrame[i+1].Length != 0x00) )
			{
				/* the valid readIndex found  correction sunccessful */
				readIndex = i+1;
				break;
			}
		}
	}

	/* check if a complete frame has been received */
	frameReceived = FALSE;
	for( i=0; i <NUMBER_REC_FRAGMENTS; i++ )
	{
		if( uxRxFrame[readIndex+i].status & FRAMECOMPLETE)
			frameReceived = TRUE;
	}

	/* copy all fragments of one frame to framebuffer */
	if( frameReceived)
	{
		// disable INTs
		prvDisableEthInterrupt();

		while( !(uxRxFrame[readIndex].status & FRAMECOMPLETE) ) 
		{
		    if( recLength != 0x00 )
		    {  
			 recLength += uxRxFrame[readIndex].Length;
			 pRec = uxRxFrame[readIndex].pReceived;

			 for( i = 0x00; i < recLength; i++ )
				*aFrameBuffer++ = *pRec++;  

			 uxRxFrame[readIndex].Length = 0x00;
			 uxRxFrame[readIndex].pReceived = 0x00;
			 uxRxFrame[readIndex].status = 0x00;
            }
			incRxIndex(readIndex);
		}
		/* now copy the last fragment */
		recLength += uxRxFrame[readIndex].Length;
		pRec = uxRxFrame[readIndex].pReceived;

		for( i = 0x00; i < recLength; i++ )
			*aFrameBuffer++ = *pRec++;  

		uxRxFrame[readIndex].Length = 0x00;
		uxRxFrame[readIndex].pReceived = 0x00;
		uxRxFrame[readIndex].status = 0x00;

		incRxIndex(readIndex);

		prvEnableEthInterrupt();
	}
	return(	recLength );
}

/****************************************************************************
* Name:			vEthSendFrame
*                  	
* Description:	transmit a delivered frame to the DMA engine
*				write a complete frame to transmit descriptor of next 
*				produce Index. After that increment ProduceIndex (take 
*				wrap around into account) 
*						
* Parameters:	- frameLength
*					count of bytes to transmit
*				- aFrameBuffer
*					buffer containing frame data
*					
* Return value:	- TRUE
*					frame delivered to HW (DMA engine)
*				- FALSE
*					cannot send frame, HW busy
* 
****************************************************************************
*/
bool eEthSendFrame(uint32_t frameLength, uint8_t* aFrameBuffer)
{
	uint32_t	i;
	uint8_t*	pTransmitDescrData;

	uint32_t	currentTXConsumeIndex, currentTXProduceIndex, nextTXProduceIndex;


	if( (frameLength == 0x00) || (aFrameBuffer == 0x00) )
		return(FALSE);

	if( frameLength > MAXLENGTH_TX_FRAME)
		return(FALSE);

	/* DMA send frame status  */ 
	currentTXProduceIndex = ETH_TXPRODIX;
	currentTXConsumeIndex = ETH_TXCONSIX;

	/* check if a produce buffer available */
	nextTXProduceIndex = currentTXProduceIndex;
	incTxIndex(nextTXProduceIndex);

	if( nextTXProduceIndex != currentTXConsumeIndex)
	{
		/* transmit buffer to hardware (DMA engine) */
		pTransmitDescrData = (uint8_t*)pxEthernetData->ucTxBuffer[currentTXProduceIndex];

		for( i= 0x00; i < frameLength; i++)
			pTransmitDescrData[i] = aFrameBuffer[i];
		
		pxEthernetData->xTxDescr[currentTXProduceIndex].control = frameLength - 1;
		pxEthernetData->xTxDescr[currentTXProduceIndex].control |= TC_LAST_FLAG | TX_CONTROL_INT;	/* last flag */

		ETH_TXPRODIX = nextTXProduceIndex;
		return(TRUE);
	}
	else
	{
		// no transmit buffers available
		return(FALSE); 
	}
}

/****************************************************************************
* Name:			prvReceiveFragment
*                  	
* Description:	handle an RX Done Int
*
*				copy received fragment information to receive array
*				for API. note: do not copy the data !!!
*				store length, pointer and status
*						
* Parameters:	none
*					
* Return value:	none
****************************************************************************
*/
void prvReceiveFragment(void)
{
	uint32_t	currentRxConsumeIndex, currentRxProduceIndex;
	uint32_t	currentFrameInfo;

	currentRxProduceIndex = ETH_RXPRODIX;
	currentRxConsumeIndex = ETH_RXCONSIX;


	// receive fragment int done

	while( currentRxConsumeIndex != currentRxProduceIndex )
	{
		currentFrameInfo =pxEthernetData->xRxStat[currentRxConsumeIndex].info;

		if(! (currentFrameInfo & RS_INFO_LAST_FLAG) )
		{
			uxRxFrame[writeIndex].status = 0x00;
			// this is a fragment, frame not complete
		}
		else
		{
			if( currentFrameInfo & RS_INFO_ERR)
			{
				/* receive frame error, normally skip frame
				   currently there is a flag named range error
				   which is set if there are frames of specific
				   ethernet types. These frames are correct and should
				   be stored.
				*/    
				uxRxFrame[writeIndex].status = FRAMECOMPLETE | FRAMEERROR; 
			}
			else
			{
				uxRxFrame[writeIndex].status = FRAMECOMPLETE;		// indicates frame complete
			}
		}
		uxRxFrame[writeIndex].Length += ((currentFrameInfo & RS_INFO_SIZE) -1);
		uxRxFrame[writeIndex].pReceived = pxEthernetData->xRxDescr[currentRxConsumeIndex].packet;
		incRxIndex(writeIndex);

		incRxIndex(currentRxConsumeIndex);
	}

	if( currentRxConsumeIndex == 0x00)
		currentRxConsumeIndex = 2;            

	ETH_RXCONSIX = currentRxConsumeIndex;
}
/****************************************************************************
* Name:			eGetLinkStatus
*                  	
* Description:	delivers the actual link status indicated by the external PHY 	
*				
*						
* Parameters:	none
*					
* Return value:	LINK_OFF
*				LINK_ON
*				NOLINKSTATE
*
****************************************************************************
*/

linkstatus eGetLinkStatus(uint32_t	aPHYDevice)
{
	uint32_t	phyAddress = aPHYDevice << 8;
	uint32_t 	phyId = 0x00;
	uint16_t	extendedStatus;


	// first of all check for the ethernet phy device
	
	phyId = prvReadPhyRegister( phyAddress | PHY_IDR1 );
	phyId <<= 16;
	phyId |= prvReadPhyRegister( phyAddress | PHY_IDR2 );

	// actually supports only DP83848C Phyter 
	switch( phyId)
	{
	case DP83848C_ID:

		/* Check the link status. */
		extendedStatus = prvReadPhyRegister (phyAddress | PHY_STS);

		if (extendedStatus & PHY_EXST_LINK_ESTABLISHED)			// link status 
			return(LINK_ON) ;
		else
			return(LINK_OFF);
 	
	default :
		break;
	}
	return( NOLINKSTATE);
}
/****************************************************************************
* Name:			vEthernetIntHandler
*                  	
* Description:	interrupt of Ethernet moduel occured
*				this could be one of the following ints
*				- receive fragment done
*				- transmit fragment done
*						
* Parameters:	none
*					
* Return value:	none
****************************************************************************
*/
void vEthIntHandler(void)
{
	uint32_t	aInterruptStatus; 
	uint32_t	currentRxProduceIndex;

	/* read interrupt status to get Int source */
	aInterruptStatus = ETH_INSTSTAT;


	/* receive status interrupts	*/
	if( aInterruptStatus & INT_RX_DONE )
	{
		/* receive fragment int done	*/
		ETH_INTCLEAR = INT_RX_DONE;
		prvReceiveFragment();
	}
	if( aInterruptStatus & INT_RX_OVERRUN)
	{
		/* receive overrun error */
		ETH_INTCLEAR = INT_RX_OVERRUN;
		ulRxOverrunErrorCounter++;
	}
	if( aInterruptStatus & INT_RX_ERR)
	{
		/* other receive errors, detailed in receive status */
		ETH_INTCLEAR = INT_RX_ERR;
		ulRxError++;
	}
	if( aInterruptStatus & INT_RX_FIN)
	{
		/* if we got such an Int it indicates   *
		* that the system is designed too slow  *
		* serving the Ethernet ints.			*
		* now frames might be lost				*/
		if( ! (aInterruptStatus & INT_RX_DONE ))
		{
			/* this case normally should not occur				*/
			/* if it does anyway, skip already received frames */
			ETH_INTCLEAR = INT_RX_FIN;
			currentRxProduceIndex = ETH_RXPRODIX;
			ETH_RXCONSIX = currentRxProduceIndex;
		}
	}
	/* transmit status interrupts	*/

	if( aInterruptStatus & INT_TX_DONE)
	{
		/* transmit fragment done	*/
		ETH_INTCLEAR = INT_TX_DONE;
	}
	if( aInterruptStatus & INT_TX_UNDERRUN)
	{
		/* transmit underrun error */
		ETH_INTCLEAR = INT_TX_UNDERRUN;
		ulTxUnderrunErrorCounter++;
	}
	if( aInterruptStatus & INT_TX_ERR)
	{
		/* transmit error			*/
		ETH_INTCLEAR = INT_TX_ERR;
		ulTxError++;
	}
	if( aInterruptStatus & INT_TX_FIN)
	{
		/* do nothing */
		ETH_INTCLEAR = INT_TX_FIN;
	}

	/* acknowledge interrupt in VIC */
	prvIntAck();                    		// Acknowledge Interrupt
}
/****************************************************************************
* Name:			vEthIntService
*                  	
* Description:	interrupt service routine called directly
*				from vectored interrupt controller
*
*               this inline assembler saves registers, then calls 
*               the C-function Ethernet handler, restores
*               registers and exits IRQ.
*    
* Parameters:	none
*					
* Return value:	none
****************************************************************************
*/
void vEthIntService(void)
{}/*											
	asm volatile(	
	"SUB	lr,lr, #4				\n\t"		
    "STMFD  sp!,{r0-r12,lr}			\n\t"		
    "MRS    r1,spsr					\n\t"		
    "STMFD  sp!,{r1}				\n\t"	   
 	"BL 		vEthIntHandler		\n\t"		
    "LDMFD   sp!,{r1}				\n\t"	
    "MSR     spsr_cxsf,r1			\n\t"	
    "LDMFD   sp!,{r0-r12,pc}^		\n\t"	
	);										
}  */
/****************************************************************************
* Name:			prvSetupInt
*                  	
* Description:	inserts the interrupt service routine into the vector

⌨️ 快捷键说明

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