?lang_form? ?lang_select? ?lang_submit? ?lang_endform?
{HEADER END}
{BLAME START}

library

?curdirlinks? -

Blame information for rev 32

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

Powered by WebSVN v2.8.3