/* | |
This file is part of the FreeRTOS.org distribution. | |
FreeRTOS.org 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. | |
FreeRTOS.org 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. See the GNU General Public License for | |
more details. | |
You should have received a copy of the GNU General Public License along | |
with FreeRTOS.org; if not, write to the Free Software Foundation, Inc., 59 | |
Temple Place, Suite 330, Boston, MA 02111-1307 USA. | |
A special exception to the GPL is included to allow you to distribute a | |
combined work that includes FreeRTOS.org without being obliged to provide | |
the source code for any proprietary components. See the licensing section | |
of http://www.FreeRTOS.org for full details. | |
*************************************************************************** | |
* * | |
* Get the FreeRTOS eBook! See http://www.FreeRTOS.org/Documentation * | |
* * | |
* This is a concise, step by step, 'hands on' guide that describes both * | |
* general multitasking concepts and FreeRTOS specifics. It presents and * | |
* explains numerous examples that are written using the FreeRTOS API. * | |
* Full source code for all the examples is provided in an accompanying * | |
* .zip file. * | |
* * | |
*************************************************************************** | |
1 tab == 4 spaces! | |
Please ensure to read the configuration and relevant port sections of the | |
online documentation. | |
*************************************************************************** | |
* * | |
* 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, training, latest information, | |
license and contact details. | |
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, | |
including FreeRTOS+Trace - an indispensable productivity tool. | |
Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell | |
the code with commercial support, indemnification, and middleware, under | |
the OpenRTOS brand: http://www.OpenRTOS.com. High Integrity Systems also | |
provide a safety engineered and independently SIL3 certified version under | |
the SafeRTOS brand: http://www.SafeRTOS.com. | |
*/ | |
/* Kernel includes. */ | |
#include "FreeRTOS.h" | |
#include "semphr.h" | |
#include "task.h" | |
/* Demo includes. */ | |
#include "FEC.h" | |
#include "fecbd.h" | |
#include "mii.h" | |
#include "eth_phy.h" | |
#include "eth.h" | |
/* uIP includes. */ | |
#include "uip.h" | |
#include "uip_arp.h" | |
/*-----------------------------------------------------------*/ | |
/* FEC hardware specifics. */ | |
#define MCF_FEC_MSCR_MII_SPEED(x) (((x)&0x3F)<<0x1) | |
#define MCF_FEC_RDAR_R_DES_ACTIVE ( 0x1000000 ) | |
#define MCF_FEC_TDAR_X_DES_ACTIVE ( 0x1000000 ) | |
/* PHY hardware specifics. */ | |
#define PHY_STATUS ( 16 ) | |
#define PHY_DUPLEX_STATUS ( 4 ) | |
/* Delay between polling the PHY to see if a link has been established. */ | |
#define fecLINK_DELAY ( 500 / portTICK_RATE_MS ) | |
/* Very short delay to use when waiting for the Tx to finish with a buffer if | |
we run out of Rx buffers. */ | |
#define fecMINIMAL_DELAY ( 3 / portTICK_RATE_MS ) | |
/* Don't block to wait for a buffer more than this many times. */ | |
#define uipBUFFER_WAIT_ATTEMPTS ( 30 ) | |
/* The Tx re-uses the Rx buffers and only has one descriptor. */ | |
#define fecNUM_TX_DESCRIPTORS ( 1 ) | |
/* The total number of buffers available, which should be greater than the | |
number of Rx descriptors. */ | |
#define fecNUM_BUFFERS ( configNUM_FEC_RX_DESCRIPTORS + 2 ) | |
/*-----------------------------------------------------------*/ | |
/* | |
* Return an unused buffer to the pool of free buffers. | |
*/ | |
static void prvReturnBuffer( unsigned char *pucBuffer ); | |
/* | |
* Find and return the next buffer that is not in use by anything else. | |
*/ | |
static unsigned char *prvGetFreeBuffer( void ); | |
/*-----------------------------------------------------------*/ | |
/* The semaphore used to wake the uIP task when data arrives. */ | |
xSemaphoreHandle xFECSemaphore = NULL; | |
/* The buffer used by the uIP stack. In this case the pointer is used to | |
point to one of the Rx buffers to avoid having to copy the Rx buffer into | |
the uIP buffer. */ | |
unsigned char *uip_buf; | |
/* The DMA descriptors. These are char arrays to allow us to align them | |
correctly. */ | |
static unsigned char xFECTxDescriptors_unaligned[ ( fecNUM_TX_DESCRIPTORS * sizeof( FECBD ) ) + 16 ]; | |
static unsigned char xFECRxDescriptors_unaligned[ ( configNUM_FEC_RX_DESCRIPTORS * sizeof( FECBD ) ) + 16 ]; | |
static FECBD *pxFECTxDescriptor; | |
static FECBD *xFECRxDescriptors; | |
/* The DMA buffer. This is a char arrays to allow it to be aligned correctly. */ | |
static unsigned char ucFECRxBuffers[ ( fecNUM_BUFFERS * configFEC_BUFFER_SIZE ) + 16 ]; | |
/* Index to the next descriptor to be inspected for received data. */ | |
static unsigned long ulNextRxDescriptor = 0; | |
/* Contains the start address of each Rx buffer, after it has been correctly | |
aligned. */ | |
static unsigned char *pucAlignedBufferStartAddresses[ fecNUM_BUFFERS ] = { 0 }; | |
/* Each ucBufferInUse index corresponds to a position in the same index in the | |
pucAlignedBufferStartAddresses array. If the index contains a 1 then the | |
buffer within pucAlignedBufferStartAddresses is in use, if it contains a 0 then | |
the buffer is free. */ | |
static unsigned char ucBufferInUse[ fecNUM_BUFFERS ] = { 0 }; | |
/*-----------------------------------------------------------*/ | |
/********************************************************************/ | |
/* | |
* 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; | |
unsigned long eimr; | |
/* Clear the MII interrupt bit */ | |
EIR = EIR_MII; | |
/* Mask the MII interrupt */ | |
eimr = EIMR; | |
EIMR &= ~EIMR_MII; | |
/* Write to the MII Management Frame Register to kick-off the MII write */ | |
MMFR = ( unsigned long ) ( FEC_MMFR_ST_01 | FEC_MMFR_OP_WRITE | FEC_MMFR_PA(phy_addr) | FEC_MMFR_RA(reg_addr) | FEC_MMFR_TA_10 | FEC_MMFR_DATA( data ) ); | |
/* Poll for the MII interrupt (interrupt should be masked) */ | |
for (timeout = 0; timeout < FEC_MII_TIMEOUT; timeout++) | |
{ | |
if( EIR & EIR_MII) | |
{ | |
break; | |
} | |
} | |
if( timeout == FEC_MII_TIMEOUT ) | |
{ | |
return 0; | |
} | |
/* Clear the MII interrupt bit */ | |
EIR = EIR_MII; | |
/* Restore the EIMR */ | |
EIMR = eimr; | |
return 1; | |
} | |
/********************************************************************/ | |
/* | |
* 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; | |
unsigned long eimr; | |
/* Clear the MII interrupt bit */ | |
EIR = 0xffffffff; | |
/* Mask the MII interrupt */ | |
eimr = EIMR; | |
EIMR &= ~EIMR_MII; | |
/* Write to the MII Management Frame Register to kick-off the MII read */ | |
MMFR = ( unsigned long ) ( FEC_MMFR_ST_01 | FEC_MMFR_OP_READ | FEC_MMFR_PA(phy_addr) | FEC_MMFR_RA(reg_addr) | FEC_MMFR_TA_10 ); | |
/* Poll for the MII interrupt (interrupt should be masked) */ | |
for (timeout = 0; timeout < FEC_MII_TIMEOUT; timeout++) | |
{ | |
if (EIR) | |
{ | |
break; | |
} | |
} | |
if(timeout == FEC_MII_TIMEOUT) | |
{ | |
return 0; | |
} | |
/* Clear the MII interrupt bit */ | |
EIR = EIR_MII; | |
/* Restore the EIMR */ | |
EIMR = eimr; | |
*data = (unsigned short)(MMFR & 0x0000FFFF); | |
return 1; | |
} | |
/********************************************************************/ | |
/* | |
* 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); | |
} | |
/********************************************************************/ | |
/* | |
* 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 | |
*/ | |
PALR = (unsigned long)((pa[0]<<24) | (pa[1]<<16) | (pa[2]<<8) | pa[3]); | |
PAUR = (unsigned long)((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) | |
{ | |
IAUR |= (unsigned long)(1 << (crc - 32)); | |
} | |
else | |
{ | |
IALR |= (unsigned long)(1 << crc); | |
} | |
} | |
/*-----------------------------------------------------------*/ | |
static void prvInitialiseFECBuffers( void ) | |
{ | |
unsigned portBASE_TYPE ux; | |
unsigned char *pcBufPointer; | |
/* Set the pointer to a correctly aligned address. */ | |
pcBufPointer = &( xFECTxDescriptors_unaligned[ 0 ] ); | |
while( ( ( unsigned long ) pcBufPointer & 0x0fUL ) != 0 ) | |
{ | |
pcBufPointer++; | |
} | |
pxFECTxDescriptor = ( FECBD * ) pcBufPointer; | |
/* Likewise the pointer to the Rx descriptor. */ | |
pcBufPointer = &( xFECRxDescriptors_unaligned[ 0 ] ); | |
while( ( ( unsigned long ) pcBufPointer & 0x0fUL ) != 0 ) | |
{ | |
pcBufPointer++; | |
} | |
xFECRxDescriptors = ( FECBD * ) pcBufPointer; | |
/* There is no Tx buffer as the Rx buffer is reused. */ | |
pxFECTxDescriptor->length = 0; | |
pxFECTxDescriptor->status = 0; | |
/* Align the Rx buffers. */ | |
pcBufPointer = &( ucFECRxBuffers[ 0 ] ); | |
while( ( ( unsigned long ) pcBufPointer & 0x0fUL ) != 0 ) | |
{ | |
pcBufPointer++; | |
} | |
/* Then fill in the Rx descriptors. */ | |
for( ux = 0; ux < configNUM_FEC_RX_DESCRIPTORS; ux++ ) | |
{ | |
xFECRxDescriptors[ ux ].status = RX_BD_E; | |
xFECRxDescriptors[ ux ].length = configFEC_BUFFER_SIZE; | |
xFECRxDescriptors[ ux ].data = pcBufPointer; | |
/* Note the start address of the buffer now that it is correctly | |
aligned. */ | |
pucAlignedBufferStartAddresses[ ux ] = pcBufPointer; | |
/* The buffer is in use by the descriptor. */ | |
ucBufferInUse[ ux ] = pdTRUE; | |
pcBufPointer += configFEC_BUFFER_SIZE; | |
} | |
/* Note the start address of the last buffer as one more buffer is | |
allocated than there are Rx descriptors. */ | |
pucAlignedBufferStartAddresses[ ux ] = pcBufPointer; | |
/* Set uip_buf to point to the last buffer. */ | |
uip_buf = pcBufPointer; | |
ucBufferInUse[ ux ] = pdTRUE; | |
/* Set the wrap bit in the last descriptors to form a ring. */ | |
xFECRxDescriptors[ configNUM_FEC_RX_DESCRIPTORS - 1 ].status |= RX_BD_W; | |
/* We start with descriptor 0. */ | |
ulNextRxDescriptor = 0; | |
} | |
/*-----------------------------------------------------------*/ | |
void vInitFEC( void ) | |
{ | |
unsigned short usData; | |
struct uip_eth_addr xAddr; | |
const unsigned char ucMACAddress[6] = | |
{ | |
configMAC_0, configMAC_1,configMAC_2,configMAC_3,configMAC_4,configMAC_5 | |
}; | |
prvInitialiseFECBuffers(); | |
/* Create the semaphore used to wake the uIP task when data arrives. */ | |
vSemaphoreCreateBinary( xFECSemaphore ); | |
/* Set the MAC address within the stack. */ | |
for( usData = 0; usData < 6; usData++ ) | |
{ | |
xAddr.addr[ usData ] = ucMACAddress[ usData ]; | |
} | |
uip_setethaddr( xAddr ); | |
/* Set the Reset bit and clear the Enable bit */ | |
ECR_RESET = 1; | |
/* Enable the clock. */ | |
SCGC4 |= SCGC4_FEC_MASK; | |
/* Wait at least 8 clock cycles */ | |
for( usData = 0; usData < 10; usData++ ) | |
{ | |
asm( "NOP" ); | |
} | |
/* Set MII speed to 2.5MHz. */ | |
MSCR = MCF_FEC_MSCR_MII_SPEED( ( ( configCPU_CLOCK_HZ / 1000000 ) / 5 ) + 1 ); | |
/* | |
* Make sure the external interface signals are enabled | |
*/ | |
PTCPF2_C0 = 1; | |
PTCPF2_C1 = 1; | |
PTCPF2_C2 = 1; | |
PTAPF1 = 0x55; | |
PTAPF2 = 0x55; | |
PTBPF1 = 0x55; | |
PTBPF2 = 0x55; | |
/* Set all pins to full drive with no filter. */ | |
PTADS = 0x06; | |
PTAIFE = 0x06; | |
PTBDS = 0xf4; | |
PTBIFE = 0xf4; | |
PTCDS = 0; | |
PTCIFE = 0; | |
/* Can we talk to the PHY? */ | |
do | |
{ | |
vTaskDelay( fecLINK_DELAY ); | |
usData = 0xffff; | |
fec_mii_read( configPHY_ADDRESS, PHY_PHYIDR1, &usData ); | |
} while( usData == 0xffff ); | |
/* 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 | |
{ | |
vTaskDelay( fecLINK_DELAY ); | |
fec_mii_read( configPHY_ADDRESS, PHY_BMSR, &usData ); | |
} while( !( usData & PHY_BMSR_AN_COMPLETE ) ); | |
/* When we get here we have a link - find out what has been negotiated. */ | |
usData = 0; | |
fec_mii_read( configPHY_ADDRESS, PHY_STATUS, &usData ); | |
/* Setup half or full duplex. */ | |
if( usData & PHY_DUPLEX_STATUS ) | |
{ | |
RCR &= (unsigned long)~RCR_DRT; | |
TCR |= TCR_FDEN; | |
} | |
else | |
{ | |
RCR |= RCR_DRT; | |
TCR &= (unsigned long)~TCR_FDEN; | |
} | |
/* Clear the Individual and Group Address Hash registers */ | |
IALR = 0; | |
IAUR = 0; | |
GALR = 0; | |
GAUR = 0; | |
/* Set the Physical Address for the selected FEC */ | |
fec_set_address( ucMACAddress ); | |
/* Set Rx Buffer Size */ | |
EMRBR = (unsigned short) configFEC_BUFFER_SIZE; | |
/* Point to the start of the circular Rx buffer descriptor queue */ | |
ERDSR = ( volatile unsigned long ) &( xFECRxDescriptors[ 0 ] ); | |
/* Point to the start of the circular Tx buffer descriptor queue */ | |
ETSDR = ( volatile unsigned long ) pxFECTxDescriptor; | |
/* Clear all FEC interrupt events */ | |
EIR = ( unsigned long ) -1; | |
/* Various mode/status setup. */ | |
RCR = 0; | |
RCR_MAX_FL = configFEC_BUFFER_SIZE; | |
RCR_MII_MODE = 1; | |
#if( configUSE_PROMISCUOUS_MODE == 1 ) | |
{ | |
RCR |= RCR_PROM; | |
} | |
#endif | |
/* Enable interrupts. */ | |
EIMR = EIR_TXF_MASK | EIMR_RXF_MASK | EIMR_RXB_MASK | EIMR_UN_MASK | EIMR_RL_MASK | EIMR_LC_MASK | EIMR_BABT_MASK | EIMR_BABR_MASK | EIMR_HBERR_MASK; | |
/* Enable the MAC itself. */ | |
ECR = ECR_ETHER_EN_MASK; | |
/* Indicate that there have been empty receive buffers produced */ | |
RDAR = MCF_FEC_RDAR_R_DES_ACTIVE; | |
} | |
/*-----------------------------------------------------------*/ | |
unsigned long ulFECRx( void ) | |
{ | |
unsigned long ulLen = 0UL; | |
/* Is a buffer ready? */ | |
if( ( xFECRxDescriptors[ ulNextRxDescriptor ].status & RX_BD_E ) == 0 ) | |
{ | |
/* uip_buf is about to be set to a new buffer, so return the buffer it | |
is already pointing to. */ | |
prvReturnBuffer( uip_buf ); | |
/* Obtain the size of the packet and put it into the "len" variable. */ | |
ulLen = xFECRxDescriptors[ ulNextRxDescriptor ].length; | |
uip_buf = xFECRxDescriptors[ ulNextRxDescriptor ].data; | |
/* The buffer that this descriptor was using is now in use by the | |
TCP/IP stack, so allocate it a new buffer. */ | |
xFECRxDescriptors[ ulNextRxDescriptor ].data = prvGetFreeBuffer(); | |
/* Doing this here could cause corruption! */ | |
xFECRxDescriptors[ ulNextRxDescriptor ].status |= RX_BD_E; | |
portENTER_CRITICAL(); | |
{ | |
ulNextRxDescriptor++; | |
if( ulNextRxDescriptor >= configNUM_FEC_RX_DESCRIPTORS ) | |
{ | |
ulNextRxDescriptor = 0; | |
} | |
} | |
portEXIT_CRITICAL(); | |
/* Tell the DMA a new buffer is available. */ | |
RDAR = MCF_FEC_RDAR_R_DES_ACTIVE; | |
} | |
return ulLen; | |
} | |
/*-----------------------------------------------------------*/ | |
void vFECTx( void ) | |
{ | |
/* When we get here the Tx descriptor should show as having completed. */ | |
while( pxFECTxDescriptor->status & TX_BD_R ) | |
{ | |
vTaskDelay( fecMINIMAL_DELAY ); | |
} | |
portENTER_CRITICAL(); | |
{ | |
/* To maintain the zero copy implementation, point the Tx descriptor | |
to the data from the Rx buffer. */ | |
pxFECTxDescriptor->data = uip_buf; | |
/* Setup the buffer descriptor for transmission */ | |
pxFECTxDescriptor->length = uip_len; | |
/* NB this assumes only one Tx descriptor! */ | |
pxFECTxDescriptor->status = ( TX_BD_R | TX_BD_L | TX_BD_TC | TX_BD_W ); | |
} | |
portEXIT_CRITICAL(); | |
/* Continue the Tx DMA task (in case it was waiting for a new TxBD) */ | |
TDAR = MCF_FEC_TDAR_X_DES_ACTIVE; | |
/* uip_buf is being used by the Tx descriptor. Allocate a new buffer to | |
uip_buf. */ | |
uip_buf = prvGetFreeBuffer(); | |
} | |
/*-----------------------------------------------------------*/ | |
static void prvReturnBuffer( unsigned char *pucBuffer ) | |
{ | |
unsigned long ul; | |
/* Mark a buffer as free for use. */ | |
for( ul = 0; ul < fecNUM_BUFFERS; ul++ ) | |
{ | |
if( pucAlignedBufferStartAddresses[ ul ] == pucBuffer ) | |
{ | |
ucBufferInUse[ ul ] = pdFALSE; | |
break; | |
} | |
} | |
} | |
/*-----------------------------------------------------------*/ | |
static unsigned char *prvGetFreeBuffer( void ) | |
{ | |
portBASE_TYPE x; | |
unsigned char *pucReturn = NULL; | |
unsigned long ulAttempts = 0; | |
while( pucReturn == NULL ) | |
{ | |
/* Look through the buffers to find one that is not in use by | |
anything else. */ | |
for( x = 0; x < fecNUM_BUFFERS; x++ ) | |
{ | |
if( ucBufferInUse[ x ] == pdFALSE ) | |
{ | |
ucBufferInUse[ x ] = pdTRUE; | |
pucReturn = pucAlignedBufferStartAddresses[ x ]; | |
break; | |
} | |
} | |
/* Was a buffer found? */ | |
if( pucReturn == NULL ) | |
{ | |
ulAttempts++; | |
if( ulAttempts >= uipBUFFER_WAIT_ATTEMPTS ) | |
{ | |
break; | |
} | |
/* Wait then look again. */ | |
vTaskDelay( fecMINIMAL_DELAY ); | |
} | |
} | |
return pucReturn; | |
} | |
/*-----------------------------------------------------------*/ | |
void interrupt 86 vFECISRHandler( void ) | |
{ | |
unsigned long ulEvent; | |
portBASE_TYPE xHighPriorityTaskWoken = pdFALSE; | |
/* Determine the cause of the interrupt. */ | |
ulEvent = EIR & EIMR; | |
EIR = ulEvent; | |
if( ulEvent & EIR_RXF_MASK ) | |
{ | |
/* A packet has been received. Wake the handler task in case it is | |
blocked. */ | |
xSemaphoreGiveFromISR( xFECSemaphore, &xHighPriorityTaskWoken ); | |
} | |
if( ulEvent & EIR_TXF_MASK ) | |
{ | |
/* The Tx has completed. Mark the buffer it was using as free again. */ | |
prvReturnBuffer( pxFECTxDescriptor->data ); | |
pxFECTxDescriptor->data = NULL; | |
} | |
if (ulEvent & ( EIR_UN_MASK | EIR_RL_MASK | EIR_LC_MASK | EIR_EBERR_MASK | EIR_BABT_MASK | EIR_BABR_MASK | EIR_HBERR_MASK ) ) | |
{ | |
/* Sledge hammer error handling. */ | |
prvInitialiseFECBuffers(); | |
RDAR = MCF_FEC_RDAR_R_DES_ACTIVE; | |
} | |
portEND_SWITCHING_ISR( xHighPriorityTaskWoken ); | |
} |