Webserver+3d print
cyclone_tcp/drivers/enc28j60.c@0:8918a71cdbe9, 2017-02-04 (annotated)
- Committer:
- Sergunb
- Date:
- Sat Feb 04 18:15:49 2017 +0000
- Revision:
- 0:8918a71cdbe9
nothing else
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Sergunb | 0:8918a71cdbe9 | 1 | /** |
Sergunb | 0:8918a71cdbe9 | 2 | * @file enc28j60.c |
Sergunb | 0:8918a71cdbe9 | 3 | * @brief ENC28J60 Ethernet controller |
Sergunb | 0:8918a71cdbe9 | 4 | * |
Sergunb | 0:8918a71cdbe9 | 5 | * @section License |
Sergunb | 0:8918a71cdbe9 | 6 | * |
Sergunb | 0:8918a71cdbe9 | 7 | * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved. |
Sergunb | 0:8918a71cdbe9 | 8 | * |
Sergunb | 0:8918a71cdbe9 | 9 | * This file is part of CycloneTCP Open. |
Sergunb | 0:8918a71cdbe9 | 10 | * |
Sergunb | 0:8918a71cdbe9 | 11 | * This program is free software; you can redistribute it and/or |
Sergunb | 0:8918a71cdbe9 | 12 | * modify it under the terms of the GNU General Public License |
Sergunb | 0:8918a71cdbe9 | 13 | * as published by the Free Software Foundation; either version 2 |
Sergunb | 0:8918a71cdbe9 | 14 | * of the License, or (at your option) any later version. |
Sergunb | 0:8918a71cdbe9 | 15 | * |
Sergunb | 0:8918a71cdbe9 | 16 | * This program is distributed in the hope that it will be useful, |
Sergunb | 0:8918a71cdbe9 | 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
Sergunb | 0:8918a71cdbe9 | 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
Sergunb | 0:8918a71cdbe9 | 19 | * GNU General Public License for more details. |
Sergunb | 0:8918a71cdbe9 | 20 | * |
Sergunb | 0:8918a71cdbe9 | 21 | * You should have received a copy of the GNU General Public License |
Sergunb | 0:8918a71cdbe9 | 22 | * along with this program; if not, write to the Free Software Foundation, |
Sergunb | 0:8918a71cdbe9 | 23 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
Sergunb | 0:8918a71cdbe9 | 24 | * |
Sergunb | 0:8918a71cdbe9 | 25 | * @author Oryx Embedded SARL (www.oryx-embedded.com) |
Sergunb | 0:8918a71cdbe9 | 26 | * @version 1.7.6 |
Sergunb | 0:8918a71cdbe9 | 27 | **/ |
Sergunb | 0:8918a71cdbe9 | 28 | |
Sergunb | 0:8918a71cdbe9 | 29 | //Switch to the appropriate trace level |
Sergunb | 0:8918a71cdbe9 | 30 | #define TRACE_LEVEL NIC_TRACE_LEVEL |
Sergunb | 0:8918a71cdbe9 | 31 | |
Sergunb | 0:8918a71cdbe9 | 32 | //Dependencies |
Sergunb | 0:8918a71cdbe9 | 33 | #include <limits.h> |
Sergunb | 0:8918a71cdbe9 | 34 | #include "core/net.h" |
Sergunb | 0:8918a71cdbe9 | 35 | #include "drivers/enc28j60.h" |
Sergunb | 0:8918a71cdbe9 | 36 | #include "debug.h" |
Sergunb | 0:8918a71cdbe9 | 37 | |
Sergunb | 0:8918a71cdbe9 | 38 | |
Sergunb | 0:8918a71cdbe9 | 39 | /** |
Sergunb | 0:8918a71cdbe9 | 40 | * @brief ENC28J60 driver |
Sergunb | 0:8918a71cdbe9 | 41 | **/ |
Sergunb | 0:8918a71cdbe9 | 42 | |
Sergunb | 0:8918a71cdbe9 | 43 | const NicDriver enc28j60Driver = |
Sergunb | 0:8918a71cdbe9 | 44 | { |
Sergunb | 0:8918a71cdbe9 | 45 | NIC_TYPE_ETHERNET, |
Sergunb | 0:8918a71cdbe9 | 46 | ETH_MTU, |
Sergunb | 0:8918a71cdbe9 | 47 | enc28j60Init, |
Sergunb | 0:8918a71cdbe9 | 48 | enc28j60Tick, |
Sergunb | 0:8918a71cdbe9 | 49 | enc28j60EnableIrq, |
Sergunb | 0:8918a71cdbe9 | 50 | enc28j60DisableIrq, |
Sergunb | 0:8918a71cdbe9 | 51 | enc28j60EventHandler, |
Sergunb | 0:8918a71cdbe9 | 52 | enc28j60SendPacket, |
Sergunb | 0:8918a71cdbe9 | 53 | enc28j60SetMulticastFilter, |
Sergunb | 0:8918a71cdbe9 | 54 | NULL, |
Sergunb | 0:8918a71cdbe9 | 55 | NULL, |
Sergunb | 0:8918a71cdbe9 | 56 | NULL, |
Sergunb | 0:8918a71cdbe9 | 57 | TRUE, |
Sergunb | 0:8918a71cdbe9 | 58 | TRUE, |
Sergunb | 0:8918a71cdbe9 | 59 | TRUE, |
Sergunb | 0:8918a71cdbe9 | 60 | FALSE |
Sergunb | 0:8918a71cdbe9 | 61 | }; |
Sergunb | 0:8918a71cdbe9 | 62 | |
Sergunb | 0:8918a71cdbe9 | 63 | |
Sergunb | 0:8918a71cdbe9 | 64 | /** |
Sergunb | 0:8918a71cdbe9 | 65 | * @brief ENC28J60 controller initialization |
Sergunb | 0:8918a71cdbe9 | 66 | * @param[in] interface Underlying network interface |
Sergunb | 0:8918a71cdbe9 | 67 | * @return Error code |
Sergunb | 0:8918a71cdbe9 | 68 | **/ |
Sergunb | 0:8918a71cdbe9 | 69 | |
Sergunb | 0:8918a71cdbe9 | 70 | error_t enc28j60Init(NetInterface *interface) |
Sergunb | 0:8918a71cdbe9 | 71 | { |
Sergunb | 0:8918a71cdbe9 | 72 | uint8_t revisionId; |
Sergunb | 0:8918a71cdbe9 | 73 | Enc28j60Context *context; |
Sergunb | 0:8918a71cdbe9 | 74 | |
Sergunb | 0:8918a71cdbe9 | 75 | //Debug message |
Sergunb | 0:8918a71cdbe9 | 76 | TRACE_INFO("Initializing ENC28J60 Ethernet controller...\r\n"); |
Sergunb | 0:8918a71cdbe9 | 77 | |
Sergunb | 0:8918a71cdbe9 | 78 | //Initialize SPI |
Sergunb | 0:8918a71cdbe9 | 79 | interface->spiDriver->init(); |
Sergunb | 0:8918a71cdbe9 | 80 | //Initialize external interrupt line |
Sergunb | 0:8918a71cdbe9 | 81 | interface->extIntDriver->init(); |
Sergunb | 0:8918a71cdbe9 | 82 | |
Sergunb | 0:8918a71cdbe9 | 83 | //Issue a system reset |
Sergunb | 0:8918a71cdbe9 | 84 | enc28j60SoftReset(interface); |
Sergunb | 0:8918a71cdbe9 | 85 | |
Sergunb | 0:8918a71cdbe9 | 86 | //After issuing the reset command, wait at least 1ms in firmware |
Sergunb | 0:8918a71cdbe9 | 87 | //for the device to be ready |
Sergunb | 0:8918a71cdbe9 | 88 | sleep(10); |
Sergunb | 0:8918a71cdbe9 | 89 | |
Sergunb | 0:8918a71cdbe9 | 90 | //Point to the driver context |
Sergunb | 0:8918a71cdbe9 | 91 | context = (Enc28j60Context *) interface->nicContext; |
Sergunb | 0:8918a71cdbe9 | 92 | |
Sergunb | 0:8918a71cdbe9 | 93 | //Initialize driver specific variables |
Sergunb | 0:8918a71cdbe9 | 94 | context->currentBank = UINT16_MAX; |
Sergunb | 0:8918a71cdbe9 | 95 | context->nextPacket = ENC28J60_RX_BUFFER_START; |
Sergunb | 0:8918a71cdbe9 | 96 | |
Sergunb | 0:8918a71cdbe9 | 97 | //Allocate RX buffer |
Sergunb | 0:8918a71cdbe9 | 98 | context->rxBuffer = memPoolAlloc(ETH_MAX_FRAME_SIZE); |
Sergunb | 0:8918a71cdbe9 | 99 | //Failed to allocate memory? |
Sergunb | 0:8918a71cdbe9 | 100 | if(context->rxBuffer == NULL) |
Sergunb | 0:8918a71cdbe9 | 101 | return ERROR_OUT_OF_MEMORY; |
Sergunb | 0:8918a71cdbe9 | 102 | |
Sergunb | 0:8918a71cdbe9 | 103 | //Read silicon revision ID |
Sergunb | 0:8918a71cdbe9 | 104 | revisionId = enc28j60ReadReg(interface, ENC28J60_REG_EREVID); |
Sergunb | 0:8918a71cdbe9 | 105 | |
Sergunb | 0:8918a71cdbe9 | 106 | //Debug message |
Sergunb | 0:8918a71cdbe9 | 107 | TRACE_INFO("ENC28J60 revision ID: 0x%02X\r\n", revisionId); |
Sergunb | 0:8918a71cdbe9 | 108 | |
Sergunb | 0:8918a71cdbe9 | 109 | //Disable CLKOUT output |
Sergunb | 0:8918a71cdbe9 | 110 | enc28j60WriteReg(interface, ENC28J60_REG_ECOCON, 0x00); |
Sergunb | 0:8918a71cdbe9 | 111 | |
Sergunb | 0:8918a71cdbe9 | 112 | //Set the MAC address |
Sergunb | 0:8918a71cdbe9 | 113 | enc28j60WriteReg(interface, ENC28J60_REG_MAADR1, interface->macAddr.b[0]); |
Sergunb | 0:8918a71cdbe9 | 114 | enc28j60WriteReg(interface, ENC28J60_REG_MAADR2, interface->macAddr.b[1]); |
Sergunb | 0:8918a71cdbe9 | 115 | enc28j60WriteReg(interface, ENC28J60_REG_MAADR3, interface->macAddr.b[2]); |
Sergunb | 0:8918a71cdbe9 | 116 | enc28j60WriteReg(interface, ENC28J60_REG_MAADR4, interface->macAddr.b[3]); |
Sergunb | 0:8918a71cdbe9 | 117 | enc28j60WriteReg(interface, ENC28J60_REG_MAADR5, interface->macAddr.b[4]); |
Sergunb | 0:8918a71cdbe9 | 118 | enc28j60WriteReg(interface, ENC28J60_REG_MAADR6, interface->macAddr.b[5]); |
Sergunb | 0:8918a71cdbe9 | 119 | |
Sergunb | 0:8918a71cdbe9 | 120 | //Set receive buffer location |
Sergunb | 0:8918a71cdbe9 | 121 | enc28j60WriteReg(interface, ENC28J60_REG_ERXSTL, LSB(ENC28J60_RX_BUFFER_START)); |
Sergunb | 0:8918a71cdbe9 | 122 | enc28j60WriteReg(interface, ENC28J60_REG_ERXSTH, MSB(ENC28J60_RX_BUFFER_START)); |
Sergunb | 0:8918a71cdbe9 | 123 | enc28j60WriteReg(interface, ENC28J60_REG_ERXNDL, LSB(ENC28J60_RX_BUFFER_STOP)); |
Sergunb | 0:8918a71cdbe9 | 124 | enc28j60WriteReg(interface, ENC28J60_REG_ERXNDH, MSB(ENC28J60_RX_BUFFER_STOP)); |
Sergunb | 0:8918a71cdbe9 | 125 | |
Sergunb | 0:8918a71cdbe9 | 126 | //The ERXRDPT register defines a location within the FIFO |
Sergunb | 0:8918a71cdbe9 | 127 | //where the receive hardware is forbidden to write to |
Sergunb | 0:8918a71cdbe9 | 128 | enc28j60WriteReg(interface, ENC28J60_REG_ERXRDPTL, LSB(ENC28J60_RX_BUFFER_STOP)); |
Sergunb | 0:8918a71cdbe9 | 129 | enc28j60WriteReg(interface, ENC28J60_REG_ERXRDPTH, MSB(ENC28J60_RX_BUFFER_STOP)); |
Sergunb | 0:8918a71cdbe9 | 130 | |
Sergunb | 0:8918a71cdbe9 | 131 | //Configure the receive filters |
Sergunb | 0:8918a71cdbe9 | 132 | enc28j60WriteReg(interface, ENC28J60_REG_ERXFCON, ERXFCON_UCEN | |
Sergunb | 0:8918a71cdbe9 | 133 | ERXFCON_CRCEN | ERXFCON_HTEN | ERXFCON_BCEN); |
Sergunb | 0:8918a71cdbe9 | 134 | |
Sergunb | 0:8918a71cdbe9 | 135 | //Initialize the hash table |
Sergunb | 0:8918a71cdbe9 | 136 | enc28j60WriteReg(interface, ENC28J60_REG_EHT0, 0x00); |
Sergunb | 0:8918a71cdbe9 | 137 | enc28j60WriteReg(interface, ENC28J60_REG_EHT1, 0x00); |
Sergunb | 0:8918a71cdbe9 | 138 | enc28j60WriteReg(interface, ENC28J60_REG_EHT2, 0x00); |
Sergunb | 0:8918a71cdbe9 | 139 | enc28j60WriteReg(interface, ENC28J60_REG_EHT3, 0x00); |
Sergunb | 0:8918a71cdbe9 | 140 | enc28j60WriteReg(interface, ENC28J60_REG_EHT4, 0x00); |
Sergunb | 0:8918a71cdbe9 | 141 | enc28j60WriteReg(interface, ENC28J60_REG_EHT5, 0x00); |
Sergunb | 0:8918a71cdbe9 | 142 | enc28j60WriteReg(interface, ENC28J60_REG_EHT6, 0x00); |
Sergunb | 0:8918a71cdbe9 | 143 | enc28j60WriteReg(interface, ENC28J60_REG_EHT7, 0x00); |
Sergunb | 0:8918a71cdbe9 | 144 | |
Sergunb | 0:8918a71cdbe9 | 145 | //Pull the MAC out of reset |
Sergunb | 0:8918a71cdbe9 | 146 | enc28j60WriteReg(interface, ENC28J60_REG_MACON2, 0x00); |
Sergunb | 0:8918a71cdbe9 | 147 | |
Sergunb | 0:8918a71cdbe9 | 148 | //Enable the MAC to receive frames |
Sergunb | 0:8918a71cdbe9 | 149 | enc28j60WriteReg(interface, ENC28J60_REG_MACON1, |
Sergunb | 0:8918a71cdbe9 | 150 | MACON1_TXPAUS | MACON1_RXPAUS | MACON1_MARXEN); |
Sergunb | 0:8918a71cdbe9 | 151 | |
Sergunb | 0:8918a71cdbe9 | 152 | //Enable automatic padding to at least 60 bytes, always append a valid CRC |
Sergunb | 0:8918a71cdbe9 | 153 | //and check frame length. MAC can operate in half-duplex or full-duplex mode |
Sergunb | 0:8918a71cdbe9 | 154 | #if (ENC28J60_FULL_DUPLEX_SUPPORT == ENABLED) |
Sergunb | 0:8918a71cdbe9 | 155 | enc28j60WriteReg(interface, ENC28J60_REG_MACON3, MACON3_PADCFG(1) | |
Sergunb | 0:8918a71cdbe9 | 156 | MACON3_TXCRCEN | MACON3_FRMLNEN | MACON3_FULDPX); |
Sergunb | 0:8918a71cdbe9 | 157 | #else |
Sergunb | 0:8918a71cdbe9 | 158 | enc28j60WriteReg(interface, ENC28J60_REG_MACON3, MACON3_PADCFG(1) | |
Sergunb | 0:8918a71cdbe9 | 159 | MACON3_TXCRCEN | MACON3_FRMLNEN); |
Sergunb | 0:8918a71cdbe9 | 160 | #endif |
Sergunb | 0:8918a71cdbe9 | 161 | |
Sergunb | 0:8918a71cdbe9 | 162 | //When the medium is occupied, the MAC will wait indefinitely for it to |
Sergunb | 0:8918a71cdbe9 | 163 | //become free when attempting to transmit |
Sergunb | 0:8918a71cdbe9 | 164 | enc28j60WriteReg(interface, ENC28J60_REG_MACON4, MACON4_DEFER); |
Sergunb | 0:8918a71cdbe9 | 165 | |
Sergunb | 0:8918a71cdbe9 | 166 | //Maximum frame length that can be received or transmitted (1518 bytes) |
Sergunb | 0:8918a71cdbe9 | 167 | enc28j60WriteReg(interface, ENC28J60_REG_MAMXFLL, LSB(1518)); |
Sergunb | 0:8918a71cdbe9 | 168 | enc28j60WriteReg(interface, ENC28J60_REG_MAMXFLH, MSB(1518)); |
Sergunb | 0:8918a71cdbe9 | 169 | |
Sergunb | 0:8918a71cdbe9 | 170 | //Configure the back-to-back inter-packet gap register |
Sergunb | 0:8918a71cdbe9 | 171 | #if (ENC28J60_FULL_DUPLEX_SUPPORT == ENABLED) |
Sergunb | 0:8918a71cdbe9 | 172 | enc28j60WriteReg(interface, ENC28J60_REG_MABBIPG, 0x15); |
Sergunb | 0:8918a71cdbe9 | 173 | #else |
Sergunb | 0:8918a71cdbe9 | 174 | enc28j60WriteReg(interface, ENC28J60_REG_MABBIPG, 0x12); |
Sergunb | 0:8918a71cdbe9 | 175 | #endif |
Sergunb | 0:8918a71cdbe9 | 176 | |
Sergunb | 0:8918a71cdbe9 | 177 | //Configure the non-back-to-back inter-packet gap register |
Sergunb | 0:8918a71cdbe9 | 178 | enc28j60WriteReg(interface, ENC28J60_REG_MAIPGL, 0x12); |
Sergunb | 0:8918a71cdbe9 | 179 | enc28j60WriteReg(interface, ENC28J60_REG_MAIPGH, 0x0C); |
Sergunb | 0:8918a71cdbe9 | 180 | |
Sergunb | 0:8918a71cdbe9 | 181 | //Collision window register |
Sergunb | 0:8918a71cdbe9 | 182 | enc28j60WriteReg(interface, ENC28J60_REG_MACLCON2, 63); |
Sergunb | 0:8918a71cdbe9 | 183 | |
Sergunb | 0:8918a71cdbe9 | 184 | //Set the PHY to the proper duplex mode |
Sergunb | 0:8918a71cdbe9 | 185 | #if (ENC28J60_FULL_DUPLEX_SUPPORT == ENABLED) |
Sergunb | 0:8918a71cdbe9 | 186 | enc28j60WritePhyReg(interface, ENC28J60_PHY_REG_PHCON1, PHCON1_PDPXMD); |
Sergunb | 0:8918a71cdbe9 | 187 | #else |
Sergunb | 0:8918a71cdbe9 | 188 | enc28j60WritePhyReg(interface, ENC28J60_PHY_REG_PHCON1, 0x0000); |
Sergunb | 0:8918a71cdbe9 | 189 | #endif |
Sergunb | 0:8918a71cdbe9 | 190 | |
Sergunb | 0:8918a71cdbe9 | 191 | //Disable half-duplex loopback in PHY |
Sergunb | 0:8918a71cdbe9 | 192 | enc28j60WritePhyReg(interface, ENC28J60_PHY_REG_PHCON2, PHCON2_HDLDIS); |
Sergunb | 0:8918a71cdbe9 | 193 | |
Sergunb | 0:8918a71cdbe9 | 194 | //LEDA displays link status and LEDB displays TX/RX activity |
Sergunb | 0:8918a71cdbe9 | 195 | enc28j60WritePhyReg(interface, ENC28J60_PHY_REG_PHLCON, |
Sergunb | 0:8918a71cdbe9 | 196 | PHLCON_LACFG(4) | PHLCON_LBCFG(7) | PHLCON_LFRQ(0) | PHLCON_STRCH); |
Sergunb | 0:8918a71cdbe9 | 197 | |
Sergunb | 0:8918a71cdbe9 | 198 | //Clear interrupt flags |
Sergunb | 0:8918a71cdbe9 | 199 | enc28j60WriteReg(interface, ENC28J60_REG_EIR, 0x00); |
Sergunb | 0:8918a71cdbe9 | 200 | |
Sergunb | 0:8918a71cdbe9 | 201 | //Configure interrupts as desired |
Sergunb | 0:8918a71cdbe9 | 202 | enc28j60WriteReg(interface, ENC28J60_REG_EIE, EIE_INTIE | |
Sergunb | 0:8918a71cdbe9 | 203 | EIE_PKTIE | EIE_LINKIE | EIE_TXIE | EIE_TXERIE); |
Sergunb | 0:8918a71cdbe9 | 204 | |
Sergunb | 0:8918a71cdbe9 | 205 | //Configure PHY interrupts as desired |
Sergunb | 0:8918a71cdbe9 | 206 | enc28j60WritePhyReg(interface, ENC28J60_PHY_REG_PHIE, |
Sergunb | 0:8918a71cdbe9 | 207 | PHIE_PLNKIE | PHIE_PGEIE); |
Sergunb | 0:8918a71cdbe9 | 208 | |
Sergunb | 0:8918a71cdbe9 | 209 | //Set RXEN to enable reception |
Sergunb | 0:8918a71cdbe9 | 210 | enc28j60SetBit(interface, ENC28J60_REG_ECON1, ECON1_RXEN); |
Sergunb | 0:8918a71cdbe9 | 211 | |
Sergunb | 0:8918a71cdbe9 | 212 | //Dump registers for debugging purpose |
Sergunb | 0:8918a71cdbe9 | 213 | enc28j60DumpReg(interface); |
Sergunb | 0:8918a71cdbe9 | 214 | enc28j60DumpPhyReg(interface); |
Sergunb | 0:8918a71cdbe9 | 215 | |
Sergunb | 0:8918a71cdbe9 | 216 | //Accept any packets from the upper layer |
Sergunb | 0:8918a71cdbe9 | 217 | osSetEvent(&interface->nicTxEvent); |
Sergunb | 0:8918a71cdbe9 | 218 | |
Sergunb | 0:8918a71cdbe9 | 219 | //Force the TCP/IP stack to poll the link state at startup |
Sergunb | 0:8918a71cdbe9 | 220 | interface->nicEvent = TRUE; |
Sergunb | 0:8918a71cdbe9 | 221 | //Notify the TCP/IP stack of the event |
Sergunb | 0:8918a71cdbe9 | 222 | osSetEvent(&netEvent); |
Sergunb | 0:8918a71cdbe9 | 223 | |
Sergunb | 0:8918a71cdbe9 | 224 | //Successful initialization |
Sergunb | 0:8918a71cdbe9 | 225 | return NO_ERROR; |
Sergunb | 0:8918a71cdbe9 | 226 | } |
Sergunb | 0:8918a71cdbe9 | 227 | |
Sergunb | 0:8918a71cdbe9 | 228 | |
Sergunb | 0:8918a71cdbe9 | 229 | /** |
Sergunb | 0:8918a71cdbe9 | 230 | * @brief ENC28J60 timer handler |
Sergunb | 0:8918a71cdbe9 | 231 | * @param[in] interface Underlying network interface |
Sergunb | 0:8918a71cdbe9 | 232 | **/ |
Sergunb | 0:8918a71cdbe9 | 233 | |
Sergunb | 0:8918a71cdbe9 | 234 | void enc28j60Tick(NetInterface *interface) |
Sergunb | 0:8918a71cdbe9 | 235 | { |
Sergunb | 0:8918a71cdbe9 | 236 | } |
Sergunb | 0:8918a71cdbe9 | 237 | |
Sergunb | 0:8918a71cdbe9 | 238 | |
Sergunb | 0:8918a71cdbe9 | 239 | /** |
Sergunb | 0:8918a71cdbe9 | 240 | * @brief Enable interrupts |
Sergunb | 0:8918a71cdbe9 | 241 | * @param[in] interface Underlying network interface |
Sergunb | 0:8918a71cdbe9 | 242 | **/ |
Sergunb | 0:8918a71cdbe9 | 243 | |
Sergunb | 0:8918a71cdbe9 | 244 | void enc28j60EnableIrq(NetInterface *interface) |
Sergunb | 0:8918a71cdbe9 | 245 | { |
Sergunb | 0:8918a71cdbe9 | 246 | //Enable interrupts |
Sergunb | 0:8918a71cdbe9 | 247 | interface->extIntDriver->enableIrq(); |
Sergunb | 0:8918a71cdbe9 | 248 | } |
Sergunb | 0:8918a71cdbe9 | 249 | |
Sergunb | 0:8918a71cdbe9 | 250 | |
Sergunb | 0:8918a71cdbe9 | 251 | /** |
Sergunb | 0:8918a71cdbe9 | 252 | * @brief Disable interrupts |
Sergunb | 0:8918a71cdbe9 | 253 | * @param[in] interface Underlying network interface |
Sergunb | 0:8918a71cdbe9 | 254 | **/ |
Sergunb | 0:8918a71cdbe9 | 255 | |
Sergunb | 0:8918a71cdbe9 | 256 | void enc28j60DisableIrq(NetInterface *interface) |
Sergunb | 0:8918a71cdbe9 | 257 | { |
Sergunb | 0:8918a71cdbe9 | 258 | //Disable interrupts |
Sergunb | 0:8918a71cdbe9 | 259 | interface->extIntDriver->disableIrq(); |
Sergunb | 0:8918a71cdbe9 | 260 | } |
Sergunb | 0:8918a71cdbe9 | 261 | |
Sergunb | 0:8918a71cdbe9 | 262 | |
Sergunb | 0:8918a71cdbe9 | 263 | /** |
Sergunb | 0:8918a71cdbe9 | 264 | * @brief ENC28J60 interrupt service routine |
Sergunb | 0:8918a71cdbe9 | 265 | * @param[in] interface Underlying network interface |
Sergunb | 0:8918a71cdbe9 | 266 | * @return TRUE if a higher priority task must be woken. Else FALSE is returned |
Sergunb | 0:8918a71cdbe9 | 267 | **/ |
Sergunb | 0:8918a71cdbe9 | 268 | |
Sergunb | 0:8918a71cdbe9 | 269 | bool_t enc28j60IrqHandler(NetInterface *interface) |
Sergunb | 0:8918a71cdbe9 | 270 | { |
Sergunb | 0:8918a71cdbe9 | 271 | bool_t flag; |
Sergunb | 0:8918a71cdbe9 | 272 | uint8_t status; |
Sergunb | 0:8918a71cdbe9 | 273 | |
Sergunb | 0:8918a71cdbe9 | 274 | //This flag will be set if a higher priority task must be woken |
Sergunb | 0:8918a71cdbe9 | 275 | flag = FALSE; |
Sergunb | 0:8918a71cdbe9 | 276 | |
Sergunb | 0:8918a71cdbe9 | 277 | //Clear the INTIE bit, immediately after an interrupt event |
Sergunb | 0:8918a71cdbe9 | 278 | enc28j60ClearBit(interface, ENC28J60_REG_EIE, EIE_INTIE); |
Sergunb | 0:8918a71cdbe9 | 279 | |
Sergunb | 0:8918a71cdbe9 | 280 | //Read interrupt status register |
Sergunb | 0:8918a71cdbe9 | 281 | status = enc28j60ReadReg(interface, ENC28J60_REG_EIR); |
Sergunb | 0:8918a71cdbe9 | 282 | |
Sergunb | 0:8918a71cdbe9 | 283 | //Link status change? |
Sergunb | 0:8918a71cdbe9 | 284 | if(status & EIR_LINKIF) |
Sergunb | 0:8918a71cdbe9 | 285 | { |
Sergunb | 0:8918a71cdbe9 | 286 | //Disable LINKIE interrupt |
Sergunb | 0:8918a71cdbe9 | 287 | enc28j60ClearBit(interface, ENC28J60_REG_EIE, EIE_LINKIE); |
Sergunb | 0:8918a71cdbe9 | 288 | |
Sergunb | 0:8918a71cdbe9 | 289 | //Set event flag |
Sergunb | 0:8918a71cdbe9 | 290 | interface->nicEvent = TRUE; |
Sergunb | 0:8918a71cdbe9 | 291 | //Notify the TCP/IP stack of the event |
Sergunb | 0:8918a71cdbe9 | 292 | flag |= osSetEventFromIsr(&netEvent); |
Sergunb | 0:8918a71cdbe9 | 293 | } |
Sergunb | 0:8918a71cdbe9 | 294 | |
Sergunb | 0:8918a71cdbe9 | 295 | //Packet received? |
Sergunb | 0:8918a71cdbe9 | 296 | if(status & EIR_PKTIF) |
Sergunb | 0:8918a71cdbe9 | 297 | { |
Sergunb | 0:8918a71cdbe9 | 298 | //Disable PKTIE interrupt |
Sergunb | 0:8918a71cdbe9 | 299 | enc28j60ClearBit(interface, ENC28J60_REG_EIE, EIE_PKTIE); |
Sergunb | 0:8918a71cdbe9 | 300 | |
Sergunb | 0:8918a71cdbe9 | 301 | //Set event flag |
Sergunb | 0:8918a71cdbe9 | 302 | interface->nicEvent = TRUE; |
Sergunb | 0:8918a71cdbe9 | 303 | //Notify the TCP/IP stack of the event |
Sergunb | 0:8918a71cdbe9 | 304 | flag |= osSetEventFromIsr(&netEvent); |
Sergunb | 0:8918a71cdbe9 | 305 | } |
Sergunb | 0:8918a71cdbe9 | 306 | |
Sergunb | 0:8918a71cdbe9 | 307 | //Packet transmission complete? |
Sergunb | 0:8918a71cdbe9 | 308 | if(status & (EIR_TXIF | EIE_TXERIE)) |
Sergunb | 0:8918a71cdbe9 | 309 | { |
Sergunb | 0:8918a71cdbe9 | 310 | //Clear interrupt flags |
Sergunb | 0:8918a71cdbe9 | 311 | enc28j60ClearBit(interface, ENC28J60_REG_EIR, EIR_TXIF | EIE_TXERIE); |
Sergunb | 0:8918a71cdbe9 | 312 | |
Sergunb | 0:8918a71cdbe9 | 313 | //Notify the TCP/IP stack that the transmitter is ready to send |
Sergunb | 0:8918a71cdbe9 | 314 | flag |= osSetEventFromIsr(&interface->nicTxEvent); |
Sergunb | 0:8918a71cdbe9 | 315 | } |
Sergunb | 0:8918a71cdbe9 | 316 | |
Sergunb | 0:8918a71cdbe9 | 317 | //Once the interrupt has been serviced, the INTIE bit |
Sergunb | 0:8918a71cdbe9 | 318 | //is set again to re-enable interrupts |
Sergunb | 0:8918a71cdbe9 | 319 | enc28j60SetBit(interface, ENC28J60_REG_EIE, EIE_INTIE); |
Sergunb | 0:8918a71cdbe9 | 320 | |
Sergunb | 0:8918a71cdbe9 | 321 | //A higher priority task must be woken? |
Sergunb | 0:8918a71cdbe9 | 322 | return flag; |
Sergunb | 0:8918a71cdbe9 | 323 | } |
Sergunb | 0:8918a71cdbe9 | 324 | |
Sergunb | 0:8918a71cdbe9 | 325 | |
Sergunb | 0:8918a71cdbe9 | 326 | /** |
Sergunb | 0:8918a71cdbe9 | 327 | * @brief ENC28J60 event handler |
Sergunb | 0:8918a71cdbe9 | 328 | * @param[in] interface Underlying network interface |
Sergunb | 0:8918a71cdbe9 | 329 | **/ |
Sergunb | 0:8918a71cdbe9 | 330 | |
Sergunb | 0:8918a71cdbe9 | 331 | void enc28j60EventHandler(NetInterface *interface) |
Sergunb | 0:8918a71cdbe9 | 332 | { |
Sergunb | 0:8918a71cdbe9 | 333 | error_t error; |
Sergunb | 0:8918a71cdbe9 | 334 | uint16_t status; |
Sergunb | 0:8918a71cdbe9 | 335 | uint16_t value; |
Sergunb | 0:8918a71cdbe9 | 336 | |
Sergunb | 0:8918a71cdbe9 | 337 | //Read interrupt status register |
Sergunb | 0:8918a71cdbe9 | 338 | status = enc28j60ReadReg(interface, ENC28J60_REG_EIR); |
Sergunb | 0:8918a71cdbe9 | 339 | |
Sergunb | 0:8918a71cdbe9 | 340 | //Check whether the link state has changed |
Sergunb | 0:8918a71cdbe9 | 341 | if(status & EIR_LINKIF) |
Sergunb | 0:8918a71cdbe9 | 342 | { |
Sergunb | 0:8918a71cdbe9 | 343 | //Clear PHY interrupts flags |
Sergunb | 0:8918a71cdbe9 | 344 | enc28j60ReadPhyReg(interface, ENC28J60_PHY_REG_PHIR); |
Sergunb | 0:8918a71cdbe9 | 345 | //Clear interrupt flag |
Sergunb | 0:8918a71cdbe9 | 346 | enc28j60ClearBit(interface, ENC28J60_REG_EIR, EIR_LINKIF); |
Sergunb | 0:8918a71cdbe9 | 347 | //Read PHY status register |
Sergunb | 0:8918a71cdbe9 | 348 | value = enc28j60ReadPhyReg(interface, ENC28J60_PHY_REG_PHSTAT2); |
Sergunb | 0:8918a71cdbe9 | 349 | |
Sergunb | 0:8918a71cdbe9 | 350 | //Check link state |
Sergunb | 0:8918a71cdbe9 | 351 | if(value & PHSTAT2_LSTAT) |
Sergunb | 0:8918a71cdbe9 | 352 | { |
Sergunb | 0:8918a71cdbe9 | 353 | //Link speed |
Sergunb | 0:8918a71cdbe9 | 354 | interface->linkSpeed = NIC_LINK_SPEED_10MBPS; |
Sergunb | 0:8918a71cdbe9 | 355 | |
Sergunb | 0:8918a71cdbe9 | 356 | #if (ENC28J60_FULL_DUPLEX_SUPPORT == ENABLED) |
Sergunb | 0:8918a71cdbe9 | 357 | //Full-duplex mode |
Sergunb | 0:8918a71cdbe9 | 358 | interface->duplexMode = NIC_FULL_DUPLEX_MODE; |
Sergunb | 0:8918a71cdbe9 | 359 | #else |
Sergunb | 0:8918a71cdbe9 | 360 | //Half-duplex mode |
Sergunb | 0:8918a71cdbe9 | 361 | interface->duplexMode = NIC_HALF_DUPLEX_MODE; |
Sergunb | 0:8918a71cdbe9 | 362 | #endif |
Sergunb | 0:8918a71cdbe9 | 363 | //Link is up |
Sergunb | 0:8918a71cdbe9 | 364 | interface->linkState = TRUE; |
Sergunb | 0:8918a71cdbe9 | 365 | } |
Sergunb | 0:8918a71cdbe9 | 366 | else |
Sergunb | 0:8918a71cdbe9 | 367 | { |
Sergunb | 0:8918a71cdbe9 | 368 | //Link is down |
Sergunb | 0:8918a71cdbe9 | 369 | interface->linkState = FALSE; |
Sergunb | 0:8918a71cdbe9 | 370 | } |
Sergunb | 0:8918a71cdbe9 | 371 | |
Sergunb | 0:8918a71cdbe9 | 372 | //Process link state change event |
Sergunb | 0:8918a71cdbe9 | 373 | nicNotifyLinkChange(interface); |
Sergunb | 0:8918a71cdbe9 | 374 | } |
Sergunb | 0:8918a71cdbe9 | 375 | |
Sergunb | 0:8918a71cdbe9 | 376 | //Check whether a packet has been received? |
Sergunb | 0:8918a71cdbe9 | 377 | if(status & EIR_PKTIF) |
Sergunb | 0:8918a71cdbe9 | 378 | { |
Sergunb | 0:8918a71cdbe9 | 379 | //Clear interrupt flag |
Sergunb | 0:8918a71cdbe9 | 380 | enc28j60ClearBit(interface, ENC28J60_REG_EIR, EIR_PKTIF); |
Sergunb | 0:8918a71cdbe9 | 381 | |
Sergunb | 0:8918a71cdbe9 | 382 | //Process all pending packets |
Sergunb | 0:8918a71cdbe9 | 383 | do |
Sergunb | 0:8918a71cdbe9 | 384 | { |
Sergunb | 0:8918a71cdbe9 | 385 | //Read incoming packet |
Sergunb | 0:8918a71cdbe9 | 386 | error = enc28j60ReceivePacket(interface); |
Sergunb | 0:8918a71cdbe9 | 387 | |
Sergunb | 0:8918a71cdbe9 | 388 | //No more data in the receive buffer? |
Sergunb | 0:8918a71cdbe9 | 389 | } while(error != ERROR_BUFFER_EMPTY); |
Sergunb | 0:8918a71cdbe9 | 390 | } |
Sergunb | 0:8918a71cdbe9 | 391 | |
Sergunb | 0:8918a71cdbe9 | 392 | //Re-enable LINKIE and PKTIE interrupts |
Sergunb | 0:8918a71cdbe9 | 393 | enc28j60SetBit(interface, ENC28J60_REG_EIE, EIE_LINKIE | EIE_PKTIE); |
Sergunb | 0:8918a71cdbe9 | 394 | } |
Sergunb | 0:8918a71cdbe9 | 395 | |
Sergunb | 0:8918a71cdbe9 | 396 | |
Sergunb | 0:8918a71cdbe9 | 397 | /** |
Sergunb | 0:8918a71cdbe9 | 398 | * @brief Send a packet |
Sergunb | 0:8918a71cdbe9 | 399 | * @param[in] interface Underlying network interface |
Sergunb | 0:8918a71cdbe9 | 400 | * @param[in] buffer Multi-part buffer containing the data to send |
Sergunb | 0:8918a71cdbe9 | 401 | * @param[in] offset Offset to the first data byte |
Sergunb | 0:8918a71cdbe9 | 402 | * @return Error code |
Sergunb | 0:8918a71cdbe9 | 403 | **/ |
Sergunb | 0:8918a71cdbe9 | 404 | |
Sergunb | 0:8918a71cdbe9 | 405 | error_t enc28j60SendPacket(NetInterface *interface, |
Sergunb | 0:8918a71cdbe9 | 406 | const NetBuffer *buffer, size_t offset) |
Sergunb | 0:8918a71cdbe9 | 407 | { |
Sergunb | 0:8918a71cdbe9 | 408 | size_t length; |
Sergunb | 0:8918a71cdbe9 | 409 | |
Sergunb | 0:8918a71cdbe9 | 410 | //Retrieve the length of the packet |
Sergunb | 0:8918a71cdbe9 | 411 | length = netBufferGetLength(buffer) - offset; |
Sergunb | 0:8918a71cdbe9 | 412 | |
Sergunb | 0:8918a71cdbe9 | 413 | //Check the frame length |
Sergunb | 0:8918a71cdbe9 | 414 | if(length > 1536) |
Sergunb | 0:8918a71cdbe9 | 415 | { |
Sergunb | 0:8918a71cdbe9 | 416 | //The transmitter can accept another packet |
Sergunb | 0:8918a71cdbe9 | 417 | osSetEvent(&interface->nicTxEvent); |
Sergunb | 0:8918a71cdbe9 | 418 | //Report an error |
Sergunb | 0:8918a71cdbe9 | 419 | return ERROR_INVALID_LENGTH; |
Sergunb | 0:8918a71cdbe9 | 420 | } |
Sergunb | 0:8918a71cdbe9 | 421 | |
Sergunb | 0:8918a71cdbe9 | 422 | //Make sure the link is up before transmitting the frame |
Sergunb | 0:8918a71cdbe9 | 423 | if(!interface->linkState) |
Sergunb | 0:8918a71cdbe9 | 424 | { |
Sergunb | 0:8918a71cdbe9 | 425 | //The transmitter can accept another packet |
Sergunb | 0:8918a71cdbe9 | 426 | osSetEventFromIsr(&interface->nicTxEvent); |
Sergunb | 0:8918a71cdbe9 | 427 | //Drop current packet |
Sergunb | 0:8918a71cdbe9 | 428 | return NO_ERROR; |
Sergunb | 0:8918a71cdbe9 | 429 | } |
Sergunb | 0:8918a71cdbe9 | 430 | |
Sergunb | 0:8918a71cdbe9 | 431 | //It is recommended to reset the transmit logic before |
Sergunb | 0:8918a71cdbe9 | 432 | //attempting to transmit a packet |
Sergunb | 0:8918a71cdbe9 | 433 | enc28j60SetBit(interface, ENC28J60_REG_ECON1, ECON1_TXRST); |
Sergunb | 0:8918a71cdbe9 | 434 | enc28j60ClearBit(interface, ENC28J60_REG_ECON1, ECON1_TXRST); |
Sergunb | 0:8918a71cdbe9 | 435 | |
Sergunb | 0:8918a71cdbe9 | 436 | //Interrupt flags should be cleared after the reset is completed |
Sergunb | 0:8918a71cdbe9 | 437 | enc28j60ClearBit(interface, ENC28J60_REG_EIR, EIR_TXIF | EIR_TXERIF); |
Sergunb | 0:8918a71cdbe9 | 438 | |
Sergunb | 0:8918a71cdbe9 | 439 | //Set transmit buffer location |
Sergunb | 0:8918a71cdbe9 | 440 | enc28j60WriteReg(interface, ENC28J60_REG_ETXSTL, LSB(ENC28J60_TX_BUFFER_START)); |
Sergunb | 0:8918a71cdbe9 | 441 | enc28j60WriteReg(interface, ENC28J60_REG_ETXSTH, MSB(ENC28J60_TX_BUFFER_START)); |
Sergunb | 0:8918a71cdbe9 | 442 | |
Sergunb | 0:8918a71cdbe9 | 443 | //Point to start of transmit buffer |
Sergunb | 0:8918a71cdbe9 | 444 | enc28j60WriteReg(interface, ENC28J60_REG_EWRPTL, LSB(ENC28J60_TX_BUFFER_START)); |
Sergunb | 0:8918a71cdbe9 | 445 | enc28j60WriteReg(interface, ENC28J60_REG_EWRPTH, MSB(ENC28J60_TX_BUFFER_START)); |
Sergunb | 0:8918a71cdbe9 | 446 | |
Sergunb | 0:8918a71cdbe9 | 447 | //Copy the data to the transmit buffer |
Sergunb | 0:8918a71cdbe9 | 448 | enc28j60WriteBuffer(interface, buffer, offset); |
Sergunb | 0:8918a71cdbe9 | 449 | |
Sergunb | 0:8918a71cdbe9 | 450 | //ETXND should point to the last byte in the data payload |
Sergunb | 0:8918a71cdbe9 | 451 | enc28j60WriteReg(interface, ENC28J60_REG_ETXNDL, LSB(ENC28J60_TX_BUFFER_START + length)); |
Sergunb | 0:8918a71cdbe9 | 452 | enc28j60WriteReg(interface, ENC28J60_REG_ETXNDH, MSB(ENC28J60_TX_BUFFER_START + length)); |
Sergunb | 0:8918a71cdbe9 | 453 | |
Sergunb | 0:8918a71cdbe9 | 454 | //Start transmission |
Sergunb | 0:8918a71cdbe9 | 455 | enc28j60SetBit(interface, ENC28J60_REG_ECON1, ECON1_TXRTS); |
Sergunb | 0:8918a71cdbe9 | 456 | |
Sergunb | 0:8918a71cdbe9 | 457 | //Successful processing |
Sergunb | 0:8918a71cdbe9 | 458 | return NO_ERROR; |
Sergunb | 0:8918a71cdbe9 | 459 | } |
Sergunb | 0:8918a71cdbe9 | 460 | |
Sergunb | 0:8918a71cdbe9 | 461 | |
Sergunb | 0:8918a71cdbe9 | 462 | /** |
Sergunb | 0:8918a71cdbe9 | 463 | * @brief Receive a packet |
Sergunb | 0:8918a71cdbe9 | 464 | * @param[in] interface Underlying network interface |
Sergunb | 0:8918a71cdbe9 | 465 | * @return Error code |
Sergunb | 0:8918a71cdbe9 | 466 | **/ |
Sergunb | 0:8918a71cdbe9 | 467 | |
Sergunb | 0:8918a71cdbe9 | 468 | error_t enc28j60ReceivePacket(NetInterface *interface) |
Sergunb | 0:8918a71cdbe9 | 469 | { |
Sergunb | 0:8918a71cdbe9 | 470 | error_t error; |
Sergunb | 0:8918a71cdbe9 | 471 | uint16_t n; |
Sergunb | 0:8918a71cdbe9 | 472 | uint16_t status; |
Sergunb | 0:8918a71cdbe9 | 473 | Enc28j60Context *context; |
Sergunb | 0:8918a71cdbe9 | 474 | |
Sergunb | 0:8918a71cdbe9 | 475 | //Point to the driver context |
Sergunb | 0:8918a71cdbe9 | 476 | context = (Enc28j60Context *) interface->nicContext; |
Sergunb | 0:8918a71cdbe9 | 477 | |
Sergunb | 0:8918a71cdbe9 | 478 | //Any packet pending in the receive buffer? |
Sergunb | 0:8918a71cdbe9 | 479 | if(enc28j60ReadReg(interface, ENC28J60_REG_EPKTCNT)) |
Sergunb | 0:8918a71cdbe9 | 480 | { |
Sergunb | 0:8918a71cdbe9 | 481 | //Point to the start of the received packet |
Sergunb | 0:8918a71cdbe9 | 482 | enc28j60WriteReg(interface, ENC28J60_REG_ERDPTL, LSB(context->nextPacket)); |
Sergunb | 0:8918a71cdbe9 | 483 | enc28j60WriteReg(interface, ENC28J60_REG_ERDPTH, MSB(context->nextPacket)); |
Sergunb | 0:8918a71cdbe9 | 484 | |
Sergunb | 0:8918a71cdbe9 | 485 | //Read the first two bytes, which are the address of the next packet |
Sergunb | 0:8918a71cdbe9 | 486 | enc28j60ReadBuffer(interface, (uint8_t *) &context->nextPacket, sizeof(uint16_t)); |
Sergunb | 0:8918a71cdbe9 | 487 | //Get the length of the received frame in bytes |
Sergunb | 0:8918a71cdbe9 | 488 | enc28j60ReadBuffer(interface, (uint8_t *) &n, sizeof(uint16_t)); |
Sergunb | 0:8918a71cdbe9 | 489 | //Read the receive status vector (RSV) |
Sergunb | 0:8918a71cdbe9 | 490 | enc28j60ReadBuffer(interface, (uint8_t *) &status, sizeof(uint16_t)); |
Sergunb | 0:8918a71cdbe9 | 491 | |
Sergunb | 0:8918a71cdbe9 | 492 | //Make sure no error occurred |
Sergunb | 0:8918a71cdbe9 | 493 | if(status & RSV_RECEIVED_OK) |
Sergunb | 0:8918a71cdbe9 | 494 | { |
Sergunb | 0:8918a71cdbe9 | 495 | //Limit the number of data to read |
Sergunb | 0:8918a71cdbe9 | 496 | n = MIN(n, ETH_MAX_FRAME_SIZE); |
Sergunb | 0:8918a71cdbe9 | 497 | //Read the Ethernet frame |
Sergunb | 0:8918a71cdbe9 | 498 | enc28j60ReadBuffer(interface, context->rxBuffer, n); |
Sergunb | 0:8918a71cdbe9 | 499 | //Valid packet received |
Sergunb | 0:8918a71cdbe9 | 500 | error = NO_ERROR; |
Sergunb | 0:8918a71cdbe9 | 501 | } |
Sergunb | 0:8918a71cdbe9 | 502 | else |
Sergunb | 0:8918a71cdbe9 | 503 | { |
Sergunb | 0:8918a71cdbe9 | 504 | //The received packet contains an error |
Sergunb | 0:8918a71cdbe9 | 505 | error = ERROR_INVALID_PACKET; |
Sergunb | 0:8918a71cdbe9 | 506 | } |
Sergunb | 0:8918a71cdbe9 | 507 | |
Sergunb | 0:8918a71cdbe9 | 508 | //Advance the ERXRDPT pointer, taking care to wrap back at the |
Sergunb | 0:8918a71cdbe9 | 509 | //end of the received memory buffer |
Sergunb | 0:8918a71cdbe9 | 510 | if(context->nextPacket == ENC28J60_RX_BUFFER_START) |
Sergunb | 0:8918a71cdbe9 | 511 | { |
Sergunb | 0:8918a71cdbe9 | 512 | enc28j60WriteReg(interface, ENC28J60_REG_ERXRDPTL, LSB(ENC28J60_RX_BUFFER_STOP)); |
Sergunb | 0:8918a71cdbe9 | 513 | enc28j60WriteReg(interface, ENC28J60_REG_ERXRDPTH, MSB(ENC28J60_RX_BUFFER_STOP)); |
Sergunb | 0:8918a71cdbe9 | 514 | } |
Sergunb | 0:8918a71cdbe9 | 515 | else |
Sergunb | 0:8918a71cdbe9 | 516 | { |
Sergunb | 0:8918a71cdbe9 | 517 | enc28j60WriteReg(interface, ENC28J60_REG_ERXRDPTL, LSB(context->nextPacket - 1)); |
Sergunb | 0:8918a71cdbe9 | 518 | enc28j60WriteReg(interface, ENC28J60_REG_ERXRDPTH, MSB(context->nextPacket - 1)); |
Sergunb | 0:8918a71cdbe9 | 519 | } |
Sergunb | 0:8918a71cdbe9 | 520 | |
Sergunb | 0:8918a71cdbe9 | 521 | //Decrement the packet counter |
Sergunb | 0:8918a71cdbe9 | 522 | enc28j60SetBit(interface, ENC28J60_REG_ECON2, ECON2_PKTDEC); |
Sergunb | 0:8918a71cdbe9 | 523 | } |
Sergunb | 0:8918a71cdbe9 | 524 | else |
Sergunb | 0:8918a71cdbe9 | 525 | { |
Sergunb | 0:8918a71cdbe9 | 526 | //No more data in the receive buffer |
Sergunb | 0:8918a71cdbe9 | 527 | error = ERROR_BUFFER_EMPTY; |
Sergunb | 0:8918a71cdbe9 | 528 | } |
Sergunb | 0:8918a71cdbe9 | 529 | |
Sergunb | 0:8918a71cdbe9 | 530 | //Check whether a valid packet has been received |
Sergunb | 0:8918a71cdbe9 | 531 | if(!error) |
Sergunb | 0:8918a71cdbe9 | 532 | { |
Sergunb | 0:8918a71cdbe9 | 533 | //Pass the packet to the upper layer |
Sergunb | 0:8918a71cdbe9 | 534 | nicProcessPacket(interface, context->rxBuffer, n); |
Sergunb | 0:8918a71cdbe9 | 535 | } |
Sergunb | 0:8918a71cdbe9 | 536 | |
Sergunb | 0:8918a71cdbe9 | 537 | //Return status code |
Sergunb | 0:8918a71cdbe9 | 538 | return error; |
Sergunb | 0:8918a71cdbe9 | 539 | } |
Sergunb | 0:8918a71cdbe9 | 540 | |
Sergunb | 0:8918a71cdbe9 | 541 | |
Sergunb | 0:8918a71cdbe9 | 542 | /** |
Sergunb | 0:8918a71cdbe9 | 543 | * @brief Configure multicast MAC address filtering |
Sergunb | 0:8918a71cdbe9 | 544 | * @param[in] interface Underlying network interface |
Sergunb | 0:8918a71cdbe9 | 545 | * @return Error code |
Sergunb | 0:8918a71cdbe9 | 546 | **/ |
Sergunb | 0:8918a71cdbe9 | 547 | |
Sergunb | 0:8918a71cdbe9 | 548 | error_t enc28j60SetMulticastFilter(NetInterface *interface) |
Sergunb | 0:8918a71cdbe9 | 549 | { |
Sergunb | 0:8918a71cdbe9 | 550 | uint_t i; |
Sergunb | 0:8918a71cdbe9 | 551 | uint_t k; |
Sergunb | 0:8918a71cdbe9 | 552 | uint32_t crc; |
Sergunb | 0:8918a71cdbe9 | 553 | uint8_t hashTable[8]; |
Sergunb | 0:8918a71cdbe9 | 554 | MacFilterEntry *entry; |
Sergunb | 0:8918a71cdbe9 | 555 | |
Sergunb | 0:8918a71cdbe9 | 556 | //Debug message |
Sergunb | 0:8918a71cdbe9 | 557 | TRACE_DEBUG("Updating ENC28J60 hash table...\r\n"); |
Sergunb | 0:8918a71cdbe9 | 558 | |
Sergunb | 0:8918a71cdbe9 | 559 | //Clear hash table |
Sergunb | 0:8918a71cdbe9 | 560 | memset(hashTable, 0, sizeof(hashTable)); |
Sergunb | 0:8918a71cdbe9 | 561 | |
Sergunb | 0:8918a71cdbe9 | 562 | //The MAC filter table contains the multicast MAC addresses |
Sergunb | 0:8918a71cdbe9 | 563 | //to accept when receiving an Ethernet frame |
Sergunb | 0:8918a71cdbe9 | 564 | for(i = 0; i < MAC_MULTICAST_FILTER_SIZE; i++) |
Sergunb | 0:8918a71cdbe9 | 565 | { |
Sergunb | 0:8918a71cdbe9 | 566 | //Point to the current entry |
Sergunb | 0:8918a71cdbe9 | 567 | entry = &interface->macMulticastFilter[i]; |
Sergunb | 0:8918a71cdbe9 | 568 | |
Sergunb | 0:8918a71cdbe9 | 569 | //Valid entry? |
Sergunb | 0:8918a71cdbe9 | 570 | if(entry->refCount > 0) |
Sergunb | 0:8918a71cdbe9 | 571 | { |
Sergunb | 0:8918a71cdbe9 | 572 | //Compute CRC over the current MAC address |
Sergunb | 0:8918a71cdbe9 | 573 | crc = enc28j60CalcCrc(&entry->addr, sizeof(MacAddr)); |
Sergunb | 0:8918a71cdbe9 | 574 | //Calculate the corresponding index in the table |
Sergunb | 0:8918a71cdbe9 | 575 | k = (crc >> 23) & 0x3F; |
Sergunb | 0:8918a71cdbe9 | 576 | //Update hash table contents |
Sergunb | 0:8918a71cdbe9 | 577 | hashTable[k / 8] |= (1 << (k % 8)); |
Sergunb | 0:8918a71cdbe9 | 578 | } |
Sergunb | 0:8918a71cdbe9 | 579 | } |
Sergunb | 0:8918a71cdbe9 | 580 | |
Sergunb | 0:8918a71cdbe9 | 581 | //Write the hash table to the ENC28J60 controller |
Sergunb | 0:8918a71cdbe9 | 582 | enc28j60WriteReg(interface, ENC28J60_REG_EHT0, hashTable[0]); |
Sergunb | 0:8918a71cdbe9 | 583 | enc28j60WriteReg(interface, ENC28J60_REG_EHT1, hashTable[1]); |
Sergunb | 0:8918a71cdbe9 | 584 | enc28j60WriteReg(interface, ENC28J60_REG_EHT2, hashTable[2]); |
Sergunb | 0:8918a71cdbe9 | 585 | enc28j60WriteReg(interface, ENC28J60_REG_EHT3, hashTable[3]); |
Sergunb | 0:8918a71cdbe9 | 586 | enc28j60WriteReg(interface, ENC28J60_REG_EHT4, hashTable[4]); |
Sergunb | 0:8918a71cdbe9 | 587 | enc28j60WriteReg(interface, ENC28J60_REG_EHT5, hashTable[5]); |
Sergunb | 0:8918a71cdbe9 | 588 | enc28j60WriteReg(interface, ENC28J60_REG_EHT6, hashTable[6]); |
Sergunb | 0:8918a71cdbe9 | 589 | enc28j60WriteReg(interface, ENC28J60_REG_EHT7, hashTable[7]); |
Sergunb | 0:8918a71cdbe9 | 590 | |
Sergunb | 0:8918a71cdbe9 | 591 | //Debug message |
Sergunb | 0:8918a71cdbe9 | 592 | TRACE_DEBUG(" EHT0 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT0)); |
Sergunb | 0:8918a71cdbe9 | 593 | TRACE_DEBUG(" EHT1 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT1)); |
Sergunb | 0:8918a71cdbe9 | 594 | TRACE_DEBUG(" EHT2 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT2)); |
Sergunb | 0:8918a71cdbe9 | 595 | TRACE_DEBUG(" EHT3 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT3)); |
Sergunb | 0:8918a71cdbe9 | 596 | TRACE_DEBUG(" EHT0 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT4)); |
Sergunb | 0:8918a71cdbe9 | 597 | TRACE_DEBUG(" EHT1 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT5)); |
Sergunb | 0:8918a71cdbe9 | 598 | TRACE_DEBUG(" EHT2 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT6)); |
Sergunb | 0:8918a71cdbe9 | 599 | TRACE_DEBUG(" EHT3 = %02" PRIX8 "\r\n", enc28j60ReadReg(interface, ENC28J60_REG_EHT7)); |
Sergunb | 0:8918a71cdbe9 | 600 | |
Sergunb | 0:8918a71cdbe9 | 601 | //Successful processing |
Sergunb | 0:8918a71cdbe9 | 602 | return NO_ERROR; |
Sergunb | 0:8918a71cdbe9 | 603 | } |
Sergunb | 0:8918a71cdbe9 | 604 | |
Sergunb | 0:8918a71cdbe9 | 605 | |
Sergunb | 0:8918a71cdbe9 | 606 | /** |
Sergunb | 0:8918a71cdbe9 | 607 | * @brief ENC28J60 controller reset |
Sergunb | 0:8918a71cdbe9 | 608 | * @param[in] interface Underlying network interface |
Sergunb | 0:8918a71cdbe9 | 609 | **/ |
Sergunb | 0:8918a71cdbe9 | 610 | |
Sergunb | 0:8918a71cdbe9 | 611 | void enc28j60SoftReset(NetInterface *interface) |
Sergunb | 0:8918a71cdbe9 | 612 | { |
Sergunb | 0:8918a71cdbe9 | 613 | //Pull the CS pin low |
Sergunb | 0:8918a71cdbe9 | 614 | interface->spiDriver->assertCs(); |
Sergunb | 0:8918a71cdbe9 | 615 | |
Sergunb | 0:8918a71cdbe9 | 616 | //Write opcode |
Sergunb | 0:8918a71cdbe9 | 617 | interface->spiDriver->transfer(ENC28J60_CMD_SRC); |
Sergunb | 0:8918a71cdbe9 | 618 | |
Sergunb | 0:8918a71cdbe9 | 619 | //Terminate the operation by raising the CS pin |
Sergunb | 0:8918a71cdbe9 | 620 | interface->spiDriver->deassertCs(); |
Sergunb | 0:8918a71cdbe9 | 621 | } |
Sergunb | 0:8918a71cdbe9 | 622 | |
Sergunb | 0:8918a71cdbe9 | 623 | |
Sergunb | 0:8918a71cdbe9 | 624 | /** |
Sergunb | 0:8918a71cdbe9 | 625 | * @brief Bank selection |
Sergunb | 0:8918a71cdbe9 | 626 | * @param[in] interface Underlying network interface |
Sergunb | 0:8918a71cdbe9 | 627 | * @param[in] address Register address |
Sergunb | 0:8918a71cdbe9 | 628 | **/ |
Sergunb | 0:8918a71cdbe9 | 629 | |
Sergunb | 0:8918a71cdbe9 | 630 | void enc28j60SelectBank(NetInterface *interface, uint16_t address) |
Sergunb | 0:8918a71cdbe9 | 631 | { |
Sergunb | 0:8918a71cdbe9 | 632 | uint16_t bank; |
Sergunb | 0:8918a71cdbe9 | 633 | Enc28j60Context *context; |
Sergunb | 0:8918a71cdbe9 | 634 | |
Sergunb | 0:8918a71cdbe9 | 635 | //Point to the driver context |
Sergunb | 0:8918a71cdbe9 | 636 | context = (Enc28j60Context *) interface->nicContext; |
Sergunb | 0:8918a71cdbe9 | 637 | |
Sergunb | 0:8918a71cdbe9 | 638 | //Get the bank number from the specified address |
Sergunb | 0:8918a71cdbe9 | 639 | bank = address & REG_BANK_MASK; |
Sergunb | 0:8918a71cdbe9 | 640 | |
Sergunb | 0:8918a71cdbe9 | 641 | //Rewrite the bank number only if a change is detected |
Sergunb | 0:8918a71cdbe9 | 642 | if(bank != context->currentBank) |
Sergunb | 0:8918a71cdbe9 | 643 | { |
Sergunb | 0:8918a71cdbe9 | 644 | //Select specified bank |
Sergunb | 0:8918a71cdbe9 | 645 | switch(bank) |
Sergunb | 0:8918a71cdbe9 | 646 | { |
Sergunb | 0:8918a71cdbe9 | 647 | case BANK_0: |
Sergunb | 0:8918a71cdbe9 | 648 | //Select bank 0 |
Sergunb | 0:8918a71cdbe9 | 649 | enc28j60ClearBit(interface, ENC28J60_REG_ECON1, ECON1_BSEL1 | ECON1_BSEL0); |
Sergunb | 0:8918a71cdbe9 | 650 | break; |
Sergunb | 0:8918a71cdbe9 | 651 | case BANK_1: |
Sergunb | 0:8918a71cdbe9 | 652 | //Select bank 1 |
Sergunb | 0:8918a71cdbe9 | 653 | enc28j60SetBit(interface, ENC28J60_REG_ECON1, ECON1_BSEL0); |
Sergunb | 0:8918a71cdbe9 | 654 | enc28j60ClearBit(interface, ENC28J60_REG_ECON1, ECON1_BSEL1); |
Sergunb | 0:8918a71cdbe9 | 655 | break; |
Sergunb | 0:8918a71cdbe9 | 656 | case BANK_2: |
Sergunb | 0:8918a71cdbe9 | 657 | //Select bank 2 |
Sergunb | 0:8918a71cdbe9 | 658 | enc28j60ClearBit(interface, ENC28J60_REG_ECON1, ECON1_BSEL0); |
Sergunb | 0:8918a71cdbe9 | 659 | enc28j60SetBit(interface, ENC28J60_REG_ECON1, ECON1_BSEL1); |
Sergunb | 0:8918a71cdbe9 | 660 | break; |
Sergunb | 0:8918a71cdbe9 | 661 | case BANK_3: |
Sergunb | 0:8918a71cdbe9 | 662 | //Select bank 3 |
Sergunb | 0:8918a71cdbe9 | 663 | enc28j60SetBit(interface, ENC28J60_REG_ECON1, ECON1_BSEL1 | ECON1_BSEL0); |
Sergunb | 0:8918a71cdbe9 | 664 | break; |
Sergunb | 0:8918a71cdbe9 | 665 | default: |
Sergunb | 0:8918a71cdbe9 | 666 | //Invalid bank |
Sergunb | 0:8918a71cdbe9 | 667 | break; |
Sergunb | 0:8918a71cdbe9 | 668 | } |
Sergunb | 0:8918a71cdbe9 | 669 | |
Sergunb | 0:8918a71cdbe9 | 670 | //Save bank number |
Sergunb | 0:8918a71cdbe9 | 671 | context->currentBank = bank; |
Sergunb | 0:8918a71cdbe9 | 672 | } |
Sergunb | 0:8918a71cdbe9 | 673 | } |
Sergunb | 0:8918a71cdbe9 | 674 | |
Sergunb | 0:8918a71cdbe9 | 675 | |
Sergunb | 0:8918a71cdbe9 | 676 | /** |
Sergunb | 0:8918a71cdbe9 | 677 | * @brief Write ENC28J60 register |
Sergunb | 0:8918a71cdbe9 | 678 | * @param[in] interface Underlying network interface |
Sergunb | 0:8918a71cdbe9 | 679 | * @param[in] address Register address |
Sergunb | 0:8918a71cdbe9 | 680 | * @param[in] data Register value |
Sergunb | 0:8918a71cdbe9 | 681 | **/ |
Sergunb | 0:8918a71cdbe9 | 682 | |
Sergunb | 0:8918a71cdbe9 | 683 | void enc28j60WriteReg(NetInterface *interface, uint16_t address, uint8_t data) |
Sergunb | 0:8918a71cdbe9 | 684 | { |
Sergunb | 0:8918a71cdbe9 | 685 | //Make sure the corresponding bank is selected |
Sergunb | 0:8918a71cdbe9 | 686 | enc28j60SelectBank(interface, address); |
Sergunb | 0:8918a71cdbe9 | 687 | |
Sergunb | 0:8918a71cdbe9 | 688 | //Pull the CS pin low |
Sergunb | 0:8918a71cdbe9 | 689 | interface->spiDriver->assertCs(); |
Sergunb | 0:8918a71cdbe9 | 690 | |
Sergunb | 0:8918a71cdbe9 | 691 | //Write opcode and register address |
Sergunb | 0:8918a71cdbe9 | 692 | interface->spiDriver->transfer(ENC28J60_CMD_WCR | (address & REG_ADDR_MASK)); |
Sergunb | 0:8918a71cdbe9 | 693 | //Write register value |
Sergunb | 0:8918a71cdbe9 | 694 | interface->spiDriver->transfer(data); |
Sergunb | 0:8918a71cdbe9 | 695 | |
Sergunb | 0:8918a71cdbe9 | 696 | //Terminate the operation by raising the CS pin |
Sergunb | 0:8918a71cdbe9 | 697 | interface->spiDriver->deassertCs(); |
Sergunb | 0:8918a71cdbe9 | 698 | } |
Sergunb | 0:8918a71cdbe9 | 699 | |
Sergunb | 0:8918a71cdbe9 | 700 | |
Sergunb | 0:8918a71cdbe9 | 701 | /** |
Sergunb | 0:8918a71cdbe9 | 702 | * @brief Read ENC28J60 register |
Sergunb | 0:8918a71cdbe9 | 703 | * @param[in] interface Underlying network interface |
Sergunb | 0:8918a71cdbe9 | 704 | * @param[in] address Register address |
Sergunb | 0:8918a71cdbe9 | 705 | * @return Register value |
Sergunb | 0:8918a71cdbe9 | 706 | **/ |
Sergunb | 0:8918a71cdbe9 | 707 | |
Sergunb | 0:8918a71cdbe9 | 708 | uint8_t enc28j60ReadReg(NetInterface *interface, uint16_t address) |
Sergunb | 0:8918a71cdbe9 | 709 | { |
Sergunb | 0:8918a71cdbe9 | 710 | uint16_t data; |
Sergunb | 0:8918a71cdbe9 | 711 | |
Sergunb | 0:8918a71cdbe9 | 712 | //Make sure the corresponding bank is selected |
Sergunb | 0:8918a71cdbe9 | 713 | enc28j60SelectBank(interface, address); |
Sergunb | 0:8918a71cdbe9 | 714 | |
Sergunb | 0:8918a71cdbe9 | 715 | //Pull the CS pin low |
Sergunb | 0:8918a71cdbe9 | 716 | interface->spiDriver->assertCs(); |
Sergunb | 0:8918a71cdbe9 | 717 | |
Sergunb | 0:8918a71cdbe9 | 718 | //Write opcode and register address |
Sergunb | 0:8918a71cdbe9 | 719 | interface->spiDriver->transfer(ENC28J60_CMD_RCR | (address & REG_ADDR_MASK)); |
Sergunb | 0:8918a71cdbe9 | 720 | |
Sergunb | 0:8918a71cdbe9 | 721 | //When reading MAC or MII registers, a dummy byte is first shifted out |
Sergunb | 0:8918a71cdbe9 | 722 | if((address & REG_TYPE_MASK) != ETH_REG_TYPE) |
Sergunb | 0:8918a71cdbe9 | 723 | interface->spiDriver->transfer(0x00); |
Sergunb | 0:8918a71cdbe9 | 724 | |
Sergunb | 0:8918a71cdbe9 | 725 | //Read register contents |
Sergunb | 0:8918a71cdbe9 | 726 | data = interface->spiDriver->transfer(0x00); |
Sergunb | 0:8918a71cdbe9 | 727 | |
Sergunb | 0:8918a71cdbe9 | 728 | //Terminate the operation by raising the CS pin |
Sergunb | 0:8918a71cdbe9 | 729 | interface->spiDriver->deassertCs(); |
Sergunb | 0:8918a71cdbe9 | 730 | |
Sergunb | 0:8918a71cdbe9 | 731 | //Return register contents |
Sergunb | 0:8918a71cdbe9 | 732 | return data; |
Sergunb | 0:8918a71cdbe9 | 733 | } |
Sergunb | 0:8918a71cdbe9 | 734 | |
Sergunb | 0:8918a71cdbe9 | 735 | |
Sergunb | 0:8918a71cdbe9 | 736 | /** |
Sergunb | 0:8918a71cdbe9 | 737 | * @brief Write PHY register |
Sergunb | 0:8918a71cdbe9 | 738 | * @param[in] interface Underlying network interface |
Sergunb | 0:8918a71cdbe9 | 739 | * @param[in] address PHY register address |
Sergunb | 0:8918a71cdbe9 | 740 | * @param[in] data Register value |
Sergunb | 0:8918a71cdbe9 | 741 | **/ |
Sergunb | 0:8918a71cdbe9 | 742 | |
Sergunb | 0:8918a71cdbe9 | 743 | void enc28j60WritePhyReg(NetInterface *interface, uint16_t address, uint16_t data) |
Sergunb | 0:8918a71cdbe9 | 744 | { |
Sergunb | 0:8918a71cdbe9 | 745 | //Write register address |
Sergunb | 0:8918a71cdbe9 | 746 | enc28j60WriteReg(interface, ENC28J60_REG_MIREGADR, address & REG_ADDR_MASK); |
Sergunb | 0:8918a71cdbe9 | 747 | |
Sergunb | 0:8918a71cdbe9 | 748 | //Write the lower 8 bits |
Sergunb | 0:8918a71cdbe9 | 749 | enc28j60WriteReg(interface, ENC28J60_REG_MIWRL, LSB(data)); |
Sergunb | 0:8918a71cdbe9 | 750 | //Write the upper 8 bits |
Sergunb | 0:8918a71cdbe9 | 751 | enc28j60WriteReg(interface, ENC28J60_REG_MIWRH, MSB(data)); |
Sergunb | 0:8918a71cdbe9 | 752 | |
Sergunb | 0:8918a71cdbe9 | 753 | //Wait until the PHY register has been written |
Sergunb | 0:8918a71cdbe9 | 754 | while(enc28j60ReadReg(interface, ENC28J60_REG_MISTAT) & MISTAT_BUSY); |
Sergunb | 0:8918a71cdbe9 | 755 | } |
Sergunb | 0:8918a71cdbe9 | 756 | |
Sergunb | 0:8918a71cdbe9 | 757 | |
Sergunb | 0:8918a71cdbe9 | 758 | /** |
Sergunb | 0:8918a71cdbe9 | 759 | * @brief Read PHY register |
Sergunb | 0:8918a71cdbe9 | 760 | * @param[in] interface Underlying network interface |
Sergunb | 0:8918a71cdbe9 | 761 | * @param[in] address PHY register address |
Sergunb | 0:8918a71cdbe9 | 762 | * @return Register value |
Sergunb | 0:8918a71cdbe9 | 763 | **/ |
Sergunb | 0:8918a71cdbe9 | 764 | |
Sergunb | 0:8918a71cdbe9 | 765 | uint16_t enc28j60ReadPhyReg(NetInterface *interface, uint16_t address) |
Sergunb | 0:8918a71cdbe9 | 766 | { |
Sergunb | 0:8918a71cdbe9 | 767 | uint16_t data; |
Sergunb | 0:8918a71cdbe9 | 768 | |
Sergunb | 0:8918a71cdbe9 | 769 | //Write register address |
Sergunb | 0:8918a71cdbe9 | 770 | enc28j60WriteReg(interface, ENC28J60_REG_MIREGADR, address & REG_ADDR_MASK); |
Sergunb | 0:8918a71cdbe9 | 771 | |
Sergunb | 0:8918a71cdbe9 | 772 | //Start read operation |
Sergunb | 0:8918a71cdbe9 | 773 | enc28j60WriteReg(interface, ENC28J60_REG_MICMD, MICMD_MIIRD); |
Sergunb | 0:8918a71cdbe9 | 774 | //Wait for the read operation to complete |
Sergunb | 0:8918a71cdbe9 | 775 | while(enc28j60ReadReg(interface, ENC28J60_REG_MISTAT) & MISTAT_BUSY); |
Sergunb | 0:8918a71cdbe9 | 776 | //Clear command register |
Sergunb | 0:8918a71cdbe9 | 777 | enc28j60WriteReg(interface, ENC28J60_REG_MICMD, 0); |
Sergunb | 0:8918a71cdbe9 | 778 | |
Sergunb | 0:8918a71cdbe9 | 779 | //Read the lower 8 bits |
Sergunb | 0:8918a71cdbe9 | 780 | data = enc28j60ReadReg(interface, ENC28J60_REG_MIRDL); |
Sergunb | 0:8918a71cdbe9 | 781 | //Read the upper 8 bits |
Sergunb | 0:8918a71cdbe9 | 782 | data |= enc28j60ReadReg(interface, ENC28J60_REG_MIRDH) << 8; |
Sergunb | 0:8918a71cdbe9 | 783 | |
Sergunb | 0:8918a71cdbe9 | 784 | //Return register contents |
Sergunb | 0:8918a71cdbe9 | 785 | return data; |
Sergunb | 0:8918a71cdbe9 | 786 | } |
Sergunb | 0:8918a71cdbe9 | 787 | |
Sergunb | 0:8918a71cdbe9 | 788 | |
Sergunb | 0:8918a71cdbe9 | 789 | /** |
Sergunb | 0:8918a71cdbe9 | 790 | * @brief Write SRAM buffer |
Sergunb | 0:8918a71cdbe9 | 791 | * @param[in] interface Underlying network interface |
Sergunb | 0:8918a71cdbe9 | 792 | * @param[in] buffer Multi-part buffer containing the data to be written |
Sergunb | 0:8918a71cdbe9 | 793 | * @param[in] offset Offset to the first data byte |
Sergunb | 0:8918a71cdbe9 | 794 | **/ |
Sergunb | 0:8918a71cdbe9 | 795 | |
Sergunb | 0:8918a71cdbe9 | 796 | void enc28j60WriteBuffer(NetInterface *interface, |
Sergunb | 0:8918a71cdbe9 | 797 | const NetBuffer *buffer, size_t offset) |
Sergunb | 0:8918a71cdbe9 | 798 | { |
Sergunb | 0:8918a71cdbe9 | 799 | uint_t i; |
Sergunb | 0:8918a71cdbe9 | 800 | size_t j; |
Sergunb | 0:8918a71cdbe9 | 801 | size_t n; |
Sergunb | 0:8918a71cdbe9 | 802 | uint8_t *p; |
Sergunb | 0:8918a71cdbe9 | 803 | |
Sergunb | 0:8918a71cdbe9 | 804 | //Pull the CS pin low |
Sergunb | 0:8918a71cdbe9 | 805 | interface->spiDriver->assertCs(); |
Sergunb | 0:8918a71cdbe9 | 806 | |
Sergunb | 0:8918a71cdbe9 | 807 | //Write opcode |
Sergunb | 0:8918a71cdbe9 | 808 | interface->spiDriver->transfer(ENC28J60_CMD_WBM); |
Sergunb | 0:8918a71cdbe9 | 809 | //Write per-packet control byte |
Sergunb | 0:8918a71cdbe9 | 810 | interface->spiDriver->transfer(0x00); |
Sergunb | 0:8918a71cdbe9 | 811 | |
Sergunb | 0:8918a71cdbe9 | 812 | //Loop through data chunks |
Sergunb | 0:8918a71cdbe9 | 813 | for(i = 0; i < buffer->chunkCount; i++) |
Sergunb | 0:8918a71cdbe9 | 814 | { |
Sergunb | 0:8918a71cdbe9 | 815 | //Is there any data to copy from the current chunk? |
Sergunb | 0:8918a71cdbe9 | 816 | if(offset < buffer->chunk[i].length) |
Sergunb | 0:8918a71cdbe9 | 817 | { |
Sergunb | 0:8918a71cdbe9 | 818 | //Point to the first byte to be read |
Sergunb | 0:8918a71cdbe9 | 819 | p = (uint8_t *) buffer->chunk[i].address + offset; |
Sergunb | 0:8918a71cdbe9 | 820 | //Compute the number of bytes to copy at a time |
Sergunb | 0:8918a71cdbe9 | 821 | n = buffer->chunk[i].length - offset; |
Sergunb | 0:8918a71cdbe9 | 822 | |
Sergunb | 0:8918a71cdbe9 | 823 | //Copy data to SRAM buffer |
Sergunb | 0:8918a71cdbe9 | 824 | for(j = 0; j < n; j++) |
Sergunb | 0:8918a71cdbe9 | 825 | interface->spiDriver->transfer(p[j]); |
Sergunb | 0:8918a71cdbe9 | 826 | |
Sergunb | 0:8918a71cdbe9 | 827 | //Process the next block from the start |
Sergunb | 0:8918a71cdbe9 | 828 | offset = 0; |
Sergunb | 0:8918a71cdbe9 | 829 | } |
Sergunb | 0:8918a71cdbe9 | 830 | else |
Sergunb | 0:8918a71cdbe9 | 831 | { |
Sergunb | 0:8918a71cdbe9 | 832 | //Skip the current chunk |
Sergunb | 0:8918a71cdbe9 | 833 | offset -= buffer->chunk[i].length; |
Sergunb | 0:8918a71cdbe9 | 834 | } |
Sergunb | 0:8918a71cdbe9 | 835 | } |
Sergunb | 0:8918a71cdbe9 | 836 | |
Sergunb | 0:8918a71cdbe9 | 837 | //Terminate the operation by raising the CS pin |
Sergunb | 0:8918a71cdbe9 | 838 | interface->spiDriver->deassertCs(); |
Sergunb | 0:8918a71cdbe9 | 839 | } |
Sergunb | 0:8918a71cdbe9 | 840 | |
Sergunb | 0:8918a71cdbe9 | 841 | |
Sergunb | 0:8918a71cdbe9 | 842 | /** |
Sergunb | 0:8918a71cdbe9 | 843 | * @brief Read SRAM buffer |
Sergunb | 0:8918a71cdbe9 | 844 | * @param[in] interface Underlying network interface |
Sergunb | 0:8918a71cdbe9 | 845 | * @param[in] data Buffer where to store the incoming data |
Sergunb | 0:8918a71cdbe9 | 846 | * @param[in] length Number of data to read |
Sergunb | 0:8918a71cdbe9 | 847 | **/ |
Sergunb | 0:8918a71cdbe9 | 848 | |
Sergunb | 0:8918a71cdbe9 | 849 | void enc28j60ReadBuffer(NetInterface *interface, |
Sergunb | 0:8918a71cdbe9 | 850 | uint8_t *data, size_t length) |
Sergunb | 0:8918a71cdbe9 | 851 | { |
Sergunb | 0:8918a71cdbe9 | 852 | size_t i; |
Sergunb | 0:8918a71cdbe9 | 853 | |
Sergunb | 0:8918a71cdbe9 | 854 | //Pull the CS pin low |
Sergunb | 0:8918a71cdbe9 | 855 | interface->spiDriver->assertCs(); |
Sergunb | 0:8918a71cdbe9 | 856 | |
Sergunb | 0:8918a71cdbe9 | 857 | //Write opcode |
Sergunb | 0:8918a71cdbe9 | 858 | interface->spiDriver->transfer(ENC28J60_CMD_RBM); |
Sergunb | 0:8918a71cdbe9 | 859 | |
Sergunb | 0:8918a71cdbe9 | 860 | //Copy data from SRAM buffer |
Sergunb | 0:8918a71cdbe9 | 861 | for(i = 0; i < length; i++) |
Sergunb | 0:8918a71cdbe9 | 862 | data[i] = interface->spiDriver->transfer(0x00); |
Sergunb | 0:8918a71cdbe9 | 863 | |
Sergunb | 0:8918a71cdbe9 | 864 | //Terminate the operation by raising the CS pin |
Sergunb | 0:8918a71cdbe9 | 865 | interface->spiDriver->deassertCs(); |
Sergunb | 0:8918a71cdbe9 | 866 | } |
Sergunb | 0:8918a71cdbe9 | 867 | |
Sergunb | 0:8918a71cdbe9 | 868 | |
Sergunb | 0:8918a71cdbe9 | 869 | /** |
Sergunb | 0:8918a71cdbe9 | 870 | * @brief Set bit field |
Sergunb | 0:8918a71cdbe9 | 871 | * @param[in] interface Underlying network interface |
Sergunb | 0:8918a71cdbe9 | 872 | * @param[in] address Register address |
Sergunb | 0:8918a71cdbe9 | 873 | * @param[in] mask Bits to set in the target register |
Sergunb | 0:8918a71cdbe9 | 874 | **/ |
Sergunb | 0:8918a71cdbe9 | 875 | |
Sergunb | 0:8918a71cdbe9 | 876 | void enc28j60SetBit(NetInterface *interface, uint16_t address, uint16_t mask) |
Sergunb | 0:8918a71cdbe9 | 877 | { |
Sergunb | 0:8918a71cdbe9 | 878 | //Pull the CS pin low |
Sergunb | 0:8918a71cdbe9 | 879 | interface->spiDriver->assertCs(); |
Sergunb | 0:8918a71cdbe9 | 880 | |
Sergunb | 0:8918a71cdbe9 | 881 | //Write opcode and register address |
Sergunb | 0:8918a71cdbe9 | 882 | interface->spiDriver->transfer(ENC28J60_CMD_BFS | (address & REG_ADDR_MASK)); |
Sergunb | 0:8918a71cdbe9 | 883 | //Write bit mask |
Sergunb | 0:8918a71cdbe9 | 884 | interface->spiDriver->transfer(mask); |
Sergunb | 0:8918a71cdbe9 | 885 | |
Sergunb | 0:8918a71cdbe9 | 886 | //Terminate the operation by raising the CS pin |
Sergunb | 0:8918a71cdbe9 | 887 | interface->spiDriver->deassertCs(); |
Sergunb | 0:8918a71cdbe9 | 888 | } |
Sergunb | 0:8918a71cdbe9 | 889 | |
Sergunb | 0:8918a71cdbe9 | 890 | |
Sergunb | 0:8918a71cdbe9 | 891 | /** |
Sergunb | 0:8918a71cdbe9 | 892 | * @brief Clear bit field |
Sergunb | 0:8918a71cdbe9 | 893 | * @param[in] interface Underlying network interface |
Sergunb | 0:8918a71cdbe9 | 894 | * @param[in] address Register address |
Sergunb | 0:8918a71cdbe9 | 895 | * @param[in] mask Bits to clear in the target register |
Sergunb | 0:8918a71cdbe9 | 896 | **/ |
Sergunb | 0:8918a71cdbe9 | 897 | |
Sergunb | 0:8918a71cdbe9 | 898 | void enc28j60ClearBit(NetInterface *interface, uint16_t address, uint16_t mask) |
Sergunb | 0:8918a71cdbe9 | 899 | { |
Sergunb | 0:8918a71cdbe9 | 900 | //Pull the CS pin low |
Sergunb | 0:8918a71cdbe9 | 901 | interface->spiDriver->assertCs(); |
Sergunb | 0:8918a71cdbe9 | 902 | |
Sergunb | 0:8918a71cdbe9 | 903 | //Write opcode and register address |
Sergunb | 0:8918a71cdbe9 | 904 | interface->spiDriver->transfer(ENC28J60_CMD_BFC | (address & REG_ADDR_MASK)); |
Sergunb | 0:8918a71cdbe9 | 905 | //Write bit mask |
Sergunb | 0:8918a71cdbe9 | 906 | interface->spiDriver->transfer(mask); |
Sergunb | 0:8918a71cdbe9 | 907 | |
Sergunb | 0:8918a71cdbe9 | 908 | //Terminate the operation by raising the CS pin |
Sergunb | 0:8918a71cdbe9 | 909 | interface->spiDriver->deassertCs(); |
Sergunb | 0:8918a71cdbe9 | 910 | } |
Sergunb | 0:8918a71cdbe9 | 911 | |
Sergunb | 0:8918a71cdbe9 | 912 | |
Sergunb | 0:8918a71cdbe9 | 913 | /** |
Sergunb | 0:8918a71cdbe9 | 914 | * @brief CRC calculation using the polynomial 0x4C11DB7 |
Sergunb | 0:8918a71cdbe9 | 915 | * @param[in] data Pointer to the data over which to calculate the CRC |
Sergunb | 0:8918a71cdbe9 | 916 | * @param[in] length Number of bytes to process |
Sergunb | 0:8918a71cdbe9 | 917 | * @return Resulting CRC value |
Sergunb | 0:8918a71cdbe9 | 918 | **/ |
Sergunb | 0:8918a71cdbe9 | 919 | |
Sergunb | 0:8918a71cdbe9 | 920 | uint32_t enc28j60CalcCrc(const void *data, size_t length) |
Sergunb | 0:8918a71cdbe9 | 921 | { |
Sergunb | 0:8918a71cdbe9 | 922 | uint_t i; |
Sergunb | 0:8918a71cdbe9 | 923 | uint_t j; |
Sergunb | 0:8918a71cdbe9 | 924 | |
Sergunb | 0:8918a71cdbe9 | 925 | //Point to the data over which to calculate the CRC |
Sergunb | 0:8918a71cdbe9 | 926 | const uint8_t *p = (uint8_t *) data; |
Sergunb | 0:8918a71cdbe9 | 927 | //CRC preset value |
Sergunb | 0:8918a71cdbe9 | 928 | uint32_t crc = 0xFFFFFFFF; |
Sergunb | 0:8918a71cdbe9 | 929 | |
Sergunb | 0:8918a71cdbe9 | 930 | //Loop through data |
Sergunb | 0:8918a71cdbe9 | 931 | for(i = 0; i < length; i++) |
Sergunb | 0:8918a71cdbe9 | 932 | { |
Sergunb | 0:8918a71cdbe9 | 933 | //The message is processed bit by bit |
Sergunb | 0:8918a71cdbe9 | 934 | for(j = 0; j < 8; j++) |
Sergunb | 0:8918a71cdbe9 | 935 | { |
Sergunb | 0:8918a71cdbe9 | 936 | //Update CRC value |
Sergunb | 0:8918a71cdbe9 | 937 | if(((crc >> 31) ^ (p[i] >> j)) & 0x01) |
Sergunb | 0:8918a71cdbe9 | 938 | crc = (crc << 1) ^ 0x04C11DB7; |
Sergunb | 0:8918a71cdbe9 | 939 | else |
Sergunb | 0:8918a71cdbe9 | 940 | crc = crc << 1; |
Sergunb | 0:8918a71cdbe9 | 941 | } |
Sergunb | 0:8918a71cdbe9 | 942 | } |
Sergunb | 0:8918a71cdbe9 | 943 | |
Sergunb | 0:8918a71cdbe9 | 944 | //Return CRC value |
Sergunb | 0:8918a71cdbe9 | 945 | return crc; |
Sergunb | 0:8918a71cdbe9 | 946 | } |
Sergunb | 0:8918a71cdbe9 | 947 | |
Sergunb | 0:8918a71cdbe9 | 948 | |
Sergunb | 0:8918a71cdbe9 | 949 | /** |
Sergunb | 0:8918a71cdbe9 | 950 | * @brief Dump registers for debugging purpose |
Sergunb | 0:8918a71cdbe9 | 951 | * @param[in] interface Underlying network interface |
Sergunb | 0:8918a71cdbe9 | 952 | **/ |
Sergunb | 0:8918a71cdbe9 | 953 | |
Sergunb | 0:8918a71cdbe9 | 954 | void enc28j60DumpReg(NetInterface *interface) |
Sergunb | 0:8918a71cdbe9 | 955 | { |
Sergunb | 0:8918a71cdbe9 | 956 | #if (TRACE_LEVEL >= TRACE_LEVEL_DEBUG) |
Sergunb | 0:8918a71cdbe9 | 957 | uint8_t i; |
Sergunb | 0:8918a71cdbe9 | 958 | uint8_t bank; |
Sergunb | 0:8918a71cdbe9 | 959 | uint16_t address; |
Sergunb | 0:8918a71cdbe9 | 960 | |
Sergunb | 0:8918a71cdbe9 | 961 | //Display header |
Sergunb | 0:8918a71cdbe9 | 962 | TRACE_DEBUG(" Bank 0 Bank 1 Bank 2 Bank 3\r\n"); |
Sergunb | 0:8918a71cdbe9 | 963 | |
Sergunb | 0:8918a71cdbe9 | 964 | //Loop through register addresses |
Sergunb | 0:8918a71cdbe9 | 965 | for(i = 0; i < 32; i++) |
Sergunb | 0:8918a71cdbe9 | 966 | { |
Sergunb | 0:8918a71cdbe9 | 967 | //Display register address |
Sergunb | 0:8918a71cdbe9 | 968 | TRACE_DEBUG("%02" PRIX8 ": ", i); |
Sergunb | 0:8918a71cdbe9 | 969 | |
Sergunb | 0:8918a71cdbe9 | 970 | //Loop through bank numbers |
Sergunb | 0:8918a71cdbe9 | 971 | for(bank = 0; bank < 4; bank++) |
Sergunb | 0:8918a71cdbe9 | 972 | { |
Sergunb | 0:8918a71cdbe9 | 973 | //Format register address |
Sergunb | 0:8918a71cdbe9 | 974 | address = (bank << 8) | i; |
Sergunb | 0:8918a71cdbe9 | 975 | |
Sergunb | 0:8918a71cdbe9 | 976 | //MAC and MII registers require a specific read sequence |
Sergunb | 0:8918a71cdbe9 | 977 | if(address >= 0x200 && address <= 0x219) |
Sergunb | 0:8918a71cdbe9 | 978 | address |= MAC_REG_TYPE; |
Sergunb | 0:8918a71cdbe9 | 979 | else if(address >= 0x300 && address <= 0x305) |
Sergunb | 0:8918a71cdbe9 | 980 | address |= MAC_REG_TYPE; |
Sergunb | 0:8918a71cdbe9 | 981 | else if(address == 0x30A) |
Sergunb | 0:8918a71cdbe9 | 982 | address |= MAC_REG_TYPE; |
Sergunb | 0:8918a71cdbe9 | 983 | |
Sergunb | 0:8918a71cdbe9 | 984 | //Display register contents |
Sergunb | 0:8918a71cdbe9 | 985 | TRACE_DEBUG("0x%02" PRIX8 " ", enc28j60ReadReg(interface, address)); |
Sergunb | 0:8918a71cdbe9 | 986 | } |
Sergunb | 0:8918a71cdbe9 | 987 | |
Sergunb | 0:8918a71cdbe9 | 988 | //Jump to the following line |
Sergunb | 0:8918a71cdbe9 | 989 | TRACE_DEBUG("\r\n"); |
Sergunb | 0:8918a71cdbe9 | 990 | } |
Sergunb | 0:8918a71cdbe9 | 991 | |
Sergunb | 0:8918a71cdbe9 | 992 | //Terminate with a line feed |
Sergunb | 0:8918a71cdbe9 | 993 | TRACE_DEBUG("\r\n"); |
Sergunb | 0:8918a71cdbe9 | 994 | #endif |
Sergunb | 0:8918a71cdbe9 | 995 | } |
Sergunb | 0:8918a71cdbe9 | 996 | |
Sergunb | 0:8918a71cdbe9 | 997 | |
Sergunb | 0:8918a71cdbe9 | 998 | /** |
Sergunb | 0:8918a71cdbe9 | 999 | * @brief Dump PHY registers for debugging purpose |
Sergunb | 0:8918a71cdbe9 | 1000 | * @param[in] interface Underlying network interface |
Sergunb | 0:8918a71cdbe9 | 1001 | **/ |
Sergunb | 0:8918a71cdbe9 | 1002 | |
Sergunb | 0:8918a71cdbe9 | 1003 | void enc28j60DumpPhyReg(NetInterface *interface) |
Sergunb | 0:8918a71cdbe9 | 1004 | { |
Sergunb | 0:8918a71cdbe9 | 1005 | #if (TRACE_LEVEL >= TRACE_LEVEL_DEBUG) |
Sergunb | 0:8918a71cdbe9 | 1006 | uint8_t i; |
Sergunb | 0:8918a71cdbe9 | 1007 | |
Sergunb | 0:8918a71cdbe9 | 1008 | //Loop through PHY registers |
Sergunb | 0:8918a71cdbe9 | 1009 | for(i = 0; i < 32; i++) |
Sergunb | 0:8918a71cdbe9 | 1010 | { |
Sergunb | 0:8918a71cdbe9 | 1011 | //Display current PHY register |
Sergunb | 0:8918a71cdbe9 | 1012 | TRACE_DEBUG("%02" PRIX8 ": 0x%04" PRIX16 "\r\n", i, enc28j60ReadPhyReg(interface, i)); |
Sergunb | 0:8918a71cdbe9 | 1013 | } |
Sergunb | 0:8918a71cdbe9 | 1014 | |
Sergunb | 0:8918a71cdbe9 | 1015 | //Terminate with a line feed |
Sergunb | 0:8918a71cdbe9 | 1016 | TRACE_DEBUG("\r\n"); |
Sergunb | 0:8918a71cdbe9 | 1017 | #endif |
Sergunb | 0:8918a71cdbe9 | 1018 | } |
Sergunb | 0:8918a71cdbe9 | 1019 |