/[H8]/trunk/docs/Microchip TCP_IP stack/TCPIP Stack/ENC28J60.c
ViewVC logotype

Contents of /trunk/docs/Microchip TCP_IP stack/TCPIP Stack/ENC28J60.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 15 - (show annotations) (download)
Thu Apr 19 09:01:15 2007 UTC (17 years, 1 month ago) by hedin
File MIME type: text/plain
File size: 67088 byte(s)
added the TCP/IP stack, source code.
1 /*********************************************************************
2 *
3 * Medium Access Control (MAC) Layer for Microchip ENC28J60
4 * Module for Microchip TCP/IP Stack
5 * -Provides access to ENC28J60 Ethernet controller
6 * -Reference: ENC28J60 Data sheet, IEEE 802.3 Standard
7 *
8 *********************************************************************
9 * FileName: ENC28J60.c
10 * Dependencies: ENC28J60.h
11 * MAC.h
12 * string.h
13 * StackTsk.h
14 * Helpers.h
15 * Delay.h
16 * Processor: PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F
17 * Complier: Microchip C18 v3.02 or higher
18 * Microchip C30 v2.01 or higher
19 * Company: Microchip Technology, Inc.
20 *
21 * Software License Agreement
22 *
23 * Copyright © 2002-2007 Microchip Technology Inc. All rights
24 * reserved.
25 *
26 * Microchip licenses to you the right to use, modify, copy, and
27 * distribute:
28 * (i) the Software when embedded on a Microchip microcontroller or
29 * digital signal controller product (“Device”) which is
30 * integrated into Licensee’s product; or
31 * (ii) ONLY the Software driver source files ENC28J60.c and
32 * ENC28J60.h ported to a non-Microchip device used in
33 * conjunction with a Microchip ethernet controller for the
34 * sole purpose of interfacing with the ethernet controller.
35 *
36 * You should refer to the license agreement accompanying this
37 * Software for additional information regarding your rights and
38 * obligations.
39 *
40 * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED “AS IS” WITHOUT
41 * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
42 * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
43 * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
44 * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
45 * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
46 * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
47 * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
48 * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
49 * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
50 * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE.
51 *
52 *
53 * Author Date Comment
54 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
55 * Howard Schlunder 6/28/04 Original
56 * Howard Schlunder 10/8/04 Cleanup
57 * Howard Schlunder 10/19/04 Small optimizations and more cleanup
58 * Howard Schlunder 11/29/04 Added Set/GetCLKOUT
59 * Howard Schlunder 12/23/05 Added B1 silicon errata workarounds
60 * Howard Schlunder 1/09/06 Added comments and minor mods
61 * Howard Schlunder 1/18/06 Added more silicon errata workarounds
62 * Howard Schlunder 6/16/06 Synchronized with PIC18F97J60 code
63 * Howard Schlunder 7/17/06 Updated TestMemory() for C30
64 * Howard Schlunder 8/07/06 Added SetRXHashTableEntry() function
65 ********************************************************************/
66 #define __ENC28J60_C
67
68 #include "TCPIP Stack/TCPIP.h"
69
70
71 // Make sure that this hardware profile has an ENC28J60 in it
72 #if defined(ENC_CS_TRIS) && !defined(STACK_USE_SLIP)
73
74
75 /** D E F I N I T I O N S ****************************************************/
76 // IMPORTANT SPI NOTE: The code in this file expects that the SPI interrupt
77 // flag (ENC_SPI_IF) be clear at all times. If the SPI is shared with
78 // other hardware, the other code should clear the ENC_SPI_IF when it is
79 // done using the SPI.
80
81 // Since the ENC28J60 doesn't support auto-negotiation, full-duplex mode is
82 // not compatible with most switches/routers. If a dedicated network is used
83 // where the duplex of the remote node can be manually configured, you may
84 // change this configuration. Otherwise, half duplex should always be used.
85 #define HALF_DUPLEX
86 //#define FULL_DUPLEX
87 //#define LEDB_DUPLEX
88
89 // Pseudo Functions
90 #define LOW(a) (a & 0xFF)
91 #define HIGH(a) ((a>>8) & 0xFF)
92
93 // ENC28J60 Opcodes (to be ORed with a 5 bit address)
94 #define WCR (0x2<<5) // Write Control Register command
95 #define BFS (0x4<<5) // Bit Field Set command
96 #define BFC (0x5<<5) // Bit Field Clear command
97 #define RCR (0x0<<5) // Read Control Register command
98 #define RBM ((0x1<<5) | 0x1A) // Read Buffer Memory command
99 #define WBM ((0x3<<5) | 0x1A) // Write Buffer Memory command
100 #define SR ((0x7<<5) | 0x1F) // System Reset command does not use an address.
101 // It requires 0x1F, however.
102
103 #define ETHER_IP (0x00u)
104 #define ETHER_ARP (0x06u)
105
106 // A header appended at the start of all RX frames by the hardware
107 typedef struct _ENC_PREAMBLE
108 {
109 WORD NextPacketPointer;
110 RXSTATUS StatusVector;
111
112 MAC_ADDR DestMACAddr;
113 MAC_ADDR SourceMACAddr;
114 WORD_VAL Type;
115 } ENC_PREAMBLE;
116
117
118 // Prototypes of functions intended for MAC layer use only.
119 static void BankSel(WORD Register);
120 static REG ReadETHReg(BYTE Address);
121 static REG ReadMACReg(BYTE Address);
122 static void WriteReg(BYTE Address, BYTE Data);
123 static void BFCReg(BYTE Address, BYTE Data);
124 static void BFSReg(BYTE Address, BYTE Data);
125 static void SendSystemReset(void);
126 //static void GetRegs(void);
127 //void Get8KBRAM(void);
128
129 // Internal MAC level variables and flags.
130 static WORD_VAL NextPacketLocation;
131 static WORD_VAL CurrentPacketLocation;
132 static BOOL WasDiscarded;
133 static BYTE ENCRevID;
134
135
136 //NOTE: All code in this module expect Bank 0 to be currently selected. If code ever changes the bank, it must restore it to Bank 0 before returning.
137
138 /******************************************************************************
139 * Function: void MACInit(void)
140 *
141 * PreCondition: None
142 *
143 * Input: None
144 *
145 * Output: None
146 *
147 * Side Effects: None
148 *
149 * Overview: MACInit sets up the PIC's SPI module and all the
150 * registers in the ENC28J60 so that normal operation can
151 * begin.
152 *
153 * Note: None
154 *****************************************************************************/
155 void MACInit(void)
156 {
157 BYTE i;
158
159 // Set up the SPI module on the PIC for communications with the ENC28J60
160 ENC_CS_IO = 1;
161 ENC_CS_TRIS = 0; // Make the Chip Select pin an output
162 ENC_SCK_TRIS = 0;
163 ENC_SDO_TRIS = 0;
164 ENC_SDI_TRIS = 1;
165
166 // Set up SPI
167 #if defined(__18CXX)
168 ENC_SPICON1 = 0x20; // SSPEN bit is set, SPI in master mode, FOSC/4,
169 // IDLE state is low level
170 ENC_SPI_IF = 0;
171 ENC_SPISTATbits.CKE = 1; // Transmit data on rising edge of clock
172 ENC_SPISTATbits.SMP = 0; // Input sampled at middle of data output time
173 #else
174 ENC_SPISTAT = 0; // clear SPI
175 #if defined(__PIC24H__) || defined(__dsPIC33F__)
176 ENC_SPICON1 = 0x0F; // 1:1 primary prescale, 5:1 secondary prescale (8MHz @ 40MIPS)
177 // ENC_SPICON1 = 0x1E; // 4:1 primary prescale, 1:1 secondary prescale (10MHz @ 40MIPS, Doesn't work. CLKRDY is incorrectly reported as being clear. Problem caused by dsPIC33/PIC24H ES silicon bug.)
178 #elif defined(__PIC24F__)
179 // ENC_SPICON1 = 0x1F; // 1:1 prescale broken on PIC24F ES silicon (16MHz @ 16MIPS)
180 ENC_SPICON1 = 0x1B; // 1:1 primary prescale, 2:1 secondary prescale (8MHz @ 16MIPS)
181 #else // dsPIC30F
182 ENC_SPICON1 = 0x17; // 1:1 primary prescale, 3:1 secondary prescale (10MHz @ 30MIPS)
183 #endif
184 ENC_SPICON2 = 0;
185 ENC_SPICON1bits.CKE = 1;
186 ENC_SPICON1bits.MSTEN = 1;
187 ENC_SPISTATbits.SPIEN = 1;
188 #endif
189
190 // Wait for CLKRDY to become set.
191 // Bit 3 in ESTAT is an unimplemented bit. If it reads out as '1' that
192 // means the part is in RESET or there is something wrong with the SPI
193 // connection. This loop makes sure that we can communicate with the
194 // ENC28J60 before proceeding.
195 do
196 {
197 i = ReadETHReg(ESTAT).Val;
198 } while((i & 0x08) || (~i & ESTAT_CLKRDY));
199
200
201 // RESET the entire ENC28J60, clearing all registers
202 SendSystemReset();
203 DelayMs(1);
204
205 // Start up in Bank 0 and configure the receive buffer boundary pointers
206 // and the buffer write protect pointer (receive buffer read pointer)
207 WasDiscarded = TRUE;
208 NextPacketLocation.Val = RXSTART;
209
210 WriteReg(ERXSTL, LOW(RXSTART));
211 WriteReg(ERXSTH, HIGH(RXSTART));
212 WriteReg(ERXRDPTL, LOW(RXSTOP)); // Write low byte first
213 WriteReg(ERXRDPTH, HIGH(RXSTOP)); // Write high byte last
214 WriteReg(ERXNDL, LOW(RXSTOP));
215 WriteReg(ERXNDH, HIGH(RXSTOP));
216 WriteReg(ETXSTL, LOW(TXSTART));
217 WriteReg(ETXSTH, HIGH(TXSTART));
218
219 // Write a permanant per packet control byte of 0x00
220 WriteReg(EWRPTL, LOW(TXSTART));
221 WriteReg(EWRPTH, HIGH(TXSTART));
222 MACPut(0x00);
223
224
225 // Enter Bank 1 and configure Receive Filters
226 // (No need to reconfigure - Unicast OR Broadcast with CRC checking is
227 // acceptable)
228 // Write ERXFCON_CRCEN only to ERXFCON to enter promiscuous mode
229
230 // Promiscious mode example:
231 //BankSel(ERXFCON);
232 //WriteReg((BYTE)ERXFCON, ERXFCON_CRCEN);
233
234 // Enter Bank 2 and configure the MAC
235 BankSel(MACON1);
236
237 // Enable the receive portion of the MAC
238 WriteReg((BYTE)MACON1, MACON1_TXPAUS | MACON1_RXPAUS | MACON1_MARXEN);
239
240 // Pad packets to 60 bytes, add CRC, and check Type/Length field.
241 #if defined(FULL_DUPLEX)
242 WriteReg((BYTE)MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN | MACON3_FULDPX);
243 WriteReg((BYTE)MABBIPG, 0x15);
244 #else
245 WriteReg((BYTE)MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN);
246 WriteReg((BYTE)MABBIPG, 0x12);
247 #endif
248
249 // Allow infinite deferals if the medium is continuously busy
250 // (do not time out a transmission if the half duplex medium is
251 // completely saturated with other people's data)
252 WriteReg((BYTE)MACON4, MACON4_DEFER);
253
254 // Late collisions occur beyond 63+8 bytes (8 bytes for preamble/start of frame delimiter)
255 // 55 is all that is needed for IEEE 802.3, but ENC28J60 B5 errata for improper link pulse
256 // collisions will occur less often with a larger number.
257 WriteReg((BYTE)MACLCON2, 63);
258
259 // Set non-back-to-back inter-packet gap to 9.6us. The back-to-back
260 // inter-packet gap (MABBIPG) is set by MACSetDuplex() which is called
261 // later.
262 WriteReg((BYTE)MAIPGL, 0x12);
263 WriteReg((BYTE)MAIPGH, 0x0C);
264
265 // Set the maximum packet size which the controller will accept
266 WriteReg((BYTE)MAMXFLL, LOW(6+6+2+1500+4)); // 1518 is the IEEE 802.3 specified limit
267 WriteReg((BYTE)MAMXFLH, HIGH(6+6+2+1500+4)); // 1518 is the IEEE 802.3 specified limit
268
269 // Enter Bank 3 and initialize physical MAC address registers
270 BankSel(MAADR1);
271 WriteReg((BYTE)MAADR1, AppConfig.MyMACAddr.v[0]);
272 WriteReg((BYTE)MAADR2, AppConfig.MyMACAddr.v[1]);
273 WriteReg((BYTE)MAADR3, AppConfig.MyMACAddr.v[2]);
274 WriteReg((BYTE)MAADR4, AppConfig.MyMACAddr.v[3]);
275 WriteReg((BYTE)MAADR5, AppConfig.MyMACAddr.v[4]);
276 WriteReg((BYTE)MAADR6, AppConfig.MyMACAddr.v[5]);
277
278 // Disable the CLKOUT output to reduce EMI generation
279 WriteReg((BYTE)ECOCON, 0x00); // Output off (0V)
280 //WriteReg((BYTE)ECOCON, 0x01); // 25.000MHz
281 //WriteReg((BYTE)ECOCON, 0x03); // 8.3333MHz (*4 with PLL is 33.3333MHz)
282
283 // Get the Rev ID so that we can implement the correct errata workarounds
284 ENCRevID = ReadETHReg((BYTE)EREVID).Val;
285
286 // Disable half duplex loopback in PHY. Bank bits changed to Bank 2 as a
287 // side effect.
288 WritePHYReg(PHCON2, PHCON2_HDLDIS);
289
290 // Configure LEDA to display LINK status, LEDB to display TX/RX activity
291 SetLEDConfig(0x3472);
292
293 // Set the MAC and PHY into the proper duplex state
294 #if defined(FULL_DUPLEX)
295 WritePHYReg(PHCON1, PHCON1_PDPXMD);
296 #elif defined(HALF_DUPLEX)
297 WritePHYReg(PHCON1, 0x0000);
298 #else
299 // Use the external LEDB polarity to determine weather full or half duplex
300 // communication mode should be set.
301 {
302 REG Register;
303 PHYREG PhyReg;
304
305 // Read the PHY duplex mode
306 PhyReg = ReadPHYReg(PHCON1);
307 DuplexState = PhyReg.PHCON1bits.PDPXMD;
308
309 // Set the MAC to the proper duplex mode
310 BankSel(MACON3);
311 Register = ReadMACReg((BYTE)MACON3);
312 Register.MACON3bits.FULDPX = PhyReg.PHCON1bits.PDPXMD;
313 WriteReg((BYTE)MACON3, Register.Val);
314
315 // Set the back-to-back inter-packet gap time to IEEE specified
316 // requirements. The meaning of the MABBIPG value changes with the duplex
317 // state, so it must be updated in this function.
318 // In full duplex, 0x15 represents 9.6us; 0x12 is 9.6us in half duplex
319 WriteReg((BYTE)MABBIPG, PhyReg.PHCON1bits.PDPXMD ? 0x15 : 0x12);
320 }
321 #endif
322
323 BankSel(ERDPTL); // Return to default Bank 0
324
325 // Enable packet reception
326 BFSReg(ECON1, ECON1_RXEN);
327 }//end MACInit
328
329
330 /******************************************************************************
331 * Function: BOOL MACIsLinked(void)
332 *
333 * PreCondition: None
334 *
335 * Input: None
336 *
337 * Output: TRUE: If the PHY reports that a link partner is present
338 * and the link has been up continuously since the last
339 * call to MACIsLinked()
340 * FALSE: If the PHY reports no link partner, or the link went
341 * down momentarily since the last call to MACIsLinked()
342 *
343 * Side Effects: None
344 *
345 * Overview: Returns the PHSTAT1.LLSTAT bit.
346 *
347 * Note: None
348 *****************************************************************************/
349 BOOL MACIsLinked(void)
350 {
351 // LLSTAT is a latching low link status bit. Therefore, if the link
352 // goes down and comes back up before a higher level stack program calls
353 // MACIsLinked(), MACIsLinked() will still return FALSE. The next
354 // call to MACIsLinked() will return TRUE (unless the link goes down
355 // again).
356 return ReadPHYReg(PHSTAT1).PHSTAT1bits.LLSTAT;
357 }
358
359
360 /******************************************************************************
361 * Function: BOOL MACIsTxReady(void)
362 *
363 * PreCondition: None
364 *
365 * Input: None
366 *
367 * Output: TRUE: If no Ethernet transmission is in progress
368 * FALSE: If a previous transmission was started, and it has
369 * not completed yet. While FALSE, the data in the
370 * transmit buffer and the TXST/TXND pointers must not
371 * be changed.
372 *
373 * Side Effects: None
374 *
375 * Overview: Returns the ECON1.TXRTS bit
376 *
377 * Note: None
378 *****************************************************************************/
379 BOOL MACIsTxReady(void)
380 {
381 return !ReadETHReg(ECON1).ECON1bits.TXRTS;
382 }
383
384
385 /******************************************************************************
386 * Function: void MACDiscardRx(void)
387 *
388 * PreCondition: None
389 *
390 * Input: None
391 *
392 * Output: None
393 *
394 * Side Effects: None
395 *
396 * Overview: Marks the last received packet (obtained using
397 * MACGetHeader())as being processed and frees the buffer
398 * memory associated with it
399 *
400 * Note: None
401 *****************************************************************************/
402 void MACDiscardRx(void)
403 {
404 WORD_VAL NewRXRDLocation;
405
406 // Make sure the current packet was not already discarded
407 if(WasDiscarded)
408 return;
409 WasDiscarded = TRUE;
410
411 // Decrement the next packet pointer before writing it into
412 // the ERXRDPT registers. This is a silicon errata workaround.
413 // RX buffer wrapping must be taken into account if the
414 // NextPacketLocation is precisely RXSTART.
415 NewRXRDLocation.Val = NextPacketLocation.Val - 1;
416 if(NewRXRDLocation.Val > RXSTOP)
417 {
418 NewRXRDLocation.Val = RXSTOP;
419 }
420
421 // Decrement the RX packet counter register, EPKTCNT
422 BFSReg(ECON2, ECON2_PKTDEC);
423
424 // Move the receive read pointer to unwrite-protect the memory used by the
425 // last packet. The writing order is important: set the low byte first,
426 // high byte last.
427 WriteReg(ERXRDPTL, NewRXRDLocation.v[0]);
428 WriteReg(ERXRDPTH, NewRXRDLocation.v[1]);
429 }
430
431
432 /******************************************************************************
433 * Function: WORD MACGetFreeRxSize(void)
434 *
435 * PreCondition: None
436 *
437 * Input: None
438 *
439 * Output: A WORD estimate of how much RX buffer space is free at
440 * the present time.
441 *
442 * Side Effects: None
443 *
444 * Overview: None
445 *
446 * Note: None
447 *****************************************************************************/
448 WORD MACGetFreeRxSize(void)
449 {
450 WORD_VAL ReadPT, WritePT;
451
452 // Read the Ethernet hardware buffer write pointer. Because packets can be
453 // received at any time, it can change between reading the low and high
454 // bytes. A loop is necessary to make certain a proper low/high byte pair
455 // is read.
456 BankSel(EPKTCNT);
457 do {
458 // Save EPKTCNT in a temporary location
459 ReadPT.v[0] = ReadETHReg((BYTE)EPKTCNT).Val;
460
461 BankSel(ERXWRPTL);
462 WritePT.v[0] = ReadETHReg(ERXWRPTL).Val;
463 WritePT.v[1] = ReadETHReg(ERXWRPTH).Val;
464
465 BankSel(EPKTCNT);
466 } while(ReadETHReg((BYTE)EPKTCNT).Val != ReadPT.v[0]);
467
468 // Determine where the write protection pointer is
469 BankSel(ERXRDPTL);
470 ReadPT.v[0] = ReadETHReg(ERXRDPTL).Val;
471 ReadPT.v[1] = ReadETHReg(ERXRDPTH).Val;
472
473 // Calculate the difference between the pointers, taking care to account
474 // for buffer wrapping conditions
475 if(WritePT.Val > ReadPT.Val)
476 {
477 return (RXSTOP - RXSTART) - (WritePT.Val - ReadPT.Val);
478 }
479 else if(WritePT.Val == ReadPT.Val)
480 {
481 return RXSIZE - 1;
482 }
483 else
484 {
485 return ReadPT.Val - WritePT.Val - 1;
486 }
487 }
488
489 /******************************************************************************
490 * Function: BOOL MACGetHeader(MAC_ADDR *remote, BYTE* type)
491 *
492 * PreCondition: None
493 *
494 * Input: *remote: Location to store the Source MAC address of the
495 * received frame.
496 * *type: Location of a BYTE to store the constant
497 * MAC_UNKNOWN, ETHER_IP, or ETHER_ARP, representing
498 * the contents of the Ethernet type field.
499 *
500 * Output: TRUE: If a packet was waiting in the RX buffer. The
501 * remote, and type values are updated.
502 * FALSE: If a packet was not pending. remote and type are
503 * not changed.
504 *
505 * Side Effects: Last packet is discarded if MACDiscardRx() hasn't already
506 * been called.
507 *
508 * Overview: None
509 *
510 * Note: None
511 *****************************************************************************/
512 BOOL MACGetHeader(MAC_ADDR *remote, BYTE* type)
513 {
514 ENC_PREAMBLE header;
515 BYTE PacketCount;
516
517 // Test if at least one packet has been received and is waiting
518 BankSel(EPKTCNT);
519 PacketCount = ReadETHReg((BYTE)EPKTCNT).Val;
520 BankSel(ERDPTL);
521 if(PacketCount == 0u)
522 return FALSE;
523
524 // Make absolutely certain that any previous packet was discarded
525 if(WasDiscarded == FALSE)
526 {
527 MACDiscardRx();
528 return FALSE;
529 }
530
531 // Set the SPI read pointer to the beginning of the next unprocessed packet
532 CurrentPacketLocation.Val = NextPacketLocation.Val;
533 WriteReg(ERDPTL, CurrentPacketLocation.v[0]);
534 WriteReg(ERDPTH, CurrentPacketLocation.v[1]);
535
536 // Obtain the MAC header from the Ethernet buffer
537 MACGetArray((BYTE*)&header, sizeof(header));
538
539 // The EtherType field, like most items transmitted on the Ethernet medium
540 // are in big endian.
541 header.Type.Val = swaps(header.Type.Val);
542
543 // Validate the data returned from the ENC28J60. Random data corruption,
544 // such as if a single SPI bit error occurs while communicating or a
545 // momentary power glitch could cause this to occur in rare circumstances.
546 if(header.NextPacketPointer > RXSTOP || ((BYTE_VAL*)(&header.NextPacketPointer))->bits.b0 ||
547 header.StatusVector.bits.Zero ||
548 header.StatusVector.bits.CRCError ||
549 header.StatusVector.bits.ByteCount > 1518u ||
550 !header.StatusVector.bits.ReceiveOk)
551 {
552 Reset();
553 }
554
555 // Save the location where the hardware will write the next packet to
556 NextPacketLocation.Val = header.NextPacketPointer;
557
558 // Return the Ethernet frame's Source MAC address field to the caller
559 // This parameter is useful for replying to requests without requiring an
560 // ARP cycle.
561 memcpy((void*)remote->v, (void*)header.SourceMACAddr.v, sizeof(*remote));
562
563 // Return a simplified version of the EtherType field to the caller
564 *type = MAC_UNKNOWN;
565 if( (header.Type.v[1] == 0x08u) &&
566 ((header.Type.v[0] == ETHER_IP) || (header.Type.v[0] == ETHER_ARP)) )
567 {
568 *type = header.Type.v[0];
569 }
570
571 // Mark this packet as discardable
572 WasDiscarded = FALSE;
573 return TRUE;
574 }
575
576
577 /******************************************************************************
578 * Function: void MACPutHeader(MAC_ADDR *remote, BYTE type, WORD dataLen)
579 *
580 * PreCondition: MACIsTxReady() must return TRUE.
581 *
582 * Input: *remote: Pointer to memory which contains the destination
583 * MAC address (6 bytes)
584 * type: The constant ETHER_ARP or ETHER_IP, defining which
585 * value to write into the Ethernet header's type field.
586 * dataLen: Length of the Ethernet data payload
587 *
588 * Output: None
589 *
590 * Side Effects: None
591 *
592 * Overview: None
593 *
594 * Note: Because of the dataLen parameter, it is probably
595 * advantagous to call this function immediately before
596 * transmitting a packet rather than initially when the
597 * packet is first created. The order in which the packet
598 * is constructed (header first or data first) is not
599 * important.
600 *****************************************************************************/
601 void MACPutHeader(MAC_ADDR *remote, BYTE type, WORD dataLen)
602 {
603 // Set the SPI write pointer to the beginning of the transmit buffer (post per packet control byte)
604 WriteReg(EWRPTL, LOW(TXSTART+1));
605 WriteReg(EWRPTH, HIGH(TXSTART+1));
606
607 // Calculate where to put the TXND pointer
608 dataLen += (WORD)sizeof(ETHER_HEADER) + TXSTART;
609
610 // Write the TXND pointer into the registers, given the dataLen given
611 WriteReg(ETXNDL, ((WORD_VAL*)&dataLen)->v[0]);
612 WriteReg(ETXNDH, ((WORD_VAL*)&dataLen)->v[1]);
613
614 // Set the per-packet control byte and write the Ethernet destination
615 // address
616 MACPutArray((BYTE*)remote, sizeof(*remote));
617
618 // Write our MAC address in the Ethernet source field
619 MACPutArray((BYTE*)&AppConfig.MyMACAddr, sizeof(AppConfig.MyMACAddr));
620
621 // Write the appropriate Ethernet Type WORD for the protocol being used
622 MACPut(0x08);
623 MACPut((type == MAC_IP) ? ETHER_IP : ETHER_ARP);
624 }
625
626 /******************************************************************************
627 * Function: void MACFlush(void)
628 *
629 * PreCondition: A packet has been created by calling MACPut() and
630 * MACPutHeader().
631 *
632 * Input: None
633 *
634 * Output: None
635 *
636 * Side Effects: None
637 *
638 * Overview: MACFlush causes the current TX packet to be sent out on
639 * the Ethernet medium. The hardware MAC will take control
640 * and handle CRC generation, collision retransmission and
641 * other details.
642 *
643 * Note: After transmission completes (MACIsTxReady() returns TRUE),
644 * the packet can be modified and transmitted again by calling
645 * MACFlush() again. Until MACPutHeader() or MACPut() is
646 * called (in the TX data area), the data in the TX buffer
647 * will not be corrupted.
648 *****************************************************************************/
649 void MACFlush(void)
650 {
651 // Reset transmit logic if a TX Error has previously occured
652 // This is a silicon errata workaround
653 BFSReg(ECON1, ECON1_TXRST);
654 BFCReg(ECON1, ECON1_TXRST);
655 BFCReg(EIR, EIR_TXERIF | EIR_TXIF);
656
657 // Start the transmission
658 // After transmission completes (MACIsTxReady() returns TRUE), the packet
659 // can be modified and transmitted again by calling MACFlush() again.
660 // Until MACPutHeader() is called, the data in the TX buffer will not be
661 // corrupted.
662 BFSReg(ECON1, ECON1_TXRTS);
663
664 // Revision B5 and B7 silicon errata workaround
665 if(ENCRevID == 0x05u || ENCRevID == 0x06u)
666 {
667 WORD AttemptCounter = 0x0000;
668 while(!(ReadETHReg(EIR).Val & (EIR_TXERIF | EIR_TXIF)) && (++AttemptCounter < 1000));
669 if(ReadETHReg(EIR).EIRbits.TXERIF || (AttemptCounter >= 1000))
670 {
671 WORD_VAL ReadPtrSave;
672 WORD_VAL TXEnd;
673 TXSTATUS TXStatus;
674 BYTE i;
675
676 // Cancel the previous transmission if it has become stuck set
677 BFCReg(ECON1, ECON1_TXRTS);
678
679 // Save the current read pointer (controlled by application)
680 ReadPtrSave.v[0] = ReadETHReg(ERDPTL).Val;
681 ReadPtrSave.v[1] = ReadETHReg(ERDPTH).Val;
682
683 // Get the location of the transmit status vector
684 TXEnd.v[0] = ReadETHReg(ETXNDL).Val;
685 TXEnd.v[1] = ReadETHReg(ETXNDH).Val;
686 TXEnd.Val++;
687
688 // Read the transmit status vector
689 WriteReg(ERDPTL, TXEnd.v[0]);
690 WriteReg(ERDPTH, TXEnd.v[1]);
691 MACGetArray((BYTE*)&TXStatus, sizeof(TXStatus));
692
693 // Implement retransmission if a late collision occured (this can
694 // happen on B5 when certain link pulses arrive at the same time
695 // as the transmission)
696 for(i = 0; i < 16u; i++)
697 {
698 if(ReadETHReg(EIR).EIRbits.TXERIF && TXStatus.bits.LateCollision)
699 {
700 // Reset the TX logic
701 BFSReg(ECON1, ECON1_TXRST);
702 BFCReg(ECON1, ECON1_TXRST);
703 BFCReg(EIR, EIR_TXERIF | EIR_TXIF);
704
705 // Transmit the packet again
706 BFSReg(ECON1, ECON1_TXRTS);
707 while(!(ReadETHReg(EIR).Val & (EIR_TXERIF | EIR_TXIF)));
708
709 // Cancel the previous transmission if it has become stuck set
710 BFCReg(ECON1, ECON1_TXRTS);
711
712 // Read transmit status vector
713 WriteReg(ERDPTL, TXEnd.v[0]);
714 WriteReg(ERDPTH, TXEnd.v[1]);
715 MACGetArray((BYTE*)&TXStatus, sizeof(TXStatus));
716 }
717 else
718 {
719 break;
720 }
721 }
722
723 // Restore the current read pointer
724 WriteReg(ERDPTL, ReadPtrSave.v[0]);
725 WriteReg(ERDPTH, ReadPtrSave.v[1]);
726 }
727 }
728 }
729
730
731 /******************************************************************************
732 * Function: void MACSetReadPtrInRx(WORD offset)
733 *
734 * PreCondition: A packet has been obtained by calling MACGetHeader() and
735 * getting a TRUE result.
736 *
737 * Input: offset: WORD specifying how many bytes beyond the Ethernet
738 * header's type field to relocate the SPI read
739 * pointer.
740 *
741 * Output: None
742 *
743 * Side Effects: None
744 *
745 * Overview: SPI read pointer are updated. All calls to
746 * MACGet() and MACGetArray() will use these new values.
747 *
748 * Note: RXSTOP must be statically defined as being > RXSTART for
749 * this function to work correctly. In other words, do not
750 * define an RX buffer which spans the 0x1FFF->0x0000 memory
751 * boundary.
752 *****************************************************************************/
753 void MACSetReadPtrInRx(WORD offset)
754 {
755 WORD_VAL ReadPT;
756
757 // Determine the address of the beginning of the entire packet
758 // and adjust the address to the desired location
759 ReadPT.Val = CurrentPacketLocation.Val + sizeof(ENC_PREAMBLE) + offset;
760
761 // Since the receive buffer is circular, adjust if a wraparound is needed
762 if(ReadPT.Val > RXSTOP)
763 ReadPT.Val -= RXSIZE;
764
765 // Set the SPI read pointer to the new calculated value
766 WriteReg(ERDPTL, ReadPT.v[0]);
767 WriteReg(ERDPTH, ReadPT.v[1]);
768 }
769
770
771 /******************************************************************************
772 * Function: WORD MACSetWritePtr(WORD Address)
773 *
774 * PreCondition: None
775 *
776 * Input: Address: Address to seek to
777 *
778 * Output: WORD: Old EWRPT location
779 *
780 * Side Effects: None
781 *
782 * Overview: SPI write pointer is updated. All calls to
783 * MACPut() and MACPutArray() will use this new value.
784 *
785 * Note: None
786 *****************************************************************************/
787 WORD MACSetWritePtr(WORD address)
788 {
789 WORD_VAL oldVal;
790
791 oldVal.v[0] = ReadETHReg(EWRPTL).Val;
792 oldVal.v[1] = ReadETHReg(EWRPTH).Val;
793
794 // Set the SPI write pointer to the new calculated value
795 WriteReg(EWRPTL, ((WORD_VAL*)&address)->v[0]);
796 WriteReg(EWRPTH, ((WORD_VAL*)&address)->v[1]);
797
798 return oldVal.Val;
799 }
800
801 /******************************************************************************
802 * Function: WORD MACSetReadPtr(WORD Address)
803 *
804 * PreCondition: None
805 *
806 * Input: Address: Address to seek to
807 *
808 * Output: WORD: Old ERDPT value
809 *
810 * Side Effects: None
811 *
812 * Overview: SPI write pointer is updated. All calls to
813 * MACPut() and MACPutArray() will use this new value.
814 *
815 * Note: None
816 *****************************************************************************/
817 WORD MACSetReadPtr(WORD address)
818 {
819 WORD_VAL oldVal;
820
821 oldVal.v[0] = ReadETHReg(ERDPTL).Val;
822 oldVal.v[1] = ReadETHReg(ERDPTH).Val;
823
824 // Set the SPI write pointer to the new calculated value
825 WriteReg(ERDPTL, ((WORD_VAL*)&address)->v[0]);
826 WriteReg(ERDPTH, ((WORD_VAL*)&address)->v[1]);
827
828 return oldVal.Val;
829 }
830
831
832 /******************************************************************************
833 * Function: WORD MACCalcRxChecksum(WORD offset, WORD len)
834 *
835 * PreCondition: None
836 *
837 * Input: offset - Number of bytes beyond the beginning of the
838 * Ethernet data (first byte after the type field)
839 * where the checksum should begin
840 * len - Total number of bytes to include in the checksum
841 *
842 * Output: 16-bit checksum as defined by RFC 793.
843 *
844 * Side Effects: None
845 *
846 * Overview: This function performs a checksum calculation in the MAC
847 * buffer itself
848 *
849 * Note: None
850 *****************************************************************************/
851 WORD MACCalcRxChecksum(WORD offset, WORD len)
852 {
853 WORD_VAL temp;
854 WORD_VAL RDSave;
855
856 // Add the offset requested by firmware plus the Ethernet header
857 temp.Val = CurrentPacketLocation.Val + sizeof(ENC_PREAMBLE) + offset;
858 if(temp.Val > RXSTOP) // Adjust value if a wrap is needed
859 {
860 temp.Val -= RXSIZE;
861 }
862
863 RDSave.v[0] = ReadETHReg(ERDPTL).Val;
864 RDSave.v[1] = ReadETHReg(ERDPTH).Val;
865
866 WriteReg(ERDPTL, temp.v[0]);
867 WriteReg(ERDPTH, temp.v[1]);
868
869 temp.Val = CalcIPBufferChecksum(len);
870
871 WriteReg(ERDPTL, RDSave.v[0]);
872 WriteReg(ERDPTH, RDSave.v[1]);
873
874 return temp.Val;
875 }
876
877
878 /******************************************************************************
879 * Function: WORD CalcIPBufferChecksum(WORD len)
880 *
881 * PreCondition: Read buffer pointer set to starting of checksum data
882 *
883 * Input: len: Total number of bytes to calculate the checksum over.
884 * The first byte included in the checksum is the byte
885 * pointed to by ERDPT, which is updated by calls to
886 * MACSetReadPtr(), MACGet(), MACGetArray(),
887 * MACGetHeader(), etc.
888 *
889 * Output: 16-bit checksum as defined by RFC 793
890 *
891 * Side Effects: None
892 *
893 * Overview: This function performs a checksum calculation in the MAC
894 * buffer itself. The ENC28J60 has a hardware DMA module
895 * which can calculate the checksum faster than software, so
896 * this function replaces the CaclIPBufferChecksum() function
897 * defined in the helpers.c file. Through the use of
898 * preprocessor defines, this replacement is automatic.
899 *
900 * Note: This function works either in the RX buffer area or the TX
901 * buffer area. No validation is done on the len parameter.
902 *****************************************************************************/
903 WORD CalcIPBufferChecksum(WORD len)
904 {
905 WORD_VAL Start;
906 DWORD_VAL Checksum = {0x00000000ul};
907 WORD ChunkLen;
908 BYTE DataBuffer[20]; // Must be an even size
909 WORD *DataPtr;
910
911 // Save the SPI read pointer starting address
912 Start.v[0] = ReadETHReg(ERDPTL).Val;
913 Start.v[1] = ReadETHReg(ERDPTH).Val;
914
915 while(len)
916 {
917 // Obtain a chunk of data (less SPI overhead compared
918 // to requesting one byte at a time)
919 ChunkLen = len > sizeof(DataBuffer) ? sizeof(DataBuffer) : len;
920 MACGetArray(DataBuffer, ChunkLen);
921
922 len -= ChunkLen;
923
924 // Take care of a last odd numbered data byte
925 if(((WORD_VAL*)&ChunkLen)->bits.b0)
926 {
927 DataBuffer[ChunkLen] = 0x00;
928 ChunkLen++;
929 }
930
931 // Calculate the checksum over this chunk
932 DataPtr = (WORD*)&DataBuffer[0];
933 while(ChunkLen)
934 {
935 Checksum.Val += *DataPtr++;
936 ChunkLen -= 2;
937 }
938 }
939
940 // Restore old read pointer location
941 WriteReg(ERDPTL, Start.v[0]);
942 WriteReg(ERDPTH, Start.v[1]);
943
944 // Do an end-around carry (one's complement arrithmatic)
945 Checksum.Val = (DWORD)Checksum.w[0] + (DWORD)Checksum.w[1];
946
947 // Do another end-around carry in case if the prior add
948 // caused a carry out
949 Checksum.w[0] += Checksum.w[1];
950
951 // Return the resulting checksum
952 return ~Checksum.w[0];
953 }
954
955
956 /******************************************************************************
957 * Function: void MACMemCopyAsync(WORD destAddr, WORD sourceAddr, WORD len)
958 *
959 * PreCondition: SPI bus must be initialized (done in MACInit()).
960 *
961 * Input: destAddr: Destination address in the Ethernet memory to
962 * copy to. If the MSb is set, the current EWRPT
963 * value will be used instead.
964 * sourceAddr: Source address to read from. If the MSb is
965 * set, the current ERDPT value will be used
966 * instead.
967 * len: Number of bytes to copy
968 *
969 * Output: Byte read from the ENC28J60's RAM
970 *
971 * Side Effects: None
972 *
973 * Overview: Bytes are asynchrnously transfered within the buffer. Call
974 * MACIsMemCopyDone() to see when the transfer is complete.
975 *
976 * Note: If a prior transfer is already in progress prior to
977 * calling this function, this function will block until it
978 * can start this transfer.
979 *
980 * If a negative value is used for the sourceAddr or destAddr
981 * parameters, then that pointer will get updated with the
982 * next address after the read or write.
983 *****************************************************************************/
984 void MACMemCopyAsync(WORD destAddr, WORD sourceAddr, WORD len)
985 {
986 WORD_VAL ReadSave, WriteSave;
987 BOOL UpdateWritePointer = FALSE;
988 BOOL UpdateReadPointer = FALSE;
989
990 if(((WORD_VAL*)&destAddr)->bits.b15)
991 {
992 UpdateWritePointer = TRUE;
993 ((WORD_VAL*)&destAddr)->v[0] = ReadETHReg(EWRPTL).Val;
994 ((WORD_VAL*)&destAddr)->v[1] = ReadETHReg(EWRPTH).Val;
995 }
996 if(((WORD_VAL*)&sourceAddr)->bits.b15)
997 {
998 UpdateReadPointer = TRUE;
999 ((WORD_VAL*)&sourceAddr)->v[0] = ReadETHReg(ERDPTL).Val;
1000 ((WORD_VAL*)&sourceAddr)->v[1] = ReadETHReg(ERDPTH).Val;
1001 }
1002
1003 // Handle special conditions where len == 0 or len == 1
1004 // The DMA module is not capable of handling those corner cases
1005 if(len <= 1u)
1006 {
1007 if(!UpdateReadPointer)
1008 {
1009 ReadSave.v[0] = ReadETHReg(ERDPTL).Val;
1010 ReadSave.v[1] = ReadETHReg(ERDPTH).Val;
1011 }
1012 if(!UpdateWritePointer)
1013 {
1014 WriteSave.v[0] = ReadETHReg(EWRPTL).Val;
1015 WriteSave.v[1] = ReadETHReg(EWRPTH).Val;
1016 }
1017 WriteReg(ERDPTL, ((WORD_VAL*)&sourceAddr)->v[0]);
1018 WriteReg(ERDPTH, ((WORD_VAL*)&sourceAddr)->v[1]);
1019 WriteReg(EWRPTL, ((WORD_VAL*)&destAddr)->v[0]);
1020 WriteReg(EWRPTH, ((WORD_VAL*)&destAddr)->v[1]);
1021 while(len--)
1022 MACPut(MACGet());
1023 if(!UpdateReadPointer)
1024 {
1025 WriteReg(ERDPTL, ReadSave.v[0]);
1026 WriteReg(ERDPTH, ReadSave.v[1]);
1027 }
1028 if(!UpdateWritePointer)
1029 {
1030 WriteReg(EWRPTL, WriteSave.v[0]);
1031 WriteReg(EWRPTH, WriteSave.v[1]);
1032 }
1033 }
1034 else
1035 {
1036 if(UpdateWritePointer)
1037 {
1038 WriteSave.Val = destAddr + len;
1039 WriteReg(EWRPTL, WriteSave.v[0]);
1040 WriteReg(EWRPTH, WriteSave.v[1]);
1041 }
1042 len += sourceAddr - 1;
1043 while(ReadETHReg(ECON1).ECON1bits.DMAST);
1044 WriteReg(EDMASTL, ((WORD_VAL*)&sourceAddr)->v[0]);
1045 WriteReg(EDMASTH, ((WORD_VAL*)&sourceAddr)->v[1]);
1046 WriteReg(EDMADSTL, ((WORD_VAL*)&destAddr)->v[0]);
1047 WriteReg(EDMADSTH, ((WORD_VAL*)&destAddr)->v[1]);
1048 if((sourceAddr <= RXSTOP) && (len > RXSTOP)) //&& (sourceAddr >= RXSTART))
1049 len -= RXSIZE;
1050 WriteReg(EDMANDL, ((WORD_VAL*)&len)->v[0]);
1051 WriteReg(EDMANDH, ((WORD_VAL*)&len)->v[1]);
1052 BFCReg(ECON1, ECON1_CSUMEN);
1053 BFSReg(ECON1, ECON1_DMAST);
1054 if(UpdateReadPointer)
1055 {
1056 len++;
1057 if((sourceAddr <= RXSTOP) && (len > RXSTOP)) //&& (sourceAddr >= RXSTART))
1058 len -= RXSIZE;
1059 WriteReg(ERDPTL, ((WORD_VAL*)&len)->v[0]);
1060 WriteReg(ERDPTH, ((WORD_VAL*)&len)->v[1]);
1061 }
1062 }
1063 }
1064
1065 BOOL MACIsMemCopyDone(void)
1066 {
1067 return !ReadETHReg(ECON1).ECON1bits.DMAST;
1068 }
1069
1070
1071 /******************************************************************************
1072 * Function: BYTE MACGet()
1073 *
1074 * PreCondition: SPI bus must be initialized (done in MACInit()).
1075 * ERDPT must point to the place to read from.
1076 *
1077 * Input: None
1078 *
1079 * Output: Byte read from the ENC28J60's RAM
1080 *
1081 * Side Effects: None
1082 *
1083 * Overview: MACGet returns the byte pointed to by ERDPT and
1084 * increments ERDPT so MACGet() can be called again. The
1085 * increment will follow the receive buffer wrapping boundary.
1086 *
1087 * Note: None
1088 *****************************************************************************/
1089 BYTE MACGet()
1090 {
1091 BYTE Result;
1092
1093 ENC_CS_IO = 0;
1094 ENC_SPI_IF = 0;
1095 ENC_SSPBUF = RBM;
1096 while(!ENC_SPI_IF); // Wait until opcode/address is transmitted.
1097 Result = ENC_SSPBUF;
1098 ENC_SPI_IF = 0;
1099 ENC_SSPBUF = 0; // Send a dummy byte to receive the register
1100 // contents.
1101 while(!ENC_SPI_IF); // Wait until register is received.
1102 Result = ENC_SSPBUF;
1103 ENC_SPI_IF = 0;
1104 ENC_CS_IO = 1;
1105
1106 return Result;
1107 }//end MACGet
1108
1109
1110 /******************************************************************************
1111 * Function: WORD MACGetArray(BYTE *val, WORD len)
1112 *
1113 * PreCondition: SPI bus must be initialized (done in MACInit()).
1114 * ERDPT must point to the place to read from.
1115 *
1116 * Input: *val: Pointer to storage location
1117 * len: Number of bytes to read from the data buffer.
1118 *
1119 * Output: Byte(s) of data read from the data buffer.
1120 *
1121 * Side Effects: None
1122 *
1123 * Overview: Burst reads several sequential bytes from the data buffer
1124 * and places them into local memory. With SPI burst support,
1125 * it performs much faster than multiple MACGet() calls.
1126 * ERDPT is incremented after each byte, following the same
1127 * rules as MACGet().
1128 *
1129 * Note: None
1130 *****************************************************************************/
1131 WORD MACGetArray(BYTE *val, WORD len)
1132 {
1133 // Debug
1134 #if defined(__18F8722) || defined(_18F8722) || \
1135 defined(__18F8627) || defined(_18F8627) || \
1136 defined(__18F8622) || defined(_18F8622) || \
1137 defined(__18F8572) || defined(_18F8572) || \
1138 defined(__18F6722) || defined(_18F6722) || \
1139 defined(__18F6627) || defined(_18F6627) || \
1140 defined(__18F6622) || defined(_18F6622) || \
1141 defined(__18F6527) || defined(_18F6527)
1142 WORD i;
1143 BYTE Dummy;
1144
1145 i = len;
1146 Dummy = 0xFF;
1147 while(i--)
1148 {
1149 if(((BYTE_VAL*)&Dummy)->bits.b0)
1150 {
1151 // End bust operation
1152 ENC_CS_IO = 1;
1153 ((BYTE_VAL*)&Dummy)->bits.b0 = 0;
1154
1155 // Start the burst operation
1156 ENC_CS_IO = 0;
1157 ENC_SPI_IF = 0;
1158 ENC_SSPBUF = RBM; // Send the Read Buffer Memory opcode.
1159 while(!ENC_SPI_IF); // Wait until opcode/address is transmitted.
1160 }
1161 else
1162 Dummy = 0xFF;
1163
1164 ENC_SPI_IF = 0;
1165 ENC_SSPBUF = 0; // Send a dummy byte to receive a byte
1166 if(val)
1167 {
1168 while(!ENC_SPI_IF); // Wait until byte is received.
1169 *val++ = ENC_SSPBUF;
1170 }
1171 else
1172 while(!ENC_SPI_IF); // Wait until byte is received.
1173 }
1174
1175 ENC_CS_IO = 1;
1176 ENC_SPI_IF = 0;
1177
1178 return len;
1179 #else
1180 WORD i;
1181 BYTE Dummy;
1182
1183 // Start the burst operation
1184 ENC_CS_IO = 0;
1185 ENC_SPI_IF = 0;
1186 ENC_SSPBUF = RBM; // Send the Read Buffer Memory opcode.
1187 i = 0;
1188 val--;
1189 while(!ENC_SPI_IF); // Wait until opcode/address is transmitted.
1190 Dummy = ENC_SSPBUF;
1191 ENC_SPI_IF = 0;
1192
1193 // Read the data
1194 while(i<len)
1195 {
1196 ENC_SSPBUF = 0; // Send a dummy byte to receive a byte
1197 i++;
1198 if(val)
1199 {
1200 val++;
1201 while(!ENC_SPI_IF); // Wait until byte is received.
1202 *val = ENC_SSPBUF;
1203 }
1204 else
1205 {
1206 while(!ENC_SPI_IF); // Wait until byte is received.
1207 Dummy = ENC_SSPBUF;
1208 }
1209 ENC_SPI_IF = 0;
1210 };
1211
1212 // Terminate the burst operation
1213 ENC_CS_IO = 1;
1214
1215 return i;
1216 #endif
1217 }//end MACGetArray
1218
1219
1220 /******************************************************************************
1221 * Function: void MACPut(BYTE val)
1222 *
1223 * PreCondition: SPI bus must be initialized (done in MACInit()).
1224 * EWRPT must point to the location to begin writing.
1225 *
1226 * Input: Byte to write into the ENC28J60 buffer memory
1227 *
1228 * Output: None
1229 *
1230 * Side Effects: None
1231 *
1232 * Overview: MACPut outputs the Write Buffer Memory opcode/constant
1233 * (8 bits) and data to write (8 bits) over the SPI.
1234 * EWRPT is incremented after the write.
1235 *
1236 * Note: None
1237 *****************************************************************************/
1238 void MACPut(BYTE val)
1239 {
1240 BYTE Dummy;
1241
1242 ENC_CS_IO = 0;
1243 ENC_SPI_IF = 0;
1244 ENC_SSPBUF = WBM; // Send the opcode and constant.
1245 while(!ENC_SPI_IF); // Wait until opcode/constant is transmitted.
1246 Dummy = ENC_SSPBUF;
1247 ENC_SPI_IF = 0;
1248 ENC_SSPBUF = val; // Send the byte to be writen.
1249 while(!ENC_SPI_IF); // Wait until byte is transmitted.
1250 Dummy = ENC_SSPBUF;
1251 ENC_SPI_IF = 0;
1252 ENC_CS_IO = 1;
1253 }//end MACPut
1254
1255
1256 /******************************************************************************
1257 * Function: void MACPutArray(BYTE *val, WORD len)
1258 *
1259 * PreCondition: SPI bus must be initialized (done in MACInit()).
1260 * EWRPT must point to the location to begin writing.
1261 *
1262 * Input: *val: Pointer to source of bytes to copy.
1263 * len: Number of bytes to write to the data buffer.
1264 *
1265 * Output: None
1266 *
1267 * Side Effects: None
1268 *
1269 * Overview: MACPutArray writes several sequential bytes to the
1270 * ENC28J60 RAM. It performs faster than multiple MACPut()
1271 * calls. EWRPT is incremented by len.
1272 *
1273 * Note: None
1274 *****************************************************************************/
1275 void MACPutArray(BYTE *val, WORD len)
1276 {
1277 // Debug
1278 #if defined(__18F8722) || defined(_18F8722) || \
1279 defined(__18F8627) || defined(_18F8627) || \
1280 defined(__18F8622) || defined(_18F8622) || \
1281 defined(__18F8572) || defined(_18F8572) || \
1282 defined(__18F6722) || defined(_18F6722) || \
1283 defined(__18F6627) || defined(_18F6627) || \
1284 defined(__18F6622) || defined(_18F6622) || \
1285 defined(__18F6527) || defined(_18F6527)
1286 WORD i;
1287 BYTE Dummy;
1288
1289 i = len;
1290 Dummy = 0xFF;
1291 while(i--)
1292 {
1293 if(((BYTE_VAL*)&Dummy)->bits.b0)
1294 {
1295 // End bust operation
1296 ENC_CS_IO = 1;
1297 ((BYTE_VAL*)&Dummy)->bits.b0 = 0;
1298
1299 // Start the burst operation
1300 ENC_CS_IO = 0;
1301 ENC_SPI_IF = 0;
1302 ENC_SSPBUF = WBM; // Send the Read Buffer Memory opcode.
1303 while(!ENC_SPI_IF); // Wait until opcode/address is transmitted.
1304 }
1305 else
1306 Dummy = 0xFF;
1307
1308 ENC_SPI_IF = 0;
1309 ENC_SSPBUF = *val++; // Send byte
1310 while(!ENC_SPI_IF); // Wait until byte is sent
1311 }
1312
1313 ENC_SPI_IF = 0;
1314 ENC_CS_IO = 1;
1315
1316 return;
1317 #else
1318 BYTE Dummy;
1319
1320 // Select the chip and send the proper opcode
1321 ENC_CS_IO = 0;
1322 ENC_SPI_IF = 0;
1323 ENC_SSPBUF = WBM; // Send the Write Buffer Memory opcode
1324 while(!ENC_SPI_IF); // Wait until opcode/constant is transmitted.
1325 Dummy = ENC_SSPBUF;
1326 ENC_SPI_IF = 0;
1327
1328 // Send the data
1329 while(len)
1330 {
1331 ENC_SSPBUF = *val; // Start sending the byte
1332 val++; // Increment after writing to ENC_SSPBUF to increase speed
1333 len--; // Decrement after writing to ENC_SSPBUF to increase speed
1334 while(!ENC_SPI_IF); // Wait until byte is transmitted
1335 Dummy = ENC_SSPBUF;
1336 ENC_SPI_IF = 0;
1337 };
1338
1339 // Terminate the burst operation
1340 ENC_CS_IO = 1;
1341 #endif
1342 }//end MACPutArray
1343
1344
1345 /******************************************************************************
1346 * Function: void MACPutROMArray(ROM BYTE *val, WORD len)
1347 *
1348 * PreCondition: SPI bus must be initialized (done in MACInit()).
1349 * EWRPT must point to the location to begin writing.
1350 *
1351 * Input: *val: Pointer to source of bytes to copy.
1352 * len: Number of bytes to write to the data buffer.
1353 *
1354 * Output: None
1355 *
1356 * Side Effects: None
1357 *
1358 * Overview: MACPutArray writes several sequential bytes to the
1359 * ENC28J60 RAM. It performs faster than multiple MACPut()
1360 * calls. EWRPT is incremented by len.
1361 *
1362 * Note: None
1363 *****************************************************************************/
1364 void MACPutROMArray(ROM BYTE *val, WORD len)
1365 {
1366 // Debug
1367 #if defined(__18F8722) || defined(_18F8722) || \
1368 defined(__18F8627) || defined(_18F8627) || \
1369 defined(__18F8622) || defined(_18F8622) || \
1370 defined(__18F8572) || defined(_18F8572) || \
1371 defined(__18F6722) || defined(_18F6722) || \
1372 defined(__18F6627) || defined(_18F6627) || \
1373 defined(__18F6622) || defined(_18F6622) || \
1374 defined(__18F6527) || defined(_18F6527)
1375 WORD i;
1376 BYTE Dummy;
1377
1378 i = len;
1379 Dummy = 0xFF;
1380 while(i--)
1381 {
1382 if(((BYTE_VAL*)&Dummy)->bits.b0)
1383 {
1384 // End bust operation
1385 ENC_CS_IO = 1;
1386 ((BYTE_VAL*)&Dummy)->bits.b0 = 0;
1387
1388 // Start the burst operation
1389 ENC_CS_IO = 0;
1390 ENC_SPI_IF = 0;
1391 ENC_SSPBUF = WBM; // Send the Read Buffer Memory opcode.
1392 while(!ENC_SPI_IF); // Wait until opcode/address is transmitted.
1393 }
1394 else
1395 Dummy = 0xFF;
1396
1397 ENC_SPI_IF = 0;
1398 ENC_SSPBUF = *val++; // Send byte
1399 while(!ENC_SPI_IF); // Wait until byte is sent
1400 }
1401
1402 ENC_SPI_IF = 0;
1403 ENC_CS_IO = 1;
1404
1405 return;
1406 #else
1407 BYTE Dummy;
1408
1409 // Select the chip and send the proper opcode
1410 ENC_CS_IO = 0;
1411 ENC_SPI_IF = 0;
1412 ENC_SSPBUF = WBM; // Send the Write Buffer Memory opcode
1413 while(!ENC_SPI_IF); // Wait until opcode/constant is transmitted.
1414 Dummy = ENC_SSPBUF;
1415 ENC_SPI_IF = 0;
1416
1417 // Send the data
1418 while(len)
1419 {
1420 ENC_SSPBUF = *val; // Start sending the byte
1421 val++; // Increment after writing to ENC_SSPBUF to increase speed
1422 len--; // Decrement after writing to ENC_SSPBUF to increase speed
1423 while(!ENC_SPI_IF); // Wait until byte is transmitted
1424 Dummy = ENC_SSPBUF;
1425 ENC_SPI_IF = 0;
1426 };
1427
1428 // Terminate the burst operation
1429 ENC_CS_IO = 1;
1430 #endif
1431 }//end MACPutROMArray
1432
1433 /******************************************************************************
1434 * Function: static void SendSystemReset(void)
1435 *
1436 * PreCondition: SPI bus must be initialized (done in MACInit()).
1437 *
1438 * Input: None
1439 *
1440 * Output: None
1441 *
1442 * Side Effects: None
1443 *
1444 * Overview: SendSystemReset sends the System Reset SPI command to
1445 * the Ethernet controller. It resets all register contents
1446 * (except for ECOCON) and returns the device to the power
1447 * on default state.
1448 *
1449 * Note: None
1450 *****************************************************************************/
1451 static void SendSystemReset(void)
1452 {
1453 BYTE Dummy;
1454
1455 ENC_CS_IO = 0;
1456 ENC_SPI_IF = 0;
1457 ENC_SSPBUF = SR;
1458 while(!ENC_SPI_IF); // Wait until the command is transmitted.
1459 Dummy = ENC_SSPBUF;
1460 ENC_SPI_IF = 0;
1461 ENC_CS_IO = 1;
1462 }//end SendSystemReset
1463
1464
1465 /******************************************************************************
1466 * Function: REG ReadETHReg(BYTE Address)
1467 *
1468 * PreCondition: SPI bus must be initialized (done in MACInit()).
1469 * Bank select bits must be set corresponding to the register
1470 * to read from.
1471 *
1472 * Input: 5 bit address of the ETH control register to read from.
1473 * The top 3 bits must be 0.
1474 *
1475 * Output: Byte read from the Ethernet controller's ETH register.
1476 *
1477 * Side Effects: None
1478 *
1479 * Overview: ReadETHReg sends the 8 bit RCR opcode/Address byte over
1480 * the SPI and then retrives the register contents in the
1481 * next 8 SPI clocks.
1482 *
1483 * Note: This routine cannot be used to access MAC/MII or PHY
1484 * registers. Use ReadMACReg() or ReadPHYReg() for that
1485 * purpose.
1486 *****************************************************************************/
1487 static REG ReadETHReg(BYTE Address)
1488 {
1489 REG r;
1490
1491 // Select the chip and send the Read Control Register opcode/address
1492 ENC_CS_IO = 0;
1493 ENC_SPI_IF = 0;
1494 ENC_SSPBUF = RCR | Address;
1495
1496 while(!ENC_SPI_IF); // Wait until the opcode/address is transmitted
1497 r.Val = ENC_SSPBUF;
1498 ENC_SPI_IF = 0;
1499 ENC_SSPBUF = 0; // Send a dummy byte to receive the register
1500 // contents
1501 while(!ENC_SPI_IF); // Wait until the register is received
1502 r.Val = ENC_SSPBUF;
1503 ENC_SPI_IF = 0;
1504 ENC_CS_IO = 1;
1505
1506 return r;
1507 }//end ReadETHReg
1508
1509
1510 /******************************************************************************
1511 * Function: REG ReadMACReg(BYTE Address)
1512 *
1513 * PreCondition: SPI bus must be initialized (done in MACInit()).
1514 * Bank select bits must be set corresponding to the register
1515 * to read from.
1516 *
1517 * Input: 5 bit address of the MAC or MII register to read from.
1518 * The top 3 bits must be 0.
1519 *
1520 * Output: Byte read from the Ethernet controller's MAC/MII register.
1521 *
1522 * Side Effects: None
1523 *
1524 * Overview: ReadMACReg sends the 8 bit RCR opcode/Address byte as well
1525 * as a dummy byte over the SPI and then retrives the
1526 * register contents in the last 8 SPI clocks.
1527 *
1528 * Note: This routine cannot be used to access ETH or PHY
1529 * registers. Use ReadETHReg() or ReadPHYReg() for that
1530 * purpose.
1531 *****************************************************************************/
1532 static REG ReadMACReg(BYTE Address)
1533 {
1534 REG r;
1535
1536 ENC_CS_IO = 0;
1537 ENC_SPI_IF = 0;
1538 ENC_SSPBUF = RCR | Address; // Send the Read Control Register opcode and
1539 // address.
1540 while(!ENC_SPI_IF); // Wait until opcode/address is transmitted.
1541 r.Val = ENC_SSPBUF;
1542 ENC_SPI_IF = 0;
1543 ENC_SSPBUF = 0; // Send a dummy byte
1544 while(!ENC_SPI_IF); // Wait for the dummy byte to be transmitted
1545 r.Val = ENC_SSPBUF;
1546 ENC_SPI_IF = 0;
1547 ENC_SSPBUF = 0; // Send another dummy byte to receive the register
1548 // contents.
1549 while(!ENC_SPI_IF); // Wait until register is received.
1550 r.Val = ENC_SSPBUF;
1551 ENC_SPI_IF = 0;
1552 ENC_CS_IO = 1;
1553
1554 return r;
1555 }//end ReadMACReg
1556
1557
1558 /******************************************************************************
1559 * Function: ReadPHYReg
1560 *
1561 * PreCondition: SPI bus must be initialized (done in MACInit()).
1562 *
1563 * Input: Address of the PHY register to read from.
1564 *
1565 * Output: 16 bits of data read from the PHY register.
1566 *
1567 * Side Effects: None
1568 *
1569 * Overview: ReadPHYReg performs an MII read operation. While in
1570 * progress, it simply polls the MII BUSY bit wasting time
1571 * (10.24us).
1572 *
1573 * Note: None
1574 *****************************************************************************/
1575 PHYREG ReadPHYReg(BYTE Register)
1576 {
1577 PHYREG Result;
1578
1579 // Set the right address and start the register read operation
1580 BankSel(MIREGADR);
1581 WriteReg((BYTE)MIREGADR, Register);
1582 WriteReg((BYTE)MICMD, MICMD_MIIRD);
1583
1584 // Loop to wait until the PHY register has been read through the MII
1585 // This requires 10.24us
1586 BankSel(MISTAT);
1587 while(ReadMACReg((BYTE)MISTAT).MISTATbits.BUSY);
1588
1589 // Stop reading
1590 BankSel(MIREGADR);
1591 WriteReg((BYTE)MICMD, 0x00);
1592
1593 // Obtain results and return
1594 Result.VAL.v[0] = ReadMACReg((BYTE)MIRDL).Val;
1595 Result.VAL.v[1] = ReadMACReg((BYTE)MIRDH).Val;
1596
1597 BankSel(ERDPTL); // Return to Bank 0
1598 return Result;
1599 }//end ReadPHYReg
1600
1601
1602 /******************************************************************************
1603 * Function: void WriteReg(BYTE Address, BYTE Data)
1604 *
1605 * PreCondition: SPI bus must be initialized (done in MACInit()).
1606 * Bank select bits must be set corresponding to the register
1607 * to modify.
1608 *
1609 * Input: 5 bit address of the ETH, MAC, or MII register to modify.
1610 * The top 3 bits must be 0.
1611 * Byte to be written into the register.
1612 *
1613 * Output: None
1614 *
1615 * Side Effects: None
1616 *
1617 * Overview: WriteReg sends the 8 bit WCR opcode/Address byte over the
1618 * SPI and then sends the data to write in the next 8 SPI
1619 * clocks.
1620 *
1621 * Note: This routine is almost identical to the BFCReg() and
1622 * BFSReg() functions. It is seperate to maximize speed.
1623 * Unlike the ReadETHReg/ReadMACReg functions, WriteReg()
1624 * can write to any ETH or MAC register. Writing to PHY
1625 * registers must be accomplished with WritePHYReg().
1626 *****************************************************************************/
1627 static void WriteReg(BYTE Address, BYTE Data)
1628 {
1629 BYTE Dummy;
1630
1631 ENC_CS_IO = 0;
1632 ENC_SPI_IF = 0;
1633 ENC_SSPBUF = WCR | Address; // Send the opcode and address.
1634 while(!ENC_SPI_IF); // Wait until opcode/address is transmitted.
1635 Dummy = ENC_SSPBUF;
1636 ENC_SPI_IF = 0;
1637 ENC_SSPBUF = Data; // Send the byte to be writen.
1638 while(!ENC_SPI_IF); // Wait until register is written.
1639 Dummy = ENC_SSPBUF;
1640 ENC_SPI_IF = 0;
1641 ENC_CS_IO = 1;
1642 }//end WriteReg
1643
1644
1645 /******************************************************************************
1646 * Function: void BFCReg(BYTE Address, BYTE Data)
1647 *
1648 * PreCondition: SPI bus must be initialized (done in MACInit()).
1649 * Bank select bits must be set corresponding to the register
1650 * to modify.
1651 *
1652 * Input: 5 bit address of the register to modify. The top 3 bits
1653 * must be 0.
1654 * Byte to be used with the Bit Field Clear operation.
1655 *
1656 * Output: None
1657 *
1658 * Side Effects: None
1659 *
1660 * Overview: BFCReg sends the 8 bit BFC opcode/Address byte over the
1661 * SPI and then sends the data in the next 8 SPI clocks.
1662 *
1663 * Note: This routine is almost identical to the WriteReg() and
1664 * BFSReg() functions. It is separate to maximize speed.
1665 * BFCReg() must only be used on ETH registers.
1666 *****************************************************************************/
1667 static void BFCReg(BYTE Address, BYTE Data)
1668 {
1669 BYTE Dummy;
1670
1671 ENC_CS_IO = 0;
1672 ENC_SPI_IF = 0;
1673 ENC_SSPBUF = BFC | Address; // Send the opcode and address.
1674 while(!ENC_SPI_IF); // Wait until opcode/address is transmitted.
1675 Dummy = ENC_SSPBUF;
1676 ENC_SPI_IF = 0;
1677 ENC_SSPBUF = Data; // Send the byte to be writen.
1678 while(!ENC_SPI_IF); // Wait until register is written.
1679 Dummy = ENC_SSPBUF;
1680 ENC_SPI_IF = 0;
1681 ENC_CS_IO = 1;
1682 }//end BFCReg
1683
1684
1685 /******************************************************************************
1686 * Function: void BFSReg(BYTE Address, BYTE Data)
1687 *
1688 * PreCondition: SPI bus must be initialized (done in MACInit()).
1689 * Bank select bits must be set corresponding to the register
1690 * to modify.
1691 *
1692 * Input: 5 bit address of the register to modify. The top 3 bits
1693 * must be 0.
1694 * Byte to be used with the Bit Field Set operation.
1695 *
1696 * Output: None
1697 *
1698 * Side Effects: None
1699 *
1700 * Overview: BFSReg sends the 8 bit BFC opcode/Address byte over the
1701 * SPI and then sends the data in the next 8 SPI clocks.
1702 *
1703 * Note: This routine is almost identical to the WriteReg() and
1704 * BFCReg() functions. It is separate to maximize speed.
1705 * BFSReg() must only be used on ETH registers.
1706 *****************************************************************************/
1707 static void BFSReg(BYTE Address, BYTE Data)
1708 {
1709 BYTE Dummy;
1710
1711 ENC_CS_IO = 0;
1712 ENC_SPI_IF = 0;
1713 ENC_SSPBUF = BFS | Address; // Send the opcode and address.
1714 while(!ENC_SPI_IF); // Wait until opcode/address is transmitted.
1715 Dummy = ENC_SSPBUF;
1716 ENC_SPI_IF = 0;
1717 ENC_SSPBUF = Data; // Send the byte to be writen.
1718 while(!ENC_SPI_IF); // Wait until register is written.
1719 Dummy = ENC_SSPBUF;
1720 ENC_SPI_IF = 0;
1721 ENC_CS_IO = 1;
1722 }//end BFSReg
1723
1724
1725 /******************************************************************************
1726 * Function: WritePHYReg
1727 *
1728 * PreCondition: SPI bus must be initialized (done in MACInit()).
1729 *
1730 * Input: Address of the PHY register to write to.
1731 * 16 bits of data to write to PHY register.
1732 *
1733 * Output: None
1734 *
1735 * Side Effects: Alters bank bits to point to Bank 3
1736 *
1737 * Overview: WritePHYReg performs an MII write operation. While in
1738 * progress, it simply polls the MII BUSY bit wasting time.
1739 *
1740 * Note: None
1741 *****************************************************************************/
1742 void WritePHYReg(BYTE Register, WORD Data)
1743 {
1744 // Write the register address
1745 BankSel(MIREGADR);
1746 WriteReg((BYTE)MIREGADR, Register);
1747
1748 // Write the data
1749 // Order is important: write low byte first, high byte last
1750 WriteReg((BYTE)MIWRL, ((WORD_VAL*)&Data)->v[0]);
1751 WriteReg((BYTE)MIWRH, ((WORD_VAL*)&Data)->v[1]);
1752
1753 // Wait until the PHY register has been written
1754 BankSel(MISTAT);
1755 while(ReadMACReg((BYTE)MISTAT).MISTATbits.BUSY);
1756
1757 BankSel(ERDPTL); // Return to Bank 0
1758 }//end WritePHYReg
1759
1760
1761 /******************************************************************************
1762 * Function: BankSel
1763 *
1764 * PreCondition: SPI bus must be initialized (done in MACInit()).
1765 *
1766 * Input: Register address with the high byte containing the 2 bank
1767 * select 2 bits.
1768 *
1769 * Output: None
1770 *
1771 * Side Effects: None
1772 *
1773 * Overview: BankSel takes the high byte of a register address and
1774 * changes the bank select bits in ETHCON1 to match.
1775 *
1776 * Note: None
1777 *****************************************************************************/
1778 static void BankSel(WORD Register)
1779 {
1780 BFCReg(ECON1, ECON1_BSEL1 | ECON1_BSEL0);
1781 BFSReg(ECON1, ((WORD_VAL*)&Register)->v[1]);
1782 }//end BankSel
1783
1784
1785 /******************************************************************************
1786 * Function: void MACPowerDown(void)
1787 *
1788 * PreCondition: SPI bus must be initialized (done in MACInit()).
1789 *
1790 * Input: None
1791 *
1792 * Output: None
1793 *
1794 * Side Effects: None
1795 *
1796 * Overview: MACPowerDown puts the ENC28J60 in low power sleep mode. In
1797 * sleep mode, no packets can be transmitted or received.
1798 * All MAC and PHY registers should not be accessed.
1799 *
1800 * Note: If a packet is being transmitted while this function is
1801 * called, this function will block until it is it complete.
1802 * If anything is being received, it will be completed.
1803 *****************************************************************************/
1804 void MACPowerDown(void)
1805 {
1806 // Disable packet reception
1807 BFCReg(ECON1, ECON1_RXEN);
1808
1809 // Make sure any last packet which was in-progress when RXEN was cleared
1810 // is completed
1811 while(ReadETHReg(ESTAT).ESTATbits.RXBUSY);
1812
1813 // If a packet is being transmitted, wait for it to finish
1814 while(ReadETHReg(ECON1).ECON1bits.TXRTS);
1815
1816 // Enter sleep mode
1817 BFSReg(ECON2, ECON2_PWRSV);
1818 }//end MACPowerDown
1819
1820
1821 /******************************************************************************
1822 * Function: void MACPowerUp(void)
1823 *
1824 * PreCondition: SPI bus must be initialized (done in MACInit()).
1825 *
1826 * Input: None
1827 *
1828 * Output: None
1829 *
1830 * Side Effects: None
1831 *
1832 * Overview: MACPowerUp returns the ENC28J60 back to normal operation
1833 * after a previous call to MACPowerDown(). Calling this
1834 * function when already powered up will have no effect.
1835 *
1836 * Note: If a link partner is present, it will take 10s of
1837 * milliseconds before a new link will be established after
1838 * waking up. While not linked, packets which are
1839 * transmitted will most likely be lost. MACIsLinked() can
1840 * be called to determine if a link is established.
1841 *****************************************************************************/
1842 void MACPowerUp(void)
1843 {
1844 // Leave power down mode
1845 BFCReg(ECON2, ECON2_PWRSV);
1846
1847 // Wait for the 300us Oscillator Startup Timer (OST) to time out. This
1848 // delay is required for the PHY module to return to an operational state.
1849 while(!ReadETHReg(ESTAT).ESTATbits.CLKRDY);
1850
1851 // Enable packet reception
1852 BFSReg(ECON1, ECON1_RXEN);
1853 }//end MACPowerUp
1854
1855
1856 /******************************************************************************
1857 * Function: void SetCLKOUT(BYTE NewConfig)
1858 *
1859 * PreCondition: SPI bus must be initialized (done in MACInit()).
1860 *
1861 * Input: NewConfig - 0x00: CLKOUT disabled (pin driven low)
1862 * 0x01: Divide by 1 (25 MHz)
1863 * 0x02: Divide by 2 (12.5 MHz)
1864 * 0x03: Divide by 3 (8.333333 MHz)
1865 * 0x04: Divide by 4 (6.25 MHz, POR default)
1866 * 0x05: Divide by 8 (3.125 MHz)
1867 *
1868 * Output: None
1869 *
1870 * Side Effects: None
1871 *
1872 * Overview: Writes the value of NewConfig into the ECOCON register.
1873 * The CLKOUT pin will beginning outputting the new frequency
1874 * immediately.
1875 *
1876 * Note:
1877 *****************************************************************************/
1878 void SetCLKOUT(BYTE NewConfig)
1879 {
1880 BankSel(ECOCON);
1881 WriteReg((BYTE)ECOCON, NewConfig);
1882 BankSel(ERDPTL);
1883 }//end SetCLKOUT
1884
1885
1886 /******************************************************************************
1887 * Function: BYTE GetCLKOUT(void)
1888 *
1889 * PreCondition: SPI bus must be initialized (done in MACInit()).
1890 *
1891 * Input: None
1892 *
1893 * Output: BYTE - 0x00: CLKOUT disabled (pin driven low)
1894 * 0x01: Divide by 1 (25 MHz)
1895 * 0x02: Divide by 2 (12.5 MHz)
1896 * 0x03: Divide by 3 (8.333333 MHz)
1897 * 0x04: Divide by 4 (6.25 MHz, POR default)
1898 * 0x05: Divide by 8 (3.125 MHz)
1899 * 0x06: Reserved
1900 * 0x07: Reserved
1901 *
1902 * Side Effects: None
1903 *
1904 * Overview: Returns the current value of the ECOCON register.
1905 *
1906 * Note: None
1907 *****************************************************************************/
1908 BYTE GetCLKOUT(void)
1909 {
1910 BYTE i;
1911
1912 BankSel(ECOCON);
1913 i = ReadETHReg((BYTE)ECOCON).Val;
1914 BankSel(ERDPTL);
1915 return i;
1916 }//end GetCLKOUT
1917
1918
1919 /******************************************************************************
1920 * Function: void SetRXHashTableEntry(MAC_ADDR DestMACAddr)
1921 *
1922 * PreCondition: SPI bus must be initialized (done in MACInit()).
1923 *
1924 * Input: DestMACAddr: 6 byte group destination MAC address to allow
1925 * through the Hash Table Filter
1926 *
1927 * Output: Sets the appropriate bit in the EHT* registers to allow
1928 * packets sent to DestMACAddr to be received if the Hash
1929 * Table receive filter is enabled
1930 *
1931 * Side Effects: None
1932 *
1933 * Overview: Calculates a CRC-32 using polynomial 0x4C11DB7 and then,
1934 * using bits 28:23 of the CRC, sets the appropriate bit in
1935 * the EHT* registers
1936 *
1937 * Note: This code is commented out to save code space on systems
1938 * that do not need this function. Change the "#if 0" line
1939 * to "#if 1" to uncomment it.
1940 *****************************************************************************/
1941 #if 0
1942 void SetRXHashTableEntry(MAC_ADDR DestMACAddr)
1943 {
1944 DWORD_VAL CRC = {0xFFFFFFFF};
1945 BYTE HTRegister;
1946 BYTE i, j;
1947
1948 // Calculate a CRC-32 over the 6 byte MAC address
1949 // using polynomial 0x4C11DB7
1950 for(i = 0; i < sizeof(MAC_ADDR); i++)
1951 {
1952 BYTE crcnext;
1953
1954 // shift in 8 bits
1955 for(j = 0; j < 8; j++)
1956 {
1957 crcnext = 0;
1958 if(((BYTE_VAL*)&(CRC.v[3]))->bits.b7)
1959 crcnext = 1;
1960 crcnext ^= (((BYTE_VAL*)&DestMACAddr.v[i])->bits.b0);
1961
1962 CRC.Val <<= 1;
1963 if(crcnext)
1964 CRC.Val ^= 0x4C11DB7;
1965 // next bit
1966 DestMACAddr.v[i] >>= 1;
1967 }
1968 }
1969
1970 // CRC-32 calculated, now extract bits 28:23
1971 // Bits 25:23 define where within the Hash Table byte the bit needs to be set
1972 // Bits 28:26 define which of the 8 Hash Table bytes that bits 25:23 apply to
1973 i = CRC.v[3] & 0x1F;
1974 HTRegister = (i >> 2) + (BYTE)EHT0;
1975 i = (i << 1) & 0x06;
1976 ((BYTE_VAL*)&i)->bits.b0 = ((BYTE_VAL*)&CRC.v[2])->bits.b7;
1977
1978 // Set the proper bit in the Hash Table
1979 BankSel(EHT0);
1980 BFSReg(HTRegister, 1<<i);
1981
1982 BankSel(ERDPTL); // Return to Bank 0
1983 }
1984 #endif
1985
1986 //// GetRegs is a function for debugging purposes only. It will read all
1987 //// registers and store them in the PIC's RAM so they can be viewed with
1988 //// the ICD2.
1989 //REG Regs[4][32];
1990 //void GetRegs(void)
1991 //{
1992 // BYTE i;
1993 //
1994 // BankSel(0x000);
1995 // for(i=0; i<0x1A; i++)
1996 // Regs[0][i] = ReadETHReg(i);
1997 // for(i=0x1B; i<32; i++)
1998 // Regs[0][i] = ReadETHReg(i);
1999 //
2000 // BankSel(0x100);
2001 // for(i=0; i<0x1A; i++)
2002 // Regs[1][i] = ReadETHReg(i);
2003 // for(i=0x1B; i<32; i++)
2004 // Regs[1][i] = ReadETHReg(i);
2005 //
2006 // BankSel(0x200);
2007 // for(i=0; i<5; i++)
2008 // Regs[2][i] = ReadMACReg(i);
2009 // Regs[2][5] = ReadETHReg(i);
2010 // for(i=6; i<0x0F; i++)
2011 // Regs[2][i] = ReadMACReg(i);
2012 // Regs[2][0x0F] = ReadETHReg(i);
2013 // for(i=0x10; i<0x13; i++)
2014 // Regs[2][i] = ReadMACReg(i);
2015 // Regs[2][0x13] = ReadETHReg(i);
2016 // for(i=0x14; i<0x1A; i++)
2017 // Regs[2][i] = ReadMACReg(i);
2018 // for(i=0x1B; i<32; i++)
2019 // Regs[2][i] = ReadETHReg(i);
2020 //
2021 // BankSel(0x300);
2022 // for(i=0; i<0x06; i++)
2023 // Regs[3][i] = ReadMACReg(i);
2024 // for(i=6; i<0x0A; i++)
2025 // Regs[3][i] = ReadETHReg(i);
2026 // Regs[3][0x0A] = ReadMACReg(i);
2027 // for(i=0x0B; i<0x1A; i++)
2028 // Regs[3][i] = ReadETHReg(i);
2029 // for(i=0x1B; i<32; i++)
2030 // Regs[3][i] = ReadETHReg(i);
2031 //
2032 // Regs[0][0x1A].Val = 0;
2033 // Regs[1][0x1A].Val = 0;
2034 // Regs[2][0x1A].Val = 0;
2035 // Regs[3][0x1A].Val = 0;
2036 //
2037 // BankSel(ERDPTL);
2038 //
2039 // return;
2040 //}
2041
2042 //// Get8KBMem is a function intended for debugging purposes. It will read all
2043 //// Ethernet RAM and output it in hex out the UART
2044 //void Get8KBMem(void)
2045 //{
2046 // WORD_VAL i;
2047 // BYTE v;
2048 // WORD_VAL RDSave;
2049 //
2050 // RDSave.v[0] = ReadETHReg(ERDPTL).Val;
2051 // RDSave.v[1] = ReadETHReg(ERDPTH).Val;
2052 //
2053 // for(i.Val = 0; i.Val < 8192; i.Val++)
2054 // {
2055 // WriteReg(ERDPTL, i.v[0]);
2056 // WriteReg(ERDPTH, i.v[1]);
2057 // v = MACGet();
2058 //
2059 // putcUART('0');
2060 // while(BusyUART());
2061 // putcUART('x');
2062 // while(BusyUART());
2063 // putcUART(btohexa_high(v));
2064 // while(BusyUART());
2065 // putcUART(btohexa_low(v));
2066 // while(BusyUART());
2067 // }
2068 //
2069 // WriteReg(ERDPTL, RDSave.v[0]);
2070 // WriteReg(ERDPTH, RDSave.v[1]);
2071 //
2072 //}
2073
2074 #endif //#if defined(ENC_CS_TRIS) && !defined(STACK_USE_SLIP)

  ViewVC Help
Powered by ViewVC 1.1.20