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:
Fri Mar 26 15:58:28 2021 +0000
Revision:
0:b599e748252c
Child:
1:bce04bfc41fe
Mbed OS Ethernet MAC (EMAC) driver for the ENC28J60 Ethernet controller.

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