📄 fec.c
字号:
/* 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 + -