Subversion Repositories HomeAutomation

Rev

Details | Last modification | View Log | SVN | RSS feed

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