LPC1768 Mini-DK EasyWeb application with SPI TFT output. Started from EasyWebCR and modified for DM9161 PHY support.
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); }