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

Revision:
3:342aa2cf54e8
Parent:
1:d13a0eb82022
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ethmac.cpp	Fri Jan 04 16:44:27 2013 +0000
@@ -0,0 +1,391 @@
+/******************************************************************
+ *****                                                        *****
+ *****  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);
+}