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.
enc28j60.c
00001 /** 00002 * @file enc28j60.c 00003 * @brief ENC28J60 Ethernet controller 00004 * 00005 * @section License 00006 * 00007 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved. 00008 * 00009 * This file is part of CycloneTCP Open. 00010 * 00011 * This program is free software; you can redistribute it and/or 00012 * modify it under the terms of the GNU General Public License 00013 * as published by the Free Software Foundation; either version 2 00014 * of the License, or (at your option) any later version. 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU General Public License 00022 * along with this program; if not, write to the Free Software Foundation, 00023 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00024 * 00025 * @author Oryx Embedded SARL (www.oryx-embedded.com) 00026 * @version 1.7.6 00027 **/ 00028 00029 //Switch to the appropriate trace level 00030 #define TRACE_LEVEL NIC_TRACE_LEVEL 00031 00032 //Dependencies 00033 #include <limits.h> 00034 #include "core/net.h" 00035 #include "drivers/enc28j60.h" 00036 #include "debug.h" 00037 00038 00039 /** 00040 * @brief ENC28J60 driver 00041 **/ 00042 00043 const NicDriver enc28j60Driver = 00044 { 00045 NIC_TYPE_ETHERNET, 00046 ETH_MTU, 00047 enc28j60Init, 00048 enc28j60Tick, 00049 enc28j60EnableIrq, 00050 enc28j60DisableIrq, 00051 enc28j60EventHandler, 00052 enc28j60SendPacket, 00053 enc28j60SetMulticastFilter, 00054 NULL, 00055 NULL, 00056 NULL, 00057 TRUE, 00058 TRUE, 00059 TRUE, 00060 FALSE 00061 }; 00062 00063 00064 /** 00065 * @brief ENC28J60 controller initialization 00066 * @param[in] interface Underlying network interface 00067 * @return Error code 00068 **/ 00069 00070 error_t enc28j60Init(NetInterface *interface) 00071 { 00072 uint8_t revisionId; 00073 Enc28j60Context *context; 00074 00075 //Debug message 00076 TRACE_INFO("Initializing ENC28J60 Ethernet controller...\r\n"); 00077 00078 //Initialize SPI 00079 interface->spiDriver->init(); 00080 //Initialize external interrupt line 00081 interface->extIntDriver->init(); 00082 00083 //Issue a system reset 00084 enc28j60SoftReset(interface); 00085 00086 //After issuing the reset command, wait at least 1ms in firmware 00087 //for the device to be ready 00088 sleep(10); 00089 00090 //Point to the driver context 00091 context = (Enc28j60Context *) interface->nicContext; 00092 00093 //Initialize driver specific variables 00094 context->currentBank = UINT16_MAX; 00095 context->nextPacket = ENC28J60_RX_BUFFER_START; 00096 00097 //Allocate RX buffer 00098 context->rxBuffer = memPoolAlloc(ETH_MAX_FRAME_SIZE); 00099 //Failed to allocate memory? 00100 if(context->rxBuffer == NULL) 00101 return ERROR_OUT_OF_MEMORY; 00102 00103 //Read silicon revision ID 00104 revisionId = enc28j60ReadReg(interface, ENC28J60_REG_EREVID); 00105 00106 //Debug message 00107 TRACE_INFO("ENC28J60 revision ID: 0x%02X\r\n", revisionId); 00108 00109 //Disable CLKOUT output 00110 enc28j60WriteReg(interface, ENC28J60_REG_ECOCON, 0x00); 00111 00112 //Set the MAC address 00113 enc28j60WriteReg(interface, ENC28J60_REG_MAADR1, interface->macAddr.b[0]); 00114 enc28j60WriteReg(interface, ENC28J60_REG_MAADR2, interface->macAddr.b[1]); 00115 enc28j60WriteReg(interface, ENC28J60_REG_MAADR3, interface->macAddr.b[2]); 00116 enc28j60WriteReg(interface, ENC28J60_REG_MAADR4, interface->macAddr.b[3]); 00117 enc28j60WriteReg(interface, ENC28J60_REG_MAADR5, interface->macAddr.b[4]); 00118 enc28j60WriteReg(interface, ENC28J60_REG_MAADR6, interface->macAddr.b[5]); 00119 00120 //Set receive buffer location 00121 enc28j60WriteReg(interface, ENC28J60_REG_ERXSTL, LSB(ENC28J60_RX_BUFFER_START)); 00122 enc28j60WriteReg(interface, ENC28J60_REG_ERXSTH, MSB(ENC28J60_RX_BUFFER_START)); 00123 enc28j60WriteReg(interface, ENC28J60_REG_ERXNDL, LSB(ENC28J60_RX_BUFFER_STOP)); 00124 enc28j60WriteReg(interface, ENC28J60_REG_ERXNDH, MSB(ENC28J60_RX_BUFFER_STOP)); 00125 00126 //The ERXRDPT register defines a location within the FIFO 00127 //where the receive hardware is forbidden to write to 00128 enc28j60WriteReg(interface, ENC28J60_REG_ERXRDPTL, LSB(ENC28J60_RX_BUFFER_STOP)); 00129 enc28j60WriteReg(interface, ENC28J60_REG_ERXRDPTH, MSB(ENC28J60_RX_BUFFER_STOP)); 00130 00131 //Configure the receive filters 00132 enc28j60WriteReg(interface, ENC28J60_REG_ERXFCON, ERXFCON_UCEN | 00133 ERXFCON_CRCEN | ERXFCON_HTEN | ERXFCON_BCEN); 00134 00135 //Initialize the hash table 00136 enc28j60WriteReg(interface, ENC28J60_REG_EHT0, 0x00); 00137 enc28j60WriteReg(interface, ENC28J60_REG_EHT1, 0x00); 00138 enc28j60WriteReg(interface, ENC28J60_REG_EHT2, 0x00); 00139 enc28j60WriteReg(interface, ENC28J60_REG_EHT3, 0x00); 00140 enc28j60WriteReg(interface, ENC28J60_REG_EHT4, 0x00); 00141 enc28j60WriteReg(interface, ENC28J60_REG_EHT5, 0x00); 00142 enc28j60WriteReg(interface, ENC28J60_REG_EHT6, 0x00); 00143 enc28j60WriteReg(interface, ENC28J60_REG_EHT7, 0x00); 00144 00145 //Pull the MAC out of reset 00146 enc28j60WriteReg(interface, ENC28J60_REG_MACON2, 0x00); 00147 00148 //Enable the MAC to receive frames 00149 enc28j60WriteReg(interface, ENC28J60_REG_MACON1, 00150 MACON1_TXPAUS | MACON1_RXPAUS | MACON1_MARXEN); 00151 00152 //Enable automatic padding to at least 60 bytes, always append a valid CRC 00153 //and check frame length. MAC can operate in half-duplex or full-duplex mode 00154 #if (ENC28J60_FULL_DUPLEX_SUPPORT == ENABLED) 00155 enc28j60WriteReg(interface, ENC28J60_REG_MACON3, MACON3_PADCFG(1) | 00156 MACON3_TXCRCEN | MACON3_FRMLNEN | MACON3_FULDPX); 00157 #else 00158 enc28j60WriteReg(interface, ENC28J60_REG_MACON3, MACON3_PADCFG(1) | 00159 MACON3_TXCRCEN | MACON3_FRMLNEN); 00160 #endif 00161 00162 //When the medium is occupied, the MAC will wait indefinitely for it to 00163 //become free when attempting to transmit 00164 enc28j60WriteReg(interface, ENC28J60_REG_MACON4, MACON4_DEFER); 00165 00166 //Maximum frame length that can be received or transmitted (1518 bytes) 00167 enc28j60WriteReg(interface, ENC28J60_REG_MAMXFLL, LSB(1518)); 00168 enc28j60WriteReg(interface, ENC28J60_REG_MAMXFLH, MSB(1518)); 00169 00170 //Configure the back-to-back inter-packet gap register 00171 #if (ENC28J60_FULL_DUPLEX_SUPPORT == ENABLED) 00172 enc28j60WriteReg(interface, ENC28J60_REG_MABBIPG, 0x15); 00173 #else 00174 enc28j60WriteReg(interface, ENC28J60_REG_MABBIPG, 0x12); 00175 #endif 00176 00177 //Configure the non-back-to-back inter-packet gap register 00178 enc28j60WriteReg(interface, ENC28J60_REG_MAIPGL, 0x12); 00179 enc28j60WriteReg(interface, ENC28J60_REG_MAIPGH, 0x0C); 00180 00181 //Collision window register 00182 enc28j60WriteReg(interface, ENC28J60_REG_MACLCON2, 63); 00183 00184 //Set the PHY to the proper duplex mode 00185 #if (ENC28J60_FULL_DUPLEX_SUPPORT == ENABLED) 00186 enc28j60WritePhyReg(interface, ENC28J60_PHY_REG_PHCON1, PHCON1_PDPXMD); 00187 #else 00188 enc28j60WritePhyReg(interface, ENC28J60_PHY_REG_PHCON1, 0x0000); 00189 #endif 00190 00191 //Disable half-duplex loopback in PHY 00192 enc28j60WritePhyReg(interface, ENC28J60_PHY_REG_PHCON2, PHCON2_HDLDIS); 00193 00194 //LEDA displays link status and LEDB displays TX/RX activity 00195 enc28j60WritePhyReg(interface, ENC28J60_PHY_REG_PHLCON, 00196 PHLCON_LACFG(4) | PHLCON_LBCFG(7) | PHLCON_LFRQ(0) | PHLCON_STRCH); 00197 00198 //Clear interrupt flags 00199 enc28j60WriteReg(interface, ENC28J60_REG_EIR, 0x00); 00200 00201 //Configure interrupts as desired 00202 enc28j60WriteReg(interface, ENC28J60_REG_EIE, EIE_INTIE | 00203 EIE_PKTIE | EIE_LINKIE | EIE_TXIE | EIE_TXERIE); 00204 00205 //Configure PHY interrupts as desired 00206 enc28j60WritePhyReg(interface, ENC28J60_PHY_REG_PHIE, 00207 PHIE_PLNKIE | PHIE_PGEIE); 00208 00209 //Set RXEN to enable reception 00210 enc28j60SetBit(interface, ENC28J60_REG_ECON1, ECON1_RXEN); 00211 00212 //Dump registers for debugging purpose 00213 enc28j60DumpReg(interface); 00214 enc28j60DumpPhyReg(interface); 00215 00216 //Accept any packets from the upper layer 00217 osSetEvent(&interface->nicTxEvent); 00218 00219 //Force the TCP/IP stack to poll the link state at startup 00220 interface->nicEvent = TRUE; 00221 //Notify the TCP/IP stack of the event 00222 osSetEvent(&netEvent); 00223 00224 //Successful initialization 00225 return NO_ERROR; 00226 } 00227 00228 00229 /** 00230 * @brief ENC28J60 timer handler 00231 * @param[in] interface Underlying network interface 00232 **/ 00233 00234 void enc28j60Tick(NetInterface *interface) 00235 { 00236 } 00237 00238 00239 /** 00240 * @brief Enable interrupts 00241 * @param[in] interface Underlying network interface 00242 **/ 00243 00244 void enc28j60EnableIrq(NetInterface *interface) 00245 { 00246 //Enable interrupts 00247 interface->extIntDriver->enableIrq(); 00248 } 00249 00250 00251 /** 00252 * @brief Disable interrupts 00253 * @param[in] interface Underlying network interface 00254 **/ 00255 00256 void enc28j60DisableIrq(NetInterface *interface) 00257 { 00258 //Disable interrupts 00259 interface->extIntDriver->disableIrq(); 00260 } 00261 00262 00263 /** 00264 * @brief ENC28J60 interrupt service routine 00265 * @param[in] interface Underlying network interface 00266 * @return TRUE if a higher priority task must be woken. Else FALSE is returned 00267 **/ 00268 00269 bool_t enc28j60IrqHandler(NetInterface *interface) 00270 { 00271 bool_t flag; 00272 uint8_t status; 00273 00274 //This flag will be set if a higher priority task must be woken 00275 flag = FALSE; 00276 00277 //Clear the INTIE bit, immediately after an interrupt event 00278 enc28j60ClearBit(interface, ENC28J60_REG_EIE, EIE_INTIE); 00279 00280 //Read interrupt status register 00281 status = enc28j60ReadReg(interface, ENC28J60_REG_EIR); 00282 00283 //Link status change? 00284 if(status & EIR_LINKIF) 00285 { 00286 //Disable LINKIE interrupt 00287 enc28j60ClearBit(interface, ENC28J60_REG_EIE, EIE_LINKIE); 00288 00289 //Set event flag 00290 interface->nicEvent = TRUE; 00291 //Notify the TCP/IP stack of the event 00292 flag |= osSetEventFromIsr(&netEvent); 00293 } 00294 00295 //Packet received? 00296 if(status & EIR_PKTIF) 00297 { 00298 //Disable PKTIE interrupt 00299 enc28j60ClearBit(interface, ENC28J60_REG_EIE, EIE_PKTIE); 00300 00301 //Set event flag 00302 interface->nicEvent = TRUE; 00303 //Notify the TCP/IP stack of the event 00304 flag |= osSetEventFromIsr(&netEvent); 00305 } 00306 00307 //Packet transmission complete? 00308 if(status & (EIR_TXIF | EIE_TXERIE)) 00309 { 00310 //Clear interrupt flags 00311 enc28j60ClearBit(interface, ENC28J60_REG_EIR, EIR_TXIF | EIE_TXERIE); 00312 00313 //Notify the TCP/IP stack that the transmitter is ready to send 00314 flag |= osSetEventFromIsr(&interface->nicTxEvent); 00315 } 00316 00317 //Once the interrupt has been serviced, the INTIE bit 00318 //is set again to re-enable interrupts 00319 enc28j60SetBit(interface, ENC28J60_REG_EIE, EIE_INTIE); 00320 00321 //A higher priority task must be woken? 00322 return flag; 00323 } 00324 00325 00326 /** 00327 * @brief ENC28J60 event handler 00328 * @param[in] interface Underlying network interface 00329 **/ 00330 00331 void enc28j60EventHandler(NetInterface *interface) 00332 { 00333 error_t error; 00334 uint16_t status; 00335 uint16_t value; 00336 00337 //Read interrupt status register 00338 status = enc28j60ReadReg(interface, ENC28J60_REG_EIR); 00339 00340 //Check whether the link state has changed 00341 if(status & EIR_LINKIF) 00342 { 00343 //Clear PHY interrupts flags 00344 enc28j60ReadPhyReg(interface, ENC28J60_PHY_REG_PHIR); 00345 //Clear interrupt flag 00346 enc28j60ClearBit(interface, ENC28J60_REG_EIR, EIR_LINKIF); 00347 //Read PHY status register 00348 value = enc28j60ReadPhyReg(interface, ENC28J60_PHY_REG_PHSTAT2); 00349 00350 //Check link state 00351 if(value & PHSTAT2_LSTAT) 00352 { 00353 //Link speed 00354 interface->linkSpeed = NIC_LINK_SPEED_10MBPS; 00355 00356 #if (ENC28J60_FULL_DUPLEX_SUPPORT == ENABLED) 00357 //Full-duplex mode 00358 interface->duplexMode = NIC_FULL_DUPLEX_MODE; 00359 #else 00360 //Half-duplex mode 00361 interface->duplexMode = NIC_HALF_DUPLEX_MODE; 00362 #endif 00363 //Link is up 00364 interface->linkState = TRUE; 00365 } 00366 else 00367 { 00368 //Link is down 00369 interface->linkState = FALSE; 00370 } 00371 00372 //Process link state change event 00373 nicNotifyLinkChange(interface); 00374 } 00375 00376 //Check whether a packet has been received? 00377 if(status & EIR_PKTIF) 00378 { 00379 //Clear interrupt flag 00380 enc28j60ClearBit(interface, ENC28J60_REG_EIR, EIR_PKTIF); 00381 00382 //Process all pending packets 00383 do 00384 { 00385 //Read incoming packet 00386 error = enc28j60ReceivePacket(interface); 00387 00388 //No more data in the receive buffer? 00389 } while(error != ERROR_BUFFER_EMPTY); 00390 } 00391 00392 //Re-enable LINKIE and PKTIE interrupts 00393 enc28j60SetBit(interface, ENC28J60_REG_EIE, EIE_LINKIE | EIE_PKTIE); 00394 } 00395 00396 00397 /** 00398 * @brief Send a packet 00399 * @param[in] interface Underlying network interface 00400 * @param[in] buffer Multi-part buffer containing the data to send 00401 * @param[in] offset Offset to the first data byte 00402 * @return Error code 00403 **/ 00404 00405 error_t enc28j60SendPacket(NetInterface *interface, 00406 const NetBuffer *buffer, size_t offset) 00407 { 00408 size_t length; 00409 00410 //Retrieve the length of the packet 00411 length = netBufferGetLength(buffer) - offset; 00412 00413 //Check the frame length 00414 if(length > 1536) 00415 { 00416 //The transmitter can accept another packet 00417 osSetEvent(&interface->nicTxEvent); 00418 //Report an error 00419 return ERROR_INVALID_LENGTH; 00420 } 00421 00422 //Make sure the link is up before transmitting the frame 00423 if(!interface->linkState) 00424 { 00425 //The transmitter can accept another packet 00426 osSetEventFromIsr(&interface->nicTxEvent); 00427 //Drop current packet 00428 return NO_ERROR; 00429 } 00430 00431 //It is recommended to reset the transmit logic before 00432 //attempting to transmit a packet 00433 enc28j60SetBit(interface, ENC28J60_REG_ECON1, ECON1_TXRST); 00434 enc28j60ClearBit(interface, ENC28J60_REG_ECON1, ECON1_TXRST); 00435 00436 //Interrupt flags should be cleared after the reset is completed 00437 enc28j60ClearBit(interface, ENC28J60_REG_EIR, EIR_TXIF | EIR_TXERIF); 00438 00439 //Set transmit buffer location 00440 enc28j60WriteReg(interface, ENC28J60_REG_ETXSTL, LSB(ENC28J60_TX_BUFFER_START)); 00441 enc28j60WriteReg(interface, ENC28J60_REG_ETXSTH, MSB(ENC28J60_TX_BUFFER_START)); 00442 00443 //Point to start of transmit buffer 00444 enc28j60WriteReg(interface, ENC28J60_REG_EWRPTL, LSB(ENC28J60_TX_BUFFER_START)); 00445 enc28j60WriteReg(interface, ENC28J60_REG_EWRPTH, MSB(ENC28J60_TX_BUFFER_START)); 00446 00447 //Copy the data to the transmit buffer 00448 enc28j60WriteBuffer(interface, buffer, offset); 00449 00450 //ETXND should point to the last byte in the data payload 00451 enc28j60WriteReg(interface, ENC28J60_REG_ETXNDL, LSB(ENC28J60_TX_BUFFER_START + length)); 00452 enc28j60WriteReg(interface, ENC28J60_REG_ETXNDH, MSB(ENC28J60_TX_BUFFER_START + length)); 00453 00454 //Start transmission 00455 enc28j60SetBit(interface, ENC28J60_REG_ECON1, ECON1_TXRTS); 00456 00457 //Successful processing 00458 return NO_ERROR; 00459 } 00460 00461 00462 /** 00463 * @brief Receive a packet 00464 * @param[in] interface Underlying network interface 00465 * @return Error code 00466 **/ 00467 00468 error_t enc28j60ReceivePacket(NetInterface *interface) 00469 { 00470 error_t error; 00471 uint16_t n; 00472 uint16_t status; 00473 Enc28j60Context *context; 00474 00475 //Point to the driver context 00476 context = (Enc28j60Context *) interface->nicContext; 00477 00478 //Any packet pending in the receive buffer? 00479 if(enc28j60ReadReg(interface, ENC28J60_REG_EPKTCNT)) 00480 { 00481 //Point to the start of the received packet 00482 enc28j60WriteReg(interface, ENC28J60_REG_ERDPTL, LSB(context->nextPacket)); 00483 enc28j60WriteReg(interface, ENC28J60_REG_ERDPTH, MSB(context->nextPacket)); 00484 00485 //Read the first two bytes, which are the address of the next packet 00486 enc28j60ReadBuffer(interface, (uint8_t *) &context->nextPacket, sizeof(uint16_t)); 00487 //Get the length of the received frame in bytes 00488 enc28j60ReadBuffer(interface, (uint8_t *) &n, sizeof(uint16_t)); 00489 //Read the receive status vector (RSV) 00490 enc28j60ReadBuffer(interface, (uint8_t *) &status, sizeof(uint16_t)); 00491 00492 //Make sure no error occurred 00493 if(status & RSV_RECEIVED_OK) 00494 { 00495 //Limit the number of data to read 00496 n = MIN(n, ETH_MAX_FRAME_SIZE); 00497 //Read the Ethernet frame 00498 enc28j60ReadBuffer(interface, context->rxBuffer, n); 00499 //Valid packet received 00500 error = NO_ERROR; 00501 } 00502 else 00503 { 00504 //The received packet contains an error 00505 error = ERROR_INVALID_PACKET; 00506 } 00507 00508 //Advance the ERXRDPT pointer, taking care to wrap back at the 00509 //end of the received memory buffer 00510 if(context->nextPacket == ENC28J60_RX_BUFFER_START) 00511 { 00512 enc28j60WriteReg(interface, ENC28J60_REG_ERXRDPTL, LSB(ENC28J60_RX_BUFFER_STOP)); 00513 enc28j60WriteReg(interface, ENC28J60_REG_ERXRDPTH, MSB(ENC28J60_RX_BUFFER_STOP)); 00514 } 00515 else 00516 { 00517 enc28j60WriteReg(interface, ENC28J60_REG_ERXRDPTL, LSB(context->nextPacket - 1)); 00518 enc28j60WriteReg(interface, ENC28J60_REG_ERXRDPTH, MSB(context->nextPacket - 1)); 00519 } 00520 00521 //Decrement the packet counter 00522 enc28j60SetBit(interface, ENC28J60_REG_ECON2, ECON2_PKTDEC); 00523 } 00524 else 00525 { 00526 //No more data in the receive buffer 00527 error = ERROR_BUFFER_EMPTY; 00528 } 00529 00530 //Check whether a valid packet has been received 00531 if(!error) 00532 { 00533 //Pass the packet to the upper layer 00534 nicProcessPacket(interface, context->rxBuffer, n); 00535 } 00536 00537 //Return status code 00538 return error; 00539 } 00540 00541 00542 /** 00543 * @brief Configure multicast MAC address filtering 00544 * @param[in] interface Underlying network interface 00545 * @return Error code 00546 **/ 00547 00548 error_t enc28j60SetMulticastFilter(NetInterface *interface) 00549 { 00550 uint_t i; 00551 uint_t k; 00552 uint32_t crc; 00553 uint8_t hashTable[8]; 00554 MacFilterEntry *entry; 00555 00556 //Debug message 00557 TRACE_DEBUG("Updating ENC28J60 hash table...\r\n"); 00558 00559 //Clear hash table 00560 memset(hashTable, 0, sizeof(hashTable)); 00561 00562 //The MAC filter table contains the multicast MAC addresses 00563 //to accept when receiving an Ethernet frame 00564 for(i = 0; i < MAC_MULTICAST_FILTER_SIZE; i++) 00565 { 00566 //Point to the current entry 00567 entry = &interface->macMulticastFilter[i]; 00568 00569 //Valid entry? 00570 if(entry->refCount > 0) 00571 { 00572 //Compute CRC over the current MAC address 00573 crc = enc28j60CalcCrc(&entry->addr, sizeof(MacAddr)); 00574 //Calculate the corresponding index in the table 00575 k = (crc >> 23) & 0x3F; 00576 //Update hash table contents 00577 hashTable[k / 8] |= (1 << (k % 8)); 00578 } 00579 } 00580 00581 //Write the hash table to the ENC28J60 controller 00582 enc28j60WriteReg(interface, ENC28J60_REG_EHT0, hashTable[0]); 00583 enc28j60WriteReg(interface, ENC28J60_REG_EHT1, hashTable[1]); 00584 enc28j60WriteReg(interface, ENC28J60_REG_EHT2, hashTable[2]); 00585 enc28j60WriteReg(interface, ENC28J60_REG_EHT3, hashTable[3]); 00586 enc28j60WriteReg(interface, ENC28J60_REG_EHT4, hashTable[4]); 00587 enc28j60WriteReg(interface, ENC28J60_REG_EHT5, hashTable[5]); 00588 enc28j60WriteReg(interface, ENC28J60_REG_EHT6, hashTable[6]); 00589 enc28j60WriteReg(interface, ENC28J60_REG_EHT7, hashTable[7]); 00590 00591 //Debug message 00592 TRACE_DEBUG(" EHT0 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT0)); 00593 TRACE_DEBUG(" EHT1 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT1)); 00594 TRACE_DEBUG(" EHT2 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT2)); 00595 TRACE_DEBUG(" EHT3 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT3)); 00596 TRACE_DEBUG(" EHT0 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT4)); 00597 TRACE_DEBUG(" EHT1 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT5)); 00598 TRACE_DEBUG(" EHT2 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT6)); 00599 TRACE_DEBUG(" EHT3 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT7)); 00600 00601 //Successful processing 00602 return NO_ERROR; 00603 } 00604 00605 00606 /** 00607 * @brief ENC28J60 controller reset 00608 * @param[in] interface Underlying network interface 00609 **/ 00610 00611 void enc28j60SoftReset(NetInterface *interface) 00612 { 00613 //Pull the CS pin low 00614 interface->spiDriver->assertCs(); 00615 00616 //Write opcode 00617 interface->spiDriver->transfer(ENC28J60_CMD_SRC); 00618 00619 //Terminate the operation by raising the CS pin 00620 interface->spiDriver->deassertCs(); 00621 } 00622 00623 00624 /** 00625 * @brief Bank selection 00626 * @param[in] interface Underlying network interface 00627 * @param[in] address Register address 00628 **/ 00629 00630 void enc28j60SelectBank(NetInterface *interface, uint16_t address) 00631 { 00632 uint16_t bank; 00633 Enc28j60Context *context; 00634 00635 //Point to the driver context 00636 context = (Enc28j60Context *) interface->nicContext; 00637 00638 //Get the bank number from the specified address 00639 bank = address & REG_BANK_MASK; 00640 00641 //Rewrite the bank number only if a change is detected 00642 if(bank != context->currentBank) 00643 { 00644 //Select specified bank 00645 switch(bank) 00646 { 00647 case BANK_0: 00648 //Select bank 0 00649 enc28j60ClearBit(interface, ENC28J60_REG_ECON1, ECON1_BSEL1 | ECON1_BSEL0); 00650 break; 00651 case BANK_1: 00652 //Select bank 1 00653 enc28j60SetBit(interface, ENC28J60_REG_ECON1, ECON1_BSEL0); 00654 enc28j60ClearBit(interface, ENC28J60_REG_ECON1, ECON1_BSEL1); 00655 break; 00656 case BANK_2: 00657 //Select bank 2 00658 enc28j60ClearBit(interface, ENC28J60_REG_ECON1, ECON1_BSEL0); 00659 enc28j60SetBit(interface, ENC28J60_REG_ECON1, ECON1_BSEL1); 00660 break; 00661 case BANK_3: 00662 //Select bank 3 00663 enc28j60SetBit(interface, ENC28J60_REG_ECON1, ECON1_BSEL1 | ECON1_BSEL0); 00664 break; 00665 default: 00666 //Invalid bank 00667 break; 00668 } 00669 00670 //Save bank number 00671 context->currentBank = bank; 00672 } 00673 } 00674 00675 00676 /** 00677 * @brief Write ENC28J60 register 00678 * @param[in] interface Underlying network interface 00679 * @param[in] address Register address 00680 * @param[in] data Register value 00681 **/ 00682 00683 void enc28j60WriteReg(NetInterface *interface, uint16_t address, uint8_t data) 00684 { 00685 //Make sure the corresponding bank is selected 00686 enc28j60SelectBank(interface, address); 00687 00688 //Pull the CS pin low 00689 interface->spiDriver->assertCs(); 00690 00691 //Write opcode and register address 00692 interface->spiDriver->transfer(ENC28J60_CMD_WCR | (address & REG_ADDR_MASK)); 00693 //Write register value 00694 interface->spiDriver->transfer(data); 00695 00696 //Terminate the operation by raising the CS pin 00697 interface->spiDriver->deassertCs(); 00698 } 00699 00700 00701 /** 00702 * @brief Read ENC28J60 register 00703 * @param[in] interface Underlying network interface 00704 * @param[in] address Register address 00705 * @return Register value 00706 **/ 00707 00708 uint8_t enc28j60ReadReg(NetInterface *interface, uint16_t address) 00709 { 00710 uint16_t data; 00711 00712 //Make sure the corresponding bank is selected 00713 enc28j60SelectBank(interface, address); 00714 00715 //Pull the CS pin low 00716 interface->spiDriver->assertCs(); 00717 00718 //Write opcode and register address 00719 interface->spiDriver->transfer(ENC28J60_CMD_RCR | (address & REG_ADDR_MASK)); 00720 00721 //When reading MAC or MII registers, a dummy byte is first shifted out 00722 if((address & REG_TYPE_MASK) != ETH_REG_TYPE) 00723 interface->spiDriver->transfer(0x00); 00724 00725 //Read register contents 00726 data = interface->spiDriver->transfer(0x00); 00727 00728 //Terminate the operation by raising the CS pin 00729 interface->spiDriver->deassertCs(); 00730 00731 //Return register contents 00732 return data; 00733 } 00734 00735 00736 /** 00737 * @brief Write PHY register 00738 * @param[in] interface Underlying network interface 00739 * @param[in] address PHY register address 00740 * @param[in] data Register value 00741 **/ 00742 00743 void enc28j60WritePhyReg(NetInterface *interface, uint16_t address, uint16_t data) 00744 { 00745 //Write register address 00746 enc28j60WriteReg(interface, ENC28J60_REG_MIREGADR, address & REG_ADDR_MASK); 00747 00748 //Write the lower 8 bits 00749 enc28j60WriteReg(interface, ENC28J60_REG_MIWRL, LSB(data)); 00750 //Write the upper 8 bits 00751 enc28j60WriteReg(interface, ENC28J60_REG_MIWRH, MSB(data)); 00752 00753 //Wait until the PHY register has been written 00754 while(enc28j60ReadReg(interface, ENC28J60_REG_MISTAT) & MISTAT_BUSY); 00755 } 00756 00757 00758 /** 00759 * @brief Read PHY register 00760 * @param[in] interface Underlying network interface 00761 * @param[in] address PHY register address 00762 * @return Register value 00763 **/ 00764 00765 uint16_t enc28j60ReadPhyReg(NetInterface *interface, uint16_t address) 00766 { 00767 uint16_t data; 00768 00769 //Write register address 00770 enc28j60WriteReg(interface, ENC28J60_REG_MIREGADR, address & REG_ADDR_MASK); 00771 00772 //Start read operation 00773 enc28j60WriteReg(interface, ENC28J60_REG_MICMD, MICMD_MIIRD); 00774 //Wait for the read operation to complete 00775 while(enc28j60ReadReg(interface, ENC28J60_REG_MISTAT) & MISTAT_BUSY); 00776 //Clear command register 00777 enc28j60WriteReg(interface, ENC28J60_REG_MICMD, 0); 00778 00779 //Read the lower 8 bits 00780 data = enc28j60ReadReg(interface, ENC28J60_REG_MIRDL); 00781 //Read the upper 8 bits 00782 data |= enc28j60ReadReg(interface, ENC28J60_REG_MIRDH) << 8; 00783 00784 //Return register contents 00785 return data; 00786 } 00787 00788 00789 /** 00790 * @brief Write SRAM buffer 00791 * @param[in] interface Underlying network interface 00792 * @param[in] buffer Multi-part buffer containing the data to be written 00793 * @param[in] offset Offset to the first data byte 00794 **/ 00795 00796 void enc28j60WriteBuffer(NetInterface *interface, 00797 const NetBuffer *buffer, size_t offset) 00798 { 00799 uint_t i; 00800 size_t j; 00801 size_t n; 00802 uint8_t *p; 00803 00804 //Pull the CS pin low 00805 interface->spiDriver->assertCs(); 00806 00807 //Write opcode 00808 interface->spiDriver->transfer(ENC28J60_CMD_WBM); 00809 //Write per-packet control byte 00810 interface->spiDriver->transfer(0x00); 00811 00812 //Loop through data chunks 00813 for(i = 0; i < buffer->chunkCount; i++) 00814 { 00815 //Is there any data to copy from the current chunk? 00816 if(offset < buffer->chunk[i].length) 00817 { 00818 //Point to the first byte to be read 00819 p = (uint8_t *) buffer->chunk[i].address + offset; 00820 //Compute the number of bytes to copy at a time 00821 n = buffer->chunk[i].length - offset; 00822 00823 //Copy data to SRAM buffer 00824 for(j = 0; j < n; j++) 00825 interface->spiDriver->transfer(p[j]); 00826 00827 //Process the next block from the start 00828 offset = 0; 00829 } 00830 else 00831 { 00832 //Skip the current chunk 00833 offset -= buffer->chunk[i].length; 00834 } 00835 } 00836 00837 //Terminate the operation by raising the CS pin 00838 interface->spiDriver->deassertCs(); 00839 } 00840 00841 00842 /** 00843 * @brief Read SRAM buffer 00844 * @param[in] interface Underlying network interface 00845 * @param[in] data Buffer where to store the incoming data 00846 * @param[in] length Number of data to read 00847 **/ 00848 00849 void enc28j60ReadBuffer(NetInterface *interface, 00850 uint8_t *data, size_t length) 00851 { 00852 size_t i; 00853 00854 //Pull the CS pin low 00855 interface->spiDriver->assertCs(); 00856 00857 //Write opcode 00858 interface->spiDriver->transfer(ENC28J60_CMD_RBM); 00859 00860 //Copy data from SRAM buffer 00861 for(i = 0; i < length; i++) 00862 data[i] = interface->spiDriver->transfer(0x00); 00863 00864 //Terminate the operation by raising the CS pin 00865 interface->spiDriver->deassertCs(); 00866 } 00867 00868 00869 /** 00870 * @brief Set bit field 00871 * @param[in] interface Underlying network interface 00872 * @param[in] address Register address 00873 * @param[in] mask Bits to set in the target register 00874 **/ 00875 00876 void enc28j60SetBit(NetInterface *interface, uint16_t address, uint16_t mask) 00877 { 00878 //Pull the CS pin low 00879 interface->spiDriver->assertCs(); 00880 00881 //Write opcode and register address 00882 interface->spiDriver->transfer(ENC28J60_CMD_BFS | (address & REG_ADDR_MASK)); 00883 //Write bit mask 00884 interface->spiDriver->transfer(mask); 00885 00886 //Terminate the operation by raising the CS pin 00887 interface->spiDriver->deassertCs(); 00888 } 00889 00890 00891 /** 00892 * @brief Clear bit field 00893 * @param[in] interface Underlying network interface 00894 * @param[in] address Register address 00895 * @param[in] mask Bits to clear in the target register 00896 **/ 00897 00898 void enc28j60ClearBit(NetInterface *interface, uint16_t address, uint16_t mask) 00899 { 00900 //Pull the CS pin low 00901 interface->spiDriver->assertCs(); 00902 00903 //Write opcode and register address 00904 interface->spiDriver->transfer(ENC28J60_CMD_BFC | (address & REG_ADDR_MASK)); 00905 //Write bit mask 00906 interface->spiDriver->transfer(mask); 00907 00908 //Terminate the operation by raising the CS pin 00909 interface->spiDriver->deassertCs(); 00910 } 00911 00912 00913 /** 00914 * @brief CRC calculation using the polynomial 0x4C11DB7 00915 * @param[in] data Pointer to the data over which to calculate the CRC 00916 * @param[in] length Number of bytes to process 00917 * @return Resulting CRC value 00918 **/ 00919 00920 uint32_t enc28j60CalcCrc(const void *data, size_t length) 00921 { 00922 uint_t i; 00923 uint_t j; 00924 00925 //Point to the data over which to calculate the CRC 00926 const uint8_t *p = (uint8_t *) data; 00927 //CRC preset value 00928 uint32_t crc = 0xFFFFFFFF; 00929 00930 //Loop through data 00931 for(i = 0; i < length; i++) 00932 { 00933 //The message is processed bit by bit 00934 for(j = 0; j < 8; j++) 00935 { 00936 //Update CRC value 00937 if(((crc >> 31) ^ (p[i] >> j)) & 0x01) 00938 crc = (crc << 1) ^ 0x04C11DB7; 00939 else 00940 crc = crc << 1; 00941 } 00942 } 00943 00944 //Return CRC value 00945 return crc; 00946 } 00947 00948 00949 /** 00950 * @brief Dump registers for debugging purpose 00951 * @param[in] interface Underlying network interface 00952 **/ 00953 00954 void enc28j60DumpReg(NetInterface *interface) 00955 { 00956 #if (TRACE_LEVEL >= TRACE_LEVEL_DEBUG) 00957 uint8_t i; 00958 uint8_t bank; 00959 uint16_t address; 00960 00961 //Display header 00962 TRACE_DEBUG(" Bank 0 Bank 1 Bank 2 Bank 3\r\n"); 00963 00964 //Loop through register addresses 00965 for(i = 0; i < 32; i++) 00966 { 00967 //Display register address 00968 TRACE_DEBUG("%02" PRIX8 ": ", i); 00969 00970 //Loop through bank numbers 00971 for(bank = 0; bank < 4; bank++) 00972 { 00973 //Format register address 00974 address = (bank << 8) | i; 00975 00976 //MAC and MII registers require a specific read sequence 00977 if(address >= 0x200 && address <= 0x219) 00978 address |= MAC_REG_TYPE; 00979 else if(address >= 0x300 && address <= 0x305) 00980 address |= MAC_REG_TYPE; 00981 else if(address == 0x30A) 00982 address |= MAC_REG_TYPE; 00983 00984 //Display register contents 00985 TRACE_DEBUG("0x%02" PRIX8 " ", enc28j60ReadReg(interface, address)); 00986 } 00987 00988 //Jump to the following line 00989 TRACE_DEBUG("\r\n"); 00990 } 00991 00992 //Terminate with a line feed 00993 TRACE_DEBUG("\r\n"); 00994 #endif 00995 } 00996 00997 00998 /** 00999 * @brief Dump PHY registers for debugging purpose 01000 * @param[in] interface Underlying network interface 01001 **/ 01002 01003 void enc28j60DumpPhyReg(NetInterface *interface) 01004 { 01005 #if (TRACE_LEVEL >= TRACE_LEVEL_DEBUG) 01006 uint8_t i; 01007 01008 //Loop through PHY registers 01009 for(i = 0; i < 32; i++) 01010 { 01011 //Display current PHY register 01012 TRACE_DEBUG("%02" PRIX8 ": 0x%04" PRIX16 "\r\n", i, enc28j60ReadPhyReg(interface, i)); 01013 } 01014 01015 //Terminate with a line feed 01016 TRACE_DEBUG("\r\n"); 01017 #endif 01018 } 01019
Generated on Tue Jul 12 2022 17:10:13 by
