mbed OS5
Fork of UIPEthernet by
Embed:
(wiki syntax)
Show/hide line numbers
Enc28J60Network.cpp
00001 /* 00002 Enc28J60Network.cpp 00003 UIPEthernet network driver for Microchip ENC28J60 Ethernet Interface. 00004 00005 Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de> 00006 All rights reserved. 00007 00008 based on enc28j60.c file from the AVRlib library by Pascal Stang. 00009 For AVRlib See http://www.procyonengineering.com/ 00010 00011 Modified (ported to mbed) by Zoltan Hudak <hudakz@inbox.com> 00012 00013 This program is free software: you can redistribute it and/or modify 00014 it under the terms of the GNU General Public License as published by 00015 the Free Software Foundation, either version 3 of the License, or 00016 (at your option) any later version. 00017 00018 This program is distributed in the hope that it will be useful, 00019 but WITHOUT ANY WARRANTY; without even the implied warranty of 00020 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00021 GNU General Public License for more details. 00022 00023 You should have received a copy of the GNU General Public License 00024 along with this program. If not, see <http://www.gnu.org/licenses/>. 00025 */ 00026 #include "Enc28J60Network.h" 00027 #include "mbed.h" 00028 00029 extern "C" 00030 { 00031 #include "enc28j60.h" 00032 #include "uip.h" 00033 } 00034 00035 uint16_t Enc28J60Network::nextPacketPtr; 00036 uint8_t Enc28J60Network::bank = 0xff; 00037 struct memblock Enc28J60Network::receivePkt; 00038 00039 /** 00040 * @brief 00041 * @note 00042 * @param 00043 * @retval 00044 */ 00045 Enc28J60Network::Enc28J60Network(PinName mosi, PinName miso, PinName sclk, PinName cs) : 00046 myMemoryPool(), 00047 _spi(mosi, miso, sclk), 00048 _cs(cs) 00049 { } 00050 00051 /** 00052 * @brief 00053 * @note 00054 * @param 00055 * @retval 00056 */ 00057 void Enc28J60Network::init(uint8_t* macaddr) { 00058 myMemoryPool::init(); // 1 byte in between RX_STOP_INIT and pool to allow prepending of controlbyte 00059 00060 // initialize SPI interface 00061 _spi.format(8, 0); // 8bit, mode 0 00062 _spi.frequency(7000000); // 7MHz 00063 wait_ms(1000); // 1 second for stable state 00064 00065 // initialize I/O 00066 _cs = 1; // ss=0 00067 00068 // perform system reset 00069 writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET); 00070 wait_ms(50); 00071 00072 // check CLKRDY bit to see if reset is complete 00073 // The CLKRDY does not work. See Rev. B4 Silicon Errata point. Just wait. 00074 //while(!(readReg(ESTAT) & ESTAT_CLKRDY)); 00075 // do bank 0 stuff 00076 // initialize receive buffer 00077 // 16-bit transfers, must write low byte first 00078 // set receive buffer start address 00079 nextPacketPtr = RXSTART_INIT; 00080 00081 // Rx start 00082 writeRegPair(ERXSTL, RXSTART_INIT); 00083 00084 // set receive pointer address 00085 writeRegPair(ERXRDPTL, RXSTART_INIT); 00086 00087 // RX end 00088 writeRegPair(ERXNDL, RXSTOP_INIT); 00089 00090 // TX start 00091 //writeRegPair(ETXSTL, TXSTART_INIT); 00092 // TX end 00093 //writeRegPair(ETXNDL, TXSTOP_INIT); 00094 // do bank 1 stuff, packet filter: 00095 // For broadcast packets we allow only ARP packtets 00096 // All other packets should be unicast only for our mac (MAADR) 00097 // 00098 // The pattern to match on is therefore 00099 // Type ETH.DST 00100 // ARP BROADCAST 00101 // 06 08 -- ff ff ff ff ff ff -> ip checksum for theses bytes=f7f9 00102 // in binary these poitions are:11 0000 0011 1111 00103 // This is hex 303F->EPMM0=0x3f,EPMM1=0x30 00104 //TODO define specific pattern to receive dhcp-broadcast packages instead of setting ERFCON_BCEN! 00105 writeReg(ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_PMEN | ERXFCON_BCEN); 00106 writeRegPair(EPMM0, 0x303f); 00107 writeRegPair(EPMCSL, 0xf7f9); 00108 00109 // 00110 // 00111 // do bank 2 stuff 00112 // enable MAC receive 00113 // and bring MAC out of reset (writes 0x00 to MACON2) 00114 writeRegPair(MACON1, MACON1_MARXEN | MACON1_TXPAUS | MACON1_RXPAUS); 00115 00116 // enable automatic padding to 60bytes and CRC operations 00117 writeOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN); 00118 00119 // set inter-frame gap (non-back-to-back) 00120 writeRegPair(MAIPGL, 0x0C12); 00121 00122 // set inter-frame gap (back-to-back) 00123 writeReg(MABBIPG, 0x12); 00124 00125 // Set the maximum packet size which the controller will accept 00126 // Do not send packets longer than MAX_FRAMELEN: 00127 writeRegPair(MAMXFLL, MAX_FRAMELEN); 00128 00129 // do bank 3 stuff 00130 // write MAC address 00131 // NOTE: MAC address in ENC28J60 is byte-backward 00132 writeReg(MAADR5, macaddr[0]); 00133 writeReg(MAADR4, macaddr[1]); 00134 writeReg(MAADR3, macaddr[2]); 00135 writeReg(MAADR2, macaddr[3]); 00136 writeReg(MAADR1, macaddr[4]); 00137 writeReg(MAADR0, macaddr[5]); 00138 00139 // no loopback of transmitted frames 00140 phyWrite(PHCON2, PHCON2_HDLDIS); 00141 00142 // switch to bank 0 00143 setBank(ECON1); 00144 00145 // enable interrutps 00146 writeOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE | EIE_PKTIE); 00147 00148 // enable packet reception 00149 writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); 00150 00151 clkout(2); // change clkout from 6.25MHz to 12.5MHz 00152 wait_us(60); // 60us 00153 00154 //Configure leds 00155 phyWrite(PHLCON, 0x476); 00156 } 00157 00158 /** 00159 * @brief 00160 * @note 00161 * @param 00162 * @retval 00163 */ 00164 memhandle Enc28J60Network::receivePacket(void) { 00165 uint8_t rxstat; 00166 uint16_t len; 00167 // check if a packet has been received and buffered 00168 00169 //if( !(readReg(EIR) & EIR_PKTIF) ){ 00170 // The above does not work. See Rev. B4 Silicon Errata point 6. 00171 if (readReg(EPKTCNT) != 0) { 00172 uint16_t readPtr = nextPacketPtr + 00173 6 > RXSTOP_INIT ? nextPacketPtr + 00174 6 - 00175 RXSTOP_INIT + 00176 RXSTART_INIT : nextPacketPtr + 00177 6; 00178 // Set the read pointer to the start of the received packet 00179 00180 writeRegPair(ERDPTL, nextPacketPtr); 00181 00182 // read the next packet pointer 00183 nextPacketPtr = readOp(ENC28J60_READ_BUF_MEM, 0); 00184 nextPacketPtr |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; 00185 00186 // read the packet length (see datasheet page 43) 00187 len = readOp(ENC28J60_READ_BUF_MEM, 0); 00188 len |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; 00189 len -= 4; //remove the CRC count 00190 00191 // read the receive status (see datasheet page 43) 00192 rxstat = readOp(ENC28J60_READ_BUF_MEM, 0); 00193 00194 //rxstat |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; 00195 #ifdef ENC28J60DEBUG 00196 printf 00197 ( 00198 "receivePacket [%d-%d], next: %d, stat: %d, count: %d -> ", 00199 readPtr, 00200 (readPtr + len) % (RXSTOP_INIT + 1), 00201 nextPacketPtr, 00202 rxstat, 00203 readReg(EPKTCNT) 00204 ); 00205 (rxstat & 0x80) != 0 ? printf("OK") : printf("failed"); 00206 printf("\r\n"); 00207 #endif 00208 // decrement the packet counter indicate we are done with this packet 00209 00210 writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC); 00211 00212 // check CRC and symbol errors (see datasheet page 44, table 7-3): 00213 // The ERXFCON.CRCEN is set by default. Normally we should not 00214 // need to check this. 00215 if ((rxstat & 0x80) != 0) { 00216 receivePkt.begin = readPtr; 00217 receivePkt.size = len; 00218 return UIP_RECEIVEBUFFERHANDLE; 00219 } 00220 00221 // Move the RX read pointer to the start of the next received packet 00222 // This frees the memory we just read out 00223 setERXRDPT(); 00224 } 00225 00226 return(NOBLOCK); 00227 } 00228 00229 /** 00230 * @brief 00231 * @note 00232 * @param 00233 * @retval 00234 */ 00235 void Enc28J60Network::setERXRDPT(void) { 00236 writeRegPair(ERXRDPTL, nextPacketPtr == RXSTART_INIT ? RXSTOP_INIT : nextPacketPtr - 1); 00237 } 00238 00239 /** 00240 * @brief 00241 * @note 00242 * @param 00243 * @retval 00244 */ 00245 memaddress Enc28J60Network::blockSize(memhandle handle) { 00246 return handle == NOBLOCK ? 0 : handle == UIP_RECEIVEBUFFERHANDLE ? receivePkt.size : blocks[handle].size; 00247 } 00248 00249 /** 00250 * @brief 00251 * @note 00252 * @param 00253 * @retval 00254 */ 00255 void Enc28J60Network::sendPacket(memhandle handle) { 00256 memblock* packet = &blocks[handle]; 00257 uint16_t start = packet->begin - 1; 00258 uint16_t end = start + packet->size; 00259 00260 // backup data at control-byte position 00261 uint8_t data = readByte(start); 00262 // write control-byte (if not 0 anyway) 00263 00264 if (data) 00265 writeByte(start, 0); 00266 00267 #ifdef ENC28J60DEBUG 00268 printf("sendPacket(%d) [%d-%d]: ", handle, start, end); 00269 for (uint16_t i = start; i <= end; i++) { 00270 printf("%d ", readByte(i)); 00271 } 00272 00273 printf("\r\n"); 00274 #endif 00275 // TX start 00276 00277 writeRegPair(ETXSTL, start); 00278 00279 // Set the TXND pointer to correspond to the packet size given 00280 writeRegPair(ETXNDL, end); 00281 00282 // send the contents of the transmit buffer onto the network 00283 writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS); 00284 00285 // Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12. 00286 if ((readReg(EIR) & EIR_TXERIF)) { 00287 writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRTS); 00288 } 00289 00290 //restore data on control-byte position 00291 if (data) 00292 writeByte(start, data); 00293 } 00294 00295 /** 00296 * @brief 00297 * @note 00298 * @param 00299 * @retval 00300 */ 00301 uint16_t Enc28J60Network::setReadPtr(memhandle handle, memaddress position, uint16_t len) { 00302 memblock* packet = handle == UIP_RECEIVEBUFFERHANDLE ? &receivePkt : &blocks[handle]; 00303 memaddress start = handle == UIP_RECEIVEBUFFERHANDLE 00304 && packet->begin + 00305 position > RXSTOP_INIT ? packet->begin + 00306 position - 00307 RXSTOP_INIT + 00308 RXSTART_INIT : packet->begin + 00309 position; 00310 00311 writeRegPair(ERDPTL, start); 00312 00313 if (len > packet->size - position) 00314 len = packet->size - position; 00315 return len; 00316 } 00317 00318 /** 00319 * @brief 00320 * @note 00321 * @param 00322 * @retval 00323 */ 00324 uint16_t Enc28J60Network::readPacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len) { 00325 len = setReadPtr(handle, position, len); 00326 readBuffer(len, buffer); 00327 return len; 00328 } 00329 00330 /** 00331 * @brief 00332 * @note 00333 * @param 00334 * @retval 00335 */ 00336 uint16_t Enc28J60Network::writePacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len) { 00337 memblock* packet = &blocks[handle]; 00338 uint16_t start = packet->begin + position; 00339 00340 writeRegPair(EWRPTL, start); 00341 00342 if (len > packet->size - position) 00343 len = packet->size - position; 00344 writeBuffer(len, buffer); 00345 return len; 00346 } 00347 00348 /** 00349 * @brief 00350 * @note 00351 * @param 00352 * @retval 00353 */ 00354 uint8_t Enc28J60Network::readByte(uint16_t addr) { 00355 uint8_t result; 00356 00357 writeRegPair(ERDPTL, addr); 00358 00359 _cs = 0; 00360 00361 // issue read command 00362 _spi.write(ENC28J60_READ_BUF_MEM); 00363 00364 // read data 00365 result = _spi.write(0x00); 00366 _cs = 1; 00367 return(result); 00368 } 00369 00370 /** 00371 * @brief 00372 * @note 00373 * @param 00374 * @retval 00375 */ 00376 void Enc28J60Network::writeByte(uint16_t addr, uint8_t data) { 00377 writeRegPair(EWRPTL, addr); 00378 00379 _cs = 0; 00380 00381 // issue write command 00382 _spi.write(ENC28J60_WRITE_BUF_MEM); 00383 00384 // write data 00385 _spi.write(data); 00386 _cs = 1; 00387 } 00388 00389 /** 00390 * @brief 00391 * @note 00392 * @param 00393 * @retval 00394 */ 00395 void Enc28J60Network::copyPacket 00396 ( 00397 memhandle dest_pkt, 00398 memaddress dest_pos, 00399 memhandle src_pkt, 00400 memaddress src_pos, 00401 uint16_t len 00402 ) { 00403 memblock* dest = &blocks[dest_pkt]; 00404 memblock* src = src_pkt == UIP_RECEIVEBUFFERHANDLE ? &receivePkt : &blocks[src_pkt]; 00405 memaddress start = src_pkt == UIP_RECEIVEBUFFERHANDLE 00406 && src->begin + 00407 src_pos > RXSTOP_INIT ? src->begin + 00408 src_pos - 00409 RXSTOP_INIT + 00410 RXSTART_INIT : src->begin + 00411 src_pos; 00412 enc28J60_mempool_block_move_callback(dest->begin + dest_pos, start, len); 00413 00414 // Move the RX read pointer to the start of the next received packet 00415 // This frees the memory we just read out 00416 setERXRDPT(); 00417 } 00418 00419 /** 00420 * @brief 00421 * @note 00422 * @param 00423 * @retval 00424 */ 00425 void Enc28J60Network::freePacket(void) { 00426 setERXRDPT(); 00427 } 00428 00429 /** 00430 * @brief 00431 * @note 00432 * @param 00433 * @retval 00434 */ 00435 uint8_t Enc28J60Network::readOp(uint8_t op, uint8_t address) { 00436 uint8_t result; 00437 00438 _cs = 0; 00439 00440 // issue read command 00441 _spi.write(op | (address & ADDR_MASK)); 00442 00443 // read data 00444 result = _spi.write(0x00); 00445 00446 // do dummy read if needed (for mac and mii, see datasheet page 29) 00447 if (address & 0x80) 00448 result = _spi.write(0x00); 00449 00450 // release CS 00451 _cs = 1; 00452 return(result); 00453 } 00454 00455 /** 00456 * @brief 00457 * @note 00458 * @param 00459 * @retval 00460 */ 00461 void Enc28J60Network::writeOp(uint8_t op, uint8_t address, uint8_t data) { 00462 _cs = 0; 00463 00464 // issue write command 00465 _spi.write(op | (address & ADDR_MASK)); 00466 00467 // write data 00468 _spi.write(data); 00469 _cs = 1; 00470 } 00471 00472 /** 00473 * @brief 00474 * @note 00475 * @param 00476 * @retval 00477 */ 00478 void Enc28J60Network::readBuffer(uint16_t len, uint8_t* data) { 00479 _cs = 0; 00480 00481 // issue read command 00482 _spi.write(ENC28J60_READ_BUF_MEM); 00483 while (len) { 00484 len--; 00485 00486 // read data 00487 *data = _spi.write(0x00); 00488 data++; 00489 } 00490 00491 *data = '\0'; 00492 _cs = 1; 00493 } 00494 00495 /** 00496 * @brief 00497 * @note 00498 * @param 00499 * @retval 00500 */ 00501 void Enc28J60Network::writeBuffer(uint16_t len, uint8_t* data) { 00502 _cs = 0; 00503 00504 // issue write command 00505 _spi.write(ENC28J60_WRITE_BUF_MEM); 00506 while (len) { 00507 len--; 00508 00509 // write data 00510 _spi.write(*data); 00511 data++; 00512 } 00513 00514 _cs = 1; 00515 } 00516 00517 /** 00518 * @brief 00519 * @note 00520 * @param 00521 * @retval 00522 */ 00523 void Enc28J60Network::setBank(uint8_t address) { 00524 00525 // set the bank (if needed) 00526 00527 if ((address & BANK_MASK) != bank) { 00528 00529 // set the bank 00530 writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1 | ECON1_BSEL0)); 00531 writeOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK) >> 5); 00532 bank = (address & BANK_MASK); 00533 } 00534 } 00535 00536 /** 00537 * @brief 00538 * @note 00539 * @param 00540 * @retval 00541 */ 00542 uint8_t Enc28J60Network::readReg(uint8_t address) { 00543 00544 // set the bank 00545 00546 setBank(address); 00547 00548 // do the read 00549 return readOp(ENC28J60_READ_CTRL_REG, address); 00550 } 00551 00552 /** 00553 * @brief 00554 * @note 00555 * @param 00556 * @retval 00557 */ 00558 void Enc28J60Network::writeReg(uint8_t address, uint8_t data) { 00559 00560 // set the bank 00561 00562 setBank(address); 00563 00564 // do the write 00565 writeOp(ENC28J60_WRITE_CTRL_REG, address, data); 00566 } 00567 00568 /** 00569 * @brief 00570 * @note 00571 * @param 00572 * @retval 00573 */ 00574 void Enc28J60Network::writeRegPair(uint8_t address, uint16_t data) { 00575 00576 // set the bank 00577 00578 setBank(address); 00579 00580 // do the write 00581 writeOp(ENC28J60_WRITE_CTRL_REG, address, (data & 0xFF)); 00582 writeOp(ENC28J60_WRITE_CTRL_REG, address + 1, (data) >> 8); 00583 } 00584 00585 /** 00586 * @brief 00587 * @note 00588 * @param 00589 * @retval 00590 */ 00591 void Enc28J60Network::phyWrite(uint8_t address, uint16_t data) { 00592 00593 // set the PHY register address 00594 00595 writeReg(MIREGADR, address); 00596 00597 // write the PHY data 00598 writeRegPair(MIWRL, data); 00599 00600 // wait until the PHY write completes 00601 while (readReg(MISTAT) & MISTAT_BUSY) { 00602 wait_us(15); 00603 } 00604 } 00605 00606 /** 00607 * @brief 00608 * @note 00609 * @param 00610 * @retval 00611 */ 00612 uint16_t Enc28J60Network::phyRead(uint8_t address) { 00613 writeReg(MIREGADR, address); 00614 writeReg(MICMD, MICMD_MIIRD); 00615 00616 // wait until the PHY read completes 00617 while (readReg(MISTAT) & MISTAT_BUSY) { 00618 wait_us(15); 00619 } //and MIRDH 00620 00621 writeReg(MICMD, 0); 00622 return(readReg(MIRDL) | readReg(MIRDH) << 8); 00623 } 00624 00625 /** 00626 * @brief 00627 * @note 00628 * @param 00629 * @retval 00630 */ 00631 void Enc28J60Network::clkout(uint8_t clk) { 00632 00633 //setup clkout: 2 is 12.5MHz: 00634 00635 writeReg(ECOCON, clk & 0x7); 00636 } 00637 00638 // read the revision of the chip: 00639 uint8_t Enc28J60Network::getrev(void) { 00640 return(readReg(EREVID)); 00641 } 00642 00643 /** 00644 * @brief 00645 * @note 00646 * @param 00647 * @retval 00648 */ 00649 uint16_t Enc28J60Network::chksum(uint16_t sum, memhandle handle, memaddress pos, uint16_t len) { 00650 uint8_t spdr; 00651 uint16_t t; 00652 uint16_t i; 00653 00654 len = setReadPtr(handle, pos, len) - 1; 00655 _cs = 0; 00656 00657 // issue read command 00658 spdr = _spi.write(ENC28J60_READ_BUF_MEM); 00659 for (i = 0; i < len; i += 2) { 00660 00661 // read data 00662 spdr = _spi.write(0x00); 00663 t = spdr << 8; 00664 spdr = _spi.write(0x00); 00665 t += spdr; 00666 sum += t; 00667 if (sum < t) { 00668 sum++; /* carry */ 00669 } 00670 } 00671 00672 if (i == len) { 00673 spdr = _spi.write(0x00); 00674 t = (spdr << 8) + 0; 00675 sum += t; 00676 if (sum < t) { 00677 sum++; /* carry */ 00678 } 00679 } 00680 00681 _cs = 1; 00682 00683 /* Return sum in host byte order. */ 00684 return sum; 00685 } 00686 00687 /** 00688 * @brief 00689 * @note 00690 * @param 00691 * @retval 00692 */ 00693 void Enc28J60Network::powerOff(void) { 00694 writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXEN); 00695 wait_ms(50); 00696 writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_VRPS); 00697 wait_ms(50); 00698 writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PWRSV); 00699 } 00700 00701 /** 00702 * @brief 00703 * @note 00704 * @param 00705 * @retval 00706 */ 00707 void Enc28J60Network::powerOn(void) { 00708 writeOp(ENC28J60_BIT_FIELD_CLR, ECON2, ECON2_PWRSV); 00709 wait_ms(50); 00710 writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); 00711 wait_ms(50); 00712 } 00713 00714 /** 00715 * @brief 00716 * @note 00717 * @param 00718 * @retval 00719 */ 00720 bool Enc28J60Network::linkStatus(void) { 00721 return(phyRead(PHSTAT2) & 0x0400) > 0; 00722 }
Generated on Tue Jul 12 2022 18:10:58 by 1.7.2