Zoltan Hudak / ENC28J60-EMAC

Dependents:   MQTT_Hello MQTT_HelloENC28J60

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers enc28j60.cpp Source File

enc28j60.cpp

00001 /*
00002  * Copyright (c) 2019 Tobias Jaster
00003  *
00004  * Modified by Zoltan Hudak
00005  *
00006  * Licensed under the Apache License, Version 2.0 (the "License");
00007  * you may not use this file except in compliance with the License.
00008  * You may obtain a copy of the License at
00009  *
00010  *     http://www.apache.org/licenses/LICENSE-2.0
00011  *
00012  * Unless required by applicable law or agreed to in writing, software
00013  * distributed under the License is distributed on an "AS IS" BASIS,
00014  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015  * See the License for the specific language governing permissions and
00016  * limitations under the License.
00017  */
00018 #include "cmsis.h"
00019 #include "enc28j60.h"
00020 
00021 #ifndef NULL
00022 #define NULL    ((void*)0)
00023 #endif
00024 #define ENC28J60_DEBUG  0
00025 
00026 #if ENC28J60_DEBUG
00027 #define ENC28J60_DEBUG_PRINTF(...)  printf(__VA_ARGS__)
00028 #else
00029 #define ENC28J60_DEBUG_PRINTF(...)
00030 #endif
00031 /** Millisec timeout macros */
00032 #define RESET_TIME_OUT_MS       10ms
00033 #define REG_WRITE_TIME_OUT_MS   50ms
00034 #define PHY_RESET_TIME_OUT_MS   100ms
00035 #define INIT_FINISH_DELAY       2000ms
00036 
00037 /**
00038  * \brief TX FIFO Size definitions
00039  *
00040  */
00041 #define TX_STATUS_FIFO_SIZE_BYTES       512U    /*< fixed allocation in bytes */
00042 #define TX_DATA_FIFO_SIZE_KBYTES_POS    8U
00043 #define TX_DATA_FIFO_SIZE_KBYTES_MASK   0x0FU
00044 #define KBYTES_TO_BYTES_MULTIPLIER      1024U
00045 
00046 /**
00047  * \brief FIFO Info definitions
00048  *
00049  */
00050 #define FIFO_USED_SPACE_MASK        0xFFFFU
00051 #define DATA_FIFO_USED_SPACE_POS    0U
00052 #define STATUS_FIFO_USED_SPACE_POS  16U
00053 
00054 #define HW_CFG_REG_RX_FIFO_POS      10U
00055 #define HW_CFG_REG_RX_FIFO_SIZE_ALL 8U
00056 #define HW_CFG_REG_RX_FIFO_SIZE_MIN 2U          /*< Min Rx fifo size in KB */
00057 #define HW_CFG_REG_RX_FIFO_SIZE_MAX 6U          /*< Max Rx fifo size in KB */
00058 #define HW_CFG_REG_RX_FIFO_SIZE     5U          /*< Rx fifo size in KB */
00059 
00060 /**
00061  * @brief
00062  * @note
00063  * @param
00064  * @retval
00065  */
00066 ENC28J60::ENC28J60(PinName mosi, PinName miso, PinName sclk, PinName cs) :
00067     _spi(new SPI(mosi, miso, sclk)),
00068     _cs(cs),
00069     _bank(0),
00070     _ready(true),
00071     _next(ERXST_INI)
00072 {
00073     init();
00074 }
00075 
00076 /**
00077  * @brief
00078  * @note
00079  * @param
00080  * @retval
00081  */
00082 ENC28J60::ENC28J60(mbed::SPI* spi, PinName cs) :
00083     _spi(spi),
00084     _cs(cs),
00085     _bank(0),
00086     _ready(true),
00087     _next(ERXST_INI)
00088 {
00089     init();
00090 }
00091 
00092 /**
00093  * @brief
00094  * @note
00095  * @param
00096  * @retval
00097  */
00098 void ENC28J60::init()
00099 {
00100     // Initialize SPI interface
00101     _cs = 1;
00102     _spi->format(8, 0);         // 8bit, mode 0
00103     _spi->frequency(20000000);  // 20MHz
00104 
00105     // Wait SPI to become stable
00106     ThisThread::sleep_for(RESET_TIME_OUT_MS);
00107 
00108     // Perform system reset
00109     writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
00110 
00111     // Check CLKRDY bit to see if reset is complete
00112     // while(!(readReg(ESTAT) & ESTAT_CLKRDY));
00113     // The CLKRDY does not work. See Rev. B4 Silicon Errata point.
00114     // Workaround: Just wait.
00115     ThisThread::sleep_for(RESET_TIME_OUT_MS);
00116 
00117     // Set pointers to receive buffer boundaries
00118     writeRegPair(ERXSTL, ERXST_INI);
00119     writeRegPair(ERXNDL, ERXND_INI);
00120 
00121     // Set receive pointer. Receive hardware will write data up to,
00122     // but not including the memory pointed to by ERXRDPT
00123     writeReg(ERXRDPTL, ERXST_INI);
00124 
00125     // All memory which is not used by the receive buffer is considered the transmission buffer.
00126     // No explicit action is required to initialize the transmission buffer.
00127     // TX buffer start.
00128     writeRegPair(ETXSTL, ETXST_INI);
00129 
00130     // TX buffer end at end of ethernet buffer memory.
00131     writeRegPair(ETXNDL, ETXND_INI);
00132 
00133     // However, he host controller should leave at least seven bytes between each
00134     // packet and the beginning of the receive buffer.
00135     // do bank 1 stuff, packet filter:
00136     // For broadcast packets we allow only ARP packtets
00137     // All other packets should be unicast only for our mac (MAADR)
00138     //
00139     // The pattern to match is therefore
00140     // Type     ETH.DST
00141     // ARP      BROADCAST
00142     // 06 08 -- ff ff ff ff ff ff -> ip checksum for theses bytes=f7f9
00143     // in binary these poitions are:11 0000 0011 1111
00144     // This is hex 303F->EPMM0=0x3f,EPMM1=0x30
00145     //TODO define specific pattern to receive dhcp-broadcast packages instead of setting ERFCON_BCEN!
00146     writeReg(ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_PMEN | ERXFCON_BCEN);
00147     writeRegPair(EPMM0, 0x303f);
00148     writeRegPair(EPMCSL, 0xf7f9);
00149 
00150     // Enable MAC receive and bring MAC out of reset (writes 0x00 to MACON2)
00151     writeRegPair(MACON1, MACON1_MARXEN | MACON1_TXPAUS | MACON1_RXPAUS);
00152 
00153     // Enable automatic padding to 60bytes and CRC operations
00154     writeOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN);
00155 
00156     // Set inter-frame gap (non-back-to-back)
00157     writeRegPair(MAIPGL, 0x0C12);
00158 
00159     // Set inter-frame gap (back-to-back)
00160     writeReg(MABBIPG, 0x12);
00161 
00162     // Set the maximum packet size which the controller will accept
00163     // Do not send packets longer than MAX_FRAMELEN:
00164     writeRegPair(MAMXFLL, MAX_FRAMELEN);
00165 
00166     // No loopback of transmitted frames
00167     phyWrite(PHCON2, PHCON2_HDLDIS);
00168 
00169     // Switch to bank 0
00170     _setBank(ECON1);
00171 
00172     // Enable interrutps
00173     writeOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE | EIE_PKTIE);
00174 
00175     // Enable packet reception
00176     writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
00177 
00178     // Configure leds
00179     phyWrite(PHLCON, 0x476);
00180 }
00181 
00182 /**
00183  * @brief
00184  * @note
00185  * @param
00186  * @retval
00187  */
00188 enc28j60_error_t ENC28J60::getPacketInfo(packet_t* packet)
00189 {
00190     enc28j60_error_t    ret;
00191     uint8_t             nextPacketAddrL;
00192     uint8_t             nextPacketAddrH;
00193     uint8_t             status[RX_STAT_LEN];
00194 
00195     if (!_ready)
00196         return ENC28J60_ERROR_LASTPACKET;
00197 
00198     // Check if a new packet has been received and buffered.
00199     // The Receive Packet Pending Interrupt Flag (EIR.PKTIF) does not reliably
00200     // report the status of pending packets. See Rev. B4 Silicon Errata point 6.
00201     // Workaround: Check EPKTCNT
00202     if (readReg(EPKTCNT) == 0)
00203         return ENC28J60_ERROR_NOPACKET;
00204 
00205     _ready = false;
00206 
00207     // Packet pointer in receive buffer is wrapped by hardware.
00208     packet->addr = _next;
00209 
00210     // Program the receive buffer read pointer to point to this packet.
00211     writeRegPair(ERDPTL, packet->addr);
00212 
00213     // Read the next packet address
00214     nextPacketAddrL = readOp(ENC28J60_READ_BUF_MEM, 0);
00215     nextPacketAddrH = readOp(ENC28J60_READ_BUF_MEM, 0);
00216     _next = (nextPacketAddrH << 8) | nextPacketAddrL;
00217 
00218     // Read the packet status vector bytes (see datasheet page 43)
00219     for (uint8_t i = 0; i < RX_STAT_LEN; i++) {
00220         status[i] = readOp(ENC28J60_READ_BUF_MEM, 0);
00221     }
00222 
00223     // Get payload length (see datasheet page 43)
00224     packet->payload.len = (status[1] << 8) | status[0];
00225 
00226     // Remove CRC bytes
00227     packet->payload.len -= RX_CRC_LEN;
00228 
00229     // Check CRC and symbol errors (see datasheet page 44, table 7-3):
00230     // The ERXFCON.CRCEN is set by default. Normally we should not
00231     // need to check this.
00232     // Bit 7 in byte 3 of receive status vectors indicates that the packet
00233     // had a valid CRC and no symbol errors.
00234     if ((status[2] & (1 << 7)) != 0) {
00235         ret = ENC28J60_ERROR_OK;
00236     }
00237     else {
00238         // Drop faulty packet:
00239         // Move the receive read pointer to the begin of the next packet.
00240         // This frees the memory we just read out.
00241         freeRxBuffer();
00242         ret = ENC28J60_ERROR_RECEIVE;
00243     }
00244 
00245     // Decrement the packet counter to indicate we are done with this packet.
00246     writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
00247 
00248     return ret;
00249 }
00250 
00251 /**
00252  * @brief
00253  * @note
00254  * @param
00255  * @retval
00256  */
00257 void ENC28J60::readPacket(packet_t* packet)
00258 {
00259     // Read operation in receive buffer wraps the read pointer automatically.
00260     // To utilize this feature we program the receive buffer read pointer (ERDPTL)
00261     // to point to the begin of this packet (see datasheet page 43).
00262     // Then we read the next packet pointer bytes + packet status vector bytes
00263     // rather than calculating the payload position and advancing ERDPTL by software.
00264     writeRegPair(ERDPTL, packet->addr);
00265 
00266     // Advance the read pointer to the payload by reading bytes out of interest.
00267     for (uint8_t i = 0; i < (RX_NEXT_LEN + RX_STAT_LEN); i++)
00268         readOp(ENC28J60_READ_BUF_MEM, 0);
00269 
00270     // The receive buffer read pointer is now pointing to the correct place.
00271     // We can read packet payload bytes.
00272     readBuf(packet->payload.buf, packet->payload.len);
00273 }
00274 
00275 /**
00276  * @brief   Frees the memory occupied by last packet.
00277  * @note    Programs the Receive Pointer (ERXRDPT)to point to the next
00278  *          packet address. Receive hardware will write data up to,
00279  *          but not including the memory pointed to by ERXRDPT.
00280  * @param
00281  * @retval
00282  */
00283 void ENC28J60::freeRxBuffer(void)
00284 {
00285     // Compensate for the errata rev B7, point 11:
00286     // The receive hardware may corrupt the circular
00287     // receive buffer (including the Next Packet Pointer
00288     // and receive status vector fields) when an even value
00289     // is programmed into the ERXRDPTH:ERXRDPTL registers.
00290     // Workaround: Never write an even address!
00291     if ((_next - 1 < ERXST_INI) || (_next - 1 > ERXND_INI))
00292         writeRegPair(ERXRDPTL, ERXND_INI);
00293     else
00294         writeRegPair(ERXRDPTL, _next - 1);
00295 
00296     _ready = true;  // ready for next packet
00297 }
00298 
00299 /**
00300  * @brief
00301  * @note
00302  * @param
00303  * @retval
00304  */
00305 enc28j60_error_t ENC28J60::loadPacketInTxBuffer(packet_t* packet)
00306 {
00307     uint8_t             controlByte = 0;
00308     enc28j60_error_t    error = ENC28J60_ERROR_OK;
00309     uint16_t            packetLen = TX_CTRL_LEN + packet->payload.len + TX_STAT_LEN;
00310 
00311     if (packetLen > ETXND_INI - ETXST_INI) {
00312         error = ENC28J60_ERROR_FIFOFULL;
00313         return error;
00314     }
00315 
00316     setWritePrt(ETXST_INI, 0);
00317 
00318     //_tx_packet.payload.len = data_len;
00319     writeBuf(&controlByte, sizeof(controlByte));
00320     error = setWritePrt(ETXST_INI, sizeof(controlByte));
00321     writeBuf(packet->payload.buf, packet->payload.len);
00322 
00323     return error;
00324 }
00325 
00326 /**
00327  * @brief
00328  * @note
00329  * @param
00330  * @retval
00331  */
00332 enc28j60_error_t ENC28J60::softReset(void)
00333 {
00334     writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
00335 
00336     ThisThread::sleep_for(1ms);
00337     return ENC28J60_ERROR_OK;
00338 }
00339 
00340 /**
00341  * @brief
00342  * @note
00343  * @param
00344  * @retval
00345  */
00346 void ENC28J60::setRxBufSize(uint32_t size_kb)
00347 {
00348     if (size_kb >= HW_CFG_REG_RX_FIFO_SIZE_MIN && size_kb <= HW_CFG_REG_RX_FIFO_SIZE_MAX) {
00349         writeRegPair(ERXSTL, ERXST_INI);
00350 
00351         // set receive pointer address
00352         writeRegPair(ERXRDPTL, ERXST_INI);
00353 
00354         // RX end
00355         writeRegPair(ERXNDL, 0x1FFF - (size_kb << HW_CFG_REG_RX_FIFO_POS));
00356     }
00357 }
00358 
00359 /**
00360  * @brief
00361  * @note
00362  * @param
00363  * @retval
00364  */
00365 enc28j60_error_t ENC28J60::resetPhy(void)
00366 {
00367     enc28j60_error_t    error = ENC28J60_ERROR_OK;
00368     uint16_t            phcon1 = 0;
00369     error = phyRead(PHCON1, &phcon1);
00370     if (error)
00371         return ENC28J60_ERROR_TIMEOUT;
00372     error = phyWrite(PHCON1, (phcon1 | PHCON1_PRST));
00373     if (error)
00374         return ENC28J60_ERROR_TIMEOUT;
00375     ThisThread::sleep_for(PHY_RESET_TIME_OUT_MS);
00376     error = phyRead(PHCON1, &phcon1);
00377     if (error || (phcon1 & PHCON1_PRST) != 0) {
00378         return ENC28J60_ERROR_TIMEOUT;
00379     }
00380 
00381     return ENC28J60_ERROR_OK;
00382 }
00383 
00384 /**
00385  * @brief
00386  * @note
00387  * @param
00388  * @retval
00389  */
00390 void ENC28J60::enableMacRecv(void)
00391 {
00392     writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
00393 }
00394 
00395 /**
00396  * @brief
00397  * @note
00398  * @param
00399  * @retval
00400  */
00401 void ENC28J60::disableMacRecv(void)
00402 {
00403     writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXEN);
00404 }
00405 
00406 /**
00407  * @brief
00408  * @note
00409  * @param
00410  * @retval
00411  */
00412 enc28j60_error_t ENC28J60::readMacAddr(char* mac)
00413 {
00414     if (!mac) {
00415         return ENC28J60_ERROR_PARAM;
00416     }
00417 
00418     _setBank(MAADR0);
00419 
00420     mac[0] = readReg(MAADR5);
00421     mac[1] = readReg(MAADR4);
00422     mac[2] = readReg(MAADR3);
00423     mac[3] = readReg(MAADR2);
00424     mac[4] = readReg(MAADR1);
00425     mac[5] = readReg(MAADR0);
00426 
00427     return ENC28J60_ERROR_OK;
00428 }
00429 
00430 /**
00431  * @brief
00432  * @note
00433  * @param
00434  * @retval
00435  */
00436 enc28j60_error_t ENC28J60::writeMacAddr(char* mac)
00437 {
00438     if (!mac) {
00439         return ENC28J60_ERROR_PARAM;
00440     }
00441 
00442     _setBank(MAADR0);
00443 
00444     writeReg(MAADR5, mac[0]);
00445     writeReg(MAADR4, mac[1]);
00446     writeReg(MAADR3, mac[2]);
00447     writeReg(MAADR2, mac[3]);
00448     writeReg(MAADR1, mac[4]);
00449     writeReg(MAADR0, mac[5]);
00450 
00451     return ENC28J60_ERROR_OK;
00452 }
00453 
00454 /**
00455  * @brief
00456  * @note
00457  * @param
00458  * @retval
00459  */
00460 enc28j60_error_t ENC28J60::setWritePrt(uint16_t position, uint16_t offset)
00461 {
00462     uint32_t    start = position + offset > ETXND_INI ? position + offset - ETXND_INI + ETXST_INI : position + offset;
00463 
00464     writeRegPair(EWRPTL, start);
00465 
00466     return ENC28J60_ERROR_OK;
00467 }
00468 
00469 /**
00470  * @brief
00471  * @note
00472  * @param
00473  * @retval
00474  */
00475 enc28j60_error_t ENC28J60::transmitPacket(packet_t* packet)
00476 {
00477     // Set Transmit Buffer Start pointer
00478     writeRegPair(ETXSTL, ETXST_INI);
00479 
00480     // Set Transmit Buffer End pointer
00481     writeRegPair(ETXNDL, ETXST_INI + TX_CTRL_LEN + packet->payload.len);
00482 
00483     // Enable transmittion
00484     writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
00485 
00486     // Wait until transmission is completed
00487     while ((readReg(ECON1) & ECON1_TXRTS) != 0) { }
00488 
00489     // Chek whether the transmission was successfull
00490     if ((readReg(ESTAT) & ESTAT_TXABRT) == 0)
00491         return ENC28J60_ERROR_OK;
00492     else
00493         return ENC28J60_ERROR_NEXTPACKET;
00494 }
00495 
00496 
00497 /**
00498  * @brief
00499  * @note
00500  * @param
00501  * @retval
00502  */
00503 uint32_t ENC28J60::getRxBufFreeSpace(void)
00504 {
00505     uint16_t    readPointer = getRecvPointer();
00506     uint16_t    writePointer = getWritePointer();
00507     uint32_t    freeSpace = 0;
00508     if (writePointer > readPointer) {
00509         freeSpace = (uint32_t) (ERXND_INI - ERXST_INI) - (writePointer - readPointer);
00510     }
00511     else
00512     if (writePointer == readPointer) {
00513         freeSpace = (ERXND_INI - ERXST_INI);
00514     }
00515     else {
00516         freeSpace = readPointer - writePointer - 1;
00517     }
00518 
00519     return freeSpace;
00520 }
00521 
00522 /**
00523  * @brief   Sets Ethernet buffer read pointer
00524  * @note    Points to a location in receive buffer to read from.
00525  * @param
00526  * @retval
00527  */
00528 enc28j60_error_t ENC28J60::setRxBufReadPtr(uint16_t position)
00529 {
00530     //
00531     // Wrap the start pointer of received data when greater than end of receive buffer
00532     if (position > ERXND_INI)
00533         position = ERXST_INI + (position - ERXND_INI - 1);
00534 
00535     writeRegPair(ERDPTL, position);
00536 
00537     return ENC28J60_ERROR_OK;
00538 }
00539 
00540 /**
00541  * @brief   Sets receive pointer.
00542  * @note    Receive hardware will write received data up to, but not including
00543  *          the memory pointed to by the receive pointer.
00544  * @param
00545  * @retval
00546  */
00547 uint16_t ENC28J60::getRecvPointer(void)
00548 {
00549     return readRegPair(ERXRDPTL);
00550 }
00551 
00552 /**
00553  * @brief   Gets receive buffer's write pointer.
00554  * @note    Location within the receive buffer where the hardware will write bytes that it receives.
00555  *          The pointer is read-only and is automatically updated by the hardware whenever
00556  *          a new packet is successfully received.
00557  * @param
00558  * @retval
00559  */
00560 uint16_t ENC28J60::getWritePointer(void)
00561 {
00562     uint16_t    count_pre = readReg(EPKTCNT);
00563     uint16_t    writePointer = readRegPair(ERXWRPTL);
00564     uint16_t    count_post = readReg(EPKTCNT);
00565     while (count_pre != count_post) {
00566         count_pre = count_post;
00567         writePointer = readRegPair(ERXWRPTL);
00568         count_post = readReg(EPKTCNT);
00569     }
00570 
00571     ENC28J60_DEBUG_PRINTF("[ENC28J60] rx_getWritePointer: %d", writePointer);
00572     return writePointer;
00573 }
00574 
00575 /**
00576  * @brief
00577  * @note
00578  * @param
00579  * @retval
00580  */
00581 void ENC28J60::readBuf(uint8_t* data, uint16_t len)
00582 {
00583     _read(ENC28J60_READ_BUF_MEM, data, len, false);
00584     data[len] = '\0';
00585 }
00586 
00587 /**
00588  * @brief
00589  * @note
00590  * @param
00591  * @retval
00592  */
00593 void ENC28J60::writeBuf(uint8_t* data, uint16_t len)
00594 {
00595     _write(ENC28J60_WRITE_BUF_MEM, data, len, false);
00596 }
00597 
00598 /**
00599  * @brief
00600  * @note
00601  * @param
00602  * @retval
00603  */
00604 uint8_t ENC28J60::readReg(uint8_t address)
00605 {
00606     _setBank(address);
00607 
00608     // do the read
00609     return readOp(ENC28J60_READ_CTRL_REG, address);
00610 }
00611 
00612 /**
00613  * @brief
00614  * @note
00615  * @param
00616  * @retval
00617  */
00618 uint16_t ENC28J60::readRegPair(uint8_t address)
00619 {
00620     uint16_t    temp;
00621 
00622     _setBank(address);
00623 
00624     // do the read
00625     temp = (uint16_t) (readOp(ENC28J60_READ_CTRL_REG, address + 1)) << 8;
00626     temp |= readOp(ENC28J60_READ_CTRL_REG, address);
00627 
00628     return temp;
00629 }
00630 
00631 /**
00632  * @brief
00633  * @note
00634  * @param
00635  * @retval
00636  */
00637 void ENC28J60::writeReg(uint8_t address, uint8_t data)
00638 {
00639     _setBank(address);
00640 
00641     // do the write
00642     writeOp(ENC28J60_WRITE_CTRL_REG, address, data);
00643 }
00644 
00645 /**
00646  * @brief
00647  * @note
00648  * @param
00649  * @retval
00650  */
00651 void ENC28J60::writeRegPair(uint8_t address, uint16_t data)
00652 {
00653     _setBank(address);
00654 
00655     // do the write
00656     writeOp(ENC28J60_WRITE_CTRL_REG, address, (data & 0xFF));
00657     writeOp(ENC28J60_WRITE_CTRL_REG, address + 1, (data) >> 8);
00658 }
00659 
00660 /**
00661  * @brief
00662  * @note
00663  * @param
00664  * @retval
00665  */
00666 enc28j60_error_t ENC28J60::phyRead(uint8_t address, uint16_t* data)
00667 {
00668     uint8_t timeout = 0;
00669     writeReg(MIREGADR, address);
00670     writeReg(MICMD, MICMD_MIIRD);
00671 
00672     // wait until the PHY read completes
00673     while (readReg(MISTAT) & MISTAT_BUSY) {
00674         wait_us(15);
00675         timeout++;
00676         if (timeout > 10)
00677             return ENC28J60_ERROR_TIMEOUT;
00678     }   //and MIRDH
00679 
00680     writeReg(MICMD, 0);
00681     *data = (readReg(MIRDL) | readReg(MIRDH) << 8);
00682     return ENC28J60_ERROR_OK;
00683 }
00684 
00685 /**
00686  * @brief
00687  * @note
00688  * @param
00689  * @retval
00690  */
00691 enc28j60_error_t ENC28J60::phyWrite(uint8_t address, uint16_t data)
00692 {
00693     uint8_t timeout = 0;
00694     // set the PHY register address
00695 
00696     writeReg(MIREGADR, address);
00697 
00698     // write the PHY data
00699     writeRegPair(MIWRL, data);
00700 
00701     // wait until the PHY write completes
00702     while (readReg(MISTAT) & MISTAT_BUSY) {
00703         wait_us(15);
00704         timeout++;
00705         if (timeout > 10)
00706             return ENC28J60_ERROR_TIMEOUT;
00707     }
00708 
00709     return ENC28J60_ERROR_OK;
00710 }
00711 
00712 /**
00713  * @brief
00714  * @note
00715  * @param
00716  * @retval
00717  */
00718 bool ENC28J60::linkStatus(void)
00719 {
00720     uint16_t    data;
00721     phyRead(PHSTAT2, &data);
00722     return(data & 0x0400) > 0;
00723 }
00724 
00725 /**
00726  * @brief
00727  * @note
00728  * @param
00729  * @retval
00730  */
00731 uint8_t ENC28J60::readOp(uint8_t op, uint8_t address)
00732 {
00733     uint8_t result;
00734     uint8_t data[2];
00735 
00736     // issue read command
00737 
00738     if (address & 0x80) {
00739         _read((op | (address & ADDR_MASK)), &data[0], 2, false);
00740         result = data[1];
00741         return result;
00742     }
00743     else {
00744         _read((op | (address & ADDR_MASK)), &data[0], 1, false);
00745     }
00746 
00747     result = data[0];
00748     return result;
00749 }
00750 
00751 /**
00752  * @brief
00753  * @note
00754  * @param
00755  * @retval
00756  */
00757 void ENC28J60::writeOp(uint8_t op, uint8_t address, uint8_t data)
00758 {
00759     // issue write command
00760 
00761     _write(op | (address & ADDR_MASK), &data, 1, false);
00762 }
00763 
00764 /**
00765  * @brief
00766  * @note
00767  * @param
00768  * @retval
00769  */
00770 void ENC28J60::_setBank(uint8_t address)
00771 {
00772     if ((address & BANK_MASK) != _bank) {
00773         writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1 | ECON1_BSEL0));
00774         writeOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK) >> 5);
00775         _bank = (address & BANK_MASK);
00776     }
00777 }
00778 
00779 /**
00780  * @brief
00781  * @note
00782  * @param
00783  * @retval
00784  */
00785 void ENC28J60::_read(uint8_t cmd, uint8_t* buf, uint16_t len, bool blocking)
00786 {
00787 #ifndef ENC28J60_READWRITE
00788     _SPIMutex.lock();
00789     _cs = 0;
00790 
00791     // issue read command
00792     _spi->write((int)cmd);
00793     while (len) {
00794         len--;
00795 
00796         // read data
00797         *buf = _spi->write(0x00);
00798         buf++;
00799     }
00800 
00801     _cs = 1;
00802     _SPIMutex.unlock();
00803 #else
00804     uint8_t*    dummy = NULL;
00805     _readwrite(cmd, buf, dummy, len, blocking);
00806 #endif
00807 }
00808 
00809 /**
00810  * @brief
00811  * @note
00812  * @param
00813  * @retval
00814  */
00815 void ENC28J60::_write(uint8_t cmd, uint8_t* buf, uint16_t len, bool blocking)
00816 {
00817 #ifndef ENC28J60_READWRITE
00818     _SPIMutex.lock();
00819     _cs = 0;
00820 
00821     // issue read command
00822     _spi->write((int)cmd);
00823     while (len) {
00824         len--;
00825 
00826         // read data
00827         _spi->write((int) *buf);
00828         buf++;
00829     }
00830 
00831     _cs = 1;
00832     _SPIMutex.unlock();
00833 #else
00834     uint8_t*    dummy = NULL;
00835     _readwrite(cmd, dummy, buf, len, blocking);
00836 #endif
00837 }
00838 
00839 #ifdef ENC28J60_READWRITE
00840 
00841 /**
00842  * @brief
00843  * @note
00844  * @param
00845  * @retval
00846  */
00847 void ENC28J60::_readwrite(uint8_t cmd, uint8_t* readbuf, uint8_t* writebuf, uint16_t len, bool blocking)
00848 {
00849     _SPIMutex.lock();
00850     _cs = 0;
00851 
00852     // issue read command
00853     _spi->write((int)cmd);
00854     while (len) {
00855         len--;
00856 
00857         if (readbuf == NULL) {
00858             _spi->write((int) *writebuf);
00859             writebuf++;
00860         }
00861         else
00862         if (writebuf == NULL) {
00863             *readbuf = _spi->write(0x00);
00864             readbuf++;
00865         }
00866         else {
00867             break;
00868         }
00869     }
00870 
00871     _cs = 1;
00872     _SPIMutex.unlock();
00873 }
00874 #endif