EMAC driver for the ENC28J60 Ethernet controller. This is a simplified fork of https://github.com/tobiasjaster/ENC28J60-EMAC-Driver published by Tobias Jaster.

Dependents:   MQTT_Hello MQTT_HelloENC28J60

EMAC driver for the ENC28J60 Ethernet controller

https://os.mbed.com/media/uploads/hudakz/enc28j60_module01.jpg

This is a fork (the INT and RST pins are not used) of the ENC28J60-EMAC driver published by Tobias Jaster at

https://github.com/tobiasjaster/ENC28J60-EMAC-Driver

Usage:

  • Connect the ENC28J60 module to the Mbed board as follows:

https://os.mbed.com/media/uploads/hudakz/enc28j60-emac.png

  • Import (add) this ENC28J60-EMAC library to your program.
  • Add a "mbed_app.json" file with the following content to the root directory of your program:

    {
        "target_overrides": {
            "*": {
                "platform.callback-nontrivial": true,
                "enc28j60-emac.mosi":  "D11",
                "enc28j60-emac.miso":  "D12",
                "enc28j60-emac.sck" :  "D13",
                "enc28j60-emac.cs"  :  "D10"
            }
        }
    }
  • Replace "D11", ..., "D10" with the actual pin names you selected on the Mbed board to be used for the SPI communication.
  • To set the MAC address define an array with the desired address bytes and call the "set_hwaddr(mac)" function before calling the network interface "connect" function.

For example:

    const uint8_t       MAC[6] = { 0, 1, 2, 3, 4, 5 };
    EthernetInterface   net;
 
    int main()
    {
        net.get_emac().set_hwaddr(MAC);             // set MAC address
        if (net.connect() != 0) {
            printf("Error: Unable to connect to the network.\n");
            return -1;
        }
     ...
Committer:
hudakz
Date:
Mon Mar 29 08:37:01 2021 +0000
Revision:
3:aa88808326b9
Parent:
1:bce04bfc41fe
Mbed OS Ethernet MAC (EMAC) driver for the ENC28J60 Ethernet controller. This a simplified fork of https://github.com/tobiasjaster/ENC28J60-EMAC-Driver published by Tobias Jaster.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
hudakz 0:b599e748252c 1 /*
hudakz 0:b599e748252c 2 * Copyright (c) 2019 Tobias Jaster
hudakz 0:b599e748252c 3 *
hudakz 0:b599e748252c 4 * Modified by Zoltan Hudak
hudakz 0:b599e748252c 5 *
hudakz 0:b599e748252c 6 * Licensed under the Apache License, Version 2.0 (the "License");
hudakz 0:b599e748252c 7 * you may not use this file except in compliance with the License.
hudakz 0:b599e748252c 8 * You may obtain a copy of the License at
hudakz 0:b599e748252c 9 *
hudakz 0:b599e748252c 10 * http://www.apache.org/licenses/LICENSE-2.0
hudakz 0:b599e748252c 11 *
hudakz 0:b599e748252c 12 * Unless required by applicable law or agreed to in writing, software
hudakz 0:b599e748252c 13 * distributed under the License is distributed on an "AS IS" BASIS,
hudakz 0:b599e748252c 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
hudakz 0:b599e748252c 15 * See the License for the specific language governing permissions and
hudakz 0:b599e748252c 16 * limitations under the License.
hudakz 0:b599e748252c 17 */
hudakz 0:b599e748252c 18 #include "cmsis.h"
hudakz 0:b599e748252c 19 #include "enc28j60.h"
hudakz 0:b599e748252c 20
hudakz 0:b599e748252c 21 #ifndef NULL
hudakz 0:b599e748252c 22 #define NULL ((void*)0)
hudakz 0:b599e748252c 23 #endif
hudakz 0:b599e748252c 24 #define ENC28J60_DEBUG 0
hudakz 0:b599e748252c 25
hudakz 0:b599e748252c 26 #if ENC28J60_DEBUG
hudakz 0:b599e748252c 27 #define ENC28J60_DEBUG_PRINTF(...) printf(__VA_ARGS__)
hudakz 0:b599e748252c 28 #else
hudakz 0:b599e748252c 29 #define ENC28J60_DEBUG_PRINTF(...)
hudakz 0:b599e748252c 30 #endif
hudakz 0:b599e748252c 31 /** Millisec timeout macros */
hudakz 0:b599e748252c 32 #define RESET_TIME_OUT_MS 10ms
hudakz 0:b599e748252c 33 #define REG_WRITE_TIME_OUT_MS 50ms
hudakz 0:b599e748252c 34 #define PHY_RESET_TIME_OUT_MS 100ms
hudakz 0:b599e748252c 35 #define INIT_FINISH_DELAY 2000ms
hudakz 0:b599e748252c 36
hudakz 0:b599e748252c 37 /**
hudakz 0:b599e748252c 38 * \brief TX FIFO Size definitions
hudakz 0:b599e748252c 39 *
hudakz 0:b599e748252c 40 */
hudakz 0:b599e748252c 41 #define TX_STATUS_FIFO_SIZE_BYTES 512U /*< fixed allocation in bytes */
hudakz 0:b599e748252c 42 #define TX_DATA_FIFO_SIZE_KBYTES_POS 8U
hudakz 0:b599e748252c 43 #define TX_DATA_FIFO_SIZE_KBYTES_MASK 0x0FU
hudakz 0:b599e748252c 44 #define KBYTES_TO_BYTES_MULTIPLIER 1024U
hudakz 0:b599e748252c 45
hudakz 0:b599e748252c 46 /**
hudakz 0:b599e748252c 47 * \brief FIFO Info definitions
hudakz 0:b599e748252c 48 *
hudakz 0:b599e748252c 49 */
hudakz 0:b599e748252c 50 #define FIFO_USED_SPACE_MASK 0xFFFFU
hudakz 0:b599e748252c 51 #define DATA_FIFO_USED_SPACE_POS 0U
hudakz 0:b599e748252c 52 #define STATUS_FIFO_USED_SPACE_POS 16U
hudakz 0:b599e748252c 53
hudakz 0:b599e748252c 54 #define HW_CFG_REG_RX_FIFO_POS 10U
hudakz 0:b599e748252c 55 #define HW_CFG_REG_RX_FIFO_SIZE_ALL 8U
hudakz 0:b599e748252c 56 #define HW_CFG_REG_RX_FIFO_SIZE_MIN 2U /*< Min Rx fifo size in KB */
hudakz 0:b599e748252c 57 #define HW_CFG_REG_RX_FIFO_SIZE_MAX 6U /*< Max Rx fifo size in KB */
hudakz 0:b599e748252c 58 #define HW_CFG_REG_RX_FIFO_SIZE 5U /*< Rx fifo size in KB */
hudakz 0:b599e748252c 59
hudakz 0:b599e748252c 60 /**
hudakz 0:b599e748252c 61 * @brief
hudakz 0:b599e748252c 62 * @note
hudakz 0:b599e748252c 63 * @param
hudakz 0:b599e748252c 64 * @retval
hudakz 0:b599e748252c 65 */
hudakz 0:b599e748252c 66 ENC28J60::ENC28J60(PinName mosi, PinName miso, PinName sclk, PinName cs) :
hudakz 0:b599e748252c 67 _spi(new SPI(mosi, miso, sclk)),
hudakz 0:b599e748252c 68 _cs(cs),
hudakz 0:b599e748252c 69 _bank(0),
hudakz 0:b599e748252c 70 _ready(true),
hudakz 0:b599e748252c 71 _next(ERXST_INI)
hudakz 0:b599e748252c 72 {
hudakz 0:b599e748252c 73 init();
hudakz 0:b599e748252c 74 }
hudakz 0:b599e748252c 75
hudakz 0:b599e748252c 76 /**
hudakz 0:b599e748252c 77 * @brief
hudakz 0:b599e748252c 78 * @note
hudakz 0:b599e748252c 79 * @param
hudakz 0:b599e748252c 80 * @retval
hudakz 0:b599e748252c 81 */
hudakz 0:b599e748252c 82 ENC28J60::ENC28J60(mbed::SPI* spi, PinName cs) :
hudakz 3:aa88808326b9 83 _spi(spi),
hudakz 0:b599e748252c 84 _cs(cs),
hudakz 0:b599e748252c 85 _bank(0),
hudakz 0:b599e748252c 86 _ready(true),
hudakz 0:b599e748252c 87 _next(ERXST_INI)
hudakz 0:b599e748252c 88 {
hudakz 0:b599e748252c 89 init();
hudakz 0:b599e748252c 90 }
hudakz 0:b599e748252c 91
hudakz 0:b599e748252c 92 /**
hudakz 0:b599e748252c 93 * @brief
hudakz 0:b599e748252c 94 * @note
hudakz 0:b599e748252c 95 * @param
hudakz 0:b599e748252c 96 * @retval
hudakz 0:b599e748252c 97 */
hudakz 0:b599e748252c 98 void ENC28J60::init()
hudakz 0:b599e748252c 99 {
hudakz 0:b599e748252c 100 // Initialize SPI interface
hudakz 0:b599e748252c 101 _cs = 1;
hudakz 0:b599e748252c 102 _spi->format(8, 0); // 8bit, mode 0
hudakz 0:b599e748252c 103 _spi->frequency(20000000); // 20MHz
hudakz 0:b599e748252c 104
hudakz 0:b599e748252c 105 // Wait SPI to become stable
hudakz 0:b599e748252c 106 ThisThread::sleep_for(RESET_TIME_OUT_MS);
hudakz 0:b599e748252c 107
hudakz 0:b599e748252c 108 // Perform system reset
hudakz 0:b599e748252c 109 writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
hudakz 0:b599e748252c 110
hudakz 0:b599e748252c 111 // Check CLKRDY bit to see if reset is complete
hudakz 0:b599e748252c 112 // while(!(readReg(ESTAT) & ESTAT_CLKRDY));
hudakz 0:b599e748252c 113 // The CLKRDY does not work. See Rev. B4 Silicon Errata point.
hudakz 0:b599e748252c 114 // Workaround: Just wait.
hudakz 0:b599e748252c 115 ThisThread::sleep_for(RESET_TIME_OUT_MS);
hudakz 0:b599e748252c 116
hudakz 0:b599e748252c 117 // Set pointers to receive buffer boundaries
hudakz 0:b599e748252c 118 writeRegPair(ERXSTL, ERXST_INI);
hudakz 0:b599e748252c 119 writeRegPair(ERXNDL, ERXND_INI);
hudakz 0:b599e748252c 120
hudakz 0:b599e748252c 121 // Set receive pointer. Receive hardware will write data up to,
hudakz 0:b599e748252c 122 // but not including the memory pointed to by ERXRDPT
hudakz 0:b599e748252c 123 writeReg(ERXRDPTL, ERXST_INI);
hudakz 0:b599e748252c 124
hudakz 0:b599e748252c 125 // All memory which is not used by the receive buffer is considered the transmission buffer.
hudakz 0:b599e748252c 126 // No explicit action is required to initialize the transmission buffer.
hudakz 0:b599e748252c 127 // TX buffer start.
hudakz 0:b599e748252c 128 writeRegPair(ETXSTL, ETXST_INI);
hudakz 0:b599e748252c 129
hudakz 0:b599e748252c 130 // TX buffer end at end of ethernet buffer memory.
hudakz 0:b599e748252c 131 writeRegPair(ETXNDL, ETXND_INI);
hudakz 0:b599e748252c 132
hudakz 0:b599e748252c 133 // However, he host controller should leave at least seven bytes between each
hudakz 0:b599e748252c 134 // packet and the beginning of the receive buffer.
hudakz 0:b599e748252c 135 // do bank 1 stuff, packet filter:
hudakz 0:b599e748252c 136 // For broadcast packets we allow only ARP packtets
hudakz 0:b599e748252c 137 // All other packets should be unicast only for our mac (MAADR)
hudakz 0:b599e748252c 138 //
hudakz 0:b599e748252c 139 // The pattern to match is therefore
hudakz 0:b599e748252c 140 // Type ETH.DST
hudakz 0:b599e748252c 141 // ARP BROADCAST
hudakz 0:b599e748252c 142 // 06 08 -- ff ff ff ff ff ff -> ip checksum for theses bytes=f7f9
hudakz 0:b599e748252c 143 // in binary these poitions are:11 0000 0011 1111
hudakz 0:b599e748252c 144 // This is hex 303F->EPMM0=0x3f,EPMM1=0x30
hudakz 0:b599e748252c 145 //TODO define specific pattern to receive dhcp-broadcast packages instead of setting ERFCON_BCEN!
hudakz 0:b599e748252c 146 writeReg(ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_PMEN | ERXFCON_BCEN);
hudakz 0:b599e748252c 147 writeRegPair(EPMM0, 0x303f);
hudakz 0:b599e748252c 148 writeRegPair(EPMCSL, 0xf7f9);
hudakz 0:b599e748252c 149
hudakz 0:b599e748252c 150 // Enable MAC receive and bring MAC out of reset (writes 0x00 to MACON2)
hudakz 0:b599e748252c 151 writeRegPair(MACON1, MACON1_MARXEN | MACON1_TXPAUS | MACON1_RXPAUS);
hudakz 0:b599e748252c 152
hudakz 0:b599e748252c 153 // Enable automatic padding to 60bytes and CRC operations
hudakz 0:b599e748252c 154 writeOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN);
hudakz 0:b599e748252c 155
hudakz 0:b599e748252c 156 // Set inter-frame gap (non-back-to-back)
hudakz 0:b599e748252c 157 writeRegPair(MAIPGL, 0x0C12);
hudakz 0:b599e748252c 158
hudakz 0:b599e748252c 159 // Set inter-frame gap (back-to-back)
hudakz 0:b599e748252c 160 writeReg(MABBIPG, 0x12);
hudakz 0:b599e748252c 161
hudakz 0:b599e748252c 162 // Set the maximum packet size which the controller will accept
hudakz 0:b599e748252c 163 // Do not send packets longer than MAX_FRAMELEN:
hudakz 0:b599e748252c 164 writeRegPair(MAMXFLL, MAX_FRAMELEN);
hudakz 0:b599e748252c 165
hudakz 0:b599e748252c 166 // No loopback of transmitted frames
hudakz 0:b599e748252c 167 phyWrite(PHCON2, PHCON2_HDLDIS);
hudakz 0:b599e748252c 168
hudakz 0:b599e748252c 169 // Switch to bank 0
hudakz 0:b599e748252c 170 _setBank(ECON1);
hudakz 0:b599e748252c 171
hudakz 0:b599e748252c 172 // Enable interrutps
hudakz 0:b599e748252c 173 writeOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE | EIE_PKTIE);
hudakz 0:b599e748252c 174
hudakz 0:b599e748252c 175 // Enable packet reception
hudakz 0:b599e748252c 176 writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
hudakz 0:b599e748252c 177
hudakz 0:b599e748252c 178 // Configure leds
hudakz 0:b599e748252c 179 phyWrite(PHLCON, 0x476);
hudakz 0:b599e748252c 180 }
hudakz 0:b599e748252c 181
hudakz 0:b599e748252c 182 /**
hudakz 0:b599e748252c 183 * @brief
hudakz 0:b599e748252c 184 * @note
hudakz 0:b599e748252c 185 * @param
hudakz 0:b599e748252c 186 * @retval
hudakz 0:b599e748252c 187 */
hudakz 0:b599e748252c 188 enc28j60_error_t ENC28J60::getPacketInfo(packet_t* packet)
hudakz 0:b599e748252c 189 {
hudakz 0:b599e748252c 190 enc28j60_error_t ret;
hudakz 0:b599e748252c 191 uint8_t nextPacketAddrL;
hudakz 0:b599e748252c 192 uint8_t nextPacketAddrH;
hudakz 0:b599e748252c 193 uint8_t status[RX_STAT_LEN];
hudakz 0:b599e748252c 194
hudakz 0:b599e748252c 195 if (!_ready)
hudakz 0:b599e748252c 196 return ENC28J60_ERROR_LASTPACKET;
hudakz 0:b599e748252c 197
hudakz 0:b599e748252c 198 // Check if a new packet has been received and buffered.
hudakz 0:b599e748252c 199 // The Receive Packet Pending Interrupt Flag (EIR.PKTIF) does not reliably
hudakz 0:b599e748252c 200 // report the status of pending packets. See Rev. B4 Silicon Errata point 6.
hudakz 0:b599e748252c 201 // Workaround: Check EPKTCNT
hudakz 0:b599e748252c 202 if (readReg(EPKTCNT) == 0)
hudakz 0:b599e748252c 203 return ENC28J60_ERROR_NOPACKET;
hudakz 0:b599e748252c 204
hudakz 0:b599e748252c 205 _ready = false;
hudakz 0:b599e748252c 206
hudakz 0:b599e748252c 207 // Packet pointer in receive buffer is wrapped by hardware.
hudakz 0:b599e748252c 208 packet->addr = _next;
hudakz 0:b599e748252c 209
hudakz 0:b599e748252c 210 // Program the receive buffer read pointer to point to this packet.
hudakz 0:b599e748252c 211 writeRegPair(ERDPTL, packet->addr);
hudakz 0:b599e748252c 212
hudakz 0:b599e748252c 213 // Read the next packet address
hudakz 0:b599e748252c 214 nextPacketAddrL = readOp(ENC28J60_READ_BUF_MEM, 0);
hudakz 0:b599e748252c 215 nextPacketAddrH = readOp(ENC28J60_READ_BUF_MEM, 0);
hudakz 0:b599e748252c 216 _next = (nextPacketAddrH << 8) | nextPacketAddrL;
hudakz 0:b599e748252c 217
hudakz 0:b599e748252c 218 // Read the packet status vector bytes (see datasheet page 43)
hudakz 0:b599e748252c 219 for (uint8_t i = 0; i < RX_STAT_LEN; i++) {
hudakz 0:b599e748252c 220 status[i] = readOp(ENC28J60_READ_BUF_MEM, 0);
hudakz 0:b599e748252c 221 }
hudakz 0:b599e748252c 222
hudakz 0:b599e748252c 223 // Get payload length (see datasheet page 43)
hudakz 0:b599e748252c 224 packet->payload.len = (status[1] << 8) | status[0];
hudakz 0:b599e748252c 225
hudakz 0:b599e748252c 226 // Remove CRC bytes
hudakz 0:b599e748252c 227 packet->payload.len -= RX_CRC_LEN;
hudakz 0:b599e748252c 228
hudakz 0:b599e748252c 229 // Check CRC and symbol errors (see datasheet page 44, table 7-3):
hudakz 0:b599e748252c 230 // The ERXFCON.CRCEN is set by default. Normally we should not
hudakz 0:b599e748252c 231 // need to check this.
hudakz 0:b599e748252c 232 // Bit 7 in byte 3 of receive status vectors indicates that the packet
hudakz 0:b599e748252c 233 // had a valid CRC and no symbol errors.
hudakz 0:b599e748252c 234 if ((status[2] & (1 << 7)) != 0) {
hudakz 0:b599e748252c 235 ret = ENC28J60_ERROR_OK;
hudakz 0:b599e748252c 236 }
hudakz 0:b599e748252c 237 else {
hudakz 0:b599e748252c 238 // Drop faulty packet:
hudakz 0:b599e748252c 239 // Move the receive read pointer to the begin of the next packet.
hudakz 0:b599e748252c 240 // This frees the memory we just read out.
hudakz 0:b599e748252c 241 freeRxBuffer();
hudakz 0:b599e748252c 242 ret = ENC28J60_ERROR_RECEIVE;
hudakz 0:b599e748252c 243 }
hudakz 0:b599e748252c 244
hudakz 0:b599e748252c 245 // Decrement the packet counter to indicate we are done with this packet.
hudakz 0:b599e748252c 246 writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
hudakz 0:b599e748252c 247
hudakz 0:b599e748252c 248 return ret;
hudakz 0:b599e748252c 249 }
hudakz 0:b599e748252c 250
hudakz 0:b599e748252c 251 /**
hudakz 0:b599e748252c 252 * @brief
hudakz 0:b599e748252c 253 * @note
hudakz 0:b599e748252c 254 * @param
hudakz 0:b599e748252c 255 * @retval
hudakz 0:b599e748252c 256 */
hudakz 0:b599e748252c 257 void ENC28J60::readPacket(packet_t* packet)
hudakz 0:b599e748252c 258 {
hudakz 0:b599e748252c 259 // Read operation in receive buffer wraps the read pointer automatically.
hudakz 0:b599e748252c 260 // To utilize this feature we program the receive buffer read pointer (ERDPTL)
hudakz 0:b599e748252c 261 // to point to the begin of this packet (see datasheet page 43).
hudakz 0:b599e748252c 262 // Then we read the next packet pointer bytes + packet status vector bytes
hudakz 0:b599e748252c 263 // rather than calculating the payload position and advancing ERDPTL by software.
hudakz 0:b599e748252c 264 writeRegPair(ERDPTL, packet->addr);
hudakz 0:b599e748252c 265
hudakz 0:b599e748252c 266 // Advance the read pointer to the payload by reading bytes out of interest.
hudakz 0:b599e748252c 267 for (uint8_t i = 0; i < (RX_NEXT_LEN + RX_STAT_LEN); i++)
hudakz 0:b599e748252c 268 readOp(ENC28J60_READ_BUF_MEM, 0);
hudakz 0:b599e748252c 269
hudakz 0:b599e748252c 270 // The receive buffer read pointer is now pointing to the correct place.
hudakz 0:b599e748252c 271 // We can read packet payload bytes.
hudakz 0:b599e748252c 272 readBuf(packet->payload.buf, packet->payload.len);
hudakz 0:b599e748252c 273 }
hudakz 0:b599e748252c 274
hudakz 0:b599e748252c 275 /**
hudakz 0:b599e748252c 276 * @brief Frees the memory occupied by last packet.
hudakz 0:b599e748252c 277 * @note Programs the Receive Pointer (ERXRDPT)to point to the next
hudakz 0:b599e748252c 278 * packet address. Receive hardware will write data up to,
hudakz 0:b599e748252c 279 * but not including the memory pointed to by ERXRDPT.
hudakz 0:b599e748252c 280 * @param
hudakz 0:b599e748252c 281 * @retval
hudakz 0:b599e748252c 282 */
hudakz 0:b599e748252c 283 void ENC28J60::freeRxBuffer(void)
hudakz 0:b599e748252c 284 {
hudakz 0:b599e748252c 285 // Compensate for the errata rev B7, point 11:
hudakz 0:b599e748252c 286 // The receive hardware may corrupt the circular
hudakz 0:b599e748252c 287 // receive buffer (including the Next Packet Pointer
hudakz 0:b599e748252c 288 // and receive status vector fields) when an even value
hudakz 0:b599e748252c 289 // is programmed into the ERXRDPTH:ERXRDPTL registers.
hudakz 0:b599e748252c 290 // Workaround: Never write an even address!
hudakz 0:b599e748252c 291 if ((_next - 1 < ERXST_INI) || (_next - 1 > ERXND_INI))
hudakz 0:b599e748252c 292 writeRegPair(ERXRDPTL, ERXND_INI);
hudakz 0:b599e748252c 293 else
hudakz 0:b599e748252c 294 writeRegPair(ERXRDPTL, _next - 1);
hudakz 0:b599e748252c 295
hudakz 0:b599e748252c 296 _ready = true; // ready for next packet
hudakz 0:b599e748252c 297 }
hudakz 0:b599e748252c 298
hudakz 0:b599e748252c 299 /**
hudakz 0:b599e748252c 300 * @brief
hudakz 0:b599e748252c 301 * @note
hudakz 0:b599e748252c 302 * @param
hudakz 0:b599e748252c 303 * @retval
hudakz 0:b599e748252c 304 */
hudakz 0:b599e748252c 305 enc28j60_error_t ENC28J60::loadPacketInTxBuffer(packet_t* packet)
hudakz 0:b599e748252c 306 {
hudakz 0:b599e748252c 307 uint8_t controlByte = 0;
hudakz 0:b599e748252c 308 enc28j60_error_t error = ENC28J60_ERROR_OK;
hudakz 0:b599e748252c 309 uint16_t packetLen = TX_CTRL_LEN + packet->payload.len + TX_STAT_LEN;
hudakz 0:b599e748252c 310
hudakz 0:b599e748252c 311 if (packetLen > ETXND_INI - ETXST_INI) {
hudakz 0:b599e748252c 312 error = ENC28J60_ERROR_FIFOFULL;
hudakz 0:b599e748252c 313 return error;
hudakz 0:b599e748252c 314 }
hudakz 0:b599e748252c 315
hudakz 0:b599e748252c 316 setWritePrt(ETXST_INI, 0);
hudakz 0:b599e748252c 317
hudakz 0:b599e748252c 318 //_tx_packet.payload.len = data_len;
hudakz 0:b599e748252c 319 writeBuf(&controlByte, sizeof(controlByte));
hudakz 0:b599e748252c 320 error = setWritePrt(ETXST_INI, sizeof(controlByte));
hudakz 0:b599e748252c 321 writeBuf(packet->payload.buf, packet->payload.len);
hudakz 0:b599e748252c 322
hudakz 0:b599e748252c 323 return error;
hudakz 0:b599e748252c 324 }
hudakz 0:b599e748252c 325
hudakz 0:b599e748252c 326 /**
hudakz 0:b599e748252c 327 * @brief
hudakz 0:b599e748252c 328 * @note
hudakz 0:b599e748252c 329 * @param
hudakz 0:b599e748252c 330 * @retval
hudakz 0:b599e748252c 331 */
hudakz 0:b599e748252c 332 enc28j60_error_t ENC28J60::softReset(void)
hudakz 0:b599e748252c 333 {
hudakz 0:b599e748252c 334 writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
hudakz 0:b599e748252c 335
hudakz 0:b599e748252c 336 ThisThread::sleep_for(1ms);
hudakz 0:b599e748252c 337 return ENC28J60_ERROR_OK;
hudakz 0:b599e748252c 338 }
hudakz 0:b599e748252c 339
hudakz 0:b599e748252c 340 /**
hudakz 0:b599e748252c 341 * @brief
hudakz 0:b599e748252c 342 * @note
hudakz 0:b599e748252c 343 * @param
hudakz 0:b599e748252c 344 * @retval
hudakz 0:b599e748252c 345 */
hudakz 0:b599e748252c 346 void ENC28J60::setRxBufSize(uint32_t size_kb)
hudakz 0:b599e748252c 347 {
hudakz 0:b599e748252c 348 if (size_kb >= HW_CFG_REG_RX_FIFO_SIZE_MIN && size_kb <= HW_CFG_REG_RX_FIFO_SIZE_MAX) {
hudakz 0:b599e748252c 349 writeRegPair(ERXSTL, ERXST_INI);
hudakz 0:b599e748252c 350
hudakz 0:b599e748252c 351 // set receive pointer address
hudakz 0:b599e748252c 352 writeRegPair(ERXRDPTL, ERXST_INI);
hudakz 0:b599e748252c 353
hudakz 0:b599e748252c 354 // RX end
hudakz 0:b599e748252c 355 writeRegPair(ERXNDL, 0x1FFF - (size_kb << HW_CFG_REG_RX_FIFO_POS));
hudakz 0:b599e748252c 356 }
hudakz 0:b599e748252c 357 }
hudakz 0:b599e748252c 358
hudakz 0:b599e748252c 359 /**
hudakz 0:b599e748252c 360 * @brief
hudakz 0:b599e748252c 361 * @note
hudakz 0:b599e748252c 362 * @param
hudakz 0:b599e748252c 363 * @retval
hudakz 0:b599e748252c 364 */
hudakz 0:b599e748252c 365 enc28j60_error_t ENC28J60::resetPhy(void)
hudakz 0:b599e748252c 366 {
hudakz 0:b599e748252c 367 enc28j60_error_t error = ENC28J60_ERROR_OK;
hudakz 0:b599e748252c 368 uint16_t phcon1 = 0;
hudakz 0:b599e748252c 369 error = phyRead(PHCON1, &phcon1);
hudakz 0:b599e748252c 370 if (error)
hudakz 0:b599e748252c 371 return ENC28J60_ERROR_TIMEOUT;
hudakz 0:b599e748252c 372 error = phyWrite(PHCON1, (phcon1 | PHCON1_PRST));
hudakz 0:b599e748252c 373 if (error)
hudakz 0:b599e748252c 374 return ENC28J60_ERROR_TIMEOUT;
hudakz 0:b599e748252c 375 ThisThread::sleep_for(PHY_RESET_TIME_OUT_MS);
hudakz 0:b599e748252c 376 error = phyRead(PHCON1, &phcon1);
hudakz 0:b599e748252c 377 if (error || (phcon1 & PHCON1_PRST) != 0) {
hudakz 0:b599e748252c 378 return ENC28J60_ERROR_TIMEOUT;
hudakz 0:b599e748252c 379 }
hudakz 0:b599e748252c 380
hudakz 0:b599e748252c 381 return ENC28J60_ERROR_OK;
hudakz 0:b599e748252c 382 }
hudakz 0:b599e748252c 383
hudakz 0:b599e748252c 384 /**
hudakz 0:b599e748252c 385 * @brief
hudakz 0:b599e748252c 386 * @note
hudakz 0:b599e748252c 387 * @param
hudakz 0:b599e748252c 388 * @retval
hudakz 0:b599e748252c 389 */
hudakz 0:b599e748252c 390 void ENC28J60::enableMacRecv(void)
hudakz 0:b599e748252c 391 {
hudakz 0:b599e748252c 392 writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
hudakz 0:b599e748252c 393 }
hudakz 0:b599e748252c 394
hudakz 0:b599e748252c 395 /**
hudakz 0:b599e748252c 396 * @brief
hudakz 0:b599e748252c 397 * @note
hudakz 0:b599e748252c 398 * @param
hudakz 0:b599e748252c 399 * @retval
hudakz 0:b599e748252c 400 */
hudakz 0:b599e748252c 401 void ENC28J60::disableMacRecv(void)
hudakz 0:b599e748252c 402 {
hudakz 0:b599e748252c 403 writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXEN);
hudakz 0:b599e748252c 404 }
hudakz 0:b599e748252c 405
hudakz 0:b599e748252c 406 /**
hudakz 0:b599e748252c 407 * @brief
hudakz 0:b599e748252c 408 * @note
hudakz 0:b599e748252c 409 * @param
hudakz 0:b599e748252c 410 * @retval
hudakz 0:b599e748252c 411 */
hudakz 0:b599e748252c 412 enc28j60_error_t ENC28J60::readMacAddr(char* mac)
hudakz 0:b599e748252c 413 {
hudakz 0:b599e748252c 414 if (!mac) {
hudakz 0:b599e748252c 415 return ENC28J60_ERROR_PARAM;
hudakz 0:b599e748252c 416 }
hudakz 0:b599e748252c 417
hudakz 0:b599e748252c 418 _setBank(MAADR0);
hudakz 0:b599e748252c 419
hudakz 0:b599e748252c 420 mac[0] = readReg(MAADR5);
hudakz 0:b599e748252c 421 mac[1] = readReg(MAADR4);
hudakz 0:b599e748252c 422 mac[2] = readReg(MAADR3);
hudakz 0:b599e748252c 423 mac[3] = readReg(MAADR2);
hudakz 0:b599e748252c 424 mac[4] = readReg(MAADR1);
hudakz 0:b599e748252c 425 mac[5] = readReg(MAADR0);
hudakz 0:b599e748252c 426
hudakz 0:b599e748252c 427 return ENC28J60_ERROR_OK;
hudakz 0:b599e748252c 428 }
hudakz 0:b599e748252c 429
hudakz 0:b599e748252c 430 /**
hudakz 0:b599e748252c 431 * @brief
hudakz 0:b599e748252c 432 * @note
hudakz 0:b599e748252c 433 * @param
hudakz 0:b599e748252c 434 * @retval
hudakz 0:b599e748252c 435 */
hudakz 0:b599e748252c 436 enc28j60_error_t ENC28J60::writeMacAddr(char* mac)
hudakz 0:b599e748252c 437 {
hudakz 0:b599e748252c 438 if (!mac) {
hudakz 0:b599e748252c 439 return ENC28J60_ERROR_PARAM;
hudakz 0:b599e748252c 440 }
hudakz 0:b599e748252c 441
hudakz 0:b599e748252c 442 _setBank(MAADR0);
hudakz 0:b599e748252c 443
hudakz 0:b599e748252c 444 writeReg(MAADR5, mac[0]);
hudakz 0:b599e748252c 445 writeReg(MAADR4, mac[1]);
hudakz 0:b599e748252c 446 writeReg(MAADR3, mac[2]);
hudakz 0:b599e748252c 447 writeReg(MAADR2, mac[3]);
hudakz 0:b599e748252c 448 writeReg(MAADR1, mac[4]);
hudakz 0:b599e748252c 449 writeReg(MAADR0, mac[5]);
hudakz 0:b599e748252c 450
hudakz 0:b599e748252c 451 return ENC28J60_ERROR_OK;
hudakz 0:b599e748252c 452 }
hudakz 0:b599e748252c 453
hudakz 0:b599e748252c 454 /**
hudakz 0:b599e748252c 455 * @brief
hudakz 0:b599e748252c 456 * @note
hudakz 0:b599e748252c 457 * @param
hudakz 0:b599e748252c 458 * @retval
hudakz 0:b599e748252c 459 */
hudakz 0:b599e748252c 460 enc28j60_error_t ENC28J60::setWritePrt(uint16_t position, uint16_t offset)
hudakz 0:b599e748252c 461 {
hudakz 0:b599e748252c 462 uint32_t start = position + offset > ETXND_INI ? position + offset - ETXND_INI + ETXST_INI : position + offset;
hudakz 0:b599e748252c 463
hudakz 0:b599e748252c 464 writeRegPair(EWRPTL, start);
hudakz 0:b599e748252c 465
hudakz 0:b599e748252c 466 return ENC28J60_ERROR_OK;
hudakz 0:b599e748252c 467 }
hudakz 0:b599e748252c 468
hudakz 0:b599e748252c 469 /**
hudakz 0:b599e748252c 470 * @brief
hudakz 0:b599e748252c 471 * @note
hudakz 0:b599e748252c 472 * @param
hudakz 0:b599e748252c 473 * @retval
hudakz 0:b599e748252c 474 */
hudakz 0:b599e748252c 475 enc28j60_error_t ENC28J60::transmitPacket(packet_t* packet)
hudakz 0:b599e748252c 476 {
hudakz 0:b599e748252c 477 // Set Transmit Buffer Start pointer
hudakz 0:b599e748252c 478 writeRegPair(ETXSTL, ETXST_INI);
hudakz 0:b599e748252c 479
hudakz 0:b599e748252c 480 // Set Transmit Buffer End pointer
hudakz 0:b599e748252c 481 writeRegPair(ETXNDL, ETXST_INI + TX_CTRL_LEN + packet->payload.len);
hudakz 0:b599e748252c 482
hudakz 0:b599e748252c 483 // Enable transmittion
hudakz 0:b599e748252c 484 writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
hudakz 0:b599e748252c 485
hudakz 0:b599e748252c 486 // Wait until transmission is completed
hudakz 0:b599e748252c 487 while ((readReg(ECON1) & ECON1_TXRTS) != 0) { }
hudakz 0:b599e748252c 488
hudakz 0:b599e748252c 489 // Chek whether the transmission was successfull
hudakz 0:b599e748252c 490 if ((readReg(ESTAT) & ESTAT_TXABRT) == 0)
hudakz 0:b599e748252c 491 return ENC28J60_ERROR_OK;
hudakz 0:b599e748252c 492 else
hudakz 0:b599e748252c 493 return ENC28J60_ERROR_NEXTPACKET;
hudakz 0:b599e748252c 494 }
hudakz 0:b599e748252c 495
hudakz 0:b599e748252c 496
hudakz 0:b599e748252c 497 /**
hudakz 0:b599e748252c 498 * @brief
hudakz 0:b599e748252c 499 * @note
hudakz 0:b599e748252c 500 * @param
hudakz 0:b599e748252c 501 * @retval
hudakz 0:b599e748252c 502 */
hudakz 0:b599e748252c 503 uint32_t ENC28J60::getRxBufFreeSpace(void)
hudakz 0:b599e748252c 504 {
hudakz 0:b599e748252c 505 uint16_t readPointer = getRecvPointer();
hudakz 0:b599e748252c 506 uint16_t writePointer = getWritePointer();
hudakz 0:b599e748252c 507 uint32_t freeSpace = 0;
hudakz 0:b599e748252c 508 if (writePointer > readPointer) {
hudakz 0:b599e748252c 509 freeSpace = (uint32_t) (ERXND_INI - ERXST_INI) - (writePointer - readPointer);
hudakz 0:b599e748252c 510 }
hudakz 0:b599e748252c 511 else
hudakz 0:b599e748252c 512 if (writePointer == readPointer) {
hudakz 0:b599e748252c 513 freeSpace = (ERXND_INI - ERXST_INI);
hudakz 0:b599e748252c 514 }
hudakz 0:b599e748252c 515 else {
hudakz 0:b599e748252c 516 freeSpace = readPointer - writePointer - 1;
hudakz 0:b599e748252c 517 }
hudakz 0:b599e748252c 518
hudakz 0:b599e748252c 519 return freeSpace;
hudakz 0:b599e748252c 520 }
hudakz 0:b599e748252c 521
hudakz 0:b599e748252c 522 /**
hudakz 0:b599e748252c 523 * @brief Sets Ethernet buffer read pointer
hudakz 0:b599e748252c 524 * @note Points to a location in receive buffer to read from.
hudakz 0:b599e748252c 525 * @param
hudakz 0:b599e748252c 526 * @retval
hudakz 0:b599e748252c 527 */
hudakz 0:b599e748252c 528 enc28j60_error_t ENC28J60::setRxBufReadPtr(uint16_t position)
hudakz 0:b599e748252c 529 {
hudakz 0:b599e748252c 530 //
hudakz 0:b599e748252c 531 // Wrap the start pointer of received data when greater than end of receive buffer
hudakz 0:b599e748252c 532 if (position > ERXND_INI)
hudakz 0:b599e748252c 533 position = ERXST_INI + (position - ERXND_INI - 1);
hudakz 0:b599e748252c 534
hudakz 0:b599e748252c 535 writeRegPair(ERDPTL, position);
hudakz 0:b599e748252c 536
hudakz 0:b599e748252c 537 return ENC28J60_ERROR_OK;
hudakz 0:b599e748252c 538 }
hudakz 0:b599e748252c 539
hudakz 0:b599e748252c 540 /**
hudakz 0:b599e748252c 541 * @brief Sets receive pointer.
hudakz 0:b599e748252c 542 * @note Receive hardware will write received data up to, but not including
hudakz 0:b599e748252c 543 * the memory pointed to by the receive pointer.
hudakz 0:b599e748252c 544 * @param
hudakz 0:b599e748252c 545 * @retval
hudakz 0:b599e748252c 546 */
hudakz 0:b599e748252c 547 uint16_t ENC28J60::getRecvPointer(void)
hudakz 0:b599e748252c 548 {
hudakz 0:b599e748252c 549 return readRegPair(ERXRDPTL);
hudakz 0:b599e748252c 550 }
hudakz 0:b599e748252c 551
hudakz 0:b599e748252c 552 /**
hudakz 0:b599e748252c 553 * @brief Gets receive buffer's write pointer.
hudakz 0:b599e748252c 554 * @note Location within the receive buffer where the hardware will write bytes that it receives.
hudakz 0:b599e748252c 555 * The pointer is read-only and is automatically updated by the hardware whenever
hudakz 0:b599e748252c 556 * a new packet is successfully received.
hudakz 0:b599e748252c 557 * @param
hudakz 0:b599e748252c 558 * @retval
hudakz 0:b599e748252c 559 */
hudakz 0:b599e748252c 560 uint16_t ENC28J60::getWritePointer(void)
hudakz 0:b599e748252c 561 {
hudakz 0:b599e748252c 562 uint16_t count_pre = readReg(EPKTCNT);
hudakz 0:b599e748252c 563 uint16_t writePointer = readRegPair(ERXWRPTL);
hudakz 0:b599e748252c 564 uint16_t count_post = readReg(EPKTCNT);
hudakz 0:b599e748252c 565 while (count_pre != count_post) {
hudakz 0:b599e748252c 566 count_pre = count_post;
hudakz 0:b599e748252c 567 writePointer = readRegPair(ERXWRPTL);
hudakz 0:b599e748252c 568 count_post = readReg(EPKTCNT);
hudakz 0:b599e748252c 569 }
hudakz 0:b599e748252c 570
hudakz 0:b599e748252c 571 ENC28J60_DEBUG_PRINTF("[ENC28J60] rx_getWritePointer: %d", writePointer);
hudakz 0:b599e748252c 572 return writePointer;
hudakz 0:b599e748252c 573 }
hudakz 0:b599e748252c 574
hudakz 0:b599e748252c 575 /**
hudakz 0:b599e748252c 576 * @brief
hudakz 0:b599e748252c 577 * @note
hudakz 0:b599e748252c 578 * @param
hudakz 0:b599e748252c 579 * @retval
hudakz 0:b599e748252c 580 */
hudakz 0:b599e748252c 581 void ENC28J60::readBuf(uint8_t* data, uint16_t len)
hudakz 0:b599e748252c 582 {
hudakz 0:b599e748252c 583 _read(ENC28J60_READ_BUF_MEM, data, len, false);
hudakz 0:b599e748252c 584 data[len] = '\0';
hudakz 0:b599e748252c 585 }
hudakz 0:b599e748252c 586
hudakz 0:b599e748252c 587 /**
hudakz 0:b599e748252c 588 * @brief
hudakz 0:b599e748252c 589 * @note
hudakz 0:b599e748252c 590 * @param
hudakz 0:b599e748252c 591 * @retval
hudakz 0:b599e748252c 592 */
hudakz 0:b599e748252c 593 void ENC28J60::writeBuf(uint8_t* data, uint16_t len)
hudakz 0:b599e748252c 594 {
hudakz 0:b599e748252c 595 _write(ENC28J60_WRITE_BUF_MEM, data, len, false);
hudakz 0:b599e748252c 596 }
hudakz 0:b599e748252c 597
hudakz 0:b599e748252c 598 /**
hudakz 0:b599e748252c 599 * @brief
hudakz 0:b599e748252c 600 * @note
hudakz 0:b599e748252c 601 * @param
hudakz 0:b599e748252c 602 * @retval
hudakz 0:b599e748252c 603 */
hudakz 0:b599e748252c 604 uint8_t ENC28J60::readReg(uint8_t address)
hudakz 0:b599e748252c 605 {
hudakz 0:b599e748252c 606 _setBank(address);
hudakz 0:b599e748252c 607
hudakz 0:b599e748252c 608 // do the read
hudakz 0:b599e748252c 609 return readOp(ENC28J60_READ_CTRL_REG, address);
hudakz 0:b599e748252c 610 }
hudakz 0:b599e748252c 611
hudakz 0:b599e748252c 612 /**
hudakz 0:b599e748252c 613 * @brief
hudakz 0:b599e748252c 614 * @note
hudakz 0:b599e748252c 615 * @param
hudakz 0:b599e748252c 616 * @retval
hudakz 0:b599e748252c 617 */
hudakz 0:b599e748252c 618 uint16_t ENC28J60::readRegPair(uint8_t address)
hudakz 0:b599e748252c 619 {
hudakz 0:b599e748252c 620 uint16_t temp;
hudakz 0:b599e748252c 621
hudakz 0:b599e748252c 622 _setBank(address);
hudakz 0:b599e748252c 623
hudakz 0:b599e748252c 624 // do the read
hudakz 0:b599e748252c 625 temp = (uint16_t) (readOp(ENC28J60_READ_CTRL_REG, address + 1)) << 8;
hudakz 0:b599e748252c 626 temp |= readOp(ENC28J60_READ_CTRL_REG, address);
hudakz 0:b599e748252c 627
hudakz 0:b599e748252c 628 return temp;
hudakz 0:b599e748252c 629 }
hudakz 0:b599e748252c 630
hudakz 0:b599e748252c 631 /**
hudakz 0:b599e748252c 632 * @brief
hudakz 0:b599e748252c 633 * @note
hudakz 0:b599e748252c 634 * @param
hudakz 0:b599e748252c 635 * @retval
hudakz 0:b599e748252c 636 */
hudakz 0:b599e748252c 637 void ENC28J60::writeReg(uint8_t address, uint8_t data)
hudakz 0:b599e748252c 638 {
hudakz 0:b599e748252c 639 _setBank(address);
hudakz 0:b599e748252c 640
hudakz 0:b599e748252c 641 // do the write
hudakz 0:b599e748252c 642 writeOp(ENC28J60_WRITE_CTRL_REG, address, data);
hudakz 0:b599e748252c 643 }
hudakz 0:b599e748252c 644
hudakz 0:b599e748252c 645 /**
hudakz 0:b599e748252c 646 * @brief
hudakz 0:b599e748252c 647 * @note
hudakz 0:b599e748252c 648 * @param
hudakz 0:b599e748252c 649 * @retval
hudakz 0:b599e748252c 650 */
hudakz 0:b599e748252c 651 void ENC28J60::writeRegPair(uint8_t address, uint16_t data)
hudakz 0:b599e748252c 652 {
hudakz 0:b599e748252c 653 _setBank(address);
hudakz 0:b599e748252c 654
hudakz 0:b599e748252c 655 // do the write
hudakz 0:b599e748252c 656 writeOp(ENC28J60_WRITE_CTRL_REG, address, (data & 0xFF));
hudakz 0:b599e748252c 657 writeOp(ENC28J60_WRITE_CTRL_REG, address + 1, (data) >> 8);
hudakz 0:b599e748252c 658 }
hudakz 0:b599e748252c 659
hudakz 0:b599e748252c 660 /**
hudakz 0:b599e748252c 661 * @brief
hudakz 0:b599e748252c 662 * @note
hudakz 0:b599e748252c 663 * @param
hudakz 0:b599e748252c 664 * @retval
hudakz 0:b599e748252c 665 */
hudakz 0:b599e748252c 666 enc28j60_error_t ENC28J60::phyRead(uint8_t address, uint16_t* data)
hudakz 0:b599e748252c 667 {
hudakz 0:b599e748252c 668 uint8_t timeout = 0;
hudakz 0:b599e748252c 669 writeReg(MIREGADR, address);
hudakz 0:b599e748252c 670 writeReg(MICMD, MICMD_MIIRD);
hudakz 0:b599e748252c 671
hudakz 0:b599e748252c 672 // wait until the PHY read completes
hudakz 0:b599e748252c 673 while (readReg(MISTAT) & MISTAT_BUSY) {
hudakz 0:b599e748252c 674 wait_us(15);
hudakz 0:b599e748252c 675 timeout++;
hudakz 0:b599e748252c 676 if (timeout > 10)
hudakz 0:b599e748252c 677 return ENC28J60_ERROR_TIMEOUT;
hudakz 0:b599e748252c 678 } //and MIRDH
hudakz 0:b599e748252c 679
hudakz 0:b599e748252c 680 writeReg(MICMD, 0);
hudakz 0:b599e748252c 681 *data = (readReg(MIRDL) | readReg(MIRDH) << 8);
hudakz 0:b599e748252c 682 return ENC28J60_ERROR_OK;
hudakz 0:b599e748252c 683 }
hudakz 0:b599e748252c 684
hudakz 0:b599e748252c 685 /**
hudakz 0:b599e748252c 686 * @brief
hudakz 0:b599e748252c 687 * @note
hudakz 0:b599e748252c 688 * @param
hudakz 0:b599e748252c 689 * @retval
hudakz 0:b599e748252c 690 */
hudakz 0:b599e748252c 691 enc28j60_error_t ENC28J60::phyWrite(uint8_t address, uint16_t data)
hudakz 0:b599e748252c 692 {
hudakz 0:b599e748252c 693 uint8_t timeout = 0;
hudakz 0:b599e748252c 694 // set the PHY register address
hudakz 0:b599e748252c 695
hudakz 0:b599e748252c 696 writeReg(MIREGADR, address);
hudakz 0:b599e748252c 697
hudakz 0:b599e748252c 698 // write the PHY data
hudakz 0:b599e748252c 699 writeRegPair(MIWRL, data);
hudakz 0:b599e748252c 700
hudakz 0:b599e748252c 701 // wait until the PHY write completes
hudakz 0:b599e748252c 702 while (readReg(MISTAT) & MISTAT_BUSY) {
hudakz 0:b599e748252c 703 wait_us(15);
hudakz 0:b599e748252c 704 timeout++;
hudakz 0:b599e748252c 705 if (timeout > 10)
hudakz 0:b599e748252c 706 return ENC28J60_ERROR_TIMEOUT;
hudakz 0:b599e748252c 707 }
hudakz 0:b599e748252c 708
hudakz 0:b599e748252c 709 return ENC28J60_ERROR_OK;
hudakz 0:b599e748252c 710 }
hudakz 0:b599e748252c 711
hudakz 0:b599e748252c 712 /**
hudakz 0:b599e748252c 713 * @brief
hudakz 0:b599e748252c 714 * @note
hudakz 0:b599e748252c 715 * @param
hudakz 0:b599e748252c 716 * @retval
hudakz 0:b599e748252c 717 */
hudakz 0:b599e748252c 718 bool ENC28J60::linkStatus(void)
hudakz 0:b599e748252c 719 {
hudakz 0:b599e748252c 720 uint16_t data;
hudakz 0:b599e748252c 721 phyRead(PHSTAT2, &data);
hudakz 0:b599e748252c 722 return(data & 0x0400) > 0;
hudakz 0:b599e748252c 723 }
hudakz 0:b599e748252c 724
hudakz 0:b599e748252c 725 /**
hudakz 0:b599e748252c 726 * @brief
hudakz 0:b599e748252c 727 * @note
hudakz 0:b599e748252c 728 * @param
hudakz 0:b599e748252c 729 * @retval
hudakz 0:b599e748252c 730 */
hudakz 0:b599e748252c 731 uint8_t ENC28J60::readOp(uint8_t op, uint8_t address)
hudakz 0:b599e748252c 732 {
hudakz 0:b599e748252c 733 uint8_t result;
hudakz 0:b599e748252c 734 uint8_t data[2];
hudakz 0:b599e748252c 735
hudakz 0:b599e748252c 736 // issue read command
hudakz 0:b599e748252c 737
hudakz 0:b599e748252c 738 if (address & 0x80) {
hudakz 0:b599e748252c 739 _read((op | (address & ADDR_MASK)), &data[0], 2, false);
hudakz 0:b599e748252c 740 result = data[1];
hudakz 0:b599e748252c 741 return result;
hudakz 0:b599e748252c 742 }
hudakz 0:b599e748252c 743 else {
hudakz 0:b599e748252c 744 _read((op | (address & ADDR_MASK)), &data[0], 1, false);
hudakz 0:b599e748252c 745 }
hudakz 0:b599e748252c 746
hudakz 0:b599e748252c 747 result = data[0];
hudakz 0:b599e748252c 748 return result;
hudakz 0:b599e748252c 749 }
hudakz 0:b599e748252c 750
hudakz 0:b599e748252c 751 /**
hudakz 0:b599e748252c 752 * @brief
hudakz 0:b599e748252c 753 * @note
hudakz 0:b599e748252c 754 * @param
hudakz 0:b599e748252c 755 * @retval
hudakz 0:b599e748252c 756 */
hudakz 0:b599e748252c 757 void ENC28J60::writeOp(uint8_t op, uint8_t address, uint8_t data)
hudakz 0:b599e748252c 758 {
hudakz 0:b599e748252c 759 // issue write command
hudakz 0:b599e748252c 760
hudakz 0:b599e748252c 761 _write(op | (address & ADDR_MASK), &data, 1, false);
hudakz 0:b599e748252c 762 }
hudakz 0:b599e748252c 763
hudakz 0:b599e748252c 764 /**
hudakz 0:b599e748252c 765 * @brief
hudakz 0:b599e748252c 766 * @note
hudakz 0:b599e748252c 767 * @param
hudakz 0:b599e748252c 768 * @retval
hudakz 0:b599e748252c 769 */
hudakz 0:b599e748252c 770 void ENC28J60::_setBank(uint8_t address)
hudakz 0:b599e748252c 771 {
hudakz 0:b599e748252c 772 if ((address & BANK_MASK) != _bank) {
hudakz 0:b599e748252c 773 writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1 | ECON1_BSEL0));
hudakz 0:b599e748252c 774 writeOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK) >> 5);
hudakz 0:b599e748252c 775 _bank = (address & BANK_MASK);
hudakz 0:b599e748252c 776 }
hudakz 0:b599e748252c 777 }
hudakz 0:b599e748252c 778
hudakz 0:b599e748252c 779 /**
hudakz 0:b599e748252c 780 * @brief
hudakz 0:b599e748252c 781 * @note
hudakz 0:b599e748252c 782 * @param
hudakz 0:b599e748252c 783 * @retval
hudakz 0:b599e748252c 784 */
hudakz 0:b599e748252c 785 void ENC28J60::_read(uint8_t cmd, uint8_t* buf, uint16_t len, bool blocking)
hudakz 0:b599e748252c 786 {
hudakz 0:b599e748252c 787 #ifndef ENC28J60_READWRITE
hudakz 0:b599e748252c 788 _SPIMutex.lock();
hudakz 0:b599e748252c 789 _cs = 0;
hudakz 0:b599e748252c 790
hudakz 0:b599e748252c 791 // issue read command
hudakz 0:b599e748252c 792 _spi->write((int)cmd);
hudakz 0:b599e748252c 793 while (len) {
hudakz 0:b599e748252c 794 len--;
hudakz 0:b599e748252c 795
hudakz 0:b599e748252c 796 // read data
hudakz 0:b599e748252c 797 *buf = _spi->write(0x00);
hudakz 0:b599e748252c 798 buf++;
hudakz 0:b599e748252c 799 }
hudakz 0:b599e748252c 800
hudakz 0:b599e748252c 801 _cs = 1;
hudakz 0:b599e748252c 802 _SPIMutex.unlock();
hudakz 0:b599e748252c 803 #else
hudakz 0:b599e748252c 804 uint8_t* dummy = NULL;
hudakz 0:b599e748252c 805 _readwrite(cmd, buf, dummy, len, blocking);
hudakz 0:b599e748252c 806 #endif
hudakz 0:b599e748252c 807 }
hudakz 0:b599e748252c 808
hudakz 0:b599e748252c 809 /**
hudakz 0:b599e748252c 810 * @brief
hudakz 0:b599e748252c 811 * @note
hudakz 0:b599e748252c 812 * @param
hudakz 0:b599e748252c 813 * @retval
hudakz 0:b599e748252c 814 */
hudakz 0:b599e748252c 815 void ENC28J60::_write(uint8_t cmd, uint8_t* buf, uint16_t len, bool blocking)
hudakz 0:b599e748252c 816 {
hudakz 0:b599e748252c 817 #ifndef ENC28J60_READWRITE
hudakz 0:b599e748252c 818 _SPIMutex.lock();
hudakz 0:b599e748252c 819 _cs = 0;
hudakz 0:b599e748252c 820
hudakz 0:b599e748252c 821 // issue read command
hudakz 0:b599e748252c 822 _spi->write((int)cmd);
hudakz 0:b599e748252c 823 while (len) {
hudakz 0:b599e748252c 824 len--;
hudakz 0:b599e748252c 825
hudakz 0:b599e748252c 826 // read data
hudakz 0:b599e748252c 827 _spi->write((int) *buf);
hudakz 0:b599e748252c 828 buf++;
hudakz 0:b599e748252c 829 }
hudakz 0:b599e748252c 830
hudakz 0:b599e748252c 831 _cs = 1;
hudakz 0:b599e748252c 832 _SPIMutex.unlock();
hudakz 0:b599e748252c 833 #else
hudakz 0:b599e748252c 834 uint8_t* dummy = NULL;
hudakz 0:b599e748252c 835 _readwrite(cmd, dummy, buf, len, blocking);
hudakz 0:b599e748252c 836 #endif
hudakz 0:b599e748252c 837 }
hudakz 0:b599e748252c 838
hudakz 0:b599e748252c 839 #ifdef ENC28J60_READWRITE
hudakz 0:b599e748252c 840
hudakz 0:b599e748252c 841 /**
hudakz 0:b599e748252c 842 * @brief
hudakz 0:b599e748252c 843 * @note
hudakz 0:b599e748252c 844 * @param
hudakz 0:b599e748252c 845 * @retval
hudakz 0:b599e748252c 846 */
hudakz 0:b599e748252c 847 void ENC28J60::_readwrite(uint8_t cmd, uint8_t* readbuf, uint8_t* writebuf, uint16_t len, bool blocking)
hudakz 0:b599e748252c 848 {
hudakz 0:b599e748252c 849 _SPIMutex.lock();
hudakz 0:b599e748252c 850 _cs = 0;
hudakz 0:b599e748252c 851
hudakz 0:b599e748252c 852 // issue read command
hudakz 0:b599e748252c 853 _spi->write((int)cmd);
hudakz 0:b599e748252c 854 while (len) {
hudakz 0:b599e748252c 855 len--;
hudakz 0:b599e748252c 856
hudakz 0:b599e748252c 857 if (readbuf == NULL) {
hudakz 0:b599e748252c 858 _spi->write((int) *writebuf);
hudakz 0:b599e748252c 859 writebuf++;
hudakz 0:b599e748252c 860 }
hudakz 0:b599e748252c 861 else
hudakz 0:b599e748252c 862 if (writebuf == NULL) {
hudakz 0:b599e748252c 863 *readbuf = _spi->write(0x00);
hudakz 0:b599e748252c 864 readbuf++;
hudakz 0:b599e748252c 865 }
hudakz 0:b599e748252c 866 else {
hudakz 0:b599e748252c 867 break;
hudakz 0:b599e748252c 868 }
hudakz 0:b599e748252c 869 }
hudakz 0:b599e748252c 870
hudakz 0:b599e748252c 871 _cs = 1;
hudakz 0:b599e748252c 872 _SPIMutex.unlock();
hudakz 0:b599e748252c 873 }
hudakz 0:b599e748252c 874 #endif