LPC1768 Mini-DK EasyWeb application with SPI TFT output. Started from EasyWebCR and modified for DM9161 PHY support.

Dependencies:   Mini-DK mbed

This is a very basic EasyWeb application.

No error checking is performed during initialisation.

Information

If the webpage is not reachable or the 'Webserver running' message does not appear, press the reset button on the Mini-DK and wait until the message 'Webserver running' appears.
This happens sometimes when powering up the Mini-DK because the DM9161 reset pin is NOT controlled by the LPC1768, it is directly connected to the reset button.

IP adress/mask/gateway in tcpip.h : 192.168.0.200 / 255.255.255.0 / 192.168.0.1

MAC address in ethmac.h : 6-5-4-3-2-1

ethmac.cpp

Committer:
frankvnk
Date:
2013-01-15
Revision:
8:4c3db9231e3f
Parent:
3:342aa2cf54e8

File content as of revision 8:4c3db9231e3f:

/******************************************************************
 *****                                                        *****
 *****  Name: ethmac.c                                        *****
 *****  Ver.: 1.0                                             *****
 *****  Date: 17/12/2012                                      *****
 *****  Auth: Frank Vannieuwkerke                             *****
 *****  Func: ethernet packet-driver for use with LAN-        *****
 *****        controller DM9161                               *****
 *****        Rewrite from Andreas Dannenberg                 *****
 *****                     HTWK Leipzig                       *****
 *****                     university of applied sciences     *****
 *****                     Germany                            *****
 *****                     adannenb@et.htwk-leipzig.de        *****
 *****                                                        *****
 ******************************************************************/
/*
NOTES:
------
- WriteToPHY and ReadFromPHY don't signal error status.
  (ReadFromPHY only returns value on success)
  Possible improvement : if status = OK  - return(0) for Write
                         if status = NOK - return(-1) for Write and Read
*/
#include "mbed.h"
#include "ethmac.h"
#include "tcpip.h"

/* MII Mgmt Configuration register - Clock divider setting */
const uint8_t EMAC_clkdiv[] = { 4, 6, 8, 10, 14, 20, 28, 36, 40, 44, 48, 52, 56, 60, 64 };

// static pointers for receive and transmit
static unsigned short *rxptr;
static unsigned short *txptr;

// write to external ethernet PHY chip
void WriteToPHY (int reg, int writeval)
{
  unsigned int loop;
  // Set up address to access in MII Mgmt Address Register
  LPC_EMAC->MADR = DM9161_DEF_ADR | reg;
  // Write value into MII Mgmt Write Data Register
  LPC_EMAC->MWTD = writeval;
  // Loop whilst write to PHY completes
  for (loop = 0; loop < MII_WR_TOUT; loop++) {
    if ((LPC_EMAC->MIND & MIND_BUSY) == 0) { break; }
  }
}

// read from external ethernet PHY chip
unsigned short ReadFromPHY (unsigned char reg) 
{
  unsigned int loop;
  // Set up address to access in MII Mgmt Address Register
  LPC_EMAC->MADR = DM9161_DEF_ADR | reg;
  // Trigger a PHY read via MII Mgmt Command Register
  LPC_EMAC->MCMD = MCMD_READ;
  // Loop whilst read from PHY completes
  for (loop = 0; loop < MII_RD_TOUT; loop++) {
    if ((LPC_EMAC->MIND & MIND_BUSY) == 0)  { break; }
  }
  LPC_EMAC->MCMD = 0; // Cancel read
  // Returned value is in MII Mgmt Read Data Register
  return (LPC_EMAC->MRDD);
}

void Init_EthMAC(void)
{
  unsigned int loop, value, phyid1, phyid2;
  
  unsigned phy_in_use = 0;
  
  // Set Ethernet power/clock control bit
  LPC_SC->PCONP |= PCENET; 

  //Enable Ethernet pins through PINSEL registers
  LPC_PINCON->PINSEL2 = ENET_PINSEL2_CONFIG; 
  LPC_PINCON->PINSEL3 = (LPC_PINCON->PINSEL3 & ~(ENET_PINSEL3_MASK)) | ENET_PINSEL3_CONFIG;

  // Set up MAC Configuration Register 1
  LPC_EMAC->MAC1 = MAC1_RES_TX | MAC1_RES_MCS_TX | MAC1_RES_RX | 
         MAC1_RES_MCS_RX |MAC1_SIM_RES | MAC1_SOFT_RES;

  // Set up MAC Command Register
  LPC_EMAC->Command = CR_REG_RES | CR_TX_RES | CR_RX_RES | CR_PASS_RUNT_FRM;
  
  // Short delay
  for (loop = 100; loop; loop--);

  // Set up MAC Configuration Register 1 to pass all receive frames
  LPC_EMAC->MAC1 = MAC1_PASS_ALL;
  // Set up MAC Configuration Register 2 to append CRC and pad out frames
  LPC_EMAC->MAC2 = MAC2_CRC_EN | MAC2_PAD_EN;
  // Set Ethernet Maximum Frame Register
  LPC_EMAC->MAXF = ETH_MAX_FLEN;
  // Set Collision Window / Retry Register
  LPC_EMAC->CLRT = CLRT_DEF;
  // Set Non Back-to-Back Inter-Packet-Gap Register
  LPC_EMAC->IPGR = IPGR_DEF;

  // Find the clock closest to desired target clock
  value = SystemCoreClock / MCFG_MII_MAXCLK;
  for (loop = 0; loop < sizeof (EMAC_clkdiv); loop++)
  {
      if (EMAC_clkdiv[loop] >= value) break;
  }
  loop++;
  // Write to MAC configuration register and reset
  LPC_EMAC->MCFG = MCFG_CLK_SEL(loop) | MCFG_RES_MII;

  // release reset
  LPC_EMAC->MCFG &= ~(MCFG_RES_MII);
  LPC_EMAC->CLRT = CLRT_DEF;
  LPC_EMAC->IPGR = IPGR_DEF;

  // Set MAC Command Register to enable Reduced MII interface
  // and prevent runt frames being filtered out
  LPC_EMAC->Command = CR_RMII | CR_PASS_RUNT_FRM;
//  LPC_EMAC->Command = CR_RMII | CR_PASS_RUNT_FRM | CR_PASS_RX_FILT;

  /* Reset Reduced MII Logic. */
  LPC_EMAC->SUPP = SUPP_RES_RMII;
  for (loop = 100; loop; loop--);
  LPC_EMAC->SUPP = 0;

  // Put DM9161 PHY into reset mode
  WriteToPHY (PHY_REG_BMCR, DM9161_RESET);

  // Loop until hardware reset completes
  for (loop = 0; loop < PHY_RESP_TOUT; loop++)
  {
    value = ReadFromPHY (PHY_REG_BMCR);
    if (!(value & DM9161_RESET))
    {
      // Reset has completed
      break;
    }
  }
  // Just check this actually is a DM9161 PHY
  phyid1 = ReadFromPHY (PHY_REG_IDR1);
  phyid2 = ReadFromPHY (PHY_REG_IDR2);

if (((phyid1 << 16) | (phyid2 & 0xFFF0)) == DM9161_ID)
    {
        phy_in_use = DM9161_ID;
    }

  if (phy_in_use != 0)
  {      
    // Safe to configure the PHY device
    // Set PHY to autonegotiation link speed
//    WriteToPHY (PHY_REG_BMCR, (DM9161_AUTONEG|DM9161_RESTART_AUTONEG));
    WriteToPHY (PHY_REG_BMCR, DM9161_AUTONEG | DM9161_SPEED_SELECT);
    // loop until autonegotiation completes
    for (loop = 0; loop < PHY_RESP_TOUT; loop++)
    {
      value = ReadFromPHY (PHY_REG_BMSR);
      if (value & DM9161_AUTONEG_COMP)
      {
        // Autonegotiation has completed
        break;
      }
    }
  }

  // Now check the link status
  for (loop = 0; loop < PHY_RESP_TOUT; loop++)
  {
    value = ReadFromPHY (PHY_REG_DSCSR);
    if ((value & DM9161_100FDX)||(value & DM9161_100HDX)||(value & DM9161_10FDX)||(value & DM9161_10HDX))
    {
      // The link is on
      break;
    }
  }

  // Now configure for 10/100Mbit and full/half duplex mode 
  if (value & DM9161_100FDX)
  {
      LPC_EMAC->MAC2    |= MAC2_FULL_DUP;
      LPC_EMAC->Command |= CR_FULL_DUP;
      LPC_EMAC->IPGT     = IPGT_FULL_DUP;
      LPC_EMAC->SUPP     = SUPP_SPEED;
      WriteToPHY (PHY_REG_BMCR, PHY_FULLD_100M);
  }
  else if (value & DM9161_100HDX)
  {
      LPC_EMAC->IPGT     = IPGT_HALF_DUP;
      LPC_EMAC->SUPP     = SUPP_SPEED;
      WriteToPHY (PHY_REG_BMCR, PHY_HALFD_100M);
  }
  else if (value & DM9161_10FDX)
  {
      LPC_EMAC->MAC2    |= MAC2_FULL_DUP;
      LPC_EMAC->Command |= CR_FULL_DUP;
      LPC_EMAC->IPGT     = IPGT_FULL_DUP;
      LPC_EMAC->SUPP     = 0;
      WriteToPHY (PHY_REG_BMCR, PHY_FULLD_10M);
  }
  else if (value & DM9161_10HDX)
  {
      LPC_EMAC->IPGT     = IPGT_HALF_DUP;
      LPC_EMAC->SUPP     = 0;
      WriteToPHY (PHY_REG_BMCR, PHY_HALFD_10M);
  }

  // Now set the Ethernet MAC Address registers
  // NOTE - MAC address must be unique on the network!
  LPC_EMAC->SA0 = (MYMAC_1 << 8) | MYMAC_2; // Station address 0 Reg
  LPC_EMAC->SA1 = (MYMAC_3 << 8) | MYMAC_4; // Station address 1 Reg
  LPC_EMAC->SA2 = (MYMAC_5 << 8) | MYMAC_6; // Station address 2 Reg

 
  // Now initialise the Rx descriptors    
  for (loop = 0; loop < NUM_RX_FRAG; loop++)
  {
    RX_DESC_PACKET(loop)  = RX_BUF(loop);
    RX_DESC_CTRL(loop)    = RCTRL_INT | (ETH_FRAG_SIZE-1);
    RX_STAT_INFO(loop)    = 0;
    RX_STAT_HASHCRC(loop) = 0;
  }

  // Set up the Receive Descriptor Base address register
  LPC_EMAC->RxDescriptor    = RX_DESC_BASE;
  // Set up the Receive Status Base address register
  LPC_EMAC->RxStatus        = RX_STAT_BASE;
  // Setup the Receive Number of Descriptor register
  LPC_EMAC->RxDescriptorNumber = NUM_RX_FRAG-1;
  //  Set Receive Consume Index register to 0
  LPC_EMAC->RxConsumeIndex  = 0;

  // Now initialise the Tx descriptors 
  for (loop = 0; loop < NUM_TX_FRAG; loop++)
  {
    TX_DESC_PACKET(loop) = TX_BUF(loop);
    TX_DESC_CTRL(loop)   = 0;
    TX_STAT_INFO(loop)   = 0;
  }

  // Set up the Transmit Descriptor Base address register
  LPC_EMAC->TxDescriptor    = TX_DESC_BASE;
  // Set up the Transmit Status Base address register
  LPC_EMAC->TxStatus        = TX_STAT_BASE;
  // Setup the Transmit Number of Descriptor register
  LPC_EMAC->TxDescriptorNumber = NUM_TX_FRAG-1;
  //  Set Transmit Consume Index register to 0
  LPC_EMAC->TxProduceIndex  = 0;
 
  // Receive Broadcast and Perfect Match Packets
  LPC_EMAC->RxFilterCtrl = RFC_MCAST_EN | RFC_BCAST_EN | RFC_PERFECT_EN;                     
 
  // Enable interrupts MAC Module Control Interrupt Enable Register
  LPC_EMAC->IntEnable = INT_RX_DONE | INT_TX_DONE;

  // Reset all ethernet interrupts in MAC module
  LPC_EMAC->IntClear  = 0xFFFF;

  // Finally enable receive and transmit mode in ethernet core
  LPC_EMAC->Command  |= (CR_RX_EN | CR_TX_EN);
  LPC_EMAC->MAC1     |= MAC1_REC_EN;
}


// writes a word in little-endian byte order to TX_BUFFER
void WriteFrame_EthMAC(unsigned short Data)
{
  *txptr++ = Data;
}

// copies bytes from MCU-memory to frame port
// NOTES: * an odd number of byte may only be transfered
//          if the frame is written to the end!
//        * MCU-memory MUST start at word-boundary
void CopyToFrame_EthMAC(void *Source, unsigned int Size)
{
  unsigned int index;
  unsigned short *pSource;

  pSource = (unsigned short *)Source;
  Size = (Size + 1) & 0xFFFE;    // round up Size to next even number
  while (Size > 0)
  {
    WriteFrame_EthMAC(*pSource++);
    Size -= 2;
  }

  index = LPC_EMAC->TxProduceIndex;
  if (++index == NUM_TX_FRAG)
    index = 0;
  LPC_EMAC->TxProduceIndex = index;
}

// reads a word in little-endian byte order from RX_BUFFER
unsigned short ReadFrame_EthMAC(void)
{
  return (*rxptr++);
}


// reads a word in big-endian byte order from RX_FRAME_PORT
unsigned short ReadFrameBE_EthMAC(void)
{
  unsigned short ReturnValue;

  ReturnValue = SwapBytes (*rxptr++);
  return (ReturnValue);
}

// copies bytes from frame port to MCU-memory
// NOTES: * an odd number of byte may only be transfered
//          if the frame is read to the end!
//        * MCU-memory MUST start at word-boundary
void CopyFromFrame_EthMAC(void *Dest, unsigned short Size)
{
  unsigned short *pDest; 

  pDest = (unsigned short *)Dest;
  while (Size > 1)
  {
    *pDest++ = ReadFrame_EthMAC();
    Size -= 2;
  }

  if (Size)
  {                                                     // check for leftover byte...
    *(unsigned char *)pDest = (char)ReadFrame_EthMAC(); // the LAN-Controller will return 0
  }                                                     // for the highbyte
}



// does a dummy read on frame-I/O-port
// NOTE: only an even number of bytes is read!
void DummyReadFrame_EthMAC(unsigned short Size)       // discards an EVEN number of bytes
{                                                     // from RX-fifo
  while (Size > 1)
  {
    ReadFrame_EthMAC();
    Size -= 2;
  }
}

// requests space in PHY on-chip memory for
// storing an outgoing frame
void RequestSend(unsigned short FrameSize)
{
  unsigned int index;
  index  = LPC_EMAC->TxProduceIndex;
  txptr = (unsigned short *)TX_DESC_PACKET(index);
  TX_DESC_CTRL(index) = FrameSize | TCTRL_LAST;
}

// check if PHY is ready to accept the
// frame we want to send
unsigned int Rdy4Tx(void)
{
  // One the LPC the ethernet controller transmits
  // much faster than the CPU can load its buffers
  // so will always be ready to accept frame    
  return (1); 
}

// Reads  length of received ethernet frame and checks
// if destination address is a broadcast message or not.
// Then returns the frame length
unsigned short StartReadingFrame(void)
{
  unsigned short ReceiveLength;
  unsigned int index;

  index = LPC_EMAC->RxConsumeIndex;
  ReceiveLength = (RX_STAT_INFO(index) & RINFO_SIZE) - 3;
  rxptr = (unsigned short *)RX_DESC_PACKET(index);
  return(ReceiveLength);
}

void StopReadingFrame(void)
{
  unsigned int index;
  index = LPC_EMAC->RxConsumeIndex;
  if (++index == NUM_RX_FRAG) index = 0;
  LPC_EMAC->RxConsumeIndex = index;
}

// check if frame has been received
unsigned int CheckIfFrameReceived(void)
{ 
  if (LPC_EMAC->RxProduceIndex != LPC_EMAC->RxConsumeIndex) 
    return(1); // Yes, packet received
  else 
    return(0);
}