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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 15 - (show annotations) (download)
Thu Apr 19 09:01:15 2007 UTC (17 years, 1 month ago) by hedin
File MIME type: text/plain
File size: 40874 byte(s)
added the TCP/IP stack, source code.
1 /*********************************************************************
2 *
3 * Medium Access Control (MAC) Layer for Microchip PIC18F97J60 family
4 * Module for Microchip TCP/IP Stack
5 * -Provides access to PIC18F97J60 family Ethernet controller
6 * -Reference: PIC18F97J60 Family data sheet, IEEE 802.3 Standard
7 *
8 *********************************************************************
9 * FileName: ETH97J60.c
10 * Dependencies: ETH97J60.h
11 * MAC.h
12 * string.h
13 * StackTsk.h
14 * Helpers.h
15 * Delay.h
16 * Processor: PIC18F97J60 family device
17 * Complier: Microchip C18 v3.10 or higher
18 * HI-TECH PICC-18 v9.50PL3 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 * Author Date Comment
53 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
54 * Rawin Rojvanit 07/26/05 Stuff
55 * Howard Schlunder 11/17/05 Ported to PIC18F97J60
56 * Howard Schlunder 06/16/06 Synchronized with ENC28J60 code
57 ********************************************************************/
58 #define __ETH97J60_C
59
60 #include "TCPIP Stack/TCPIP.h"
61
62 // Make sure that this hardware profile has a PIC18F97J60 family device in it
63 #if (defined(__18F97J60) || defined(__18F96J65) || defined(__18F96J60) || defined(__18F87J60) || defined(__18F86J65) || defined(__18F86J60) || defined(__18F67J60) || defined(__18F66J65) || defined(__18F66J60) || \
64 defined(_18F97J60) || defined(_18F96J65) || defined(_18F96J60) || defined(_18F87J60) || defined(_18F86J65) || defined(_18F86J60) || defined(_18F67J60) || defined(_18F66J65) || defined(_18F66J60)) \
65 && !defined(STACK_USE_SLIP) && !defined(ENC_CS_TRIS)
66
67
68 /** D E F I N I T I O N S ****************************************************/
69 // Since the Ethernet PHY doesn't support auto-negotiation, full-duplex mode is
70 // not compatible with most switches/routers. If a dedicated network is used
71 // where the duplex of the remote node can be manually configured, you may
72 // change this configuration. Otherwise, half duplex should always be used.
73 #define HALF_DUPLEX
74 //#define FULL_DUPLEX
75
76 // Pseudo Functions
77 #define LOW(a) (a & 0xFF)
78 #define HIGH(a) ((a>>8) & 0xFF)
79
80 #define ETHER_IP (0x00u)
81 #define ETHER_ARP (0x06u)
82
83 // A header appended at the start of all RX frames by the hardware
84 typedef struct _ENC_PREAMBLE
85 {
86 WORD NextPacketPointer;
87 RXSTATUS StatusVector;
88
89 MAC_ADDR DestMACAddr;
90 MAC_ADDR SourceMACAddr;
91 WORD_VAL Type;
92 } ENC_PREAMBLE;
93
94
95 // Internal MAC level variables and flags.
96 static WORD_VAL NextPacketLocation;
97 static WORD_VAL CurrentPacketLocation;
98 static BOOL WasDiscarded;
99 #if defined(HI_TECH_C)
100 static BYTE ErrataTemp;
101 #endif
102
103 /******************************************************************************
104 * Function: void MACInit(void)
105 *
106 * PreCondition: None
107 *
108 * Input: None
109 *
110 * Output: None
111 *
112 * Side Effects: None
113 *
114 * Overview: MACInit enables the Ethernet module, waits for the
115 * to become ready, and programs all registers for future
116 * TX/RX operations.
117 *
118 * Note: This function blocks for at least 1ms, waiting for the
119 * hardware to stabilize.
120 *****************************************************************************/
121 void MACInit(void)
122 {
123 BYTE i;
124
125
126 LATAbits.LATA0 = 0;
127 LATAbits.LATA1 = 0;
128 TRISAbits.TRISA0 = 0; // Set LED0 as output
129 TRISAbits.TRISA1 = 0; // Set LED1 as output
130 ECON2bits.ETHEN = 1; // Enable Ethernet!
131
132 // Wait for PHYRDY to become set.
133 while(!ESTATbits.PHYRDY);
134
135 // Configure the receive buffer boundary pointers
136 // and the buffer write protect pointer (receive buffer read pointer)
137 WasDiscarded = TRUE;
138 NextPacketLocation.Val = RXSTART;
139 ERXST = RXSTART;
140 ERXRDPTL = LOW(RXSTOP); // Write low byte first
141 ERXRDPTH = HIGH(RXSTOP);// Write high byte last
142 ERXND = RXSTOP;
143 ETXST = TXSTART;
144
145 // Write a permanant per packet control byte of 0x00
146 EWRPT = TXSTART;
147 MACPut(0x00);
148
149 // Configure Receive Filters
150 // (No need to reconfigure - Unicast OR Broadcast with CRC checking is
151 // acceptable)
152 //ERXFCON = ERXFCON_CRCEN; // Promiscious mode
153
154 // Configure the MAC
155 // Enable the receive portion of the MAC
156 MACON1 = MACON1_TXPAUS | MACON1_RXPAUS | MACON1_MARXEN; Nop();
157
158 // Pad packets to 60 bytes, add CRC, and check Type/Length field.
159 #if defined(FULL_DUPLEX)
160 MACON3 = MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN | MACON3_FULDPX; Nop();
161 MABBIPG = 0x15; Nop();
162 #else
163 MACON3 = MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN; Nop();
164 MABBIPG = 0x12; Nop();
165 #endif
166
167 // Allow infinite deferals if the medium is continuously busy
168 // (do not time out a transmission if the half duplex medium is
169 // completely saturated with other people's data)
170 MACON4 = MACON4_DEFER; Nop();
171
172 // Set non-back-to-back inter-packet gap to 9.6us. The back-to-back
173 // inter-packet gap (MABBIPG) is set by MACSetDuplex() which is called
174 // later.
175 MAIPGL = 0x12; Nop();
176 MAIPGH = 0x0C; Nop();
177
178 // Set the maximum packet size which the controller will accept
179 MAMXFLL = LOW(6+6+2+1500+4); Nop();
180 MAMXFLH = HIGH(6+6+2+1500+4); Nop();
181
182 // Initialize physical MAC address registers
183 MAADR1 = AppConfig.MyMACAddr.v[0]; Nop();
184 MAADR2 = AppConfig.MyMACAddr.v[1]; Nop();
185 MAADR3 = AppConfig.MyMACAddr.v[2]; Nop();
186 MAADR4 = AppConfig.MyMACAddr.v[3]; Nop();
187 MAADR5 = AppConfig.MyMACAddr.v[4]; Nop();
188 MAADR6 = AppConfig.MyMACAddr.v[5]; Nop();
189
190 // Disable half duplex loopback in PHY and set RXAPDIS bit as per errata
191 WritePHYReg(PHCON2, PHCON2_HDLDIS | PHCON2_RXAPDIS);
192
193 // Configure LEDA to display LINK status, LEDB to display TX/RX activity
194 SetLEDConfig(0x3472);
195
196 // Set the PHY into the proper duplex state
197 #if defined(FULL_DUPLEX)
198 WritePHYReg(PHCON1, PHCON1_PDPXMD);
199 #else
200 WritePHYReg(PHCON1, 0x0000);
201 #endif
202
203 // Enable packet reception
204 ECON1bits.RXEN = 1;
205 }//end MACInit
206
207
208 /******************************************************************************
209 * Function: BOOL MACIsLinked(void)
210 *
211 * PreCondition: None
212 *
213 * Input: None
214 *
215 * Output: TRUE: If the PHY reports that a link partner is present
216 * and the link has been up continuously since the last
217 * call to MACIsLinked()
218 * FALSE: If the PHY reports no link partner, or the link went
219 * down momentarily since the last call to MACIsLinked()
220 *
221 * Side Effects: None
222 *
223 * Overview: Returns the PHSTAT1.LLSTAT bit.
224 *
225 * Note: None
226 *****************************************************************************/
227 BOOL MACIsLinked(void)
228 {
229 // LLSTAT is a latching low link status bit. Therefore, if the link
230 // goes down and comes back up before a higher level stack program calls
231 // MACIsLinked(), MACIsLinked() will still return FALSE. The next
232 // call to MACIsLinked() will return TRUE (unless the link goes down
233 // again).
234 return ReadPHYReg(PHSTAT1).PHSTAT1bits.LLSTAT;
235 }
236
237
238 /******************************************************************************
239 * Function: BOOL MACIsTxReady(void)
240 *
241 * PreCondition: None
242 *
243 * Input: None
244 *
245 * Output: TRUE: If no Ethernet transmission is in progress
246 * FALSE: If a previous transmission was started, and it has
247 * not completed yet. While FALSE, the data in the
248 * transmit buffer and the TXST/TXND pointers must not
249 * be changed.
250 *
251 * Side Effects: None
252 *
253 * Overview: Returns the ECON1.TXRTS bit
254 *
255 * Note: None
256 *****************************************************************************/
257 BOOL MACIsTxReady(void)
258 {
259 return !ECON1bits.TXRTS;
260 }
261
262
263 /******************************************************************************
264 * Function: void MACDiscardRx(void)
265 *
266 * PreCondition: None
267 *
268 * Input: None
269 *
270 * Output: None
271 *
272 * Side Effects: None
273 *
274 * Overview: Marks the last received packet (obtained using
275 * MACGetHeader())as being processed and frees the buffer
276 * memory associated with it
277 *
278 * Note: None
279 *****************************************************************************/
280 void MACDiscardRx(void)
281 {
282 WORD_VAL NewRXRDLocation;
283
284 // Make sure the current packet was not already discarded
285 if(WasDiscarded)
286 return;
287 WasDiscarded = TRUE;
288
289 // Decrement the next packet pointer before writing it into
290 // the ERXRDPT registers. This is a silicon errata workaround.
291 // RX buffer wrapping must be taken into account if the
292 // NextPacketLocation is precisely RXSTART.
293 NewRXRDLocation.Val = NextPacketLocation.Val - 1;
294 #if RXSTART == 0
295 if(NewRXRDLocation.Val > RXSTOP)
296 #else
297 if(NewRXRDLocation.Val < RXSTART || NewRXRDLocation.Val > RXSTOP)
298 #endif
299 {
300 NewRXRDLocation.Val = RXSTOP;
301 }
302
303 // Decrement the RX packet counter register, EPKTCNT
304 ECON2bits.PKTDEC = 1;
305
306 // Move the receive read pointer to unwrite-protect the memory used by the
307 // last packet. The writing order is important: set the low byte first,
308 // high byte last.
309 ERXRDPTL = NewRXRDLocation.v[0];
310 ERXRDPTH = NewRXRDLocation.v[1];
311
312 // The PKTIF flag should automatically be cleared by hardware, but
313 // early beta silicon requires that you manually clear it. This should be
314 // unneeded for production A0 silicon and later.
315 EIRbits.PKTIF = 0;
316 }
317
318
319 /******************************************************************************
320 * Function: WORD MACGetFreeRxSize(void)
321 *
322 * PreCondition: None
323 *
324 * Input: None
325 *
326 * Output: A WORD estimate of how much RX buffer space is free at
327 * the present time.
328 *
329 * Side Effects: None
330 *
331 * Overview: None
332 *
333 * Note: None
334 *****************************************************************************/
335 WORD MACGetFreeRxSize(void)
336 {
337 WORD_VAL ReadPT, WritePT;
338
339 // Read the Ethernet hardware buffer write pointer. Because packets can be
340 // received at any time, it can change between reading the low and high
341 // bytes. A loop is necessary to make certain a proper low/high byte pair
342 // is read.
343 do {
344 // Save EPKTCNT in a temporary location
345 ReadPT.v[0] = EPKTCNT;
346
347 WritePT.Val = ERXWRPT;
348 } while(EPKTCNT != ReadPT.v[0]);
349
350 // Determine where the write protection pointer is
351 ReadPT.Val = ERXRDPT;
352
353
354 // Calculate the difference between the pointers, taking care to account
355 // for buffer wrapping conditions
356 if(WritePT.Val > ReadPT.Val)
357 {
358 return (RXSTOP - RXSTART) - (WritePT.Val - ReadPT.Val);
359 }
360 else if(WritePT.Val == ReadPT.Val)
361 {
362 return RXSIZE - 1;
363 }
364 else
365 {
366 return ReadPT.Val - WritePT.Val - 1;
367 }
368 }
369
370 /******************************************************************************
371 * Function: BOOL MACGetHeader(MAC_ADDR *remote, BYTE* type)
372 *
373 * PreCondition: None
374 *
375 * Input: *remote: Location to store the Source MAC address of the
376 * received frame.
377 * *type: Location of a BYTE to store the constant
378 * MAC_UNKNOWN, ETHER_IP, or ETHER_ARP, representing
379 * the contents of the Ethernet type field.
380 *
381 * Output: TRUE: If a packet was waiting in the RX buffer. The
382 * remote, and type values are updated.
383 * FALSE: If a packet was not pending. remote and type are
384 * not changed.
385 *
386 * Side Effects: Last packet is discarded if MACDiscardRx() hasn't already
387 * been called.
388 *
389 * Overview: None
390 *
391 * Note: None
392 *****************************************************************************/
393 BOOL MACGetHeader(MAC_ADDR *remote, BYTE* type)
394 {
395 ENC_PREAMBLE header;
396
397 // Test if at least one packet has been received and is waiting
398 if(EPKTCNT == 0u)
399 {
400 return FALSE;
401 }
402
403 // Make absolutely certain that any previous packet was discarded
404 if(WasDiscarded == FALSE)
405 {
406 MACDiscardRx();
407 return FALSE;
408 }
409 // Save the location of this packet
410 CurrentPacketLocation.Val = NextPacketLocation.Val;
411
412 // Set the read pointer to the beginning of the next unprocessed packet
413 ERDPT = CurrentPacketLocation.Val;
414
415 // Obtain the MAC header from the Ethernet buffer
416 MACGetArray((BYTE*)&header, sizeof(header));
417
418 // The EtherType field, like most items transmitted on the Ethernet medium
419 // are in big endian.
420 header.Type.Val = swaps(header.Type.Val);
421
422 // Do a sanity check. There might be a bug in code someplace if this
423 // Reset() ever happens. Check for potential errors in array/pointer writing code.
424 if(header.NextPacketPointer > RXSTOP || ((BYTE_VAL*)(&header.NextPacketPointer))->bits.b0 ||
425 header.StatusVector.bits.Zero ||
426 header.StatusVector.bits.CRCError ||
427 header.StatusVector.bits.ByteCount > 1518u ||
428 !header.StatusVector.bits.ReceiveOk)
429 {
430 Reset();
431 }
432
433 // Save the location where the hardware will write the next packet to
434 NextPacketLocation.Val = header.NextPacketPointer;
435
436 // Return the Ethernet frame's Source MAC address field to the caller
437 // This parameter is useful for replying to requests without requiring an
438 // ARP cycle.
439 memcpy((void*)remote->v, (void*)header.SourceMACAddr.v, sizeof(*remote));
440
441 // Return a simplified version of the EtherType field to the caller
442 *type = MAC_UNKNOWN;
443 if( (header.Type.v[1] == 0x08u) &&
444 ((header.Type.v[0] == ETHER_IP) || (header.Type.v[0] == ETHER_ARP)) )
445 {
446 *type = header.Type.v[0];
447 }
448
449 // Mark this packet as discardable
450 WasDiscarded = FALSE;
451 return TRUE;
452 }
453
454
455 /******************************************************************************
456 * Function: void MACPutHeader(MAC_ADDR *remote, BYTE type, WORD dataLen)
457 *
458 * PreCondition: MACIsTxReady() must return TRUE.
459 *
460 * Input: *remote: Pointer to memory which contains the destination
461 * MAC address (6 bytes)
462 * type: The constant ETHER_ARP or ETHER_IP, defining which
463 * value to write into the Ethernet header's type field.
464 * dataLen: Length of the Ethernet data payload
465 *
466 * Output: None
467 *
468 * Side Effects: None
469 *
470 * Overview: None
471 *
472 * Note: Because of the dataLen parameter, it is probably
473 * advantagous to call this function immediately before
474 * transmitting a packet rather than initially when the
475 * packet is first created. The order in which the packet
476 * is constructed (header first or data first) is not
477 * important.
478 *****************************************************************************/
479 void MACPutHeader(MAC_ADDR *remote, BYTE type, WORD dataLen)
480 {
481 // Set the write pointer to the beginning of the transmit buffer
482 EWRPT = TXSTART + 1;
483
484 // Calculate where to put the TXND pointer
485 dataLen += (WORD)sizeof(ETHER_HEADER) + TXSTART;
486
487 // Write the TXND pointer into the registers, given the dataLen given
488 ETXND = dataLen;
489
490 // Set the per-packet control byte and write the Ethernet destination
491 // address
492 MACPutArray((BYTE*)remote, sizeof(*remote));
493
494 // Write our MAC address in the Ethernet source field
495 MACPutArray((BYTE*)&AppConfig.MyMACAddr, sizeof(AppConfig.MyMACAddr));
496
497 // Write the appropriate Ethernet Type WORD for the protocol being used
498 MACPut(0x08);
499 MACPut((type == MAC_IP) ? ETHER_IP : ETHER_ARP);
500 }
501
502 /******************************************************************************
503 * Function: void MACFlush(void)
504 *
505 * PreCondition: A packet has been created by calling MACPut() and
506 * MACPutHeader().
507 *
508 * Input: None
509 *
510 * Output: None
511 *
512 * Side Effects: None
513 *
514 * Overview: MACFlush causes the current TX packet to be sent out on
515 * the Ethernet medium. The hardware MAC will take control
516 * and handle CRC generation, collision retransmission and
517 * other details.
518 *
519 * Note: After transmission completes (MACIsTxReady() returns TRUE),
520 * the packet can be modified and transmitted again by calling
521 * MACFlush() again. Until MACPutHeader() or MACPut() is
522 * called (in the TX data area), the data in the TX buffer
523 * will not be corrupted.
524 *****************************************************************************/
525 void MACFlush(void)
526 {
527 // Start the transmission
528 // After transmission completes (MACIsTxReady() returns TRUE), the packet
529 // can be modified and transmitted again by calling MACFlush() again.
530 // Until MACPutHeader() is called, the data in the TX buffer will not be
531 // corrupted.
532 ECON1bits.TXRTS = 1;
533 }
534
535
536 /******************************************************************************
537 * Function: void MACSetReadPtrInRx(WORD offset)
538 *
539 * PreCondition: A packet has been obtained by calling MACGetHeader() and
540 * getting a TRUE result.
541 *
542 * Input: offset: WORD specifying how many bytes beyond the Ethernet
543 * header's type field to relocate the SPI read
544 * pointer.
545 *
546 * Output: None
547 *
548 * Side Effects: None
549 *
550 * Overview: SPI read pointer are updated. All calls to
551 * MACGet() and MACGetArray() will use these new values.
552 *
553 * Note: RXSTOP must be statically defined as being > RXSTART for
554 * this function to work correctly. In other words, do not
555 * define an RX buffer which spans the 0x1FFF->0x0000 memory
556 * boundary.
557 *****************************************************************************/
558 void MACSetReadPtrInRx(WORD offset)
559 {
560 WORD_VAL ReadPT;
561
562 // Determine the address of the beginning of the entire packet
563 // and adjust the address to the desired location
564 ReadPT.Val = CurrentPacketLocation.Val + sizeof(ENC_PREAMBLE) + offset;
565
566 // Since the receive buffer is circular, adjust if a wraparound is needed
567 if(ReadPT.Val > RXSTOP)
568 ReadPT.Val -= RXSIZE;
569
570 // Set the read pointer to the new calculated value
571 ERDPTL = ReadPT.v[0];
572 ERDPTH = ReadPT.v[1];
573 }
574
575
576 /******************************************************************************
577 * Function: WORD MACSetWritePtr(WORD Address)
578 *
579 * PreCondition: None
580 *
581 * Input: Address: Address to seek to
582 *
583 * Output: WORD: Old EWRPT location
584 *
585 * Side Effects: None
586 *
587 * Overview: SPI write pointer is updated. All calls to
588 * MACPut() and MACPutArray() will use this new value.
589 *
590 * Note: None
591 *****************************************************************************/
592 WORD MACSetWritePtr(WORD address)
593 {
594 WORD oldVal;
595
596 oldVal = EWRPT;
597 EWRPT = address;
598 return oldVal;
599 }
600
601 /******************************************************************************
602 * Function: WORD MACSetReadPtr(WORD Address)
603 *
604 * PreCondition: None
605 *
606 * Input: Address: Address to seek to
607 *
608 * Output: WORD: Old ERDPT value
609 *
610 * Side Effects: None
611 *
612 * Overview: SPI write pointer is updated. All calls to
613 * MACPut() and MACPutArray() will use this new value.
614 *
615 * Note: None
616 *****************************************************************************/
617 WORD MACSetReadPtr(WORD address)
618 {
619 WORD oldVal;
620
621 oldVal = ERDPT;
622 ERDPT = address;
623 return oldVal;
624 }
625
626
627 /******************************************************************************
628 * Function: WORD MACCalcRxChecksum(WORD offset, WORD len)
629 *
630 * PreCondition: None
631 *
632 * Input: offset - Number of bytes beyond the beginning of the
633 * Ethernet data (first byte after the type field)
634 * where the checksum should begin
635 * len - Total number of bytes to include in the checksum
636 *
637 * Output: 16-bit checksum as defined by RFC 793.
638 *
639 * Side Effects: None
640 *
641 * Overview: This function performs a checksum calculation in the MAC
642 * buffer itself
643 *
644 * Note: None
645 *****************************************************************************/
646 WORD MACCalcRxChecksum(WORD offset, WORD len)
647 {
648 WORD temp;
649 WORD RDSave;
650
651 // Add the offset requested by firmware plus the Ethernet header
652 temp = CurrentPacketLocation.Val + sizeof(ENC_PREAMBLE) + offset;
653 if(temp > RXSTOP) // Adjust value if a wrap is needed
654 {
655 temp -= RXSIZE;
656 }
657
658 RDSave = ERDPT;
659 ERDPT = temp;
660 temp = CalcIPBufferChecksum(len);
661 ERDPT = RDSave;
662
663 return temp;
664 }
665
666
667 /******************************************************************************
668 * Function: WORD CalcIPBufferChecksum(WORD len)
669 *
670 * PreCondition: Read buffer pointer set to starting of checksum data
671 *
672 * Input: len: Total number of bytes to calculate the checksum over.
673 * The first byte included in the checksum is the byte
674 * pointed to by ERDPT, which is updated by calls to
675 * MACGet(), MACSetRxBuffer(), MACSetTxBuffer(), etc.
676 *
677 * Output: 16-bit checksum as defined by RFC 793
678 *
679 * Side Effects: None
680 *
681 * Overview: This function performs a checksum calculation in the MAC
682 * buffer itself. The MAC has a hardware DMA module
683 * which can calculate the checksum faster than software, so
684 * this function replaces the CaclIPBufferChecksum() function
685 * defined in the helpers.c file. Through the use of
686 * preprocessor defines, this replacement is automatic.
687 *
688 * Note: This function works either in the RX buffer area or the TX
689 * buffer area. No validation is done on the len parameter.
690 *****************************************************************************/
691 WORD CalcIPBufferChecksum(WORD len)
692 {
693 WORD_VAL temp;
694
695 // Take care of special cases which the DMA cannot be used for
696 if(len == 0u)
697 {
698 return 0xFFFF;
699 }
700 else if(len == 1u)
701 {
702 return ~((WORD)MACGet());
703 }
704
705
706 // Set the DMA starting address to the RAM read pointer value
707 temp.Val = ERDPT;
708 EDMAST = temp.Val;
709
710 // See if we are calculating a checksum within the RX buffer (where
711 // wrapping rules apply) or TX/unused area (where wrapping rules are
712 // not applied)
713 #if RXSTART == 0
714 if(temp.Val <= RXSTOP)
715 #else
716 if(temp.Val >= RXSTART && temp.Val <= RXSTOP)
717 #endif
718 {
719 // Calculate the DMA ending address given the starting address and len
720 // parameter. The DMA will follow the receive buffer wrapping boundary.
721 temp.Val += len-1;
722 if(temp.Val > RXSTOP)
723 {
724 temp.Val -= RXSIZE;
725 }
726 }
727 else
728 {
729 temp.Val += len-1;
730 }
731
732 // Write the DMA end address
733 EDMAND = temp.Val;
734
735 // Begin the DMA checksum calculation and wait until it is finished
736 ECON1bits.CSUMEN = 1;
737 ECON1bits.DMAST = 1;
738 while(ECON1bits.DMAST);
739
740 // Return the resulting good stuff
741 return (((WORD)EDMACSL)<<8) | EDMACSH;
742 }
743
744
745 /******************************************************************************
746 * Function: WORD CalcIPBufferChecksum(WORD len)
747 *
748 * PreCondition: Read buffer pointer set to starting of checksum data
749 *
750 * Input: len: Total number of bytes to calculate the checksum over.
751 * The first byte included in the checksum is the byte
752 * pointed to by ERDPT, which is updated by calls to
753 * MACSetReadPtr(), MACGet(), MACGetArray(),
754 * MACGetHeader(), etc.
755 *
756 * Output: 16-bit checksum as defined by RFC 793
757 *
758 * Side Effects: None
759 *
760 * Overview: This function performs a checksum calculation in the MAC
761 * buffer itself
762 *
763 * Note: This function works either in the RX buffer area or the TX
764 * buffer area. No validation is done on the len parameter.
765 *****************************************************************************/
766 /*
767 WORD CalcIPBufferChecksum(WORD len)
768 {
769 WORD Start;
770 DWORD_VAL Checksum = {0x00000000ul};
771 WORD ChunkLen;
772 BYTE DataBuffer[20]; // Must be an even size
773 WORD *DataPtr;
774
775 // Save the read pointer starting address
776 Start = ERDPT;
777
778 while(len)
779 {
780 // Obtain a chunk of data (less SPI overhead compared
781 // to requesting one byte at a time)
782 ChunkLen = len > sizeof(DataBuffer) ? sizeof(DataBuffer) : len;
783 MACGetArray(DataBuffer, ChunkLen);
784
785 len -= ChunkLen;
786
787 // Take care of a last odd numbered data byte
788 if(((WORD_VAL*)&ChunkLen)->bits.b0)
789 {
790 DataBuffer[ChunkLen] = 0x00;
791 ChunkLen++;
792 }
793
794 // Calculate the checksum over this chunk
795 DataPtr = (WORD*)&DataBuffer[0];
796 while(ChunkLen)
797 {
798 Checksum.Val += *DataPtr++;
799 ChunkLen -= 2;
800 }
801 }
802
803 // Restore old read pointer location
804 ERDPT = Start;
805
806 // Do an end-around carry (one's complement arrithmatic)
807 Checksum.Val = (DWORD)Checksum.w[0] + (DWORD)Checksum.w[1];
808
809 // Do another end-around carry in case if the prior add
810 // caused a carry out
811 Checksum.w[0] += Checksum.w[1];
812
813 // Return the resulting checksum
814 return ~Checksum.w[0];
815 }
816 */
817
818 /******************************************************************************
819 * Function: void MACMemCopyAsync(WORD destAddr, WORD sourceAddr, WORD len)
820 *
821 * PreCondition: None
822 *
823 * Input: destAddr: Destination address in the Ethernet memory to
824 * copy to. If the MSb is set, the current EWRPT
825 * value will be used instead.
826 * sourceAddr: Source address to read from. If the MSb is
827 * set, the current ERDPT value will be used
828 * instead.
829 * len: Number of bytes to copy
830 *
831 * Output: Byte read from the ENC28J60's RAM
832 *
833 * Side Effects: None
834 *
835 * Overview: Bytes are asynchrnously transfered within the buffer. Call
836 * MACIsMemCopyDone() to see when the transfer is complete.
837 *
838 * Note: If a prior transfer is already in progress prior to
839 * calling this function, this function will block until it
840 * can start this transfer.
841 *****************************************************************************/
842 void MACMemCopyAsync(WORD destAddr, WORD sourceAddr, WORD len)
843 {
844 WORD_VAL ReadSave, WriteSave;
845 BOOL UpdateWritePointer = FALSE;
846 BOOL UpdateReadPointer = FALSE;
847
848 if(((WORD_VAL*)&destAddr)->bits.b15)
849 {
850 UpdateWritePointer = TRUE;
851 destAddr = EWRPT;
852 }
853 if(((WORD_VAL*)&sourceAddr)->bits.b15)
854 {
855 UpdateReadPointer = TRUE;
856 sourceAddr = ERDPT;
857 }
858
859 /*
860 ReadSave.Val = ERDPT;
861 WriteSave.Val = EWRPT;
862 ERDPT = sourceAddr;
863 EWRPT = destAddr;
864 while(len--)
865 MACPut(MACGet());
866 if(!UpdateReadPointer)
867 {
868 ERDPT = ReadSave.Val;
869 }
870 if(!UpdateWritePointer)
871 {
872 EWRPT = WriteSave.Val;
873 }
874 */
875
876 // Handle special conditions where len == 0 or len == 1
877 // The DMA module is not capable of handling those corner cases
878 if(len <= 1u)
879 {
880 ReadSave.Val = ERDPT;
881 WriteSave.Val = EWRPT;
882 ERDPT = sourceAddr;
883 EWRPT = destAddr;
884 while(len--)
885 MACPut(MACGet());
886 if(!UpdateReadPointer)
887 {
888 ERDPT = ReadSave.Val;
889 }
890 if(!UpdateWritePointer)
891 {
892 EWRPT = WriteSave.Val;
893 }
894 }
895 else
896 {
897 if(UpdateWritePointer)
898 {
899 WriteSave.Val = destAddr + len;
900 EWRPT = WriteSave.Val;
901 }
902 len += sourceAddr - 1;
903 while(ECON1bits.DMAST);
904 EDMAST = sourceAddr;
905 EDMADST = destAddr;
906 if((sourceAddr <= RXSTOP) && (len > RXSTOP)) //&& (sourceAddr >= RXSTART))
907 len -= RXSIZE;
908 EDMAND = len;
909 ECON1bits.CSUMEN = 0;
910 ECON1bits.DMAST = 1;
911 if(UpdateReadPointer)
912 {
913 len++;
914 if((sourceAddr <= RXSTOP) && (len > RXSTOP)) //&& (sourceAddr >= RXSTART))
915 len -= RXSIZE;
916 ERDPT = len;
917 }
918 }
919 }
920
921 BOOL MACIsMemCopyDone(void)
922 {
923 return !ECON1bits.DMAST;
924 }
925
926 /******************************************************************************
927 * Function: BYTE MACGet()
928 *
929 * PreCondition: ERDPT must point to the place to read from.
930 *
931 * Input: None
932 *
933 * Output: Byte read from the Ethernet's buffer RAM
934 *
935 * Side Effects: None
936 *
937 * Overview: MACGet returns the byte pointed to by ERDPT and
938 * increments ERDPT so MACGet() can be called again. The
939 * increment will follow the receive buffer wrapping boundary.
940 *
941 * Note: For better performance, implement this function as a macro:
942 * #define MACGet() (EDATA)
943 *****************************************************************************/
944 BYTE MACGet()
945 {
946 return EDATA;
947 }//end MACGet
948
949
950 /******************************************************************************
951 * Function: WORD MACGetArray(BYTE *val, WORD len)
952 *
953 * PreCondition: ERDPT must point to the place to read from.
954 *
955 * Input: *val: Pointer to storage location
956 * len: Number of bytes to read from the data buffer.
957 *
958 * Output: Byte(s) of data read from the data buffer.
959 *
960 * Side Effects: None
961 *
962 * Overview: Reads several sequential bytes from the data buffer
963 * and places them into local memory. ERDPT is incremented
964 * after each byte, following the same rules as MACGet().
965 *
966 * Note: None
967 *****************************************************************************/
968 WORD MACGetArray(BYTE *val, WORD len)
969 {
970 WORD w = len;
971 BYTE i;
972
973 if(val)
974 {
975 while(w--)
976 {
977 *val++ = EDATA;
978 }
979 }
980 else
981 {
982 while(w--)
983 {
984 i = EDATA;
985 }
986 }
987
988 return len;
989 }//end MACGetArray
990
991
992 /******************************************************************************
993 * Function: void MACPut(BYTE val)
994 *
995 * PreCondition: EWRPT must point to the location to begin writing.
996 *
997 * Input: Byte to write into the Ethernet buffer memory
998 *
999 * Output: None
1000 *
1001 * Side Effects: None
1002 *
1003 * Overview: Writes to the EDATA register, which will indirectly
1004 * increment EWRPTH:EWRPTL.
1005 *
1006 * Note: For better performance, implement this function as a macro:
1007 * #define MACPut(a) EDATA = a
1008 *****************************************************************************/
1009 void MACPut(BYTE val)
1010 {
1011 // Note: Due to a PIC18F97J60 bug, you must use the MOVFF instruction to
1012 // write to EDATA or else the read pointer (ERDPT) will inadvertently
1013 // increment.
1014 #if defined(HI_TECH_C)
1015 ErrataTemp = val;
1016 asm("movff _ErrataTemp, _EDATA");
1017 #else
1018 _asm movff val, EDATA _endasm
1019 #endif
1020 }//end MACPut
1021
1022
1023 /******************************************************************************
1024 * Function: void MACPutArray(BYTE *val, WORD len)
1025 *
1026 * PreCondition: EWRPT must point to the location to begin writing.
1027 *
1028 * Input: *val: Pointer to source of bytes to copy.
1029 * len: Number of bytes to write to the data buffer.
1030 *
1031 * Output: None
1032 *
1033 * Side Effects: None
1034 *
1035 * Overview: MACPutArray writes several sequential bytes to the
1036 * Ethernet buffer RAM. It performs faster than multiple MACPut()
1037 * calls. EWRPT is incremented by len.
1038 *
1039 * Note: None
1040 *****************************************************************************/
1041 void MACPutArray(BYTE *val, WORD len)
1042 {
1043 while(len--)
1044 {
1045 // Note: Due to a PIC18F97J60 bug, you must use the MOVFF instruction to
1046 // write to EDATA or else the read pointer (ERDPT) will inadvertently
1047 // increment.
1048 #if defined(HI_TECH_C)
1049 ErrataTemp = *val++;
1050 asm("movff _ErrataTemp, _EDATA");
1051 #else
1052 BYTE i;
1053
1054 i = *val++;
1055 _asm movff i, EDATA _endasm
1056 #endif
1057 }
1058 }//end MACPutArray
1059
1060 void MACPutROMArray(ROM BYTE *val, WORD len)
1061 {
1062 while(len--)
1063 {
1064 // Note: Due to a PIC18F97J60 bug, you must use the MOVFF instruction to
1065 // write to EDATA or else the read pointer (ERDPT) will inadvertently
1066 // increment.
1067 #if defined(HI_TECH_C)
1068 ErrataTemp = *val++;
1069 asm("movff _ErrataTemp, _EDATA");
1070 #else
1071 BYTE i;
1072
1073 i = *val++;
1074 _asm movff i, EDATA _endasm
1075 #endif
1076 }
1077 }//end MACPutArray
1078
1079
1080 /******************************************************************************
1081 * Function: ReadPHYReg
1082 *
1083 * PreCondition: Ethernet module must be enabled (ECON1.ETHEN = 1).
1084 *
1085 * Input: Address of the PHY register to read from.
1086 *
1087 * Output: 16 bits of data read from the PHY register.
1088 *
1089 * Side Effects: None
1090 *
1091 * Overview: ReadPHYReg performs an MII read operation. While in
1092 * progress, it simply polls the MII BUSY bit wasting time
1093 * (10.24us).
1094 *
1095 * Note: None
1096 *****************************************************************************/
1097 PHYREG ReadPHYReg(BYTE Register)
1098 {
1099 PHYREG Result;
1100
1101 // Set the right address and start the register read operation
1102 MIREGADR = Register; Nop();
1103 MICMD = MICMD_MIIRD; Nop();
1104
1105 // Loop to wait until the PHY register has been read through the MII
1106 // This requires 10.24us
1107 while(MISTATbits.BUSY);
1108
1109 // Stop reading
1110 MICMD = 0x00; Nop();
1111
1112 // Obtain results and return
1113 Result.VAL.v[0] = MIRDL;
1114 Nop();
1115 Result.VAL.v[1] = MIRDH;
1116
1117 return Result;
1118 }//end ReadPHYReg
1119
1120
1121 /******************************************************************************
1122 * Function: WritePHYReg
1123 *
1124 * PreCondition: Ethernet module must be enabled (ECON1.ETHEN = 1).
1125 *
1126 * Input: Address of the PHY register to write to.
1127 * 16 bits of data to write to PHY register.
1128 *
1129 * Output: None
1130 *
1131 * Side Effects: None
1132 *
1133 * Overview: WritePHYReg performs an MII write operation. While in
1134 * progress, it simply polls the MII BUSY bit wasting time
1135 * (10.24us).
1136 *
1137 * Note: None
1138 *****************************************************************************/
1139 void WritePHYReg(BYTE Register, WORD Data)
1140 {
1141 // Write the register address
1142 MIREGADR = Register; Nop();
1143
1144 // Write the data
1145 // Order is important: write low byte first, high byte last
1146 MIWRL = ((WORD_VAL*)&Data)->v[0]; Nop();
1147 MIWRH = ((WORD_VAL*)&Data)->v[1]; Nop();
1148
1149 // Wait until the PHY register has been written
1150 // This operation requires 10.24us
1151 while(MISTATbits.BUSY);
1152 }//end WritePHYReg
1153
1154
1155 /******************************************************************************
1156 * Function: void MACPowerDown(void)
1157 *
1158 * PreCondition: None
1159 *
1160 * Input: None
1161 *
1162 * Output: None
1163 *
1164 * Side Effects: None
1165 *
1166 * Overview: MACPowerDown disables the Ethernet module.
1167 * All MAC and PHY registers should not be accessed.
1168 *
1169 * Note: Normally, this function would be called before putting the
1170 * PIC to sleep. If a packet is being transmitted while this
1171 * function is called, this function will block until it is
1172 * it complete. If anything is being received, it will be
1173 * completed.
1174 *
1175 * The Ethernet module will continue to draw significant
1176 * power in sleep mode if this function is not called first.
1177 *****************************************************************************/
1178 void MACPowerDown(void)
1179 {
1180 // Disable packet reception
1181 ECON1bits.RXEN = 0;
1182
1183 // Make sure any last packet which was in-progress when RXEN was cleared
1184 // is completed
1185 while(ESTATbits.RXBUSY);
1186
1187 // If a packet is being transmitted, wait for it to finish
1188 while(ECON1bits.TXRTS);
1189
1190 // Disable the Ethernet module
1191 ECON2bits.ETHEN = 0;
1192 }//end MACPowerDown
1193
1194 /******************************************************************************
1195 * Function: void MACPowerUp(void)
1196 *
1197 * PreCondition: None
1198 *
1199 * Input: None
1200 *
1201 * Output: None
1202 *
1203 * Side Effects: None
1204 *
1205 * Overview: MACPowerUp returns the Ethernet module back to normal operation
1206 * after a previous call to MACPowerDown(). Calling this
1207 * function when already powered up will have no effect.
1208 *
1209 * Note: If a link partner is present, it will take 10s of
1210 * milliseconds before a new link will be established after
1211 * waking up. While not linked, packets which are
1212 * transmitted will most likely be lost. MACIsLinked() can
1213 * be called to determine if a link is established.
1214 *****************************************************************************/
1215 void MACPowerUp(void)
1216 {
1217 // Power up the Ethernet module
1218 ECON2bits.ETHEN = 1;
1219
1220 // Wait for PHY to become ready
1221 while(!ESTATbits.PHYRDY)
1222
1223 // Enable packet reception
1224 ECON1bits.RXEN = 1;
1225 }//end MACPowerUp
1226
1227
1228
1229 /******************************************************************************
1230 * Function: void SetRXHashTableEntry(MAC_ADDR DestMACAddr)
1231 *
1232 * PreCondition: SPI bus must be initialized (done in MACInit()).
1233 *
1234 * Input: DestMACAddr: 6 byte group destination MAC address to allow
1235 * through the Hash Table Filter
1236 *
1237 * Output: Sets the appropriate bit in the EHT* registers to allow
1238 * packets sent to DestMACAddr to be received if the Hash
1239 * Table receive filter is enabled
1240 *
1241 * Side Effects: None
1242 *
1243 * Overview: Calculates a CRC-32 using polynomial 0x4C11DB7 and then,
1244 * using bits 28:23 of the CRC, sets the appropriate bit in
1245 * the EHT* registers
1246 *
1247 * Note: This code is commented out to save code space on systems
1248 * that do not need this function. Change the "#if 0" line
1249 * to "#if 1" to uncomment it.
1250 *****************************************************************************/
1251 #if 0
1252 void SetRXHashTableEntry(MAC_ADDR DestMACAddr)
1253 {
1254 DWORD_VAL CRC = {0xFFFFFFFF};
1255 BYTE *HTRegister;
1256 BYTE i, j;
1257
1258 // Calculate a CRC-32 over the 6 byte MAC address
1259 // using polynomial 0x4C11DB7
1260 for(i = 0; i < sizeof(MAC_ADDR); i++)
1261 {
1262 BYTE crcnext;
1263
1264 // shift in 8 bits
1265 for(j = 0; j < 8; j++)
1266 {
1267 crcnext = 0;
1268 if(((BYTE_VAL*)&(CRC.v[3]))->bits.b7)
1269 crcnext = 1;
1270 crcnext ^= (((BYTE_VAL*)&DestMACAddr.v[i])->bits.b0);
1271
1272 CRC.Val <<= 1;
1273 if(crcnext)
1274 CRC.Val ^= 0x4C11DB7;
1275 // next bit
1276 DestMACAddr.v[i] >>= 1;
1277 }
1278 }
1279
1280 // CRC-32 calculated, now extract bits 28:23
1281 // Bits 25:23 define where within the Hash Table byte the bit needs to be set
1282 // Bits 28:26 define which of the 8 Hash Table bytes that bits 25:23 apply to
1283 i = CRC.v[3] & 0x1F;
1284 HTRegister = (i >> 2) + &EHT0;
1285 i = (i << 1) & 0x06;
1286 ((BYTE_VAL*)&i)->bits.b0 = ((BYTE_VAL*)&CRC.v[2])->bits.b7;
1287
1288 // Set the proper bit in the Hash Table
1289 *HTRegister |= 1<<i;
1290 }
1291 #endif
1292
1293
1294
1295 #endif //#if (defined(__18F97J60) || defined(__18F96J65) || defined(__18F96J60) || defined(__18F87J60) || defined(__18F86J65) || defined(__18F86J60) || defined(__18F67J60) || defined(__18F66J65) || defined(__18F66J60)) || defined(HI_TECH_C) && !defined(STACK_USE_SLIP)

  ViewVC Help
Powered by ViewVC 1.1.20