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