📄 enc28j60.c
字号:
/*********************************************************************
*
* MAC Module (Microchip ENC28J60) for Microchip TCP/IP Stack
*
*********************************************************************
* FileName: ENC28J60.c
* Dependencies: ENC28J60.h
* MAC.h
* string.h
* StackTsk.h
* Helpers.h
* Delay.h
* Processor: PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F
* Complier: Microchip C18 v3.02 or higher
* Microchip C30 v2.01 or higher
* Company: Microchip Technology, Inc.
*
* Software License Agreement
*
* This software is owned by Microchip Technology Inc. ("Microchip")
* and is supplied to you for use exclusively as described in the
* associated software agreement. This software is protected by
* software and other intellectual property laws. Any use in
* violation of the software license may subject the user to criminal
* sanctions as well as civil liability. Copyright 2006 Microchip
* Technology Inc. All rights reserved.
*
* This software is provided "AS IS." MICROCHIP DISCLAIMS ALL
* WARRANTIES, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, NOT LIMITED
* TO MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
* INFRINGEMENT. Microchip shall in no event be liable for special,
* incidental, or consequential damages.
*
*
* Author Date Comment
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Howard Schlunder 6/28/04 Original
* Howard Schlunder 10/8/04 Cleanup
* Howard Schlunder 10/19/04 Small optimizations and more cleanup
* Howard Schlunder 11/29/04 Added Set/GetCLKOUT
* Howard Schlunder 12/23/05 Added B1 silicon errata workarounds
* Howard Schlunder 1/09/06 Added comments and minor mods
* Howard Schlunder 1/18/06 Added more silicon errata workarounds
* Howard Schlunder 6/16/06 Synchronized with PIC18F97J60 code
* Howard Schlunder 7/17/06 Updated TestMemory() for C30
* Howard Schlunder 8/07/06 Added SetRXHashTableEntry() function
********************************************************************/
#define THIS_IS_MAC_LAYER
#include <string.h>
#include "..\Include\StackTsk.h"
#include "..\Include\Helpers.h"
#include "..\Include\Delay.h"
#include "..\Include\MAC.h"
#include "..\Include\ENC28J60.h"
#if defined(STACK_USE_SLIP)
#error Unexpected module is detected.
#error This file must be linked when SLIP module is not in use.
#endif
/** D E F I N I T I O N S ****************************************************/
// IMPORTANT SPI NOTE: The code in this file expects that the SPI interrupt
// flag (ENC_SPI_IF) be clear at all times. If the SPI is shared with
// other hardware, the other code should clear the ENC_SPI_IF when it is
// done using the SPI.
// Since the ENC28J60 doesn't support auto-negotiation, full-duplex mode is
// not compatible with most switches/routers. If a dedicated network is used
// where the duplex of the remote node can be manually configured, you may
// change this configuration. Otherwise, half duplex should always be used.
#define HALF_DUPLEX
//#define FULL_DUPLEX
//#define LEDB_DUPLEX
// Pseudo Functions
#define LOW(a) (a & 0xFF)
#define HIGH(a) ((a>>8) & 0xFF)
// NIC RAM definitions
#define RAMSIZE 8192ul
#define TXSTART (RAMSIZE-(MAC_TX_BUFFER_COUNT * (MAC_TX_BUFFER_SIZE + 8ul)))
#define RXSTART (0ul) // Should be an even memory address
#define RXSTOP ((TXSTART-2ul) | 0x0001ul) // Odd for errata workaround
#define RXSIZE (RXSTOP-RXSTART+1ul)
// ENC28J60 Opcodes (to be ORed with a 5 bit address)
#define WCR (0b010<<5) // Write Control Register command
#define BFS (0b100<<5) // Bit Field Set command
#define BFC (0b101<<5) // Bit Field Clear command
#define RCR (0b000<<5) // Read Control Register command
#define RBM ((0b001<<5) | 0x1A) // Read Buffer Memory command
#define WBM ((0b011<<5) | 0x1A) // Write Buffer Memory command
#define SR ((0b111<<5) | 0x1F) // System Reset command does not use an address.
// It requires 0x1F, however.
#define ETHER_IP (0x00u)
#define ETHER_ARP (0x06u)
#define MAXFRAMEC (1500u+sizeof(ETHER_HEADER)+4u)
// A generic structure representing the Ethernet header starting all Ethernet
// frames
typedef struct _ETHER_HEADER
{
MAC_ADDR DestMACAddr;
MAC_ADDR SourceMACAddr;
WORD_VAL Type;
} ETHER_HEADER;
// A header appended at the start of all RX frames by the hardware
typedef struct _ENC_PREAMBLE
{
WORD NextPacketPointer;
RXSTATUS StatusVector;
MAC_ADDR DestMACAddr;
MAC_ADDR SourceMACAddr;
WORD_VAL Type;
} ENC_PREAMBLE;
typedef struct _DATA_BUFFER
{
WORD_VAL StartAddress;
WORD_VAL EndAddress;
struct
{
unsigned char bFree : 1;
unsigned char bTransmitted : 1;
} Flags;
} DATA_BUFFER;
// Prototypes of functions intended for MAC layer use only.
static void BankSel(WORD Register);
static REG ReadETHReg(BYTE Address);
static REG ReadMACReg(BYTE Address);
static void WriteReg(BYTE Address, BYTE Data);
static void BFCReg(BYTE Address, BYTE Data);
static void BFSReg(BYTE Address, BYTE Data);
static void SendSystemReset(void);
//static void GetRegs(void);
#ifdef MAC_POWER_ON_TEST
static BOOL TestMemory(void);
#endif
// Internal and externally used MAC level variables.
#if MAC_TX_BUFFER_COUNT > 1
static DATA_BUFFER TxBuffers[MAC_TX_BUFFER_COUNT];
#endif
BUFFER CurrentTxBuffer;
BUFFER LastTXedBuffer;
// Internal MAC level variables and flags.
WORD_VAL NextPacketLocation;
WORD_VAL CurrentPacketLocation;
BOOL WasDiscarded;
BYTE ENCRevID;
/******************************************************************************
* Function: void MACInit(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: MACInit sets up the PIC's SPI module and all the
* registers in the ENC28J60 so that normal operation can
* begin.
*
* Note: None
*****************************************************************************/
void MACInit(void)
{
BYTE i;
// Set up the SPI module on the PIC for communications with the ENC28J60
ENC_CS_IO = 1;
ENC_CS_TRIS = 0; // Make the Chip Select pin an output
ENC_SCK_TRIS = 0;
ENC_SDO_TRIS = 0;
ENC_SDI_TRIS = 1;
// Set up SPI
#if defined(__18CXX)
ENC_SPICON1 = 0x20; // SSPEN bit is set, SPI in master mode, FOSC/4,
// IDLE state is low level
ENC_SPI_IF = 0;
ENC_SPISTATbits.CKE = 1; // Transmit data on rising edge of clock
ENC_SPISTATbits.SMP = 0; // Input sampled at middle of data output time
#else
ENC_SPISTAT = 0; // clear SPI
#if defined(__PIC24H__) || defined(__dsPIC33F__)
ENC_SPICON1 = 0x0F; // 1:1 primary prescale, 5:1 secondary prescale (8MHz @ 40MIPS)
// 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.)
#elif defined(__PIC24F__)
// ENC_SPICON1 = 0x1F; // 1:1 prescale broken on PIC24F ES silicon (16MHz @ 16MIPS)
ENC_SPICON1 = 0x1B; // 1:1 primary prescale, 2:1 secondary prescale (8MHz @ 16MIPS)
#else // dsPIC30F
ENC_SPICON1 = 0x17; // 1:1 primary prescale, 3:1 secondary prescale (10MHz @ 30MIPS)
#endif
ENC_SPICON2 = 0;
ENC_SPICON1bits.CKE = 1;
ENC_SPICON1bits.MSTEN = 1;
ENC_SPISTATbits.SPIEN = 1;
#endif
// Wait for CLKRDY to become set.
// Bit 3 in ESTAT is an unimplemented bit. If it reads out as '1' that
// means the part is in RESET or there is something wrong with the SPI
// connection. This loop makes sure that we can communicate with the
// ENC28J60 before proceeding.
do
{
i = ReadETHReg(ESTAT).Val;
} while((i & 0x08) || (~i & ESTAT_CLKRDY));
#ifdef MAC_POWER_ON_TEST
// Do the memory test and enter a while always trap if a hardware error
// occured. The LEDA and LEDB pins will be configured to blink
// periodically in an abnormal manner to indicate to the user that the
// error occured.
if( !TestMemory() )
{
SetLEDConfig(0x0AA2); // Set LEDs to blink periodically
while(1);
}
#endif
// RESET the entire ENC28J60, clearing all registers
SendSystemReset();
DelayMs(1);
#if MAC_TX_BUFFER_COUNT > 1
// On Init, all transmit buffers are free.
for (i = 0; i < MAC_TX_BUFFER_COUNT; i++ )
{
TxBuffers[i].StartAddress.Val = TXSTART + ((WORD)i * (MAC_TX_BUFFER_SIZE+8));
TxBuffers[i].Flags.bFree = TRUE;
}
#endif
CurrentTxBuffer = 0;
// Start up in Bank 0 and configure the receive buffer boundary pointers
// and the buffer write protect pointer (receive buffer read pointer)
WasDiscarded = TRUE;
NextPacketLocation.Val = RXSTART;
WriteReg(ERXSTL, LOW(RXSTART));
WriteReg(ERXSTH, HIGH(RXSTART));
WriteReg(ERXRDPTL, LOW(RXSTOP)); // Write low byte first
WriteReg(ERXRDPTH, HIGH(RXSTOP)); // Write high byte last
#if RXSTOP != 0x1FFF // The RESET default ERXND is 0x1FFF
WriteReg(ERXNDL, LOW(RXSTOP));
WriteReg(ERXNDH, HIGH(RXSTOP));
#endif
#if TXSTART != 0 // The RESET default ETXST is 0
WriteReg(ETXSTL, LOW(TXSTART));
WriteReg(ETXSTH, HIGH(TXSTART));
#endif
// Enter Bank 1 and configure Receive Filters
// (No need to reconfigure - Unicast OR Broadcast with CRC checking is
// acceptable)
// Write ERXFCON_CRCEN only to ERXFCON to enter promiscuous mode
//BankSel(ERXFCON);
//WriteReg((BYTE)ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_BCEN | ERXFCON_HTEN);
// Enter Bank 2 and configure the MAC
BankSel(MACON1);
// Enable the receive portion of the MAC
WriteReg((BYTE)MACON1, MACON1_TXPAUS | MACON1_RXPAUS | MACON1_MARXEN);
// Pad packets to 60 bytes, add CRC, and check Type/Length field.
WriteReg((BYTE)MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN);
// Allow infinite deferals if the medium is continuously busy
// (do not time out a transmission if the half duplex medium is
// completely saturated with other people's data)
WriteReg((BYTE)MACON4, MACON4_DEFER);
// Late collisions occur beyond 63+8 bytes (8 bytes for preamble/start of frame delimiter)
// 55 is all that is needed for IEEE 802.3, but ENC28J60 B5 errata for improper link pulse
// collisions will occur less often with a larger number.
WriteReg((BYTE)MACLCON2, 63);
// Set non-back-to-back inter-packet gap to 9.6us. The back-to-back
// inter-packet gap (MABBIPG) is set by MACSetDuplex() which is called
// later.
WriteReg((BYTE)MAIPGL, 0x12);
WriteReg((BYTE)MAIPGH, 0x0C);
// Set the maximum packet size which the controller will accept
WriteReg((BYTE)MAMXFLL, LOW(MAXFRAMEC));
WriteReg((BYTE)MAMXFLH, HIGH(MAXFRAMEC));
// Enter Bank 3 and initialize physical MAC address registers
BankSel(MAADR1);
WriteReg((BYTE)MAADR1, AppConfig.MyMACAddr.v[0]);
WriteReg((BYTE)MAADR2, AppConfig.MyMACAddr.v[1]);
WriteReg((BYTE)MAADR3, AppConfig.MyMACAddr.v[2]);
WriteReg((BYTE)MAADR4, AppConfig.MyMACAddr.v[3]);
WriteReg((BYTE)MAADR5, AppConfig.MyMACAddr.v[4]);
WriteReg((BYTE)MAADR6, AppConfig.MyMACAddr.v[5]);
// Get the Rev ID so that we can implement the correct errata workarounds
ENCRevID = ReadETHReg((BYTE)EREVID).Val;
// Disable half duplex loopback in PHY. Bank bits changed to Bank 2 as a
// side effect.
WritePHYReg(PHCON2, PHCON2_HDLDIS);
// Configure LEDA to display LINK status, LEDB to display TX/RX activity
SetLEDConfig(0x0472);
// Set the MAC and PHY into the proper duplex state
#if defined(FULL_DUPLEX)
MACSetDuplex(FULL); // Function exits with Bank 2 selected
#elif defined(HALF_DUPLEX)
MACSetDuplex(HALF); // Function exits with Bank 2 selected
#else
// Use the external LEDB polarity to determine weather full or half duplex
// communication mode should be set.
MACSetDuplex(USE_PHY); // Function exits with Bank 2 selected
#endif
// Enable packet reception
BFSReg(ECON1, ECON1_RXEN);
}//end MACInit
/******************************************************************************
* Function: BOOL MACIsLinked(void)
*
* PreCondition: None
*
* Input: None
*
* Output: TRUE: If the PHY reports that a link partner is present
* and the link has been up continuously since the last
* call to MACIsLinked()
* FALSE: If the PHY reports no link partner, or the link went
* down momentarily since the last call to MACIsLinked()
*
* Side Effects: None
*
* Overview: Returns the PHSTAT1.LLSTAT bit.
*
* Note: None
*****************************************************************************/
BOOL MACIsLinked(void)
{
// LLSTAT is a latching low link status bit. Therefore, if the link
// goes down and comes back up before a higher level stack program calls
// MACIsLinked(), MACIsLinked() will still return FALSE. The next
// call to MACIsLinked() will return TRUE (unless the link goes down
// again).
return ReadPHYReg(PHSTAT1).PHSTAT1bits.LLSTAT;
}
/******************************************************************************
* Function: BOOL MACIsTxReady(BOOL HighPriority)
*
* PreCondition: None
*
* Input: HighPriority: TRUE: Check the hardware ECON1.TXRTS bit
* FALSE: Check if a TX buffer is free
*
* Output: TRUE: If no Ethernet transmission is in progress
* FALSE: If a previous transmission was started, and it has
* not completed yet. While FALSE, the data in the
* transmit buffer and the TXST/TXND pointers must not
* be changed.
*
* Side Effects: None
*
* Overview: Returns the ECON1.TXRTS bit
*
* Note: None
*****************************************************************************/
BOOL MACIsTxReady(BOOL HighPriority)
{
#if MAC_TX_BUFFER_COUNT > 1
BUFFER i;
if(HighPriority)
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -