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

Dependencies:   Mini-DK mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ethmac.cpp Source File

ethmac.cpp

00001 /******************************************************************
00002  *****                                                        *****
00003  *****  Name: ethmac.c                                        *****
00004  *****  Ver.: 1.0                                             *****
00005  *****  Date: 17/12/2012                                      *****
00006  *****  Auth: Frank Vannieuwkerke                             *****
00007  *****  Func: ethernet packet-driver for use with LAN-        *****
00008  *****        controller DM9161                               *****
00009  *****        Rewrite from Andreas Dannenberg                 *****
00010  *****                     HTWK Leipzig                       *****
00011  *****                     university of applied sciences     *****
00012  *****                     Germany                            *****
00013  *****                     adannenb@et.htwk-leipzig.de        *****
00014  *****                                                        *****
00015  ******************************************************************/
00016 /*
00017 NOTES:
00018 ------
00019 - WriteToPHY and ReadFromPHY don't signal error status.
00020   (ReadFromPHY only returns value on success)
00021   Possible improvement : if status = OK  - return(0) for Write
00022                          if status = NOK - return(-1) for Write and Read
00023 */
00024 #include "mbed.h"
00025 #include "ethmac.h"
00026 #include "tcpip.h"
00027 
00028 /* MII Mgmt Configuration register - Clock divider setting */
00029 const uint8_t EMAC_clkdiv[] = { 4, 6, 8, 10, 14, 20, 28, 36, 40, 44, 48, 52, 56, 60, 64 };
00030 
00031 // static pointers for receive and transmit
00032 static unsigned short *rxptr;
00033 static unsigned short *txptr;
00034 
00035 // write to external ethernet PHY chip
00036 void WriteToPHY (int reg, int writeval)
00037 {
00038   unsigned int loop;
00039   // Set up address to access in MII Mgmt Address Register
00040   LPC_EMAC->MADR = DM9161_DEF_ADR | reg;
00041   // Write value into MII Mgmt Write Data Register
00042   LPC_EMAC->MWTD = writeval;
00043   // Loop whilst write to PHY completes
00044   for (loop = 0; loop < MII_WR_TOUT; loop++) {
00045     if ((LPC_EMAC->MIND & MIND_BUSY) == 0) { break; }
00046   }
00047 }
00048 
00049 // read from external ethernet PHY chip
00050 unsigned short ReadFromPHY (unsigned char reg) 
00051 {
00052   unsigned int loop;
00053   // Set up address to access in MII Mgmt Address Register
00054   LPC_EMAC->MADR = DM9161_DEF_ADR | reg;
00055   // Trigger a PHY read via MII Mgmt Command Register
00056   LPC_EMAC->MCMD = MCMD_READ;
00057   // Loop whilst read from PHY completes
00058   for (loop = 0; loop < MII_RD_TOUT; loop++) {
00059     if ((LPC_EMAC->MIND & MIND_BUSY) == 0)  { break; }
00060   }
00061   LPC_EMAC->MCMD = 0; // Cancel read
00062   // Returned value is in MII Mgmt Read Data Register
00063   return (LPC_EMAC->MRDD);
00064 }
00065 
00066 void Init_EthMAC(void)
00067 {
00068   unsigned int loop, value, phyid1, phyid2;
00069   
00070   unsigned phy_in_use = 0;
00071   
00072   // Set Ethernet power/clock control bit
00073   LPC_SC->PCONP |= PCENET; 
00074 
00075   //Enable Ethernet pins through PINSEL registers
00076   LPC_PINCON->PINSEL2 = ENET_PINSEL2_CONFIG; 
00077   LPC_PINCON->PINSEL3 = (LPC_PINCON->PINSEL3 & ~(ENET_PINSEL3_MASK)) | ENET_PINSEL3_CONFIG;
00078 
00079   // Set up MAC Configuration Register 1
00080   LPC_EMAC->MAC1 = MAC1_RES_TX | MAC1_RES_MCS_TX | MAC1_RES_RX | 
00081          MAC1_RES_MCS_RX |MAC1_SIM_RES | MAC1_SOFT_RES;
00082 
00083   // Set up MAC Command Register
00084   LPC_EMAC->Command = CR_REG_RES | CR_TX_RES | CR_RX_RES | CR_PASS_RUNT_FRM;
00085   
00086   // Short delay
00087   for (loop = 100; loop; loop--);
00088 
00089   // Set up MAC Configuration Register 1 to pass all receive frames
00090   LPC_EMAC->MAC1 = MAC1_PASS_ALL;
00091   // Set up MAC Configuration Register 2 to append CRC and pad out frames
00092   LPC_EMAC->MAC2 = MAC2_CRC_EN | MAC2_PAD_EN;
00093   // Set Ethernet Maximum Frame Register
00094   LPC_EMAC->MAXF = ETH_MAX_FLEN;
00095   // Set Collision Window / Retry Register
00096   LPC_EMAC->CLRT = CLRT_DEF;
00097   // Set Non Back-to-Back Inter-Packet-Gap Register
00098   LPC_EMAC->IPGR = IPGR_DEF;
00099 
00100   // Find the clock closest to desired target clock
00101   value = SystemCoreClock / MCFG_MII_MAXCLK;
00102   for (loop = 0; loop < sizeof (EMAC_clkdiv); loop++)
00103   {
00104       if (EMAC_clkdiv[loop] >= value) break;
00105   }
00106   loop++;
00107   // Write to MAC configuration register and reset
00108   LPC_EMAC->MCFG = MCFG_CLK_SEL(loop) | MCFG_RES_MII;
00109 
00110   // release reset
00111   LPC_EMAC->MCFG &= ~(MCFG_RES_MII);
00112   LPC_EMAC->CLRT = CLRT_DEF;
00113   LPC_EMAC->IPGR = IPGR_DEF;
00114 
00115   // Set MAC Command Register to enable Reduced MII interface
00116   // and prevent runt frames being filtered out
00117   LPC_EMAC->Command = CR_RMII | CR_PASS_RUNT_FRM;
00118 //  LPC_EMAC->Command = CR_RMII | CR_PASS_RUNT_FRM | CR_PASS_RX_FILT;
00119 
00120   /* Reset Reduced MII Logic. */
00121   LPC_EMAC->SUPP = SUPP_RES_RMII;
00122   for (loop = 100; loop; loop--);
00123   LPC_EMAC->SUPP = 0;
00124 
00125   // Put DM9161 PHY into reset mode
00126   WriteToPHY (PHY_REG_BMCR, DM9161_RESET);
00127 
00128   // Loop until hardware reset completes
00129   for (loop = 0; loop < PHY_RESP_TOUT; loop++)
00130   {
00131     value = ReadFromPHY (PHY_REG_BMCR);
00132     if (!(value & DM9161_RESET))
00133     {
00134       // Reset has completed
00135       break;
00136     }
00137   }
00138   // Just check this actually is a DM9161 PHY
00139   phyid1 = ReadFromPHY (PHY_REG_IDR1);
00140   phyid2 = ReadFromPHY (PHY_REG_IDR2);
00141 
00142 if (((phyid1 << 16) | (phyid2 & 0xFFF0)) == DM9161_ID)
00143     {
00144         phy_in_use = DM9161_ID;
00145     }
00146 
00147   if (phy_in_use != 0)
00148   {      
00149     // Safe to configure the PHY device
00150     // Set PHY to autonegotiation link speed
00151 //    WriteToPHY (PHY_REG_BMCR, (DM9161_AUTONEG|DM9161_RESTART_AUTONEG));
00152     WriteToPHY (PHY_REG_BMCR, DM9161_AUTONEG | DM9161_SPEED_SELECT);
00153     // loop until autonegotiation completes
00154     for (loop = 0; loop < PHY_RESP_TOUT; loop++)
00155     {
00156       value = ReadFromPHY (PHY_REG_BMSR);
00157       if (value & DM9161_AUTONEG_COMP)
00158       {
00159         // Autonegotiation has completed
00160         break;
00161       }
00162     }
00163   }
00164 
00165   // Now check the link status
00166   for (loop = 0; loop < PHY_RESP_TOUT; loop++)
00167   {
00168     value = ReadFromPHY (PHY_REG_DSCSR);
00169     if ((value & DM9161_100FDX)||(value & DM9161_100HDX)||(value & DM9161_10FDX)||(value & DM9161_10HDX))
00170     {
00171       // The link is on
00172       break;
00173     }
00174   }
00175 
00176   // Now configure for 10/100Mbit and full/half duplex mode 
00177   if (value & DM9161_100FDX)
00178   {
00179       LPC_EMAC->MAC2    |= MAC2_FULL_DUP;
00180       LPC_EMAC->Command |= CR_FULL_DUP;
00181       LPC_EMAC->IPGT     = IPGT_FULL_DUP;
00182       LPC_EMAC->SUPP     = SUPP_SPEED;
00183       WriteToPHY (PHY_REG_BMCR, PHY_FULLD_100M);
00184   }
00185   else if (value & DM9161_100HDX)
00186   {
00187       LPC_EMAC->IPGT     = IPGT_HALF_DUP;
00188       LPC_EMAC->SUPP     = SUPP_SPEED;
00189       WriteToPHY (PHY_REG_BMCR, PHY_HALFD_100M);
00190   }
00191   else if (value & DM9161_10FDX)
00192   {
00193       LPC_EMAC->MAC2    |= MAC2_FULL_DUP;
00194       LPC_EMAC->Command |= CR_FULL_DUP;
00195       LPC_EMAC->IPGT     = IPGT_FULL_DUP;
00196       LPC_EMAC->SUPP     = 0;
00197       WriteToPHY (PHY_REG_BMCR, PHY_FULLD_10M);
00198   }
00199   else if (value & DM9161_10HDX)
00200   {
00201       LPC_EMAC->IPGT     = IPGT_HALF_DUP;
00202       LPC_EMAC->SUPP     = 0;
00203       WriteToPHY (PHY_REG_BMCR, PHY_HALFD_10M);
00204   }
00205 
00206   // Now set the Ethernet MAC Address registers
00207   // NOTE - MAC address must be unique on the network!
00208   LPC_EMAC->SA0 = (MYMAC_1 << 8) | MYMAC_2; // Station address 0 Reg
00209   LPC_EMAC->SA1 = (MYMAC_3 << 8) | MYMAC_4; // Station address 1 Reg
00210   LPC_EMAC->SA2 = (MYMAC_5 << 8) | MYMAC_6; // Station address 2 Reg
00211 
00212  
00213   // Now initialise the Rx descriptors    
00214   for (loop = 0; loop < NUM_RX_FRAG; loop++)
00215   {
00216     RX_DESC_PACKET(loop)  = RX_BUF(loop);
00217     RX_DESC_CTRL(loop)    = RCTRL_INT | (ETH_FRAG_SIZE-1);
00218     RX_STAT_INFO(loop)    = 0;
00219     RX_STAT_HASHCRC(loop) = 0;
00220   }
00221 
00222   // Set up the Receive Descriptor Base address register
00223   LPC_EMAC->RxDescriptor    = RX_DESC_BASE;
00224   // Set up the Receive Status Base address register
00225   LPC_EMAC->RxStatus        = RX_STAT_BASE;
00226   // Setup the Receive Number of Descriptor register
00227   LPC_EMAC->RxDescriptorNumber = NUM_RX_FRAG-1;
00228   //  Set Receive Consume Index register to 0
00229   LPC_EMAC->RxConsumeIndex  = 0;
00230 
00231   // Now initialise the Tx descriptors 
00232   for (loop = 0; loop < NUM_TX_FRAG; loop++)
00233   {
00234     TX_DESC_PACKET(loop) = TX_BUF(loop);
00235     TX_DESC_CTRL(loop)   = 0;
00236     TX_STAT_INFO(loop)   = 0;
00237   }
00238 
00239   // Set up the Transmit Descriptor Base address register
00240   LPC_EMAC->TxDescriptor    = TX_DESC_BASE;
00241   // Set up the Transmit Status Base address register
00242   LPC_EMAC->TxStatus        = TX_STAT_BASE;
00243   // Setup the Transmit Number of Descriptor register
00244   LPC_EMAC->TxDescriptorNumber = NUM_TX_FRAG-1;
00245   //  Set Transmit Consume Index register to 0
00246   LPC_EMAC->TxProduceIndex  = 0;
00247  
00248   // Receive Broadcast and Perfect Match Packets
00249   LPC_EMAC->RxFilterCtrl = RFC_MCAST_EN | RFC_BCAST_EN | RFC_PERFECT_EN;                     
00250  
00251   // Enable interrupts MAC Module Control Interrupt Enable Register
00252   LPC_EMAC->IntEnable = INT_RX_DONE | INT_TX_DONE;
00253 
00254   // Reset all ethernet interrupts in MAC module
00255   LPC_EMAC->IntClear  = 0xFFFF;
00256 
00257   // Finally enable receive and transmit mode in ethernet core
00258   LPC_EMAC->Command  |= (CR_RX_EN | CR_TX_EN);
00259   LPC_EMAC->MAC1     |= MAC1_REC_EN;
00260 }
00261 
00262 
00263 // writes a word in little-endian byte order to TX_BUFFER
00264 void WriteFrame_EthMAC(unsigned short Data)
00265 {
00266   *txptr++ = Data;
00267 }
00268 
00269 // copies bytes from MCU-memory to frame port
00270 // NOTES: * an odd number of byte may only be transfered
00271 //          if the frame is written to the end!
00272 //        * MCU-memory MUST start at word-boundary
00273 void CopyToFrame_EthMAC(void *Source, unsigned int Size)
00274 {
00275   unsigned int index;
00276   unsigned short *pSource;
00277 
00278   pSource = (unsigned short *)Source;
00279   Size = (Size + 1) & 0xFFFE;    // round up Size to next even number
00280   while (Size > 0)
00281   {
00282     WriteFrame_EthMAC(*pSource++);
00283     Size -= 2;
00284   }
00285 
00286   index = LPC_EMAC->TxProduceIndex;
00287   if (++index == NUM_TX_FRAG)
00288     index = 0;
00289   LPC_EMAC->TxProduceIndex = index;
00290 }
00291 
00292 // reads a word in little-endian byte order from RX_BUFFER
00293 unsigned short ReadFrame_EthMAC(void)
00294 {
00295   return (*rxptr++);
00296 }
00297 
00298 
00299 // reads a word in big-endian byte order from RX_FRAME_PORT
00300 unsigned short ReadFrameBE_EthMAC(void)
00301 {
00302   unsigned short ReturnValue;
00303 
00304   ReturnValue = SwapBytes (*rxptr++);
00305   return (ReturnValue);
00306 }
00307 
00308 // copies bytes from frame port to MCU-memory
00309 // NOTES: * an odd number of byte may only be transfered
00310 //          if the frame is read to the end!
00311 //        * MCU-memory MUST start at word-boundary
00312 void CopyFromFrame_EthMAC(void *Dest, unsigned short Size)
00313 {
00314   unsigned short *pDest; 
00315 
00316   pDest = (unsigned short *)Dest;
00317   while (Size > 1)
00318   {
00319     *pDest++ = ReadFrame_EthMAC();
00320     Size -= 2;
00321   }
00322 
00323   if (Size)
00324   {                                                     // check for leftover byte...
00325     *(unsigned char *)pDest = (char)ReadFrame_EthMAC(); // the LAN-Controller will return 0
00326   }                                                     // for the highbyte
00327 }
00328 
00329 
00330 
00331 // does a dummy read on frame-I/O-port
00332 // NOTE: only an even number of bytes is read!
00333 void DummyReadFrame_EthMAC(unsigned short Size)       // discards an EVEN number of bytes
00334 {                                                     // from RX-fifo
00335   while (Size > 1)
00336   {
00337     ReadFrame_EthMAC();
00338     Size -= 2;
00339   }
00340 }
00341 
00342 // requests space in PHY on-chip memory for
00343 // storing an outgoing frame
00344 void RequestSend(unsigned short FrameSize)
00345 {
00346   unsigned int index;
00347   index  = LPC_EMAC->TxProduceIndex;
00348   txptr = (unsigned short *)TX_DESC_PACKET(index);
00349   TX_DESC_CTRL(index) = FrameSize | TCTRL_LAST;
00350 }
00351 
00352 // check if PHY is ready to accept the
00353 // frame we want to send
00354 unsigned int Rdy4Tx(void)
00355 {
00356   // One the LPC the ethernet controller transmits
00357   // much faster than the CPU can load its buffers
00358   // so will always be ready to accept frame    
00359   return (1); 
00360 }
00361 
00362 // Reads  length of received ethernet frame and checks
00363 // if destination address is a broadcast message or not.
00364 // Then returns the frame length
00365 unsigned short StartReadingFrame(void)
00366 {
00367   unsigned short ReceiveLength;
00368   unsigned int index;
00369 
00370   index = LPC_EMAC->RxConsumeIndex;
00371   ReceiveLength = (RX_STAT_INFO(index) & RINFO_SIZE) - 3;
00372   rxptr = (unsigned short *)RX_DESC_PACKET(index);
00373   return(ReceiveLength);
00374 }
00375 
00376 void StopReadingFrame(void)
00377 {
00378   unsigned int index;
00379   index = LPC_EMAC->RxConsumeIndex;
00380   if (++index == NUM_RX_FRAG) index = 0;
00381   LPC_EMAC->RxConsumeIndex = index;
00382 }
00383 
00384 // check if frame has been received
00385 unsigned int CheckIfFrameReceived(void)
00386 { 
00387   if (LPC_EMAC->RxProduceIndex != LPC_EMAC->RxConsumeIndex) 
00388     return(1); // Yes, packet received
00389   else 
00390     return(0);
00391 }