LPC1768 Mini-DK EasyWeb application with SPI TFT output. Started from EasyWebCR and modified for DM9161 PHY support.
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 }
Generated on Thu Jul 14 2022 05:47:26 by 1.7.2