mbed OS5

Fork of UIPEthernet by Zoltan Hudak

Committer:
hudakz
Date:
Thu Nov 20 21:26:54 2014 +0000
Revision:
1:01c2344f98a3
Parent:
uitility/Enc28J60Network.cpp@0:5350a66d5279
rev. 01

Who changed what in which revision?

UserRevisionLine numberNew contents of line
hudakz 0:5350a66d5279 1 /*
hudakz 0:5350a66d5279 2 Enc28J60Network.h
hudakz 0:5350a66d5279 3 UIPEthernet network driver for Microchip ENC28J60 Ethernet Interface.
hudakz 0:5350a66d5279 4
hudakz 0:5350a66d5279 5 Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de>
hudakz 0:5350a66d5279 6 All rights reserved.
hudakz 0:5350a66d5279 7
hudakz 0:5350a66d5279 8 based on enc28j60.c file from the AVRlib library by Pascal Stang.
hudakz 0:5350a66d5279 9 For AVRlib See http://www.procyonengineering.com/
hudakz 0:5350a66d5279 10
hudakz 0:5350a66d5279 11 Modified (ported to mbed) by Zoltan Hudak <hudakz@inbox.com>
hudakz 0:5350a66d5279 12
hudakz 0:5350a66d5279 13 This program is free software: you can redistribute it and/or modify
hudakz 0:5350a66d5279 14 it under the terms of the GNU General Public License as published by
hudakz 0:5350a66d5279 15 the Free Software Foundation, either version 3 of the License, or
hudakz 0:5350a66d5279 16 (at your option) any later version.
hudakz 0:5350a66d5279 17
hudakz 0:5350a66d5279 18 This program is distributed in the hope that it will be useful,
hudakz 0:5350a66d5279 19 but WITHOUT ANY WARRANTY; without even the implied warranty of
hudakz 0:5350a66d5279 20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
hudakz 0:5350a66d5279 21 GNU General Public License for more details.
hudakz 0:5350a66d5279 22
hudakz 0:5350a66d5279 23 You should have received a copy of the GNU General Public License
hudakz 0:5350a66d5279 24 along with this program. If not, see <http://www.gnu.org/licenses/>.
hudakz 0:5350a66d5279 25 */
hudakz 0:5350a66d5279 26 #include "Enc28J60Network.h"
hudakz 0:5350a66d5279 27 #include "mbed.h"
hudakz 0:5350a66d5279 28
hudakz 0:5350a66d5279 29 extern "C"
hudakz 0:5350a66d5279 30 {
hudakz 0:5350a66d5279 31 #include "enc28j60.h"
hudakz 0:5350a66d5279 32 #include "uip.h"
hudakz 0:5350a66d5279 33 }
hudakz 0:5350a66d5279 34 #define DMARUNNING 1
hudakz 0:5350a66d5279 35 #define DMANEWPACKET 2
hudakz 0:5350a66d5279 36
hudakz 0:5350a66d5279 37 #define waitspi() while(!(SPSR & (1 << SPIF)))
hudakz 0:5350a66d5279 38 Enc28J60Network::Enc28J60Network(PinName mosi, PinName miso, PinName sclk, PinName cs) :
hudakz 0:5350a66d5279 39 MemoryPool(TXSTART_INIT + 1, TXSTOP_INIT - TXSTART_INIT),
hudakz 0:5350a66d5279 40
hudakz 0:5350a66d5279 41 // 1 byte in between RX_STOP_INIT and pool to allow prepending of controlbyte
hudakz 0:5350a66d5279 42 bank(0xff),
hudakz 0:5350a66d5279 43 _spi(mosi, miso, sclk),
hudakz 0:5350a66d5279 44 _cs(cs) { }
hudakz 0:5350a66d5279 45
hudakz 0:5350a66d5279 46 /**
hudakz 0:5350a66d5279 47 * @brief
hudakz 0:5350a66d5279 48 * @note
hudakz 0:5350a66d5279 49 * @param
hudakz 0:5350a66d5279 50 * @retval
hudakz 0:5350a66d5279 51 */
hudakz 0:5350a66d5279 52 void Enc28J60Network::init(uint8_t* macaddr) {
hudakz 0:5350a66d5279 53
hudakz 0:5350a66d5279 54 // initialize SPI interface
hudakz 0:5350a66d5279 55
hudakz 0:5350a66d5279 56 _spi.format(8, 0); // 8bit, mode 0
hudakz 0:5350a66d5279 57 _spi.frequency(7000000); // 7MHz
hudakz 0:5350a66d5279 58 wait(1); // 1 second for stable state
hudakz 0:5350a66d5279 59
hudakz 0:5350a66d5279 60 // initialize I/O
hudakz 0:5350a66d5279 61 _cs = 1; // ss=0
hudakz 0:5350a66d5279 62
hudakz 0:5350a66d5279 63 // initialize SPI interface
hudakz 0:5350a66d5279 64 // master mode and Fosc/2 clock:
hudakz 0:5350a66d5279 65 //SPCR = (1<<SPE)|(1<<MSTR);
hudakz 0:5350a66d5279 66 //SPSR |= (1<<SPI2X);
hudakz 0:5350a66d5279 67 // perform system reset
hudakz 0:5350a66d5279 68 writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
hudakz 0:5350a66d5279 69 wait(0.020); // 20ms
hudakz 0:5350a66d5279 70
hudakz 0:5350a66d5279 71 // check CLKRDY bit to see if reset is complete
hudakz 0:5350a66d5279 72 // The CLKRDY does not work. See Rev. B4 Silicon Errata point. Just wait.
hudakz 0:5350a66d5279 73 //while(!(readReg(ESTAT) & ESTAT_CLKRDY));
hudakz 0:5350a66d5279 74 // do bank 0 stuff
hudakz 0:5350a66d5279 75 // initialize receive buffer
hudakz 0:5350a66d5279 76 // 16-bit transfers, must write low byte first
hudakz 0:5350a66d5279 77 // set receive buffer start address
hudakz 0:5350a66d5279 78 nextPacketPtr = RXSTART_INIT;
hudakz 0:5350a66d5279 79
hudakz 0:5350a66d5279 80 // Rx start
hudakz 0:5350a66d5279 81 writeRegPair(ERXSTL, RXSTART_INIT);
hudakz 0:5350a66d5279 82
hudakz 0:5350a66d5279 83 // set receive pointer address
hudakz 0:5350a66d5279 84 writeRegPair(ERXRDPTL, RXSTART_INIT);
hudakz 0:5350a66d5279 85
hudakz 0:5350a66d5279 86 // RX end
hudakz 0:5350a66d5279 87 writeRegPair(ERXNDL, RXSTOP_INIT);
hudakz 0:5350a66d5279 88
hudakz 0:5350a66d5279 89 // TX start
hudakz 0:5350a66d5279 90 //writeRegPair(ETXSTL, TXSTART_INIT);
hudakz 0:5350a66d5279 91 // TX end
hudakz 0:5350a66d5279 92 //writeRegPair(ETXNDL, TXSTOP_INIT);
hudakz 0:5350a66d5279 93 // do bank 1 stuff, packet filter:
hudakz 0:5350a66d5279 94 // For broadcast packets we allow only ARP packtets
hudakz 0:5350a66d5279 95 // All other packets should be unicast only for our mac (MAADR)
hudakz 0:5350a66d5279 96 //
hudakz 0:5350a66d5279 97 // The pattern to match on is therefore
hudakz 0:5350a66d5279 98 // Type ETH.DST
hudakz 0:5350a66d5279 99 // ARP BROADCAST
hudakz 0:5350a66d5279 100 // 06 08 -- ff ff ff ff ff ff -> ip checksum for theses bytes=f7f9
hudakz 0:5350a66d5279 101 // in binary these poitions are:11 0000 0011 1111
hudakz 0:5350a66d5279 102 // This is hex 303F->EPMM0=0x3f,EPMM1=0x30
hudakz 0:5350a66d5279 103 //TODO define specific pattern to receive dhcp-broadcast packages instead of setting ERFCON_BCEN!
hudakz 0:5350a66d5279 104 writeReg(ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_PMEN | ERXFCON_BCEN);
hudakz 0:5350a66d5279 105 writeRegPair(EPMM0, 0x303f);
hudakz 0:5350a66d5279 106 writeRegPair(EPMCSL, 0xf7f9);
hudakz 0:5350a66d5279 107
hudakz 0:5350a66d5279 108 //
hudakz 0:5350a66d5279 109 //
hudakz 0:5350a66d5279 110 // do bank 2 stuff
hudakz 0:5350a66d5279 111 // enable MAC receive
hudakz 0:5350a66d5279 112 // and bring MAC out of reset (writes 0x00 to MACON2)
hudakz 0:5350a66d5279 113 writeRegPair(MACON1, MACON1_MARXEN | MACON1_TXPAUS | MACON1_RXPAUS);
hudakz 0:5350a66d5279 114
hudakz 0:5350a66d5279 115 // enable automatic padding to 60bytes and CRC operations
hudakz 0:5350a66d5279 116 writeOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN);
hudakz 0:5350a66d5279 117
hudakz 0:5350a66d5279 118 // set inter-frame gap (non-back-to-back)
hudakz 0:5350a66d5279 119 writeRegPair(MAIPGL, 0x0C12);
hudakz 0:5350a66d5279 120
hudakz 0:5350a66d5279 121 // set inter-frame gap (back-to-back)
hudakz 0:5350a66d5279 122 writeReg(MABBIPG, 0x12);
hudakz 0:5350a66d5279 123
hudakz 0:5350a66d5279 124 // Set the maximum packet size which the controller will accept
hudakz 0:5350a66d5279 125 // Do not send packets longer than MAX_FRAMELEN:
hudakz 0:5350a66d5279 126 writeRegPair(MAMXFLL, MAX_FRAMELEN);
hudakz 0:5350a66d5279 127
hudakz 0:5350a66d5279 128 // do bank 3 stuff
hudakz 0:5350a66d5279 129 // write MAC address
hudakz 0:5350a66d5279 130 // NOTE: MAC address in ENC28J60 is byte-backward
hudakz 0:5350a66d5279 131 writeReg(MAADR5, macaddr[0]);
hudakz 0:5350a66d5279 132 writeReg(MAADR4, macaddr[1]);
hudakz 0:5350a66d5279 133 writeReg(MAADR3, macaddr[2]);
hudakz 0:5350a66d5279 134 writeReg(MAADR2, macaddr[3]);
hudakz 0:5350a66d5279 135 writeReg(MAADR1, macaddr[4]);
hudakz 0:5350a66d5279 136 writeReg(MAADR0, macaddr[5]);
hudakz 0:5350a66d5279 137
hudakz 0:5350a66d5279 138 // no loopback of transmitted frames
hudakz 0:5350a66d5279 139 phyWrite(PHCON2, PHCON2_HDLDIS);
hudakz 0:5350a66d5279 140
hudakz 0:5350a66d5279 141 // switch to bank 0
hudakz 0:5350a66d5279 142 setBank(ECON1);
hudakz 0:5350a66d5279 143
hudakz 0:5350a66d5279 144 // enable interrutps
hudakz 0:5350a66d5279 145 writeOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE | EIE_PKTIE);
hudakz 0:5350a66d5279 146
hudakz 0:5350a66d5279 147 // enable packet reception
hudakz 0:5350a66d5279 148 writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
hudakz 0:5350a66d5279 149 clkout(2); // change clkout from 6.25MHz to 12.5MHz
hudakz 0:5350a66d5279 150 wait(0.000060); // 60us
hudakz 0:5350a66d5279 151
hudakz 0:5350a66d5279 152 //Configure leds
hudakz 0:5350a66d5279 153 phyWrite(PHLCON, 0x476);
hudakz 0:5350a66d5279 154 }
hudakz 0:5350a66d5279 155
hudakz 0:5350a66d5279 156 /**
hudakz 0:5350a66d5279 157 * @brief
hudakz 0:5350a66d5279 158 * @note
hudakz 0:5350a66d5279 159 * @param
hudakz 0:5350a66d5279 160 * @retval
hudakz 0:5350a66d5279 161 */
hudakz 0:5350a66d5279 162 memhandle Enc28J60Network::receivePacket(void) {
hudakz 0:5350a66d5279 163 uint16_t rxstat;
hudakz 0:5350a66d5279 164 uint16_t len;
hudakz 0:5350a66d5279 165 // check if a packet has been received and buffered
hudakz 0:5350a66d5279 166
hudakz 0:5350a66d5279 167 //if( !(readReg(EIR) & EIR_PKTIF) ){
hudakz 0:5350a66d5279 168 // The above does not work. See Rev. B4 Silicon Errata point 6.
hudakz 0:5350a66d5279 169 if(readReg(EPKTCNT) != 0) {
hudakz 0:5350a66d5279 170 uint16_t readPtr = nextPacketPtr + 6;
hudakz 0:5350a66d5279 171 // Set the read pointer to the start of the received packet
hudakz 0:5350a66d5279 172
hudakz 0:5350a66d5279 173 writeRegPair(ERDPTL, nextPacketPtr);
hudakz 0:5350a66d5279 174
hudakz 0:5350a66d5279 175 // read the next packet pointer
hudakz 0:5350a66d5279 176 nextPacketPtr = readOp(ENC28J60_READ_BUF_MEM, 0);
hudakz 0:5350a66d5279 177 nextPacketPtr |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8;
hudakz 0:5350a66d5279 178
hudakz 0:5350a66d5279 179 // read the packet length (see datasheet page 43)
hudakz 0:5350a66d5279 180 len = readOp(ENC28J60_READ_BUF_MEM, 0);
hudakz 0:5350a66d5279 181 len |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8;
hudakz 0:5350a66d5279 182 len -= 4; //remove the CRC count
hudakz 0:5350a66d5279 183
hudakz 0:5350a66d5279 184 // read the receive status (see datasheet page 43)
hudakz 0:5350a66d5279 185 rxstat = readOp(ENC28J60_READ_BUF_MEM, 0);
hudakz 0:5350a66d5279 186 rxstat |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8;
hudakz 0:5350a66d5279 187
hudakz 0:5350a66d5279 188 // decrement the packet counter indicate we are done with this packet
hudakz 0:5350a66d5279 189 writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
hudakz 0:5350a66d5279 190
hudakz 0:5350a66d5279 191 // check CRC and symbol errors (see datasheet page 44, table 7-3):
hudakz 0:5350a66d5279 192 // The ERXFCON.CRCEN is set by default. Normally we should not
hudakz 0:5350a66d5279 193 // need to check this.
hudakz 0:5350a66d5279 194 if((rxstat & 0x80) != 0) {
hudakz 0:5350a66d5279 195 receivePkt.begin = readPtr;
hudakz 0:5350a66d5279 196 receivePkt.size = len;
hudakz 0:5350a66d5279 197 return UIP_RECEIVEBUFFERHANDLE;
hudakz 0:5350a66d5279 198 }
hudakz 0:5350a66d5279 199
hudakz 0:5350a66d5279 200 // Move the RX read pointer to the start of the next received packet
hudakz 0:5350a66d5279 201 // This frees the memory we just read out
hudakz 0:5350a66d5279 202 setERXRDPT();
hudakz 0:5350a66d5279 203 }
hudakz 0:5350a66d5279 204
hudakz 0:5350a66d5279 205 return(NOBLOCK);
hudakz 0:5350a66d5279 206 }
hudakz 0:5350a66d5279 207
hudakz 0:5350a66d5279 208 /**
hudakz 0:5350a66d5279 209 * @brief
hudakz 0:5350a66d5279 210 * @note
hudakz 0:5350a66d5279 211 * @param
hudakz 0:5350a66d5279 212 * @retval
hudakz 0:5350a66d5279 213 */
hudakz 0:5350a66d5279 214 void Enc28J60Network::setERXRDPT(void) {
hudakz 0:5350a66d5279 215 writeRegPair(ERXRDPTL, nextPacketPtr == RXSTART_INIT ? RXSTOP_INIT : nextPacketPtr - 1);
hudakz 0:5350a66d5279 216 }
hudakz 0:5350a66d5279 217
hudakz 0:5350a66d5279 218 /**
hudakz 0:5350a66d5279 219 * @brief
hudakz 0:5350a66d5279 220 * @note
hudakz 0:5350a66d5279 221 * @param
hudakz 0:5350a66d5279 222 * @retval
hudakz 0:5350a66d5279 223 */
hudakz 0:5350a66d5279 224 memaddress Enc28J60Network::blockSize(memhandle handle) {
hudakz 0:5350a66d5279 225 return handle == UIP_RECEIVEBUFFERHANDLE ? receivePkt.size : blocks[handle].size;
hudakz 0:5350a66d5279 226 }
hudakz 0:5350a66d5279 227
hudakz 0:5350a66d5279 228 /**
hudakz 0:5350a66d5279 229 * @brief
hudakz 0:5350a66d5279 230 * @note
hudakz 0:5350a66d5279 231 * @param
hudakz 0:5350a66d5279 232 * @retval
hudakz 0:5350a66d5279 233 */
hudakz 0:5350a66d5279 234 void Enc28J60Network::sendPacket(memhandle handle) {
hudakz 0:5350a66d5279 235 memblock* packet = &blocks[handle];
hudakz 0:5350a66d5279 236 uint16_t start = packet->begin - 1;
hudakz 0:5350a66d5279 237 uint16_t end = start + packet->size;
hudakz 0:5350a66d5279 238
hudakz 0:5350a66d5279 239 // backup data at control-byte position
hudakz 0:5350a66d5279 240 uint8_t data = readByte(start);
hudakz 0:5350a66d5279 241 // write control-byte (if not 0 anyway)
hudakz 0:5350a66d5279 242
hudakz 0:5350a66d5279 243 if(data)
hudakz 0:5350a66d5279 244 writeByte(start, 0);
hudakz 0:5350a66d5279 245
hudakz 0:5350a66d5279 246 #ifdef ENC28J60DEBUG
hudakz 0:5350a66d5279 247 pc.print("sendPacket(");
hudakz 0:5350a66d5279 248 pc.print(handle);
hudakz 0:5350a66d5279 249 pc.print(") [");
hudakz 0:5350a66d5279 250 pc.print(start);
hudakz 0:5350a66d5279 251 pc.print("-");
hudakz 0:5350a66d5279 252 pc.print(end);
hudakz 0:5350a66d5279 253 pc.println("]:");
hudakz 0:5350a66d5279 254 for(uint16_t i = start; i <= end; i++) {
hudakz 0:5350a66d5279 255 pc.print(readByte(i), HEX);
hudakz 0:5350a66d5279 256 pc.print(" ");
hudakz 0:5350a66d5279 257 }
hudakz 0:5350a66d5279 258
hudakz 0:5350a66d5279 259 pc.println();
hudakz 0:5350a66d5279 260 #endif
hudakz 0:5350a66d5279 261 // TX start
hudakz 0:5350a66d5279 262
hudakz 0:5350a66d5279 263 writeRegPair(ETXSTL, start);
hudakz 0:5350a66d5279 264
hudakz 0:5350a66d5279 265 // Set the TXND pointer to correspond to the packet size given
hudakz 0:5350a66d5279 266 writeRegPair(ETXNDL, end);
hudakz 0:5350a66d5279 267
hudakz 0:5350a66d5279 268 // send the contents of the transmit buffer onto the network
hudakz 0:5350a66d5279 269 writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
hudakz 0:5350a66d5279 270
hudakz 0:5350a66d5279 271 // Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12.
hudakz 0:5350a66d5279 272 if((readReg(EIR) & EIR_TXERIF)) {
hudakz 0:5350a66d5279 273 writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRTS);
hudakz 0:5350a66d5279 274 }
hudakz 0:5350a66d5279 275
hudakz 0:5350a66d5279 276 //restore data on control-byte position
hudakz 0:5350a66d5279 277 if(data)
hudakz 0:5350a66d5279 278 writeByte(start, data);
hudakz 0:5350a66d5279 279 }
hudakz 0:5350a66d5279 280
hudakz 0:5350a66d5279 281 /**
hudakz 0:5350a66d5279 282 * @brief
hudakz 0:5350a66d5279 283 * @note
hudakz 0:5350a66d5279 284 * @param
hudakz 0:5350a66d5279 285 * @retval
hudakz 0:5350a66d5279 286 */
hudakz 0:5350a66d5279 287 uint16_t Enc28J60Network::setReadPtr(memhandle handle, memaddress position, uint16_t len) {
hudakz 0:5350a66d5279 288 memblock* packet = handle == UIP_RECEIVEBUFFERHANDLE ? &receivePkt : &blocks[handle];
hudakz 0:5350a66d5279 289 memaddress start = packet->begin + position;
hudakz 0:5350a66d5279 290
hudakz 0:5350a66d5279 291 writeRegPair(ERDPTL, start);
hudakz 0:5350a66d5279 292
hudakz 0:5350a66d5279 293 if(len > packet->size - position)
hudakz 0:5350a66d5279 294 len = packet->size - position;
hudakz 0:5350a66d5279 295 return len;
hudakz 0:5350a66d5279 296 }
hudakz 0:5350a66d5279 297
hudakz 0:5350a66d5279 298 /**
hudakz 0:5350a66d5279 299 * @brief
hudakz 0:5350a66d5279 300 * @note
hudakz 0:5350a66d5279 301 * @param
hudakz 0:5350a66d5279 302 * @retval
hudakz 0:5350a66d5279 303 */
hudakz 0:5350a66d5279 304 uint16_t Enc28J60Network::readPacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len) {
hudakz 0:5350a66d5279 305 len = setReadPtr(handle, position, len);
hudakz 0:5350a66d5279 306 readBuffer(len, buffer);
hudakz 0:5350a66d5279 307 return len;
hudakz 0:5350a66d5279 308 }
hudakz 0:5350a66d5279 309
hudakz 0:5350a66d5279 310 /**
hudakz 0:5350a66d5279 311 * @brief
hudakz 0:5350a66d5279 312 * @note
hudakz 0:5350a66d5279 313 * @param
hudakz 0:5350a66d5279 314 * @retval
hudakz 0:5350a66d5279 315 */
hudakz 0:5350a66d5279 316 uint16_t Enc28J60Network::writePacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len) {
hudakz 0:5350a66d5279 317 memblock* packet = &blocks[handle];
hudakz 0:5350a66d5279 318 uint16_t start = packet->begin + position;
hudakz 0:5350a66d5279 319
hudakz 0:5350a66d5279 320 writeRegPair(EWRPTL, start);
hudakz 0:5350a66d5279 321
hudakz 0:5350a66d5279 322 if(len > packet->size - position)
hudakz 0:5350a66d5279 323 len = packet->size - position;
hudakz 0:5350a66d5279 324 writeBuffer(len, buffer);
hudakz 0:5350a66d5279 325 return len;
hudakz 0:5350a66d5279 326 }
hudakz 0:5350a66d5279 327
hudakz 0:5350a66d5279 328 /**
hudakz 0:5350a66d5279 329 * @brief
hudakz 0:5350a66d5279 330 * @note
hudakz 0:5350a66d5279 331 * @param
hudakz 0:5350a66d5279 332 * @retval
hudakz 0:5350a66d5279 333 */
hudakz 0:5350a66d5279 334 uint8_t Enc28J60Network::readByte(uint16_t addr) {
hudakz 0:5350a66d5279 335 uint8_t result;
hudakz 0:5350a66d5279 336
hudakz 0:5350a66d5279 337 writeRegPair(ERDPTL, addr);
hudakz 0:5350a66d5279 338
hudakz 0:5350a66d5279 339 _cs = 0;
hudakz 0:5350a66d5279 340
hudakz 0:5350a66d5279 341 // issue read command
hudakz 0:5350a66d5279 342 _spi.write(ENC28J60_READ_BUF_MEM);
hudakz 0:5350a66d5279 343
hudakz 0:5350a66d5279 344 // read data
hudakz 0:5350a66d5279 345 result = _spi.write(0x00);
hudakz 0:5350a66d5279 346 _cs = 1;
hudakz 0:5350a66d5279 347 return(result);
hudakz 0:5350a66d5279 348 }
hudakz 0:5350a66d5279 349
hudakz 0:5350a66d5279 350 /**
hudakz 0:5350a66d5279 351 * @brief
hudakz 0:5350a66d5279 352 * @note
hudakz 0:5350a66d5279 353 * @param
hudakz 0:5350a66d5279 354 * @retval
hudakz 0:5350a66d5279 355 */
hudakz 0:5350a66d5279 356 void Enc28J60Network::writeByte(uint16_t addr, uint8_t data) {
hudakz 0:5350a66d5279 357 writeRegPair(EWRPTL, addr);
hudakz 0:5350a66d5279 358
hudakz 0:5350a66d5279 359 _cs = 0;
hudakz 0:5350a66d5279 360
hudakz 0:5350a66d5279 361 // issue write command
hudakz 0:5350a66d5279 362 _spi.write(ENC28J60_WRITE_BUF_MEM);
hudakz 0:5350a66d5279 363
hudakz 0:5350a66d5279 364 // write data
hudakz 0:5350a66d5279 365 _spi.write(data);
hudakz 0:5350a66d5279 366 _cs = 1;
hudakz 0:5350a66d5279 367 }
hudakz 0:5350a66d5279 368
hudakz 0:5350a66d5279 369 /**
hudakz 0:5350a66d5279 370 * @brief
hudakz 0:5350a66d5279 371 * @note
hudakz 0:5350a66d5279 372 * @param
hudakz 0:5350a66d5279 373 * @retval
hudakz 0:5350a66d5279 374 */
hudakz 0:5350a66d5279 375 void Enc28J60Network::copyPacket
hudakz 0:5350a66d5279 376 (
hudakz 0:5350a66d5279 377 memhandle dest_pkt,
hudakz 0:5350a66d5279 378 memaddress dest_pos,
hudakz 0:5350a66d5279 379 memhandle src_pkt,
hudakz 0:5350a66d5279 380 memaddress src_pos,
hudakz 0:5350a66d5279 381 uint16_t len
hudakz 0:5350a66d5279 382 ) {
hudakz 0:5350a66d5279 383 memblock* dest = &blocks[dest_pkt];
hudakz 0:5350a66d5279 384 memblock* src = src_pkt == UIP_RECEIVEBUFFERHANDLE ? &receivePkt : &blocks[src_pkt];
hudakz 0:5350a66d5279 385 memblock_mv_cb(dest->begin + dest_pos, src->begin + src_pos, len);
hudakz 0:5350a66d5279 386
hudakz 0:5350a66d5279 387 // Move the RX read pointer to the start of the next received packet
hudakz 0:5350a66d5279 388 // This frees the memory we just read out
hudakz 0:5350a66d5279 389 setERXRDPT();
hudakz 0:5350a66d5279 390 }
hudakz 0:5350a66d5279 391
hudakz 0:5350a66d5279 392 /**
hudakz 0:5350a66d5279 393 * @brief
hudakz 0:5350a66d5279 394 * @note
hudakz 0:5350a66d5279 395 * @param
hudakz 0:5350a66d5279 396 * @retval
hudakz 0:5350a66d5279 397 */
hudakz 0:5350a66d5279 398 void Enc28J60Network::memblock_mv_cb(uint16_t dest, uint16_t src, uint16_t len) {
hudakz 0:5350a66d5279 399
hudakz 0:5350a66d5279 400 //as ENC28J60 DMA is unable to copy single bytes:
hudakz 0:5350a66d5279 401
hudakz 0:5350a66d5279 402 if(len == 1) {
hudakz 0:5350a66d5279 403 writeByte(dest, readByte(src));
hudakz 0:5350a66d5279 404 }
hudakz 0:5350a66d5279 405 else {
hudakz 0:5350a66d5279 406
hudakz 0:5350a66d5279 407 // calculate address of last byte
hudakz 0:5350a66d5279 408 len += src - 1;
hudakz 0:5350a66d5279 409
hudakz 0:5350a66d5279 410 /* 1. Appropriately program the EDMAST, EDMAND
hudakz 0:5350a66d5279 411 and EDMADST register pairs. The EDMAST
hudakz 0:5350a66d5279 412 registers should point to the first byte to copy
hudakz 0:5350a66d5279 413 from, the EDMAND registers should point to the
hudakz 0:5350a66d5279 414 last byte to copy and the EDMADST registers
hudakz 0:5350a66d5279 415 should point to the first byte in the destination
hudakz 0:5350a66d5279 416 range. The destination range will always be
hudakz 0:5350a66d5279 417 linear, never wrapping at any values except from
hudakz 0:5350a66d5279 418 8191 to 0 (the 8-Kbyte memory boundary).
hudakz 0:5350a66d5279 419 Extreme care should be taken when
hudakz 0:5350a66d5279 420 programming the start and end pointers to
hudakz 0:5350a66d5279 421 prevent a never ending DMA operation which
hudakz 0:5350a66d5279 422 would overwrite the entire 8-Kbyte buffer.
hudakz 0:5350a66d5279 423 */
hudakz 0:5350a66d5279 424 writeRegPair(EDMASTL, src);
hudakz 0:5350a66d5279 425 writeRegPair(EDMADSTL, dest);
hudakz 0:5350a66d5279 426
hudakz 0:5350a66d5279 427 if((src <= RXSTOP_INIT) && (len > RXSTOP_INIT))
hudakz 0:5350a66d5279 428 len -= (RXSTOP_INIT - RXSTART_INIT);
hudakz 0:5350a66d5279 429 writeRegPair(EDMANDL, len);
hudakz 0:5350a66d5279 430
hudakz 0:5350a66d5279 431 /*
hudakz 0:5350a66d5279 432 2. If an interrupt at the end of the copy process is
hudakz 0:5350a66d5279 433 desired, set EIE.DMAIE and EIE.INTIE and
hudakz 0:5350a66d5279 434 clear EIR.DMAIF.
hudakz 0:5350a66d5279 435
hudakz 0:5350a66d5279 436 3. Verify that ECON1.CSUMEN is clear. */
hudakz 0:5350a66d5279 437 writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_CSUMEN);
hudakz 0:5350a66d5279 438
hudakz 0:5350a66d5279 439 /* 4. Start the DMA copy by setting ECON1.DMAST. */
hudakz 0:5350a66d5279 440 writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_DMAST);
hudakz 0:5350a66d5279 441
hudakz 0:5350a66d5279 442 // wait until runnig DMA is completed
hudakz 0:5350a66d5279 443 while(readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_DMAST);
hudakz 0:5350a66d5279 444 }
hudakz 0:5350a66d5279 445 }
hudakz 0:5350a66d5279 446
hudakz 0:5350a66d5279 447 /**
hudakz 0:5350a66d5279 448 * @brief
hudakz 0:5350a66d5279 449 * @note
hudakz 0:5350a66d5279 450 * @param
hudakz 0:5350a66d5279 451 * @retval
hudakz 0:5350a66d5279 452 */
hudakz 0:5350a66d5279 453 void Enc28J60Network::freePacket(void) {
hudakz 0:5350a66d5279 454 setERXRDPT();
hudakz 0:5350a66d5279 455 }
hudakz 0:5350a66d5279 456
hudakz 0:5350a66d5279 457 /**
hudakz 0:5350a66d5279 458 * @brief
hudakz 0:5350a66d5279 459 * @note
hudakz 0:5350a66d5279 460 * @param
hudakz 0:5350a66d5279 461 * @retval
hudakz 0:5350a66d5279 462 */
hudakz 0:5350a66d5279 463 uint8_t Enc28J60Network::readOp(uint8_t op, uint8_t address) {
hudakz 0:5350a66d5279 464 uint8_t result;
hudakz 0:5350a66d5279 465
hudakz 0:5350a66d5279 466 _cs = 0;
hudakz 0:5350a66d5279 467
hudakz 0:5350a66d5279 468 // issue read command
hudakz 0:5350a66d5279 469 _spi.write(op | (address & ADDR_MASK));
hudakz 0:5350a66d5279 470
hudakz 0:5350a66d5279 471 // read data
hudakz 0:5350a66d5279 472 result = _spi.write(0x00);
hudakz 0:5350a66d5279 473
hudakz 0:5350a66d5279 474 // do dummy read if needed (for mac and mii, see datasheet page 29)
hudakz 0:5350a66d5279 475 if(address & 0x80)
hudakz 0:5350a66d5279 476 result = _spi.write(0x00);
hudakz 0:5350a66d5279 477
hudakz 0:5350a66d5279 478 // release CS
hudakz 0:5350a66d5279 479 _cs = 1;
hudakz 0:5350a66d5279 480 return(result);
hudakz 0:5350a66d5279 481 }
hudakz 0:5350a66d5279 482
hudakz 0:5350a66d5279 483 /**
hudakz 0:5350a66d5279 484 * @brief
hudakz 0:5350a66d5279 485 * @note
hudakz 0:5350a66d5279 486 * @param
hudakz 0:5350a66d5279 487 * @retval
hudakz 0:5350a66d5279 488 */
hudakz 0:5350a66d5279 489 void Enc28J60Network::writeOp(uint8_t op, uint8_t address, uint8_t data) {
hudakz 0:5350a66d5279 490 _cs = 0;
hudakz 0:5350a66d5279 491
hudakz 0:5350a66d5279 492 // issue write command
hudakz 0:5350a66d5279 493 _spi.write(op | (address & ADDR_MASK));
hudakz 0:5350a66d5279 494
hudakz 0:5350a66d5279 495 // write data
hudakz 0:5350a66d5279 496 _spi.write(data);
hudakz 0:5350a66d5279 497 _cs = 1;
hudakz 0:5350a66d5279 498 }
hudakz 0:5350a66d5279 499
hudakz 0:5350a66d5279 500 /**
hudakz 0:5350a66d5279 501 * @brief
hudakz 0:5350a66d5279 502 * @note
hudakz 0:5350a66d5279 503 * @param
hudakz 0:5350a66d5279 504 * @retval
hudakz 0:5350a66d5279 505 */
hudakz 0:5350a66d5279 506 void Enc28J60Network::readBuffer(uint16_t len, uint8_t* data) {
hudakz 0:5350a66d5279 507 _cs = 0;
hudakz 0:5350a66d5279 508
hudakz 0:5350a66d5279 509 // issue read command
hudakz 0:5350a66d5279 510 _spi.write(ENC28J60_READ_BUF_MEM);
hudakz 0:5350a66d5279 511 while(len) {
hudakz 0:5350a66d5279 512 len--;
hudakz 0:5350a66d5279 513
hudakz 0:5350a66d5279 514 // read data
hudakz 0:5350a66d5279 515 *data = _spi.write(0x00);
hudakz 0:5350a66d5279 516 data++;
hudakz 0:5350a66d5279 517 }
hudakz 0:5350a66d5279 518
hudakz 0:5350a66d5279 519 *data = '\0';
hudakz 0:5350a66d5279 520 _cs = 1;
hudakz 0:5350a66d5279 521 }
hudakz 0:5350a66d5279 522
hudakz 0:5350a66d5279 523 /**
hudakz 0:5350a66d5279 524 * @brief
hudakz 0:5350a66d5279 525 * @note
hudakz 0:5350a66d5279 526 * @param
hudakz 0:5350a66d5279 527 * @retval
hudakz 0:5350a66d5279 528 */
hudakz 0:5350a66d5279 529 void Enc28J60Network::writeBuffer(uint16_t len, uint8_t* data) {
hudakz 0:5350a66d5279 530 _cs = 0;
hudakz 0:5350a66d5279 531
hudakz 0:5350a66d5279 532 // issue write command
hudakz 0:5350a66d5279 533 _spi.write(ENC28J60_WRITE_BUF_MEM);
hudakz 0:5350a66d5279 534 while(len) {
hudakz 0:5350a66d5279 535 len--;
hudakz 0:5350a66d5279 536
hudakz 0:5350a66d5279 537 // write data
hudakz 0:5350a66d5279 538 _spi.write(*data);
hudakz 0:5350a66d5279 539 data++;
hudakz 0:5350a66d5279 540 }
hudakz 0:5350a66d5279 541
hudakz 0:5350a66d5279 542 _cs = 1;
hudakz 0:5350a66d5279 543 }
hudakz 0:5350a66d5279 544
hudakz 0:5350a66d5279 545 /**
hudakz 0:5350a66d5279 546 * @brief
hudakz 0:5350a66d5279 547 * @note
hudakz 0:5350a66d5279 548 * @param
hudakz 0:5350a66d5279 549 * @retval
hudakz 0:5350a66d5279 550 */
hudakz 0:5350a66d5279 551 void Enc28J60Network::setBank(uint8_t address) {
hudakz 0:5350a66d5279 552
hudakz 0:5350a66d5279 553 // set the bank (if needed)
hudakz 0:5350a66d5279 554
hudakz 0:5350a66d5279 555 if((address & BANK_MASK) != bank) {
hudakz 0:5350a66d5279 556
hudakz 0:5350a66d5279 557 // set the bank
hudakz 0:5350a66d5279 558 writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1 | ECON1_BSEL0));
hudakz 0:5350a66d5279 559 writeOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK) >> 5);
hudakz 0:5350a66d5279 560 bank = (address & BANK_MASK);
hudakz 0:5350a66d5279 561 }
hudakz 0:5350a66d5279 562 }
hudakz 0:5350a66d5279 563
hudakz 0:5350a66d5279 564 /**
hudakz 0:5350a66d5279 565 * @brief
hudakz 0:5350a66d5279 566 * @note
hudakz 0:5350a66d5279 567 * @param
hudakz 0:5350a66d5279 568 * @retval
hudakz 0:5350a66d5279 569 */
hudakz 0:5350a66d5279 570 uint8_t Enc28J60Network::readReg(uint8_t address) {
hudakz 0:5350a66d5279 571
hudakz 0:5350a66d5279 572 // set the bank
hudakz 0:5350a66d5279 573
hudakz 0:5350a66d5279 574 setBank(address);
hudakz 0:5350a66d5279 575
hudakz 0:5350a66d5279 576 // do the read
hudakz 0:5350a66d5279 577 return readOp(ENC28J60_READ_CTRL_REG, address);
hudakz 0:5350a66d5279 578 }
hudakz 0:5350a66d5279 579
hudakz 0:5350a66d5279 580 /**
hudakz 0:5350a66d5279 581 * @brief
hudakz 0:5350a66d5279 582 * @note
hudakz 0:5350a66d5279 583 * @param
hudakz 0:5350a66d5279 584 * @retval
hudakz 0:5350a66d5279 585 */
hudakz 0:5350a66d5279 586 void Enc28J60Network::writeReg(uint8_t address, uint8_t data) {
hudakz 0:5350a66d5279 587
hudakz 0:5350a66d5279 588 // set the bank
hudakz 0:5350a66d5279 589
hudakz 0:5350a66d5279 590 setBank(address);
hudakz 0:5350a66d5279 591
hudakz 0:5350a66d5279 592 // do the write
hudakz 0:5350a66d5279 593 writeOp(ENC28J60_WRITE_CTRL_REG, address, data);
hudakz 0:5350a66d5279 594 }
hudakz 0:5350a66d5279 595
hudakz 0:5350a66d5279 596 /**
hudakz 0:5350a66d5279 597 * @brief
hudakz 0:5350a66d5279 598 * @note
hudakz 0:5350a66d5279 599 * @param
hudakz 0:5350a66d5279 600 * @retval
hudakz 0:5350a66d5279 601 */
hudakz 0:5350a66d5279 602 void Enc28J60Network::writeRegPair(uint8_t address, uint16_t data) {
hudakz 0:5350a66d5279 603
hudakz 0:5350a66d5279 604 // set the bank
hudakz 0:5350a66d5279 605
hudakz 0:5350a66d5279 606 setBank(address);
hudakz 0:5350a66d5279 607
hudakz 0:5350a66d5279 608 // do the write
hudakz 0:5350a66d5279 609 writeOp(ENC28J60_WRITE_CTRL_REG, address, (data & 0xFF));
hudakz 0:5350a66d5279 610 writeOp(ENC28J60_WRITE_CTRL_REG, address + 1, (data) >> 8);
hudakz 0:5350a66d5279 611 }
hudakz 0:5350a66d5279 612
hudakz 0:5350a66d5279 613 /**
hudakz 0:5350a66d5279 614 * @brief
hudakz 0:5350a66d5279 615 * @note
hudakz 0:5350a66d5279 616 * @param
hudakz 0:5350a66d5279 617 * @retval
hudakz 0:5350a66d5279 618 */
hudakz 0:5350a66d5279 619 void Enc28J60Network::phyWrite(uint8_t address, uint16_t data) {
hudakz 0:5350a66d5279 620
hudakz 0:5350a66d5279 621 // set the PHY register address
hudakz 0:5350a66d5279 622
hudakz 0:5350a66d5279 623 writeReg(MIREGADR, address);
hudakz 0:5350a66d5279 624
hudakz 0:5350a66d5279 625 // write the PHY data
hudakz 0:5350a66d5279 626 writeRegPair(MIWRL, data);
hudakz 0:5350a66d5279 627
hudakz 0:5350a66d5279 628 // wait until the PHY write completes
hudakz 0:5350a66d5279 629 while(readReg(MISTAT) & MISTAT_BUSY) {
hudakz 0:5350a66d5279 630 wait(0.000015);
hudakz 0:5350a66d5279 631 }
hudakz 0:5350a66d5279 632 }
hudakz 0:5350a66d5279 633
hudakz 0:5350a66d5279 634 /**
hudakz 0:5350a66d5279 635 * @brief
hudakz 0:5350a66d5279 636 * @note
hudakz 0:5350a66d5279 637 * @param
hudakz 0:5350a66d5279 638 * @retval
hudakz 0:5350a66d5279 639 */
hudakz 0:5350a66d5279 640 void Enc28J60Network::clkout(uint8_t clk) {
hudakz 0:5350a66d5279 641
hudakz 0:5350a66d5279 642 //setup clkout: 2 is 12.5MHz:
hudakz 0:5350a66d5279 643
hudakz 0:5350a66d5279 644 writeReg(ECOCON, clk & 0x7);
hudakz 0:5350a66d5279 645 }
hudakz 0:5350a66d5279 646
hudakz 0:5350a66d5279 647 // read the revision of the chip:
hudakz 0:5350a66d5279 648 uint8_t Enc28J60Network::getRev(void) {
hudakz 0:5350a66d5279 649 return(readReg(EREVID));
hudakz 0:5350a66d5279 650 }
hudakz 0:5350a66d5279 651
hudakz 0:5350a66d5279 652 /**
hudakz 0:5350a66d5279 653 * @brief
hudakz 0:5350a66d5279 654 * @note
hudakz 0:5350a66d5279 655 * @param
hudakz 0:5350a66d5279 656 * @retval
hudakz 0:5350a66d5279 657 */
hudakz 0:5350a66d5279 658 uint16_t Enc28J60Network::chksum(uint16_t sum, memhandle handle, memaddress pos, uint16_t len) {
hudakz 0:5350a66d5279 659 uint8_t spdr;
hudakz 0:5350a66d5279 660 uint16_t t;
hudakz 0:5350a66d5279 661 uint16_t i;
hudakz 0:5350a66d5279 662
hudakz 0:5350a66d5279 663 len = setReadPtr(handle, pos, len) - 1;
hudakz 0:5350a66d5279 664 _cs = 0;
hudakz 0:5350a66d5279 665
hudakz 0:5350a66d5279 666 // issue read command
hudakz 0:5350a66d5279 667 spdr = _spi.write(ENC28J60_READ_BUF_MEM);
hudakz 0:5350a66d5279 668 for(i = 0; i < len; i += 2) {
hudakz 0:5350a66d5279 669
hudakz 0:5350a66d5279 670 // read data
hudakz 0:5350a66d5279 671 spdr = _spi.write(0x00);
hudakz 0:5350a66d5279 672 t = spdr << 8;
hudakz 0:5350a66d5279 673 spdr = _spi.write(0x00);
hudakz 0:5350a66d5279 674 t += spdr;
hudakz 0:5350a66d5279 675 sum += t;
hudakz 0:5350a66d5279 676 if(sum < t) {
hudakz 0:5350a66d5279 677 sum++; /* carry */
hudakz 0:5350a66d5279 678 }
hudakz 0:5350a66d5279 679 }
hudakz 0:5350a66d5279 680
hudakz 0:5350a66d5279 681 if(i == len) {
hudakz 0:5350a66d5279 682 spdr = _spi.write(0x00);
hudakz 0:5350a66d5279 683 t = (spdr << 8) + 0;
hudakz 0:5350a66d5279 684 sum += t;
hudakz 0:5350a66d5279 685 if(sum < t) {
hudakz 0:5350a66d5279 686 sum++; /* carry */
hudakz 0:5350a66d5279 687 }
hudakz 0:5350a66d5279 688 }
hudakz 0:5350a66d5279 689
hudakz 0:5350a66d5279 690 _cs = 1;
hudakz 0:5350a66d5279 691
hudakz 0:5350a66d5279 692 /* Return sum in host byte order. */
hudakz 0:5350a66d5279 693 return sum;
hudakz 0:5350a66d5279 694 }
hudakz 0:5350a66d5279 695