mbed OS5

Fork of UIPEthernet by Zoltan Hudak

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Enc28J60Network.cpp Source File

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 }