/* | |
FreeRTOS V8.0.1 - Copyright (C) 2014 Real Time Engineers Ltd. | |
All rights reserved | |
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. | |
*************************************************************************** | |
* * | |
* FreeRTOS provides completely free yet professionally developed, * | |
* robust, strictly quality controlled, supported, and cross * | |
* platform software that has become a de facto standard. * | |
* * | |
* Help yourself get started quickly and support the FreeRTOS * | |
* project by purchasing a FreeRTOS tutorial book, reference * | |
* manual, or both from: http://www.FreeRTOS.org/Documentation * | |
* * | |
* Thank you! * | |
* * | |
*************************************************************************** | |
This file is part of the FreeRTOS distribution. | |
FreeRTOS is free software; you can redistribute it and/or modify it under | |
the terms of the GNU General Public License (version 2) as published by the | |
Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. | |
>>! NOTE: The modification to the GPL is included to allow you to !<< | |
>>! distribute a combined work that includes FreeRTOS without being !<< | |
>>! obliged to provide the source code for proprietary components !<< | |
>>! outside of the FreeRTOS kernel. !<< | |
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY | |
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
FOR A PARTICULAR PURPOSE. Full license text is available from the following | |
link: http://www.freertos.org/a00114.html | |
1 tab == 4 spaces! | |
*************************************************************************** | |
* * | |
* Having a problem? Start by reading the FAQ "My application does * | |
* not run, what could be wrong?" * | |
* * | |
* http://www.FreeRTOS.org/FAQHelp.html * | |
* * | |
*************************************************************************** | |
http://www.FreeRTOS.org - Documentation, books, training, latest versions, | |
license and Real Time Engineers Ltd. contact details. | |
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, | |
including FreeRTOS+Trace - an indispensable productivity tool, a DOS | |
compatible FAT file system, and our tiny thread aware UDP/IP stack. | |
http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High | |
Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS | |
licenses offer ticketed support, indemnification and middleware. | |
http://www.SafeRTOS.com - High Integrity Systems also provide a safety | |
engineered and independently SIL3 certified version for use in safety and | |
mission critical applications that require provable dependability. | |
1 tab == 4 spaces! | |
*/ | |
/* Kernel includes. */ | |
#include "FreeRTOS.h" | |
#include "semphr.h" | |
#include "task.h" | |
/* Hardware includes. */ | |
#include "fecbd.h" | |
#include "mii.h" | |
#include "eth_phy.h" | |
#include "eth.h" | |
/* uIP includes. */ | |
#include "uip.h" | |
#include "uip_arp.h" | |
/* Delay between polling the PHY to see if a link has been established. */ | |
#define fecLINK_DELAY ( 500 / portTICK_RATE_MS ) | |
/* Delay to wait for an MII access. */ | |
#define fecMII_DELAY ( 10 / portTICK_RATE_MS ) | |
#define fecMAX_POLLS ( 20 ) | |
/* Constants used to delay while waiting for a tx descriptor to be free. */ | |
#define fecMAX_WAIT_FOR_TX_BUFFER ( 200 / portTICK_RATE_MS ) | |
/* We only use a single Tx descriptor which can lead to Txed packets being sent | |
twice (due to a bug in the FEC silicon). However, in this case the bug is used | |
to our advantage in that it means the uip-split mechanism is not required. */ | |
#define fecNUM_FEC_TX_BUFFERS ( 1 ) | |
#define fecTX_BUFFER_TO_USE ( 0 ) | |
/*-----------------------------------------------------------*/ | |
/* The semaphore used to wake the uIP task when data arrives. */ | |
xSemaphoreHandle xFECSemaphore = NULL, xTxSemaphore = NULL; | |
/* The buffer used by the uIP stack. In this case the pointer is used to | |
point to one of the Rx buffers to effect a zero copy policy. */ | |
unsigned char *uip_buf; | |
/* The DMA descriptors. This is a char array to allow us to align it correctly. */ | |
static unsigned char xFECTxDescriptors_unaligned[ ( fecNUM_FEC_TX_BUFFERS * sizeof( FECBD ) ) + 16 ]; | |
static unsigned char xFECRxDescriptors_unaligned[ ( configNUM_FEC_RX_BUFFERS * sizeof( FECBD ) ) + 16 ]; | |
static FECBD *xFECTxDescriptors; | |
static FECBD *xFECRxDescriptors; | |
/* The DMA buffers. These are char arrays to allow them to be aligned correctly. */ | |
static unsigned char ucFECRxBuffers[ ( configNUM_FEC_RX_BUFFERS * configFEC_BUFFER_SIZE ) + 16 ]; | |
static unsigned portBASE_TYPE uxNextRxBuffer = 0, uxIndexToBufferOwner = 0; | |
/*-----------------------------------------------------------*/ | |
/* | |
* Enable all the required interrupts in the FEC and in the interrupt controller. | |
*/ | |
static void prvEnableFECInterrupts( void ); | |
/* | |
* Reset the FEC if we get into an unrecoverable state. | |
*/ | |
static void prvResetFEC( portBASE_TYPE xCalledFromISR ); | |
/********************************************************************/ | |
/* | |
* FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE | |
* | |
* Write a value to a PHY's MII register. | |
* | |
* Parameters: | |
* ch FEC channel | |
* phy_addr Address of the PHY. | |
* reg_addr Address of the register in the PHY. | |
* data Data to be written to the PHY register. | |
* | |
* Return Values: | |
* 0 on failure | |
* 1 on success. | |
* | |
* Please refer to your PHY manual for registers and their meanings. | |
* mii_write() polls for the FEC's MII interrupt event and clears it. | |
* If after a suitable amount of time the event isn't triggered, a | |
* value of 0 is returned. | |
*/ | |
static int fec_mii_write( int phy_addr, int reg_addr, int data ) | |
{ | |
int timeout, iReturn; | |
uint32 eimr; | |
/* Clear the MII interrupt bit */ | |
MCF_FEC_EIR = MCF_FEC_EIR_MII; | |
/* Mask the MII interrupt */ | |
eimr = MCF_FEC_EIMR; | |
MCF_FEC_EIMR &= ~MCF_FEC_EIMR_MII; | |
/* Write to the MII Management Frame Register to kick-off the MII write */ | |
MCF_FEC_MMFR = MCF_FEC_MMFR_ST_01 | MCF_FEC_MMFR_OP_WRITE | MCF_FEC_MMFR_PA(phy_addr) | MCF_FEC_MMFR_RA(reg_addr) | MCF_FEC_MMFR_TA_10 | MCF_FEC_MMFR_DATA( data ); | |
/* Poll for the MII interrupt (interrupt should be masked) */ | |
for( timeout = 0; timeout < fecMAX_POLLS; timeout++ ) | |
{ | |
if( MCF_FEC_EIR & MCF_FEC_EIR_MII ) | |
{ | |
break; | |
} | |
else | |
{ | |
vTaskDelay( fecMII_DELAY ); | |
} | |
} | |
if( timeout == fecMAX_POLLS ) | |
{ | |
iReturn = 0; | |
} | |
else | |
{ | |
iReturn = 1; | |
} | |
/* Clear the MII interrupt bit */ | |
MCF_FEC_EIR = MCF_FEC_EIR_MII; | |
/* Restore the EIMR */ | |
MCF_FEC_EIMR = eimr; | |
return iReturn; | |
} | |
/********************************************************************/ | |
/* | |
* FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE | |
* | |
* Read a value from a PHY's MII register. | |
* | |
* Parameters: | |
* ch FEC channel | |
* phy_addr Address of the PHY. | |
* reg_addr Address of the register in the PHY. | |
* data Pointer to storage for the Data to be read | |
* from the PHY register (passed by reference) | |
* | |
* Return Values: | |
* 0 on failure | |
* 1 on success. | |
* | |
* Please refer to your PHY manual for registers and their meanings. | |
* mii_read() polls for the FEC's MII interrupt event and clears it. | |
* If after a suitable amount of time the event isn't triggered, a | |
* value of 0 is returned. | |
*/ | |
static int fec_mii_read( int phy_addr, int reg_addr, unsigned short* data ) | |
{ | |
int timeout, iReturn; | |
uint32 eimr; | |
/* Clear the MII interrupt bit */ | |
MCF_FEC_EIR = MCF_FEC_EIR_MII; | |
/* Mask the MII interrupt */ | |
eimr = MCF_FEC_EIMR; | |
MCF_FEC_EIMR &= ~MCF_FEC_EIMR_MII; | |
/* Write to the MII Management Frame Register to kick-off the MII read */ | |
MCF_FEC_MMFR = MCF_FEC_MMFR_ST_01 | MCF_FEC_MMFR_OP_READ | MCF_FEC_MMFR_PA(phy_addr) | MCF_FEC_MMFR_RA(reg_addr) | MCF_FEC_MMFR_TA_10; | |
/* Poll for the MII interrupt (interrupt should be masked) */ | |
for( timeout = 0; timeout < fecMAX_POLLS; timeout++ ) | |
{ | |
if (MCF_FEC_EIR & MCF_FEC_EIR_MII) | |
{ | |
break; | |
} | |
else | |
{ | |
vTaskDelay( fecMII_DELAY ); | |
} | |
} | |
if( timeout == fecMAX_POLLS ) | |
{ | |
iReturn = 0; | |
} | |
else | |
{ | |
*data = (uint16)(MCF_FEC_MMFR & 0x0000FFFF); | |
iReturn = 1; | |
} | |
/* Clear the MII interrupt bit */ | |
MCF_FEC_EIR = MCF_FEC_EIR_MII; | |
/* Restore the EIMR */ | |
MCF_FEC_EIMR = eimr; | |
return iReturn; | |
} | |
/********************************************************************/ | |
/* | |
* FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE | |
* | |
* Generate the hash table settings for the given address | |
* | |
* Parameters: | |
* addr 48-bit (6 byte) Address to generate the hash for | |
* | |
* Return Value: | |
* The 6 most significant bits of the 32-bit CRC result | |
*/ | |
static unsigned char fec_hash_address( const unsigned char* addr ) | |
{ | |
unsigned long crc; | |
unsigned char byte; | |
int i, j; | |
crc = 0xFFFFFFFF; | |
for(i=0; i<6; ++i) | |
{ | |
byte = addr[i]; | |
for(j=0; j<8; ++j) | |
{ | |
if((byte & 0x01)^(crc & 0x01)) | |
{ | |
crc >>= 1; | |
crc = crc ^ 0xEDB88320; | |
} | |
else | |
{ | |
crc >>= 1; | |
} | |
byte >>= 1; | |
} | |
} | |
return (unsigned char)(crc >> 26); | |
} | |
/********************************************************************/ | |
/* | |
* FUNCTION ADAPTED FROM FREESCALE SUPPLIED SOURCE | |
* | |
* Set the Physical (Hardware) Address and the Individual Address | |
* Hash in the selected FEC | |
* | |
* Parameters: | |
* ch FEC channel | |
* pa Physical (Hardware) Address for the selected FEC | |
*/ | |
static void fec_set_address( const unsigned char *pa ) | |
{ | |
unsigned char crc; | |
/* | |
* Set the Physical Address | |
*/ | |
/* Set the source address for the controller */ | |
MCF_FEC_PALR = ( pa[ 0 ] << 24 ) | ( pa[ 1 ] << 16 ) | ( pa[ 2 ] << 8 ) | ( pa[ 3 ] << 0 ); | |
MCF_FEC_PAUR = ( pa[ 4 ] << 24 ) | ( pa[ 5 ] << 16 ); | |
/* | |
* Calculate and set the hash for given Physical Address | |
* in the Individual Address Hash registers | |
*/ | |
crc = fec_hash_address( pa ); | |
if( crc >= 32 ) | |
{ | |
MCF_FEC_IAUR |= (unsigned long)(1 << (crc - 32)); | |
} | |
else | |
{ | |
MCF_FEC_IALR |= (unsigned long)(1 << crc); | |
} | |
} | |
/*-----------------------------------------------------------*/ | |
static void prvInitialiseFECBuffers( void ) | |
{ | |
unsigned portBASE_TYPE ux; | |
unsigned char *pcBufPointer; | |
/* Correctly align the Tx descriptor pointer. */ | |
pcBufPointer = &( xFECTxDescriptors_unaligned[ 0 ] ); | |
while( ( ( unsigned long ) pcBufPointer & 0x0fUL ) != 0 ) | |
{ | |
pcBufPointer++; | |
} | |
xFECTxDescriptors = ( FECBD * ) pcBufPointer; | |
/* Likewise the Rx descriptor pointer. */ | |
pcBufPointer = &( xFECRxDescriptors_unaligned[ 0 ] ); | |
while( ( ( unsigned long ) pcBufPointer & 0x0fUL ) != 0 ) | |
{ | |
pcBufPointer++; | |
} | |
xFECRxDescriptors = ( FECBD * ) pcBufPointer; | |
/* Setup the Tx buffers and descriptors. There is no separate Tx buffer | |
to point to (the Rx buffers are actually used) so the data member is | |
set to NULL for now. */ | |
for( ux = 0; ux < fecNUM_FEC_TX_BUFFERS; ux++ ) | |
{ | |
xFECTxDescriptors[ ux ].status = TX_BD_TC; | |
xFECTxDescriptors[ ux ].data = NULL; | |
xFECTxDescriptors[ ux ].length = 0; | |
} | |
/* Setup the Rx buffers and descriptors, having first ensured correct | |
alignment. */ | |
pcBufPointer = &( ucFECRxBuffers[ 0 ] ); | |
while( ( ( unsigned long ) pcBufPointer & 0x0fUL ) != 0 ) | |
{ | |
pcBufPointer++; | |
} | |
for( ux = 0; ux < configNUM_FEC_RX_BUFFERS; ux++ ) | |
{ | |
xFECRxDescriptors[ ux ].status = RX_BD_E; | |
xFECRxDescriptors[ ux ].length = configFEC_BUFFER_SIZE; | |
xFECRxDescriptors[ ux ].data = pcBufPointer; | |
pcBufPointer += configFEC_BUFFER_SIZE; | |
} | |
/* 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 short usData; | |
struct uip_eth_addr xAddr; | |
unsigned portBASE_TYPE ux; | |
/* The MAC address is set at the foot of FreeRTOSConfig.h. */ | |
const unsigned char 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 long)~MCF_FEC_RCR_DRT; | |
MCF_FEC_TCR |= MCF_FEC_TCR_FDEN; | |
} | |
else | |
{ | |
MCF_FEC_RCR |= MCF_FEC_RCR_DRT; | |
MCF_FEC_TCR &= (unsigned long)~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 short)configFEC_BUFFER_SIZE; | |
/* Point to the start of the circular Rx buffer descriptor queue */ | |
MCF_FEC_ERDSR = ( volatile unsigned long ) &( xFECRxDescriptors[ 0 ] ); | |
/* Point to the start of the circular Tx buffer descriptor queue */ | |
MCF_FEC_ETSDR = ( volatile unsigned long ) &( xFECTxDescriptors[ 0 ] ); | |
/* Mask all FEC interrupts */ | |
MCF_FEC_EIMR = ( unsigned long ) -1; | |
/* Clear all FEC interrupt events */ | |
MCF_FEC_EIR = ( unsigned long ) -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 short 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 long 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(); } | |