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

📄 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/iolpc2378.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;

/******************************************************************************
** 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;

#if RMII
  /* RMII configuration */
  MCFG = 0x0018;	/* host clock divided by 20, no suppress preamble, no scan increment */
  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;
#else
  COMMAND &= ~0x0200;
  SUPP = 0x0000;
#endif

  /* Find PHY Address, because controller have pull-up and PHY have pull-down resistors
     on RXD lines some times PHY latch different addresses - 0x01, 0x19, 0x09, 0x17 */

  for(PhyAddr = (1UL << 8); PhyAddr < (32UL << 8); PhyAddr += (1UL << 8))
  {
    /* check PHY IDs to make sure the reset takes place and PHY
    is in its default state. See Micrel PHY KS8721 Users Manual
    for more details */
    regValue = ReadPHY( PHY_PHYIDR1 );
    if ( (regValue & 0xFFFF) != 0x0022 )
    {
      continue;
    }

    regValue = ReadPHY( PHY_PHYIDR2 );
    if ( (regValue & 0xFFFF) == 0x1619 )
    {
      break;
    }
  }

  if(PhyAddr == (32UL << 8))
  {
    // Can't find Micrel PHY
    return( FALSE );
  }


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

  timeout = MII_BMSR_TIMEOUT;
  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 );
  }

  if(ReadPHY( PHY_BMSR ) & BMSR_PREAMBLE_SUPP)
  {
    // PHY support preamble suppression
    MCFG |= 1 << 1;
  }

#if AUTO_NEGOTIATION_ENA != 0
  /* set Auto-Negotiation Advertisement Register
     a valid 802.3 selector field, 100 HD, 100 FD, 10 HD, 10 FD */
  WritePHY( PHY_ANAR, 0x01E1 );

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

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

  /* Link established from here on */
  regValue = ReadPHY( PHY_PHYCR );
  switch(regValue & PHYCR_MODE)
  {
  case 0x04:  // 10 BASE T Half-duplex
    Speed = SPEED_10;
    Duplex = HALF_DUPLEX;
    break;
  case 0x08:  // 100 BASE TX Half-duplex
    Speed = SPEED_100;
    Duplex = HALF_DUPLEX;
    break;
  case 0x14: // 10 BASE T Full-duplex
    Speed = SPEED_10;
    Duplex = FULL_DUPLEX;
    break;
  case 0x18: // 100 BASE TX Full-duplex
    Speed = SPEED_100;
    Duplex = FULL_DUPLEX;
    break;
  default:
    return ( FALSE );
  }
#else
  /* Set fixed Speed and Duplex settings */
  WritePHY( PHY_BMCR, ((FIX_SPEED == SPEED_100)?BMCR_SPEED_100:0) |
                      ((FIX_DUPLEX == FULL_DUPLEX)?BMCR_DUPLEX:0));
  timeout = MII_BMSR_TIMEOUT;
  while ( timeout != 0 )
  {
    regValue = ReadPHY( PHY_BMSR );
    if (regValue & BMSR_LINK_ESTABLISHED)
    {
      break;    /* link established if bit 0 is set */
    }
    timeout--;
  }

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

  Speed = FIX_SPEED;
  Duplex = FIX_DUPLEX;
#endif // AUTO_NEGOTIATION_ENA != 0

  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]
  *-----------------------------------------------------------------------------*/
  /* documentation needs to be updated */
#if RMII
  // Pins assignment
  //------------------------------------------------------
  // 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 + -