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