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.
Dependencies: mbed
Fork of EasyWebCR by
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 18:57:49 by
1.7.2
