Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
ethmac.c
00001 /****************************************************************** 00002 ***** ***** 00003 ***** Name: cs8900.c ***** 00004 ***** Ver.: 1.0 ***** 00005 ***** Date: 07/05/2001 ***** 00006 ***** Auth: Andreas Dannenberg ***** 00007 ***** HTWK Leipzig ***** 00008 ***** university of applied sciences ***** 00009 ***** Germany ***** 00010 ***** adannenb@et.htwk-leipzig.de ***** 00011 ***** Func: ethernet packet-driver for use with LAN- ***** 00012 ***** controller CS8900 from Crystal/Cirrus Logic ***** 00013 ***** ***** 00014 ******************************************************************/ 00015 00016 // Modifications by Code Red Technologies for NXP LPC1776 00017 // Filename changed to ethmac.c as no longer for cs8900 00018 00019 // CodeRed - updated include to match new filename 00020 00021 #include "mbed.h" 00022 00023 #include "ethmac.h" 00024 00025 // CodeRed - add additional includes 00026 #include "tcpip.h" 00027 00028 00029 // CodeRed - new static pointers for receive and transmit 00030 static unsigned short *rxptr; 00031 static unsigned short *txptr; 00032 00033 // CodeRed - function added to write to external ethernet PHY chip 00034 void WriteToPHY (int reg, int writeval) 00035 { 00036 unsigned int loop; 00037 // Set up address to access in MII Mgmt Address Register 00038 LPC_EMAC->MADR = DP83848C_DEF_ADR | reg; 00039 // Write value into MII Mgmt Write Data Register 00040 LPC_EMAC->MWTD = writeval; 00041 // Loop whilst write to PHY completes 00042 for (loop = 0; loop < MII_WR_TOUT; loop++) { 00043 if ((LPC_EMAC->MIND & MIND_BUSY) == 0) { break; } 00044 } 00045 } 00046 00047 // CodeRed - function added to read from external ethernet PHY chip 00048 unsigned short ReadFromPHY (unsigned char reg) 00049 { 00050 unsigned int loop; 00051 // Set up address to access in MII Mgmt Address Register 00052 LPC_EMAC->MADR = DP83848C_DEF_ADR | reg; 00053 // Trigger a PHY read via MII Mgmt Command Register 00054 LPC_EMAC->MCMD = MCMD_READ; 00055 // Loop whilst read from PHY completes 00056 for (loop = 0; loop < MII_RD_TOUT; loop++) { 00057 if ((LPC_EMAC->MIND & MIND_BUSY) == 0) { break; } 00058 } 00059 LPC_EMAC->MCMD = 0; // Cancel read 00060 // Returned value is in MII Mgmt Read Data Register 00061 return (LPC_EMAC->MRDD); 00062 } 00063 00064 00065 00066 // CodeRed - Init8900() replaced by Init_EthMAC() 00067 /* 00068 // configure port-pins for use with LAN-controller, 00069 // reset it and send the configuration-sequence 00070 // (InitSeq[]) 00071 00072 void Init8900(void) 00073 { 00074 unsigned int i; 00075 00076 P3SEL = 0x30; // reserve P3.4 and P3.5 for rs232 00077 P3OUT = IOR | IOW; // reset outputs, control lines high 00078 P3DIR = 0xFF; // port 3 as output (all pins but rs232) 00079 00080 P5SEL = 0; // select standard port functions 00081 P5OUT = 0; // reset outputs 00082 P5DIR = 0xFF; // switch data port to output 00083 00084 Write8900(ADD_PORT, PP_SelfCTL); 00085 Write8900(DATA_PORT, POWER_ON_RESET); // Reset the Ethernet-Controller 00086 00087 Write8900(ADD_PORT, PP_SelfST); 00088 while (!(Read8900(DATA_PORT) & INIT_DONE)); // wait until chip-reset is done 00089 00090 for (i = 0; i < sizeof InitSeq / sizeof (TInitSeq); i++) // configure the CS8900 00091 { 00092 Write8900(ADD_PORT, InitSeq[i].Addr); 00093 Write8900(DATA_PORT, InitSeq[i].Data); 00094 } 00095 } 00096 */ 00097 00098 // Ethernet power/clock control bit in PCONP register 00099 #define PCENET 0x40000000 00100 // Ethernet configuration for PINSEL2, as per user guide section 5.3 00101 #define ENET_PINSEL2_CONFIG 0x50150105 00102 // Ethernet configuration for PINSEL3, as per user guide section 5.4 00103 #define ENET_PINSEL3_CONFIG 0x00000005 00104 // Only bottom byte of PINSEL3 relevant to Ethernet 00105 #define ENET_PINSEL3_MASK 0x0000000F 00106 00107 void Init_EthMAC(void) 00108 { 00109 unsigned int loop, value, phyid1, phyid2; 00110 00111 unsigned phy_in_use = 0; 00112 unsigned phy_linkstatus_reg; 00113 unsigned phy_linkstatus_mask; 00114 00115 // Set Ethernet power/clock control bit 00116 LPC_SC->PCONP |= PCENET; 00117 00118 //Enable Ethernet pins through PINSEL registers 00119 LPC_PINCON->PINSEL2 = ENET_PINSEL2_CONFIG; 00120 LPC_PINCON->PINSEL3 = (LPC_PINCON->PINSEL3 & ~(ENET_PINSEL3_MASK)) | ENET_PINSEL3_CONFIG; 00121 00122 // Set up MAC Configuration Register 1 00123 LPC_EMAC->MAC1 = MAC1_RES_TX | MAC1_RES_MCS_TX | MAC1_RES_RX | 00124 MAC1_RES_MCS_RX |MAC1_SIM_RES | MAC1_SOFT_RES; 00125 00126 // Set up MAC Command Register 00127 LPC_EMAC->Command = CR_REG_RES | CR_TX_RES | CR_RX_RES | CR_PASS_RUNT_FRM; 00128 00129 // Short delay 00130 for (loop = 100; loop; loop--); 00131 00132 // Set up MAC Configuration Register 1 to pass all receive frames 00133 LPC_EMAC->MAC1 = MAC1_PASS_ALL; 00134 // Set up MAC Configuration Register 2 to append CRC and pad out frames 00135 LPC_EMAC->MAC2 = MAC2_CRC_EN | MAC2_PAD_EN; 00136 00137 // Set Ethernet Maximum Frame Register 00138 LPC_EMAC->MAXF = ETH_MAX_FLEN; 00139 // Set Collision Window / Retry Register 00140 LPC_EMAC->CLRT = CLRT_DEF; 00141 // Set Non Back-to-Back Inter-Packet-Gap Register 00142 LPC_EMAC->IPGR = IPGR_DEF; 00143 00144 // Set MAC Command Register to enable Reduced MII interface 00145 // and prevent runt frames being filtered out 00146 LPC_EMAC->Command = CR_RMII | CR_PASS_RUNT_FRM; 00147 00148 00149 // Put DP83848C PHY into reset mode 00150 WriteToPHY (PHY_REG_BMCR, 0x8000); 00151 00152 // Loop until hardware reset completes 00153 for (loop = 0; loop < 0x100000; loop++) { 00154 value = ReadFromPHY (PHY_REG_BMCR); 00155 if (!(value & 0x8000)) { 00156 // Reset has completed 00157 break; 00158 } 00159 } 00160 00161 // Just check this actually is a DP83848C PHY 00162 phyid1 = ReadFromPHY (PHY_REG_IDR1); 00163 phyid2 = ReadFromPHY (PHY_REG_IDR2); 00164 00165 if (((phyid1 << 16) | (phyid2 & 0xFFF0)) == DP83848C_ID) { 00166 phy_in_use = DP83848C_ID; 00167 } 00168 else if (((phyid1 << 16) | (phyid2 & 0xFFF0)) == LAN8720_ID) { 00169 phy_in_use = LAN8720_ID; 00170 } 00171 00172 if (phy_in_use != 0) { 00173 // Safe to configure the PHY device 00174 00175 // Set PHY to autonegotiation link speed 00176 WriteToPHY (PHY_REG_BMCR, PHY_AUTO_NEG); 00177 // loop until autonegotiation completes 00178 for (loop = 0; loop < 0x100000; loop++) { 00179 value = ReadFromPHY (PHY_REG_BMSR); 00180 if (value & 0x0020) { 00181 // Autonegotiation has completed 00182 break; 00183 } 00184 } 00185 } 00186 00187 phy_linkstatus_reg = PHY_REG_STS; // Default to DP83848C 00188 phy_linkstatus_mask = 0x0001; 00189 00190 if (phy_in_use == LAN8720_ID) { 00191 phy_linkstatus_reg = PHY_REG_BMSR; 00192 phy_linkstatus_mask = 0x0002; 00193 } 00194 00195 // Now check the link status 00196 for (loop = 0; loop < 0x10000; loop++) { 00197 value = ReadFromPHY (phy_linkstatus_reg); 00198 if (value & phy_linkstatus_mask) { 00199 // The link is on 00200 break; 00201 } 00202 } 00203 00204 // Now configure for full/half duplex mode 00205 if (value & 0x0004) { 00206 // We are in full duplex is enabled mode 00207 LPC_EMAC->MAC2 |= MAC2_FULL_DUP; 00208 LPC_EMAC->Command |= CR_FULL_DUP; 00209 LPC_EMAC->IPGT = IPGT_FULL_DUP; 00210 } 00211 else { 00212 // Otherwise we are in half duplex mode 00213 LPC_EMAC->IPGT = IPGT_HALF_DUP; 00214 } 00215 00216 // Now configure 100MBit or 10MBit mode 00217 if (value & 0x0002) { 00218 // 10MBit mode 00219 LPC_EMAC->SUPP = 0; 00220 } 00221 else { 00222 // 100MBit mode 00223 LPC_EMAC->SUPP = SUPP_SPEED; 00224 } 00225 00226 // Now set the Ethernet MAC Address registers 00227 // NOTE - MAC address must be unique on the network! 00228 LPC_EMAC->SA0 = (MYMAC_1 << 8) | MYMAC_2; // Station address 0 Reg 00229 LPC_EMAC->SA1 = (MYMAC_3 << 8) | MYMAC_4; // Station address 1 Reg 00230 LPC_EMAC->SA2 = (MYMAC_5 << 8) | MYMAC_6; // Station address 2 Reg 00231 00232 00233 // Now initialise the Rx descriptors 00234 for (loop = 0; loop < NUM_RX_FRAG; loop++) { 00235 RX_DESC_PACKET(loop) = RX_BUF(loop); 00236 RX_DESC_CTRL(loop) = RCTRL_INT | (ETH_FRAG_SIZE-1); 00237 RX_STAT_INFO(loop) = 0; 00238 RX_STAT_HASHCRC(loop) = 0; 00239 } 00240 00241 // Set up the Receive Descriptor Base address register 00242 LPC_EMAC->RxDescriptor = RX_DESC_BASE; 00243 // Set up the Receive Status Base address register 00244 LPC_EMAC->RxStatus = RX_STAT_BASE; 00245 // Setup the Receive Number of Descriptor register 00246 LPC_EMAC->RxDescriptorNumber = NUM_RX_FRAG-1; 00247 // Set Receive Consume Index register to 0 00248 LPC_EMAC->RxConsumeIndex = 0; 00249 00250 // Now initialise the Tx descriptors 00251 for (loop = 0; loop < NUM_TX_FRAG; loop++) { 00252 TX_DESC_PACKET(loop) = TX_BUF(loop); 00253 TX_DESC_CTRL(loop) = 0; 00254 TX_STAT_INFO(loop) = 0; 00255 } 00256 00257 // Set up the Transmit Descriptor Base address register 00258 LPC_EMAC->TxDescriptor = TX_DESC_BASE; 00259 // Set up the Transmit Status Base address register 00260 LPC_EMAC->TxStatus = TX_STAT_BASE; 00261 // Setup the Transmit Number of Descriptor register 00262 LPC_EMAC->TxDescriptorNumber = NUM_TX_FRAG-1; 00263 // Set Transmit Consume Index register to 0 00264 LPC_EMAC->TxProduceIndex = 0; 00265 00266 // Receive Broadcast and Perfect Match Packets 00267 00268 00269 00270 LPC_EMAC->RxFilterCtrl = RFC_BCAST_EN | RFC_PERFECT_EN; 00271 00272 // Enable interrupts MAC Module Control Interrupt Enable Register 00273 LPC_EMAC->IntEnable = INT_RX_DONE | INT_TX_DONE; 00274 00275 // Reset all ethernet interrupts in MAC module 00276 LPC_EMAC->IntClear = 0xFFFF; 00277 00278 // Finally enable receive and transmit mode in ethernet core 00279 LPC_EMAC->Command |= (CR_RX_EN | CR_TX_EN); 00280 LPC_EMAC->MAC1 |= MAC1_REC_EN; 00281 } 00282 00283 00284 // CodeRed - Write8900() not needed 00285 // for RDB1768 port 00286 00287 /* 00288 // writes a word in little-endian byte order to 00289 // a specified port-address 00290 00291 void Write8900(unsigned char Address, unsigned int Data) 00292 { 00293 P5DIR = 0xFF; // data port to output 00294 P3OUT = IOR | IOW | Address; // put address on bus 00295 00296 P5OUT = Data; // write low order byte to data bus 00297 P3OUT &= ~IOW; // toggle IOW-signal 00298 P3OUT = IOR | IOW | (Address + 1); // and put next address on bus 00299 00300 P5OUT = Data >> 8; // write high order byte to data bus 00301 P3OUT &= ~IOW; // toggle IOW-signal 00302 P3OUT |= IOW; 00303 } 00304 */ 00305 00306 // Code Red - updated for LPC1776 port 00307 /* 00308 // writes a word in little-endian byte order to TX_FRAME_PORT 00309 00310 void WriteFrame8900(unsigned int Data) 00311 { 00312 P5DIR = 0xFF; // data port to output 00313 P3OUT = IOR | IOW | TX_FRAME_PORT; // put address on bus 00314 00315 P5OUT = Data; // write low order byte to data bus 00316 P3OUT &= ~IOW; // toggle IOW-signal 00317 P3OUT = IOR | IOW | (TX_FRAME_PORT + 1); // and put next address on bus 00318 00319 P5OUT = Data >> 8; // write high order byte to data bus 00320 P3OUT &= ~IOW; // toggle IOW-signal 00321 P3OUT |= IOW; 00322 } 00323 */ 00324 00325 // writes a word in little-endian byte order to TX_BUFFER 00326 void WriteFrame_EthMAC(unsigned short Data) 00327 { 00328 *txptr++ = Data; 00329 } 00330 00331 00332 00333 // copies bytes from MCU-memory to frame port 00334 // NOTES: * an odd number of byte may only be transfered 00335 // if the frame is written to the end! 00336 // * MCU-memory MUST start at word-boundary 00337 00338 // Code Red - rewritten for LPC1776 00339 /* 00340 void CopyToFrame8900(void *Source, unsigned int Size) 00341 { 00342 P5DIR = 0xFF; // data port to output 00343 00344 while (Size > 1) { 00345 WriteFrame8900(*((unsigned int *)Source)++); 00346 Size -= 2; 00347 } 00348 00349 if (Size) // if odd num. of bytes... 00350 WriteFrame8900(*(unsigned char *)Source); // write leftover byte (the LAN-controller 00351 } // ignores the highbyte) 00352 */ 00353 00354 void CopyToFrame_EthMAC(void *Source, unsigned int Size) 00355 { 00356 unsigned int index; 00357 unsigned short *pSource; 00358 00359 pSource = (unsigned short *)Source; 00360 Size = (Size + 1) & 0xFFFE; // round up Size to next even number 00361 while (Size > 0) { 00362 WriteFrame_EthMAC(*pSource++); 00363 Size -= 2; 00364 } 00365 00366 index = LPC_EMAC->TxProduceIndex; 00367 if (++index == NUM_TX_FRAG) 00368 index = 0; 00369 LPC_EMAC->TxProduceIndex = index; 00370 } 00371 00372 // CodeRed - Read8900() not needed 00373 // for LPC1768 port 00374 /* 00375 00376 // reads a word in little-endian byte order from 00377 // a specified port-address 00378 00379 unsigned int Read8900(unsigned char Address) 00380 { 00381 unsigned int ReturnValue; 00382 00383 P5DIR = 0x00; // data port to input 00384 P3OUT = IOR | IOW | Address; // put address on bus 00385 00386 P3OUT &= ~IOR; // IOR-signal low 00387 00388 ReturnValue = P5IN; // get low order byte from data bus 00389 P3OUT = IOR | IOW | (Address + 1); // IOR high and put next address on bus 00390 P3OUT &= ~IOR; // IOR-signal low 00391 00392 ReturnValue |= P5IN << 8; // get high order byte from data bus 00393 00394 P3OUT |= IOR; 00395 00396 return ReturnValue; 00397 } 00398 */ 00399 // reads a word in little-endian byte order from RX_FRAME_PORT 00400 00401 // Code Red - ReadFrame8900 rewritten for RDB1768 port 00402 /* 00403 unsigned int ReadFrame8900(void) 00404 { 00405 unsigned int ReturnValue; 00406 00407 P5DIR = 0x00; // data port to input 00408 P3OUT = IOR | IOW | RX_FRAME_PORT; // access to RX_FRAME_PORT 00409 00410 P3OUT &= ~IOR; // IOR-signal low 00411 00412 ReturnValue = P5IN; // get 1st byte from data bus (low-byte) 00413 P3OUT = IOR | IOW | (RX_FRAME_PORT + 1); // IOR high and put next address on bus 00414 P3OUT &= ~IOR; // IOR-signal low 00415 00416 ReturnValue |= P5IN << 8; // get 2nd byte from data bus (high-byte) 00417 00418 P3OUT |= IOR; 00419 00420 return ReturnValue; 00421 } 00422 */ 00423 00424 // reads a word in little-endian byte order from RX_BUFFER 00425 00426 unsigned short ReadFrame_EthMAC(void) 00427 { 00428 return (*rxptr++); 00429 } 00430 00431 00432 // reads a word in big-endian byte order from RX_FRAME_PORT 00433 // (useful to avoid permanent byte-swapping while reading 00434 // TCP/IP-data) 00435 00436 // CodeRed - rewritten for LPC1768 00437 /* 00438 00439 unsigned int ReadFrameBE8900(void) 00440 { 00441 unsigned int ReturnValue; 00442 00443 P5DIR = 0x00; // data port to input 00444 P3OUT = IOR | IOW | RX_FRAME_PORT; // access to RX_FRAME_PORT 00445 00446 P3OUT &= ~IOR; // IOR-signal low 00447 00448 ReturnValue = P5IN << 8; // get 1st byte from data bus (high-byte) 00449 P3OUT = IOR | IOW | (RX_FRAME_PORT + 1); // IOR high and put next address on bus 00450 P3OUT &= ~IOR; // IOR-signal low 00451 00452 ReturnValue |= P5IN; // get 2nd byte from data bus (low-byte) 00453 00454 P3OUT |= IOR; 00455 00456 return ReturnValue; 00457 } 00458 */ 00459 00460 unsigned short ReadFrameBE_EthMAC(void) 00461 { 00462 unsigned short ReturnValue; 00463 00464 ReturnValue = SwapBytes (*rxptr++); 00465 return (ReturnValue); 00466 } 00467 00468 // CodeRed - not required for RDB1768 port 00469 /* 00470 // reads a word in little-endian byte order from 00471 // a specified port-address 00472 // NOTE: this func. xfers the high-byte 1st, must be used to 00473 // access some special registers (e.g. RxStatus) 00474 00475 unsigned int ReadHB1ST8900(unsigned char Address) 00476 { 00477 unsigned int ReturnValue; 00478 00479 P5DIR = 0x00; // data port to input 00480 P3OUT = IOR | IOW | (Address + 1); // put address on bus 00481 00482 P3OUT &= ~IOR; // IOR-signal low 00483 00484 ReturnValue = P5IN << 8; // get high order byte from data bus 00485 P3OUT = IOR | IOW | Address; // IOR high and put next address on bus 00486 P3OUT &= ~IOR; // IOR-signal low 00487 00488 ReturnValue |= P5IN; // get low order byte from data bus 00489 00490 P3OUT |= IOR; 00491 00492 return ReturnValue; 00493 } 00494 */ 00495 00496 00497 // copies bytes from frame port to MCU-memory 00498 // NOTES: * an odd number of byte may only be transfered 00499 // if the frame is read to the end! 00500 // * MCU-memory MUST start at word-boundary 00501 00502 // Code Red - rewritten for LPC1776 port 00503 /* 00504 void CopyFromFrame8900(void *Dest, unsigned int Size) 00505 { 00506 while (Size > 1) { 00507 *((unsigned int *)Dest)++ = ReadFrame8900(); 00508 Size -= 2; 00509 } 00510 00511 if (Size) // check for leftover byte... 00512 *(unsigned char *)Dest = ReadFrame8900(); // the LAN-Controller will return 0 00513 } // for the highbyte 00514 */ 00515 00516 void CopyFromFrame_EthMAC(void *Dest, unsigned short Size) 00517 { 00518 unsigned short *pDest; 00519 00520 pDest = (unsigned short *)Dest; 00521 while (Size > 1) { 00522 *pDest++ = ReadFrame_EthMAC(); 00523 Size -= 2; 00524 } 00525 00526 if (Size) { // check for leftover byte... 00527 *(unsigned char *)pDest = (char)ReadFrame_EthMAC();// the LAN-Controller will return 0 00528 } // for the highbyte 00529 } 00530 00531 00532 00533 // does a dummy read on frame-I/O-port 00534 // NOTE: only an even number of bytes is read! 00535 00536 // Code Red - updated for LPC1776 00537 //void DummyReadFrame8900(unsigned int Size) // discards an EVEN number of bytes 00538 void DummyReadFrame_EthMAC(unsigned short Size) // discards an EVEN number of bytes 00539 { // from RX-fifo 00540 while (Size > 1) { 00541 // Code Red - updated for LPC1776 00542 // ReadFrame8900(); 00543 ReadFrame_EthMAC(); 00544 Size -= 2; 00545 } 00546 } 00547 00548 // requests space in CS8900's on-chip memory for 00549 // storing an outgoing frame 00550 00551 // CodeRed - updated for LPC1768 port 00552 /* 00553 void RequestSend(unsigned int FrameSize) 00554 { 00555 Write8900(TX_CMD_PORT, TX_START_ALL_BYTES); 00556 Write8900(TX_LEN_PORT, FrameSize); 00557 } 00558 */ 00559 void RequestSend(unsigned short FrameSize) 00560 { 00561 unsigned int index; 00562 index = LPC_EMAC->TxProduceIndex; 00563 txptr = (unsigned short *)TX_DESC_PACKET(index); 00564 TX_DESC_CTRL(index) = FrameSize | TCTRL_LAST; 00565 } 00566 00567 // check if CS8900 is ready to accept the 00568 // frame we want to send 00569 00570 unsigned int Rdy4Tx(void) 00571 { 00572 // Code Red - updated for LPC1768 00573 // Write8900(ADD_PORT, PP_BusST); 00574 // return (Read8900(DATA_PORT) & READY_FOR_TX_NOW); 00575 00576 // One the LPC the ethernet controller transmits 00577 // much faster than the CPU can load its buffers 00578 // so will always be ready to accept frame 00579 return (1); 00580 // 00581 } 00582 00583 // CodeRed - New function 00584 00585 // Reads length of received ethernet frame and checks 00586 // if destination address is a broadcast message or not. 00587 // Then returns the frame length 00588 unsigned short StartReadingFrame(void) 00589 { 00590 unsigned short ReceiveLength; 00591 unsigned int index; 00592 00593 index = LPC_EMAC->RxConsumeIndex; 00594 ReceiveLength = (RX_STAT_INFO(index) & RINFO_SIZE) - 3; 00595 rxptr = (unsigned short *)RX_DESC_PACKET(index); 00596 return(ReceiveLength); 00597 } 00598 00599 // CodeRed - new function 00600 00601 void StopReadingFrame(void) 00602 { 00603 unsigned int index; 00604 index = LPC_EMAC->RxConsumeIndex; 00605 if (++index == NUM_RX_FRAG) index = 0; 00606 LPC_EMAC->RxConsumeIndex = index; 00607 } 00608 00609 // CodeRed - new function to check if frame has been received 00610 unsigned int CheckIfFrameReceived(void) 00611 { 00612 if (LPC_EMAC->RxProduceIndex != LPC_EMAC->RxConsumeIndex) 00613 return(1); // Yes, packet received 00614 else 00615 return(0); 00616 }
Generated on Tue Jul 12 2022 22:58:15 by
1.7.2