📄 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
* Complier: MCC18 v3.00 or higher
* HITECH PICC-18 V8.10PL1 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 2/20/06 Fixed TXSTART, RXSTOP
********************************************************************/
#define THIS_IS_MAC_LAYER
#include <string.h>
#include "StackTsk.h"
//#include "Helpers.h"
//#include "Delay.h"
#include "MAC.h"
#include "ENC28J60.h"
extern void delay( unsigned short time);
extern unsigned char getSPIchar(unsigned char Address);
extern void putSPIchar2(unsigned char Address, unsigned char Data);
extern void putSPIchar(char ucData);
#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 ****************************************************/
/* Hardware interface to NIC. */
#define MCP_RESET_TRIS (TRISB_RB5)
#define MCP_RESET_IO (LATB5)
#define MCP_CS_TRIS (TRISB_RB3)
#define MCP_CS_IO (LATB3)
// The following SPI pins are used but are not configurable
// RC3 is used for the SCK pin and is an output
// RC4 is used for the SDI pin and is an input
// RC5 is used for the SDO pin and is an output
// IMPORTANT SPI NOTE: The code in this file expects that the SPI interrupt
// flag (PIR1_SSPIF) be clear at all times. If the SPI is shared with
// other hardware, the other code should clear the PIR1_SSPIF 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)
#define SPISelectEthernet() MCP_CS_IO = 0
#define SPIUnselectEthernet() MCP_CS_IO = 1
/* 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 (0x2<<5) // Write Control Register command
#define BFS (0x4<<5) // Bit Field Set command
#define BFC (0x5<<5) // Bit Field Clear command
#define RCR (0x000<<5) // Read Control Register command
#define RBM ((0x1<<5) | 0x1A) // Read Buffer Memory command
#define WBM ((0x3<<5) | 0x1A) // Write Buffer Memory command
#define SR ((0x7<<5) | 0x1F) // System Reset command does not use an address.
// It requires 0x1F, however.
#define ETHER_IP (0x00)
#define ETHER_ARP (0x06)
#define MAXFRAMEC (1500+sizeof(ETHER_HEADER)+4)
APP_CONFIG AppConfig;
// A generic structure representing the Ethernet header starting all Ethernet
// frames
typedef struct _ETHER_HEADER
{
MAC_ADDR DestMACAddr;
MAC_ADDR SourceMACAddr;
WORD_VAL Type;
}__attribute__ ((packed)) ETHER_HEADER;
// A header appended at the start of all RX frames by the hardware
typedef struct _MCP_PREAMBLE
{
WORD NextPacketPointer;//2
RXSTATUS StatusVector;//4
MAC_ADDR DestMACAddr;//6
MAC_ADDR SourceMACAddr;//6
WORD_VAL Type;//2
} __attribute__ ((packed)) MCP_PREAMBLE;
typedef struct _DATA_BUFFER
{
WORD_VAL StartAddress;
// WORD_VAL EndAddress;
BOOL bFree;
}__attribute__ ((packed)) DATA_BUFFER;
/* Prototypes of functions intended for MAC layer use only */
void BankSel(WORD Register);
REG ReadETHReg(unsigned char Address);
REG ReadMACReg(unsigned char Address);
void WriteReg(unsigned char Address, unsigned char Data);
void BFCReg(unsigned char Address, unsigned char Data);
void BFSReg(unsigned char Address, unsigned char Data);
void SendSystemReset(void);
void Software_Reset_Ethernet(void);
unsigned char Read_RCR(unsigned char addr);
unsigned char Read_MACRCR(unsigned char addr);
void Write_WCR(unsigned char addr,unsigned char data);
unsigned char Read_RBM(void);
void Write_WBM(unsigned char data);
void Set_BFS(unsigned char addr,unsigned char data);
void Clear_BFC(unsigned char addr,unsigned char data);
void Bank_Select(unsigned char bank);
void Write_PHY(unsigned char addr,unsigned int data);
unsigned int Read_PHY(unsigned char addr);
unsigned int Scan_PHY(unsigned char addr);
void Led_Init(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
unsigned char NICCurrentTxBuffer;
/* Internal MAC level variables and flags */
WORD_VAL NextPacketLocation;
WORD_VAL CurrentPacketLocation;
BOOL WasDiscarded;
/***added by lfei 2007/02/05********/
/*function: Used for transmitting data packet for MACFLUSH*/
unsigned char ENCRevID;
/*******************************/
unsigned short swaps(unsigned short v)
{
WORD_VAL t;
unsigned char b;
t.Val = v;
b = t.v[1];
t.v[1] = t.v[0];
t.v[0] = b;
return t.Val;
}
/******************************************************************************
* 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
*****************************************************************************/
short MACInit(void)
{
unsigned char i;
short Ret = 1;
int j=0;
// 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 otherwise our SPI pin is being driven
// incorrectly. Make sure it is working before proceeding.
j = 0;
do
{
i = ReadETHReg(ESTAT).Val;
j++;
if(j>=5000)
{
Ret = 0;
break;
}
} 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();
delay(1000);
#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 = TXSTART + ((WORD)i * (MAC_TX_BUFFER_SIZE+8));
TxBuffers[i].bFree = TRUE;
}
#endif
NICCurrentTxBuffer = 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)
*/
BankSel(ERXFCON);
WriteReg(ERXFCON, ERXFCON_CRCEN);
/*
* Enter Bank 2 and configure the MAC
*/
BankSel(MACON1);
/*--------added by lfei 2007/01/21--*/
// Clear MARST in MACON2, MAC exits reset status
WriteReg( MACON2, MACON2_MARST_CLR);
/*-------------------------------*/
// Enable the receive portion of the MAC
WriteReg(MACON1, MACON1_TXPAUS | MACON1_RXPAUS | MACON1_MARXEN);
// Pad packets to 60 bytes, add CRC, and check Type/Length field.
// Default status of FULDPX is 0, that is, MAC is in half-duplex mode
WriteReg(MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN);
// 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(MAIPGL, 0x12);
WriteReg(MAIPGH, 0x0C);
// Set the maximum packet size which the controller will accept
WriteReg(MAMXFLL, LOW(MAXFRAMEC));
WriteReg(MAMXFLH, HIGH(MAXFRAMEC));
/*
* Enter Bank 3 and initialize physical MAC address registers
*/
BankSel(MAADR1);
// print1("Set MAC address:\n");
WriteReg(MAADR1, MY_MAC_BYTE1);
if(Read_MACRCR(MAADR1)!=MY_MAC_BYTE1)
Ret = 0;
WriteReg(MAADR2, MY_MAC_BYTE2);
if(Read_MACRCR(MAADR2)!=MY_MAC_BYTE2)
Ret = 0;
WriteReg(MAADR3, MY_MAC_BYTE3);
if(Read_MACRCR(MAADR3)!=MY_MAC_BYTE3)
Ret = 0;
WriteReg(MAADR4, MY_MAC_BYTE4);
if(Read_MACRCR(MAADR4)!=MY_MAC_BYTE4)
Ret = 0;
WriteReg(MAADR5, MY_MAC_BYTE5);
if(Read_MACRCR(MAADR5)!=MY_MAC_BYTE5)
Ret = 0;
WriteReg(MAADR6, MY_MAC_BYTE6);
if(Read_MACRCR(MAADR6)!=MY_MAC_BYTE6)
Ret = 0;
/***added by lfei 2007/02/05********************/
// Get the Rev ID so that we can implement the correct errata workarounds
return Ret;
}//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;
// return 0;
}
/******************************************************************************
* Function: BOOL MACIsTxReady(void)
*
* PreCondition: None
*
* Input: None
*
* 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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -