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

Powered by WebSVN v2.8.3