⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 emac.c

📁 NXP LPC系列AMR7的开发程序源码(LCD
💻 C
字号:
/*****************************************************************************
 *   emac.c:  Ethernet module file for NXP LPC230x Family Microprocessors
 *
 *   Copyright(C) 2006, NXP Semiconductor
 *   All rights reserved.
 *
 *   History
 *   2006.09.01  ver 1.00    Prelimnary version, first Release
 *
******************************************************************************/
#include <nxp/iolpc2468.h>
#include "type.h"
#include "irq.h"
#include "emac.h"

#include <intrinsics.h>

volatile DWORD Duplex;
volatile DWORD Speed;

volatile DWORD RXOverrunCount = 0;
volatile DWORD RXErrorCount = 0;

volatile DWORD TXUnderrunCount = 0;
volatile DWORD TXErrorCount = 0;
volatile DWORD RxFinishedCount = 0;
volatile DWORD TxFinishedCount = 0;
volatile DWORD TxDoneCount = 0;
volatile DWORD RxDoneCount = 0;

volatile DWORD CurrentRxPtr = EMAC_RX_BUFFER_ADDR;
volatile DWORD ReceiveLength = 0;
volatile DWORD PacketReceived = FALSE;

#if ENABLE_WOL
volatile DWORD WOLCount = 0;
volatile DWORD WOLArrived = FALSE;
#endif

static DWORD PhyAddr = (1<<8); /* in MAC_MADR, bit 8~12 */

/******************************************************************************
** Function name:   EMAC_TxEnable/EMAC_TxDisable
**
** Descriptions:    EMAC TX API modules
**
** parameters:      None
** Returned value:    None
**
******************************************************************************/
void EMAC_TxEnable( void )
{
  COMMAND |= 0x02;
  return;
}

void EMAC_TxDisable( void )
{
  COMMAND &= ~0x02;
  return;
}

/******************************************************************************
** Function name:   EMAC_RxEnable/EMAC_RxDisable
**
** Descriptions:    EMAC RX API modules
**
** parameters:      None
** Returned value:    None
**
******************************************************************************/
void EMAC_RxEnable( void )
{
  COMMAND |= 0x01;
  MAC1 |= 0x01;
  return;
}

void EMAC_RxDisable( void )
{
  COMMAND &= ~0x01;
  MAC1 &= ~0x01;
  return;
}

/******************************************************************************
** Function name:   EMACHandler
**
** Descriptions:    EMAC interrupt handler
**
** parameters:      None
** Returned value:    None
**
******************************************************************************/
__irq __nested __arm void EMACHandler (void)
{
volatile DWORD IntStatus;
DWORD *rxptr;

  __enable_interrupt(); /* handles nested interrupt */

  IntStatus = INTSTATUS;
  if ( IntStatus != 0 ) /* At least one interrupt */
  {
#if ENABLE_WOL
    if ( IntStatus & EMAC_INT_WOL )
    {
      INTCLEAR = EMAC_INT_WOL;
      WOLCount++;
      WOLArrived = TRUE;
      /* the packet will be lost, no need to anything else, bail out */
      VICAddress = 0;    /* Acknowledge Interrupt */
      return;
    }
#endif
    if ( IntStatus & EMAC_INT_RXOVERRUN )
    {
      INTCLEAR = EMAC_INT_RXOVERRUN;
      RXOverrunCount++;
      VICADDRESS = 0; /* Acknowledge Interrupt */
      return;
    }

    if ( IntStatus & EMAC_INT_RXERROR )
    {
      INTCLEAR = EMAC_INT_RXERROR;
      RXErrorCount++;
      VICADDRESS = 0; /* Acknowledge Interrupt */
      return;
    }

    if ( IntStatus & EMAC_INT_RXFINISHED )
    {
      INTCLEAR = EMAC_INT_RXFINISHED;
      RxFinishedCount++;
      /* Below should never happen or RX is seriously wrong */
      while ( RXPRODUCEINDEX != (RXCONSUMEINDEX - 1) );
    }

    if ( IntStatus & EMAC_INT_RXDONE )
    {
      INTCLEAR = EMAC_INT_RXDONE;
      ReceiveLength = EMACReceive( rxptr );
      PacketReceived = TRUE;
      RxDoneCount++;
    }

    if ( IntStatus & EMAC_INT_TXUNDERRUN )
    {
      INTCLEAR = EMAC_INT_TXUNDERRUN;
      TXUnderrunCount++;
      VICADDRESS = 0; /* Acknowledge Interrupt */
      return;
    }

    if ( IntStatus & EMAC_INT_TXERROR )
    {
      INTCLEAR = EMAC_INT_TXERROR;
      TXErrorCount++;
      VICADDRESS = 0; /* Acknowledge Interrupt */
      return;
    }

    if ( IntStatus & EMAC_INT_TXFINISHED )
    {
      INTCLEAR = EMAC_INT_TXFINISHED;
      TxFinishedCount++;
    }

    if ( IntStatus & EMAC_INT_TXDONE )
    {
      INTCLEAR = EMAC_INT_TXDONE;
      TxDoneCount++;
    }
  }

  VICADDRESS = 0;                   /* Acknowledge Interrupt */
  return;
}

/*****************************************************************************
** Function name:   WritePHY
**
** Descriptions:    Write Data to the PHY port
**
** parameters:      PHY register, write data
** Returned value:    None
**
*****************************************************************************/
void WritePHY( DWORD PHYReg, DWORD PHYData )
{
  MADR = PhyAddr | PHYReg; /* [12:8] == PHY addr, [4:0]=0x00(BMCR) register addr */
  MCMD = 0x0000;      /* write command */
  MWTD = PHYData;
  while ( MIND_bit.BUSY );
  return;
}

/*****************************************************************************
** Function name:   ReadPHY
**
** Descriptions:    Read data from the PHY port
**
** parameters:      PHY register
** Returned value:    PHY data
**
*****************************************************************************/
DWORD ReadPHY( DWORD PHYReg )
{
  MADR = PhyAddr | PHYReg; /* [12:8] == PHY addr, [4:0]=0x00(BMCR) register addr */
  MCMD = 0x0001;      /* read command */
  while ( MIND_bit.BUSY || MIND_bit.NOT_VALID );
  MCMD = 0x0000;
  return( MRDD );
}

/*****************************************************************************
** Function name:   PHYInit
**
** Descriptions:    initialize PHY port
**
** parameters:      None
** Returned value:    None
**
*****************************************************************************/
DWORD PHYInit( void )
{

DWORD i, regValue;
DWORD timeout;

  /* MII configuration, I may just need to do either RMII or MII configuration, not both. */
  MCFG = 0x0018;	/* host clock divided by 20, no suppress preamble, no scan increment */

  /* RMII configuration */
  COMMAND |= 0x0200;
  SUPP = 0x8900;  /* RMII setting, Reset MII Management hardware,
                     PHY support: [8]=0 ->10 Mbps mode, =1 -> 100 Mbps mode */
  /*  (note bit 4 was set in original test, although spec says its unused) */
  for ( i = 0; i < 0x20; i++ );	/* short delay */
  SUPP = 0x0100;

  WritePHY( PHY_BMCR, BMCR_RESET );
  for ( i = 0; i < 0x20; i++ );	/* short delay */

  timeout = MII_BMSR_TIMEOUT * 4;
  while ( timeout != 0 )
  {
    regValue = ReadPHY( PHY_BMCR );
    if ( (regValue & BMCR_RESET) == 0x0000 )	
    {
      break;		/* Reset self cleaned once the reset process is complete */	
    }
    timeout--;	
  }
  if ( timeout == 0 )
  {
    return ( FALSE );
  }

  /* check PHY IDs to make sure the reset takes place and PHY
  is in its default state. See National PHY DP83848 Users Manual
  for more details */
  regValue = ReadPHY( PHY_PHYIDR1 );
  if ( (regValue & 0x2000) != 0x2000 )
  {
    return ( FALSE );
  }

  regValue = ReadPHY( PHY_PHYIDR2 );
  if ( (regValue & 0x5C90) != 0x5C90 )
  {
    return ( FALSE );
  }

  WritePHY( PHY_BMCR, BMCR_AN | BMCR_RE_AN ); /* auto negotiation, restart AN */
  timeout = MII_BMSR_TIMEOUT;
  while ( timeout != 0 )
  {
    regValue = ReadPHY( PHY_PHYSTS );
    if ( (regValue & 0x0011) == 0x0011 )	
    {
      break;		/* link established if bit 0 is set */
    }
    timeout--;
  }

  if ( timeout == 0 )
  {
    return ( FALSE );
  }

  /* Link established from here on */
  if ( regValue & 0x04 )
    Duplex = FULL_DUPLEX;
  else
    Duplex = HALF_DUPLEX;

  if ( regValue & 0x02 )
    Speed = SPEED_10;
  else
    Speed = SPEED_100;

  return ( TRUE );
}

/*****************************************************************************
** Function name:   EMACTxDesciptorInit
**
** Descriptions:    initialize EMAC TX descriptor table
**
** parameters:      None
** Returned value:    None
**
*****************************************************************************/
void EMACTxDescriptorInit( void )
{
DWORD i;
DWORD *tx_desc_addr, *tx_status_addr;

  /*-----------------------------------------------------------------------------
  * setup the Tx status,descriptor registers --
  * Note, the actual tx packet data is loaded into the ahb2_sram16k memory as part
  * of the simulation
  *----------------------------------------------------------------------------*/
  TXDESCRIPTOR = TX_DESCRIPTOR_ADDR;  /* Base addr of tx descriptor array */
  TXSTATUS = TX_STATUS_ADDR;    /* Base addr of tx status */
  TXDESCRIPTORNUMBER = EMAC_TX_DESCRIPTOR_COUNT - 1;  /* number of tx descriptors, 16 */

  for ( i = 0; i < EMAC_TX_DESCRIPTOR_COUNT; i++ )
  {
    tx_desc_addr = (DWORD *)(TX_DESCRIPTOR_ADDR + i * 8); /* two words at a time, packet and control */
    *tx_desc_addr = (DWORD)(EMAC_TX_BUFFER_ADDR + i * EMAC_BLOCK_SIZE);
    *(tx_desc_addr+1) = (DWORD)(EMAC_TX_DESC_INT | (EMAC_BLOCK_SIZE - 1));  /* set size only */
  }

  for ( i = 0; i < EMAC_TX_DESCRIPTOR_COUNT; i++ )
  {
    tx_status_addr = (DWORD *)(TX_STATUS_ADDR + i * 4); /* TX status, one word only, status info. */
    *tx_status_addr = (DWORD)0;   /* initially, set status info to 0 */
  }
  TXPRODUCEINDEX = 0x0; /* TX descriptors point to zero */
  return;
}

/*****************************************************************************
** Function name:   EMACRxDesciptorInit
**
** Descriptions:    initialize EMAC RX descriptor table
**
** parameters:      None
** Returned value:    None
**
*****************************************************************************/
void EMACRxDescriptorInit( void )
{
DWORD i;
DWORD *rx_desc_addr, *rx_status_addr;

  /*-----------------------------------------------------------------------------
  * setup the Rx status,descriptor registers --
  * Note, the actual rx packet data is loaded into the ahb2_sram16k memory as part
  * of the simulation
  *----------------------------------------------------------------------------*/
  RXDESCRIPTOR = RX_DESCRIPTOR_ADDR;  /* Base addr of rx descriptor array */
  RXSTATUS = RX_STATUS_ADDR;      /* Base addr of rx status */
  RXDESCRIPTORNUMBER = EMAC_RX_DESCRIPTOR_COUNT - 1;  /* number of rx descriptors, 16 */

  for ( i = 0; i < EMAC_RX_DESCRIPTOR_COUNT; i++ )
  {
    /* two words at a time, packet and control */
    rx_desc_addr = (DWORD *)(RX_DESCRIPTOR_ADDR + i * 8);
    *rx_desc_addr = (DWORD)(EMAC_RX_BUFFER_ADDR + i * EMAC_BLOCK_SIZE);
    *(rx_desc_addr+1) = (DWORD)(EMAC_RX_DESC_INT | (EMAC_BLOCK_SIZE - 1));  /* set size only */
  }

  for ( i = 0; i < EMAC_RX_DESCRIPTOR_COUNT; i++ )
  {
    /* RX status, two words, status info. and status hash CRC. */
    rx_status_addr = (DWORD *)(RX_STATUS_ADDR + i * 8);
    *rx_status_addr = (DWORD)0; /* initially, set both status info and hash CRC to 0 */
    *(rx_status_addr+1) = (DWORD)0;
  }
  RXCONSUMEINDEX = 0x0; /* RX descriptor points to zero */
  return;
}

/*****************************************************************************
** Function name:   EMACInit
**
** Descriptions:    initialize EMAC port
**
** parameters:      None
** Returned value:    None
**
*****************************************************************************/
DWORD EMACInit( void )
{

DWORD regVal;
DWORD i;

  /* turn on the ethernet MAC clock in PCONP, bit 30 */
  regVal = PCONP;
  regVal |= PCONP_EMAC_CLOCK;
  PCONP = regVal;

  /*------------------------------------------------------
  * Write to PINSEL2/3 to select the PHY functions on P1[17:0]
  * P1.6, ENET-TX_CLK, has to be set for Rev '-' devices and it
  * must not be set for Rev 'A

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -