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

📄 fec.c

📁 FreeRTOS is a portable, open source, mini Real Time Kernel - a free to download and royalty free RTO
💻 C
📖 第 1 页 / 共 2 页
字号:
	/* Set the wrap bit in the last descriptors to form a ring. */
	xFECTxDescriptors[ fecNUM_FEC_TX_BUFFERS - 1 ].status |= TX_BD_W;
	xFECRxDescriptors[ configNUM_FEC_RX_BUFFERS - 1 ].status |= RX_BD_W;

	uxNextRxBuffer = 0;
}
/*-----------------------------------------------------------*/

void vFECInit( void )
{
unsigned portSHORT usData;
struct uip_eth_addr xAddr;
unsigned portBASE_TYPE ux;

/* The MAC address is set at the foot of FreeRTOSConfig.h. */
const unsigned portCHAR ucMACAddress[6] =
{
	configMAC_0, configMAC_1,configMAC_2, configMAC_3, configMAC_4, configMAC_5
};

	/* Create the semaphore used by the ISR to wake the uIP task. */
	vSemaphoreCreateBinary( xFECSemaphore );

	/* Create the semaphore used to unblock any tasks that might be waiting
	for a Tx descriptor. */
	vSemaphoreCreateBinary( xTxSemaphore );

	/* Initialise all the buffers and descriptors used by the DMA. */
	prvInitialiseFECBuffers();

	for( usData = 0; usData < 6; usData++ )
	{
		xAddr.addr[ usData ] = ucMACAddress[ usData ];
	}
	uip_setethaddr( xAddr );

	/* Set the Reset bit and clear the Enable bit */
	MCF_FEC_ECR = MCF_FEC_ECR_RESET;

	/* Wait at least 8 clock cycles */
	for( usData = 0; usData < 10; usData++ )
	{
		asm( "NOP" );
	}

	/* Set MII speed to 2.5MHz. */
	MCF_FEC_MSCR = MCF_FEC_MSCR_MII_SPEED( ( ( ( configCPU_CLOCK_HZ / 1000000 ) / 5 ) + 1 ) );

	/* Initialize PLDPAR to enable Ethernet LEDs. */
	MCF_GPIO_PLDPAR =  MCF_GPIO_PLDPAR_ACTLED_ACTLED | MCF_GPIO_PLDPAR_LINKLED_LINKLED | MCF_GPIO_PLDPAR_SPDLED_SPDLED
					 | MCF_GPIO_PLDPAR_DUPLED_DUPLED | MCF_GPIO_PLDPAR_COLLED_COLLED | MCF_GPIO_PLDPAR_RXLED_RXLED
					 | MCF_GPIO_PLDPAR_TXLED_TXLED;

	/* Initialize Port TA to enable Axcel control. */
	MCF_GPIO_PTAPAR = 0x00;
	MCF_GPIO_DDRTA  = 0x0F;
	MCF_GPIO_PORTTA = 0x04;

	/* Set phy address to zero. */
	MCF_EPHY_EPHYCTL1 = MCF_EPHY_EPHYCTL1_PHYADD( 0 );

	/* Enable EPHY module with PHY clocks disabled.  Do not turn on PHY clocks
	until both FEC and EPHY are completely setup (see Below). */
	MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0_DIS100 | MCF_EPHY_EPHYCTL0_DIS10);

	/* Enable auto_neg at start-up */
	MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0 & (MCF_EPHY_EPHYCTL0_ANDIS));

	/* Enable EPHY module. */
	MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0_EPHYEN | MCF_EPHY_EPHYCTL0);

	/* Let PHY PLLs be determined by PHY. */
	MCF_EPHY_EPHYCTL0 = (uint8)(MCF_EPHY_EPHYCTL0  & ~(MCF_EPHY_EPHYCTL0_DIS100 | MCF_EPHY_EPHYCTL0_DIS10));

	/* Settle. */
	vTaskDelay( fecLINK_DELAY );

	/* Can we talk to the PHY? */
	do
	{
		vTaskDelay( fecLINK_DELAY );
		usData = 0;
		fec_mii_read( configPHY_ADDRESS, PHY_PHYIDR1, &usData );

	} while( usData == 0xffff );

	do
	{
		/* Start auto negotiate. */
		fec_mii_write( configPHY_ADDRESS, PHY_BMCR, ( PHY_BMCR_AN_RESTART | PHY_BMCR_AN_ENABLE ) );

		/* Wait for auto negotiate to complete. */
		do
		{
			ux++;
			if( ux > 10 )
			{
				/* Hardware bug workaround!  Force 100Mbps half duplex. */
				while( !fec_mii_read( configPHY_ADDRESS, 0, &usData ) ){};
				usData &= ~0x2000;							/* 10Mbps */
				usData &= ~0x0100;							/* Half Duplex */
				usData &= ~0x1000;							/* Manual Mode */
				while( !fec_mii_write( configPHY_ADDRESS, 0, usData ) ){};
				while( !fec_mii_write( configPHY_ADDRESS, 0, (usData|0x0200) )){}; /* Force re-negotiate */
				break;
			}
			vTaskDelay( fecLINK_DELAY );
			fec_mii_read( configPHY_ADDRESS, PHY_BMSR, &usData );

		} while( !( usData & PHY_BMSR_AN_COMPLETE ) );

	} while( 0 ); //while( !( usData & PHY_BMSR_LINK ) );

	/* When we get here we have a link - find out what has been negotiated. */
	fec_mii_read( configPHY_ADDRESS, PHY_ANLPAR, &usData );

	if( ( usData & PHY_ANLPAR_100BTX_FDX ) || ( usData & PHY_ANLPAR_100BTX ) )
	{
		/* Speed is 100. */
	}
	else
	{
		/* Speed is 10. */
	}

	if( ( usData & PHY_ANLPAR_100BTX_FDX ) || ( usData & PHY_ANLPAR_10BTX_FDX ) )
	{
		MCF_FEC_RCR &= (unsigned portLONG)~MCF_FEC_RCR_DRT;
		MCF_FEC_TCR |= MCF_FEC_TCR_FDEN;
	}
	else
	{
		MCF_FEC_RCR |= MCF_FEC_RCR_DRT;
		MCF_FEC_TCR &= (unsigned portLONG)~MCF_FEC_TCR_FDEN;
	}

	/* Clear the Individual and Group Address Hash registers */
	MCF_FEC_IALR = 0;
	MCF_FEC_IAUR = 0;
	MCF_FEC_GALR = 0;
	MCF_FEC_GAUR = 0;

	/* Set the Physical Address for the selected FEC */
	fec_set_address( ucMACAddress );

	/* Set Rx Buffer Size */
	MCF_FEC_EMRBR = (unsigned portSHORT)configFEC_BUFFER_SIZE;

	/* Point to the start of the circular Rx buffer descriptor queue */
	MCF_FEC_ERDSR = ( volatile unsigned portLONG ) &( xFECRxDescriptors[ 0 ] );

	/* Point to the start of the circular Tx buffer descriptor queue */
	MCF_FEC_ETSDR = ( volatile unsigned portLONG ) &( xFECTxDescriptors[ 0 ] );

	/* Mask all FEC interrupts */
	MCF_FEC_EIMR = ( unsigned portLONG ) -1;

	/* Clear all FEC interrupt events */
	MCF_FEC_EIR = ( unsigned portLONG ) -1;

	/* Initialize the Receive Control Register */
	MCF_FEC_RCR = MCF_FEC_RCR_MAX_FL(ETH_MAX_FRM) | MCF_FEC_RCR_FCE;

	MCF_FEC_RCR |= MCF_FEC_RCR_MII_MODE;

	#if( configUSE_PROMISCUOUS_MODE == 1 )
	{
		MCF_FEC_RCR |= MCF_FEC_RCR_PROM;
	}
	#endif

	prvEnableFECInterrupts();

	/* Finally... enable. */
	MCF_FEC_ECR = MCF_FEC_ECR_ETHER_EN;
	MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;
}
/*-----------------------------------------------------------*/

static void prvEnableFECInterrupts( void )
{
const unsigned portBASE_TYPE uxFirstFECVector = 23, uxLastFECVector = 35;
unsigned portBASE_TYPE ux;

#if configFEC_INTERRUPT_PRIORITY > configMAX_SYSCALL_INTERRUPT_PRIORITY
	#error configFEC_INTERRUPT_PRIORITY must be less than or equal to configMAX_SYSCALL_INTERRUPT_PRIORITY
#endif

	/* Set the priority of each of the FEC interrupts. */
	for( ux = uxFirstFECVector; ux <= uxLastFECVector; ux++ )
	{
		MCF_INTC0_ICR( ux ) = MCF_INTC_ICR_IL( configFEC_INTERRUPT_PRIORITY );
	}

	/* Enable the FEC interrupts in the mask register */
	MCF_INTC0_IMRH &= ~( MCF_INTC_IMRH_INT_MASK33 | MCF_INTC_IMRH_INT_MASK34 | MCF_INTC_IMRH_INT_MASK35 );
	MCF_INTC0_IMRL &= ~( MCF_INTC_IMRL_INT_MASK25 | MCF_INTC_IMRL_INT_MASK26 | MCF_INTC_IMRL_INT_MASK27
						| MCF_INTC_IMRL_INT_MASK28 | MCF_INTC_IMRL_INT_MASK29 | MCF_INTC_IMRL_INT_MASK30
						| MCF_INTC_IMRL_INT_MASK31 | MCF_INTC_IMRL_INT_MASK23 | MCF_INTC_IMRL_INT_MASK24
						| MCF_INTC_IMRL_MASKALL );

	/* Clear any pending FEC interrupt events */
	MCF_FEC_EIR = MCF_FEC_EIR_CLEAR_ALL;

	/* Unmask all FEC interrupts */
	MCF_FEC_EIMR = MCF_FEC_EIMR_UNMASK_ALL;
}
/*-----------------------------------------------------------*/

static void prvResetFEC( portBASE_TYPE xCalledFromISR )
{
portBASE_TYPE x;

	/* A critical section is used unless this function is being called from
	an ISR. */
	if( xCalledFromISR == pdFALSE )
	{
		taskENTER_CRITICAL();
	}

	{
		/* Reset all buffers and descriptors. */
		prvInitialiseFECBuffers();

		/* Set the Reset bit and clear the Enable bit */
		MCF_FEC_ECR = MCF_FEC_ECR_RESET;

		/* Wait at least 8 clock cycles */
		for( x = 0; x < 10; x++ )
		{
			asm( "NOP" );
		}

		/* Re-enable. */
		MCF_FEC_ECR = MCF_FEC_ECR_ETHER_EN;
		MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;
	}

	if( xCalledFromISR == pdFALSE )
	{
		taskEXIT_CRITICAL();
	}
}
/*-----------------------------------------------------------*/

unsigned short usFECGetRxedData( void )
{
unsigned portSHORT usLen;

	/* Obtain the size of the packet and put it into the "len" variable. */
	usLen = xFECRxDescriptors[ uxNextRxBuffer ].length;

	if( ( usLen != 0 ) && ( ( xFECRxDescriptors[ uxNextRxBuffer ].status & RX_BD_E ) == 0 ) )
	{
		uip_buf = xFECRxDescriptors[ uxNextRxBuffer ].data;
	}
	else
	{
		usLen = 0;
	}

	return usLen;
}
/*-----------------------------------------------------------*/

void vFECRxProcessingCompleted( void )
{
	/* Free the descriptor as the buffer it points to is no longer in use. */
	xFECRxDescriptors[ uxNextRxBuffer ].status |= RX_BD_E;
	MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;
	uxNextRxBuffer++;
	if( uxNextRxBuffer >= configNUM_FEC_RX_BUFFERS )
	{
		uxNextRxBuffer = 0;
	}
}
/*-----------------------------------------------------------*/

void vFECSendData( void )
{
	/* Ensure no Tx frames are outstanding. */
	if( xSemaphoreTake( xTxSemaphore, fecMAX_WAIT_FOR_TX_BUFFER ) == pdPASS )
	{
		/* Get a DMA buffer into which we can write the data to send. */
		if( xFECTxDescriptors[ fecTX_BUFFER_TO_USE ].status & TX_BD_R )
		{
			/*** ERROR didn't expect this.  Sledge hammer error handling. ***/
			prvResetFEC( pdFALSE );

			/* Make sure we leave the semaphore in the expected state as nothing
			is being transmitted this will not happen in the Tx ISR. */
			xSemaphoreGive( xTxSemaphore );
		}
		else
		{
			/* Setup the buffer descriptor for transmission.  The data being
			sent is actually stored in one of the Rx descriptor buffers,
			pointed to by uip_buf. */
			xFECTxDescriptors[ fecTX_BUFFER_TO_USE ].length = uip_len;
			xFECTxDescriptors[ fecTX_BUFFER_TO_USE ].status |= ( TX_BD_R | TX_BD_L );
			xFECTxDescriptors[ fecTX_BUFFER_TO_USE ].data = uip_buf;

			/* Remember which Rx descriptor owns the buffer we are sending. */
			uxIndexToBufferOwner = uxNextRxBuffer;

			/* We have finished with this Rx descriptor now. */
			uxNextRxBuffer++;
			if( uxNextRxBuffer >= configNUM_FEC_RX_BUFFERS )
			{
				uxNextRxBuffer = 0;
			}

			/* Continue the Tx DMA (in case it was waiting for a new TxBD) */
			MCF_FEC_TDAR = MCF_FEC_TDAR_X_DES_ACTIVE;
		}
	}
	else
	{
		/* Gave up waiting.  Free the buffer back to the DMA. */
		vFECRxProcessingCompleted();
	}
}
/*-----------------------------------------------------------*/

void vFEC_ISR( void )
{
unsigned portLONG ulEvent;
portBASE_TYPE xHighPriorityTaskWoken = pdFALSE;

	/* This handler is called in response to any of the many separate FEC
	interrupt. */

	/* Find the cause of the interrupt, then clear the interrupt. */
	ulEvent = MCF_FEC_EIR & MCF_FEC_EIMR;
	MCF_FEC_EIR = ulEvent;

	if( ( ulEvent & MCF_FEC_EIR_RXB ) || ( ulEvent & MCF_FEC_EIR_RXF ) )
	{
		/* A packet has been received.  Wake the handler task. */
		xSemaphoreGiveFromISR( xFECSemaphore, &xHighPriorityTaskWoken );
	}

	if( ulEvent & ( MCF_FEC_EIR_UN | MCF_FEC_EIR_RL | MCF_FEC_EIR_LC | MCF_FEC_EIR_EBERR | MCF_FEC_EIR_BABT | MCF_FEC_EIR_BABR | MCF_FEC_EIR_HBERR ) )
	{
		/* Sledge hammer error handling. */
		prvResetFEC( pdTRUE );
	}

	if( ( ulEvent & MCF_FEC_EIR_TXF ) || ( ulEvent & MCF_FEC_EIR_TXB ) )
	{
		/* The buffer being sent is pointed to by an Rx descriptor, now the
		buffer has been sent we can mark the Rx descriptor as free again. */
		xFECRxDescriptors[ uxIndexToBufferOwner ].status |= RX_BD_E;
		MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;
		xSemaphoreGiveFromISR( xTxSemaphore, &xHighPriorityTaskWoken );
	}

	portEND_SWITCHING_ISR( xHighPriorityTaskWoken );
}
/*-----------------------------------------------------------*/

/* Install the many different interrupt vectors, all of which call the same
handler function. */
void __attribute__ ((interrupt)) __cs3_isr_interrupt_87( void ) { vFEC_ISR(); }
void __attribute__ ((interrupt)) __cs3_isr_interrupt_88( void ) { vFEC_ISR(); }
void __attribute__ ((interrupt)) __cs3_isr_interrupt_89( void ) { vFEC_ISR(); }
void __attribute__ ((interrupt)) __cs3_isr_interrupt_90( void ) { vFEC_ISR(); }
void __attribute__ ((interrupt)) __cs3_isr_interrupt_91( void ) { vFEC_ISR(); }
void __attribute__ ((interrupt)) __cs3_isr_interrupt_92( void ) { vFEC_ISR(); }
void __attribute__ ((interrupt)) __cs3_isr_interrupt_93( void ) { vFEC_ISR(); }
void __attribute__ ((interrupt)) __cs3_isr_interrupt_94( void ) { vFEC_ISR(); }
void __attribute__ ((interrupt)) __cs3_isr_interrupt_95( void ) { vFEC_ISR(); }
void __attribute__ ((interrupt)) __cs3_isr_interrupt_96( void ) { vFEC_ISR(); }
void __attribute__ ((interrupt)) __cs3_isr_interrupt_97( void ) { vFEC_ISR(); }
void __attribute__ ((interrupt)) __cs3_isr_interrupt_98( void ) { vFEC_ISR(); }
void __attribute__ ((interrupt)) __cs3_isr_interrupt_99( void ) { vFEC_ISR(); }


⌨️ 快捷键说明

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