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.
Dependents: MQTT_Hello MQTT_HelloENC28J60
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
Generated on Wed Jul 13 2022 10:47:04 by
