📄 ethernet_lpc23xx.c
字号:
/*
********************************************************************
* Project: ethernet driver for LPC23xx/24xx
* File: ethernet_lpc23xx.c
*
* System: ARM7TDMI-S 32 Bit
* Compiler: GCC 4.0.3
*
* Date: 2006-08-31
* Author: Wenz
*
* Rights: Hitex Development Tools GmbH
* Greschbachstr. 12
* D-76229 Karlsruhe
********************************************************************
* Description:
*
* ethernet driver for LPC23xx controller ethernet module.
* The iplementation is tested on a MCB2300 board with
* LPC2378 Controller
* DP8348C external PHY
*
********************************************************************
* History:
*
* Revision 1.0 2006/09/27 We
* Initial revision
********************************************************************
* This software is provided by the author 'AS IS' without any
* warranties. Hitex Development Tools GmbH shall not be held
* liable for any direct, indirect or consequential damages with
* respect to any claims arising from the content of such software.
********************************************************************/
#include "peripherals_lpc23xx.h" /* LPC23xx definitions */
#include "ethernet_lpc23xx.h"
#include "peripherals_config.h"
/* extern declarations */
/* global function prototypes */
bool eEthInit(void);
uint32_t ulReadFrame(uint8_t* aFrameBuffer);
bool eEthSendFrame(uint32_t frameLength, uint8_t* aFrameBuffer);
void vEthSetStationAddress( uint8_t* pAddress);
linkstatus eGetLinkStatus(uint32_t aPHYDevice);
void vEthIntHandler(void);
void vEthIntService(void) __attribute__((naked)) ;
/* Local variables */
static const uint32_t PHYREADCOMMAND = 0x01;
static const uint32_t PHYWRITECOMMAND = 0x02;
static const uint32_t MII_COMMAND_TIMEOUT = 0x5000;
static const uint32_t MII_AUTONEG_TIMEOUT = 0x50000;
static const uint32_t MII_LINKSTAT_TIMEOUT = 0x50000;
static const uint32_t PHY_RESET_TIMEOUT = 0x10000;
/*
*********************************************************************
* data for the DMA engine; descriptors
* location in ethernet RAM
*********************************************************************/
static eth_data* const pxEthernetData = (eth_data*)ETHDATA_STARTADDRESS;
/* data exchange to application or stack
* only the length, pointer to data, and status is stored
* the data is left inside receive DMA engine */
static fragment uxRxFrame[NUMBER_REC_FRAGMENTS];
static uint32_t readIndex;
static uint32_t writeIndex;
/* error counters */
static uint32_t ulRxOverrunErrorCounter;
static uint32_t ulRxError;
static uint32_t ulTxUnderrunErrorCounter;
static uint32_t ulTxError;
/* local function prototypes */
static void prvInitAPI(void);
static void prvInitDMAEngine(void);
static uint16_t prvConfigurePHY(uint32_t aPHYDevice);
static uint16_t prvReadPhyRegister( uint32_t aPhyRegisterAdr );
static uint16_t prvWritePhyRegister( uint32_t aPhyRegisterAdr, uint16_t aRegisterValue );
static void prvConfigureRxFilters(void);
static void prvReceiveFragment(void);
static void prvSetupInt(uint32_t aIntSource, uint32_t aIntServiceAdr, uint32_t aPriority );
/* macros incrementing the index taking wrap around mechannism into account */
#define incRxIndex(Index) if( (++Index) == NUMBER_REC_FRAGMENTS ) \
Index = 0x00
#define incTxIndex(Index) if( (++Index) == NUMBER_TX_FRAGMENTS ) \
Index = 0x00
/****************************************************************************
* Name: prvInitAPI
*
* Description: initialize the data which should
* be interfaced to upper layers.
*
* Parameters: none
*
* Return value: none
*
****************************************************************************
*/
static void prvInitAPI(void)
{
int i;
readIndex = 0x00;
writeIndex = 0x00;
ulRxOverrunErrorCounter = 0x00;
ulRxError = 0x00;
ulTxUnderrunErrorCounter = 0x00;
ulTxError = 0x00;
for( i = 0x00; i < NUMBER_REC_FRAGMENTS; i++ )
{
uxRxFrame[i].Length = 0x00;
uxRxFrame[i].pReceived = 0x00;
uxRxFrame[i].status = 0x00;
}
}
/****************************************************************************
* Name: prvInitDMAEngine
*
* Description: initialize the DMA registers
* note: the data to transfer via Ethernet
* is located in 16K SRAM connected to AHB 1
* at address 0x7FE00000
*
*
* Parameters: none
*
* Return value: none
*
****************************************************************************
*/
static void prvInitDMAEngine(void)
{
uint32_t i;
// initialize receive DMA
for( i=0; i < NUMBER_REC_FRAGMENTS; i++ )
{
pxEthernetData->xRxDescr[i].packet = (uint8_t*)(&pxEthernetData->ucRxBuffer[i][0]);
pxEthernetData->xRxDescr[i].control = MAXLENGTH_REC_FRAGMENT;
pxEthernetData->xRxDescr[i].control |= RX_CONTROL_INT;
pxEthernetData->xRxStat[i].info = 0x00;
pxEthernetData->xRxStat[i].hashCRC = 0x00;
}
// configure receive descriptor register
ETH_RXDESC = (volatile uint32_t)&pxEthernetData->xRxDescr[0]; // start of rec data descr. table
ETH_RXSTAT = (volatile uint32_t)&pxEthernetData->xRxStat[0]; // start of rec status info table
ETH_RXDESCRNO = NUMBER_REC_FRAGMENTS -1; // number of descriptors -1
ETH_RXCONSIX = 0x00; // consumer index
// initialize transmit DMA
for( i=0; i < NUMBER_TX_FRAGMENTS; i++ )
{
pxEthernetData->xTxDescr[i].packet = &pxEthernetData->ucTxBuffer[i][0];
pxEthernetData->xTxDescr[i].control = 0x00;
pxEthernetData->xTxStat[i].status = 0x00;
}
// configure transmit descriptor register
ETH_TXDESC = (volatile uint32_t)&pxEthernetData->xTxDescr[0]; // start of transmit data table
ETH_TXSTAT = (volatile uint32_t)&pxEthernetData->xTxStat[0]; // start of transmit status table
ETH_TXDESCRNO = NUMBER_TX_FRAGMENTS -1; // number of descriptors -1
ETH_TXPRODIX = 0x00; // producer index
}
/****************************************************************************
* Name: prvReadPhyRegister
*
* Description: read a given register from phy ethernet
*
*
* Parameters: aPhyRegisterAdr
* address of the PHY register which is concatenated
* of device + register offset
*
* Return value: register value (32 Bits) or 0xFFFF if access fails
*
****************************************************************************
*/
static uint16_t prvReadPhyRegister( uint32_t aPhyRegisterAdr )
{
uint32_t aTimeout;
uint32_t aMII_Indicator;
uint16_t aRegisterValue = 0xFFFF;
ETH_MIIADR = aPhyRegisterAdr;
ETH_MIICMD = PHYREADCOMMAND;
/* Wait until operation completed */
for (aTimeout = 0; aTimeout < MII_COMMAND_TIMEOUT; aTimeout++)
{
aMII_Indicator = ETH_MIIIND;
if((aMII_Indicator & (0x01 << MII_IND_BUSY)) == 0)
{
aRegisterValue = (uint16_t)ETH_MIIRDD;
break;
}
}
ETH_MIICMD = 0x00;
return (aRegisterValue);
}
/****************************************************************************
* Name: prvWritePhyRegister
*
* Description: write valuie to a given register of ethernet-phy
*
*
* Parameters: aPhyRegisterAdr
* address of the PHY register which is concatenated
* of device + register offset
* aRegisterValue
* data to write
*
* Return value: 0x00 --> ok
* 0xFFFF --> fail
*
****************************************************************************
*/
static uint16_t prvWritePhyRegister( uint32_t aPhyRegisterAdr, uint16_t aRegisterValue )
{
uint32_t aTimeout;
uint32_t aMII_Indicator;
uint16_t ret = 0xFFFF;
ETH_MIIADR = aPhyRegisterAdr;
ETH_MIIWTD = aRegisterValue;
/* Wait until operation completed */
for (aTimeout = 0; aTimeout < MII_COMMAND_TIMEOUT; aTimeout++)
{
aMII_Indicator = ETH_MIIIND;
if((aMII_Indicator & ( 0x01 << MII_IND_BUSY)) == 0)
{
ret = 0x00;
break;
}
}
return (ret);
}
/****************************************************************************
* Name: prvConfigurePHY
*
* Description: configures the PHY registers according to
* settings in config.h
*
*
* Parameters: aPHYDevice
* address of the phy device in ETH
*
* Return value: extended Status register of DP83848C PHY
* indicates link status among others
*
****************************************************************************
*/
static uint16_t prvConfigurePHY(uint32_t aPHYDevice)
{
uint32_t phyAddress = aPHYDevice << 8;
uint32_t phyId = 0x00;
uint32_t aTimeout;
uint16_t basicModeStatus, extendedStatus, basicModeControl;
/* Put the DP83848C in reset mode */
prvWritePhyRegister (phyAddress | PHY_BMCR, 0x8000);
/* Wait for hardware reset to end. */
for (aTimeout = 0; aTimeout < PHY_RESET_TIMEOUT; aTimeout++)
{
basicModeControl = prvReadPhyRegister (phyAddress | PHY_BMCR);
if (!(basicModeControl & PHY_RESET))
{
/* Reset complete */
break;
}
}
// 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:
if( LOOPBACK)
prvWritePhyRegister( phyAddress | PHY_BMCR, PHY_FULLD_100M | PHY_LOOPBACK);
else
{
switch( PHYSPEED )
{
case AUTONEGOTIATION:
/* configure autonegotiation */
prvWritePhyRegister( phyAddress | PHY_BMCR, PHY_AUTO_NEG | PHY_RESTART_AUTON);
/* Wait to complete Auto_Negotiation. */
for (aTimeout = 0; aTimeout < MII_AUTONEG_TIMEOUT; aTimeout++)
{
basicModeStatus = prvReadPhyRegister (phyAddress | PHY_BMSR);
if (basicModeStatus & PHY_AUTO_DONE) // autonegotiation complete
break;
}
break;
case FDX_100:
prvWritePhyRegister( phyAddress | PHY_BMCR, PHY_FULLD_100M );
break;
case FDX_10:
prvWritePhyRegister( phyAddress | PHY_BMCR, PHY_FULLD_10M );
break;
case HDX_100:
prvWritePhyRegister( phyAddress | PHY_BMCR, PHY_HALFD_100M );
break;
case HDX_10:
prvWritePhyRegister( phyAddress | PHY_BMCR, PHY_HALFD_10M );
break;
default:
prvWritePhyRegister( phyAddress | PHY_BMCR, PHY_AUTO_NEG | PHY_RESTART_AUTON);
break;
}
}
/* Check the link status. */
for (aTimeout = 0; aTimeout < MII_LINKSTAT_TIMEOUT; aTimeout++)
{
extendedStatus = prvReadPhyRegister (phyAddress | PHY_STS);
if (extendedStatus & PHY_EXST_LINK_ESTABLISHED) // link status
break;
}
break;
default :
break;
}
return( extendedStatus);
}
/****************************************************************************
* Name: prvConfigureRxFilters
*
* Description: configure receive filtering
*
*
* Parameters: none
*
* Return value: none
*
****************************************************************************
*/
static void prvConfigureRxFilters(void)
{
if(ACCEPTUNICAST)
ETH_RXFILTERCTL = RFC_UCAST_EN; /* Accept Unicast Frames Enable */
if(ACCEPTBROADCAST)
ETH_RXFILTERCTL |= RFC_BCAST_EN; /* Accept Broadcast Frames Enable */
if(ACCEPTMULTICAST)
ETH_RXFILTERCTL |= RFC_MCAST_EN; /* Accept Multicast frames Enable */
if(ACCEPTPERFECT)
ETH_RXFILTERCTL |= RFC_PERFECT_EN; /* Accept Perfect Match Enable */
}
/****************************************************************************
* Name: vSetStationAddress
*
* Description: set the MAC address
*
*
* Parameters: pointer to byte array containing 6 bytes station address
*
* Return value: none
*
****************************************************************************
*/
void vEthSetStationAddress( uint8_t* pAddress)
{
ETH_SA0 = ( (uint32_t)pAddress[0] <<8) | (uint32_t)pAddress[1];
ETH_SA1 = ( (uint32_t)pAddress[2] <<8) | (uint32_t)pAddress[3];
ETH_SA2 = ( (uint32_t)pAddress[4] <<8) | (uint32_t)pAddress[5];
}
/****************************************************************************
* Name: vEthInit
*
* Description: Initialize
*
*
* Parameters: none
*
* Return value: TRUE --> driver successfully initialized, link established
* FALSE --> driver not initialized.
*
****************************************************************************
*/
bool eEthInit(void)
{
uint16_t aPhyStatus = 0x00;
uint8_t aMACAddress[6];
uint32_t Timeout;
/* initialize data to application (stack) */
prvInitAPI();
/* Power Up the ethernet MAC controller. */
PCONP |= PCON_ENET;
/* Ethernet port is GPIO_1 P1.0 up to P1.17
enable ethernet by switching to Pinfunction 2 = 01 */
#ifdef RMII_INTERFACE
/* P1.6, ETHERNET-TX_CLK, has to be set for ethernet module to address a BUG in
the engineering
version, even if this pin is not used for RMII interface. This bug has been fixed,
and this port pin can be used as GPIO pin in the future release.
Unfortunately, this MCB2300 board still has the old eng. version LPC23xx chip
on it. */
PINSEL2 = 0x50151105; /* selects P1[0,1,4,8,9,10,14,15] */
PINSEL3 = 0x00000005; /* selects P1[17:16] */
#elif
PINSEL2 = 0x55555555; /* selects P1[15:0] */
PINSEL3 = (PINSEL3 & ~0x0000000F) | 0x00000005; /* selects P1[17:16] */
#endif
/* Reset all MAC internal modules. */
ETH_MAC1 = MAC1_RES_TX | MAC1_RES_MCS_TX | MAC1_RES_RX | MAC1_RES_MCS_RX |
MAC1_SIM_RES | MAC1_SOFT_RES;
/* reset all datapaths and the host registers */
ETH_COMMAND = CR_REG_RES | CR_TX_RES | CR_RX_RES;
/* A short delay after reset. */
for (Timeout = 200; Timeout; Timeout--);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -