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) |
Powered by WebSVN v2.8.3