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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 15 - (hide annotations) (download)
Thu Apr 19 09:01:15 2007 UTC (17 years, 2 months ago) by hedin
File MIME type: text/plain
File size: 67088 byte(s)
added the TCP/IP stack, source code.
1 hedin 15 /*********************************************************************
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