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