You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
714 lines
19 KiB
714 lines
19 KiB
/*! \file enc28j60.c \brief Microchip ENC28J60 Ethernet Interface Driver. */
|
|
//*****************************************************************************
|
|
//
|
|
// File Name : 'enc28j60.c'
|
|
// Title : Microchip ENC28J60 Ethernet Interface Driver
|
|
// Author : Pascal Stang (c)2005
|
|
// Created : 9/22/2005
|
|
// Revised : 9/22/2005
|
|
// Version : 0.1
|
|
// Target MCU : Atmel AVR series
|
|
// Editor Tabs : 4
|
|
//
|
|
// Description : This driver provides initialization and transmit/receive
|
|
// functions for the Microchip ENC28J60 10Mb Ethernet Controller and PHY.
|
|
// This chip is novel in that it is a full MAC+PHY interface all in a 28-pin
|
|
// chip, using an SPI interface to the host processor.
|
|
//
|
|
//*****************************************************************************
|
|
#include "wiring.h"
|
|
#include <avr/pgmspace.h>
|
|
#include "avr/io.h"
|
|
|
|
#include "avrlibdefs.h"
|
|
#include "avrlibtypes.h"
|
|
|
|
#include "HardwareSerial.h"
|
|
|
|
#include "programStrings.h"
|
|
|
|
// include configuration
|
|
#include "enc28j60conf.h"
|
|
#include "enc28j60.h"
|
|
|
|
#ifdef SPDR0
|
|
#define SPDR SPDR0
|
|
#define SPCR SPCR0
|
|
#define SPSR SPSR0
|
|
|
|
#define SPIF SPIF0
|
|
#define MSTR MSTR0
|
|
#define CPOL CPOL0
|
|
#define DORD DORD0
|
|
#define SPR0 SPR00
|
|
#define SPR1 SPR01
|
|
#define SPI2X SPI2X0
|
|
#define SPE SPE0
|
|
#endif
|
|
|
|
u08 Enc28j60Bank;
|
|
u16 NextPacketPtr;
|
|
|
|
void nicInit(void)
|
|
{
|
|
enc28j60Init();
|
|
}
|
|
|
|
void nicSend(unsigned int len, unsigned char* packet)
|
|
{
|
|
enc28j60PacketSend(len, packet);
|
|
}
|
|
|
|
unsigned int nicPoll(unsigned int maxlen, unsigned char* packet)
|
|
{
|
|
return enc28j60PacketReceive(maxlen, packet);
|
|
}
|
|
|
|
void nicGetMacAddress(uint8_t* macaddr)
|
|
{
|
|
// read MAC address registers
|
|
// NOTE: MAC address in ENC28J60 is byte-backward
|
|
*macaddr++ = enc28j60Read(MAADR5);
|
|
*macaddr++ = enc28j60Read(MAADR4);
|
|
*macaddr++ = enc28j60Read(MAADR3);
|
|
*macaddr++ = enc28j60Read(MAADR2);
|
|
*macaddr++ = enc28j60Read(MAADR1);
|
|
*macaddr++ = enc28j60Read(MAADR0);
|
|
}
|
|
|
|
void nicSetMacAddress(uint8_t* macaddr)
|
|
{
|
|
// write MAC address
|
|
// NOTE: MAC address in ENC28J60 is byte-backward
|
|
enc28j60Write(MAADR5, *macaddr++);
|
|
enc28j60Write(MAADR4, *macaddr++);
|
|
enc28j60Write(MAADR3, *macaddr++);
|
|
enc28j60Write(MAADR2, *macaddr++);
|
|
enc28j60Write(MAADR1, *macaddr++);
|
|
enc28j60Write(MAADR0, *macaddr++);
|
|
}
|
|
|
|
void nicRegDump(void)
|
|
{
|
|
enc28j60RegDump();
|
|
}
|
|
|
|
void nicHardReset(void)
|
|
{
|
|
#ifndef ENC28J60_HARD_RESET_DISABLED
|
|
enc28j60hardReset();
|
|
#endif
|
|
}
|
|
|
|
void nicSoftReset(void)
|
|
{
|
|
enc28j60softReset();
|
|
}
|
|
|
|
void nicReboot(void)
|
|
{
|
|
enc28j60Reboot();
|
|
}
|
|
|
|
void enc28j60Reboot(void)
|
|
{
|
|
#ifndef ENC28J60_HARD_RESET_DISABLED
|
|
enc28j60hardReset();
|
|
#else
|
|
delayMicroseconds(10);
|
|
#endif
|
|
|
|
enc28j60softReset();
|
|
}
|
|
|
|
void enc28j60softReset(void)
|
|
{
|
|
// perform system reset
|
|
enc28j60WriteOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
|
|
delayMicroseconds(50);
|
|
|
|
// check CLKRDY bit to see if reset is complete
|
|
//while(!(enc28j60Read(ESTAT) & ESTAT_CLKRDY));
|
|
// Errata workaround #1, CLKRDY check is unreliable, delay 1 mS instead
|
|
delay(1);
|
|
}
|
|
|
|
#ifndef ENC28J60_HARD_RESET_DISABLED
|
|
void enc28j60hardReset(void)
|
|
{
|
|
// HW reset
|
|
sbi(ENC28J60_CONTROL_DDR, ENC28J60_CONTROL_HRESET);
|
|
|
|
cbi(ENC28J60_CONTROL_PORT, ENC28J60_CONTROL_HRESET); // Down
|
|
delayMicroseconds(10);
|
|
sbi(ENC28J60_CONTROL_PORT, ENC28J60_CONTROL_HRESET); // Up
|
|
|
|
delay(1);
|
|
}
|
|
#endif
|
|
|
|
uint8_t enc28j60ReadOp(uint8_t op, uint8_t address)
|
|
{
|
|
uint8_t data;
|
|
|
|
// assert CS
|
|
cbi(ENC28J60_CONTROL_PORT, ENC28J60_CONTROL_CS);
|
|
|
|
// issue read command
|
|
SPDR = op | (address & ADDR_MASK);
|
|
while(!(SPSR & (1<<SPIF)));
|
|
// read data
|
|
SPDR = 0x00;
|
|
while(!(SPSR & (1<<SPIF)));
|
|
// do dummy read if needed
|
|
if(address & 0x80)
|
|
{
|
|
SPDR = 0x00;
|
|
while(!(SPSR & (1<<SPIF)));
|
|
}
|
|
|
|
data = SPDR;
|
|
|
|
// release CS
|
|
sbi(ENC28J60_CONTROL_PORT, ENC28J60_CONTROL_CS);
|
|
|
|
return data;
|
|
}
|
|
|
|
void enc28j60WriteOp(uint8_t op, uint8_t address, uint8_t data)
|
|
{
|
|
// assert CS
|
|
cbi(ENC28J60_CONTROL_PORT, ENC28J60_CONTROL_CS);
|
|
|
|
// issue write command
|
|
SPDR = op | (address & ADDR_MASK);
|
|
while(!(SPSR & (1<<SPIF)));
|
|
|
|
// write data
|
|
SPDR = data;
|
|
while(!(SPSR & (1<<SPIF)));
|
|
|
|
// release CS
|
|
sbi(ENC28J60_CONTROL_PORT, ENC28J60_CONTROL_CS);
|
|
}
|
|
|
|
void enc28j60ReadBuffer(uint16_t len, uint8_t* data)
|
|
{
|
|
// assert CS
|
|
cbi(ENC28J60_CONTROL_PORT, ENC28J60_CONTROL_CS);
|
|
|
|
// issue read command
|
|
SPDR = ENC28J60_READ_BUF_MEM;
|
|
while(!(SPSR & (1<<SPIF)));
|
|
while(len--)
|
|
{
|
|
// read data
|
|
SPDR = 0x00;
|
|
while(!(SPSR & (1<<SPIF)));
|
|
*data++ = SPDR;
|
|
}
|
|
// release CS
|
|
sbi(ENC28J60_CONTROL_PORT, ENC28J60_CONTROL_CS);
|
|
}
|
|
|
|
void enc28j60WriteBuffer(uint16_t len, uint8_t* data)
|
|
{
|
|
// assert CS
|
|
cbi(ENC28J60_CONTROL_PORT, ENC28J60_CONTROL_CS);
|
|
|
|
// issue write command
|
|
SPDR = ENC28J60_WRITE_BUF_MEM;
|
|
while(!(SPSR & (1<<SPIF)));
|
|
while(len--)
|
|
{
|
|
// write data
|
|
SPDR = *data++;
|
|
while(!(SPSR & (1<<SPIF)));
|
|
}
|
|
// release CS
|
|
sbi(ENC28J60_CONTROL_PORT, ENC28J60_CONTROL_CS);
|
|
}
|
|
|
|
void enc28j60SetBank(uint8_t address)
|
|
{
|
|
// set the bank (if needed)
|
|
if((address & BANK_MASK) != Enc28j60Bank)
|
|
{
|
|
// set the bank
|
|
enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1|ECON1_BSEL0));
|
|
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK)>>5);
|
|
Enc28j60Bank = (address & BANK_MASK);
|
|
}
|
|
}
|
|
|
|
uint8_t enc28j60Read(uint8_t address)
|
|
{
|
|
// set the bank
|
|
enc28j60SetBank(address);
|
|
// do the read
|
|
return enc28j60ReadOp(ENC28J60_READ_CTRL_REG, address);
|
|
}
|
|
|
|
void enc28j60Write(uint8_t address, uint8_t data)
|
|
{
|
|
// set the bank
|
|
enc28j60SetBank(address);
|
|
// do the write
|
|
enc28j60WriteOp(ENC28J60_WRITE_CTRL_REG, address, data);
|
|
}
|
|
|
|
uint16_t enc28j60PhyRead(uint8_t address)
|
|
{
|
|
uint16_t data;
|
|
|
|
// Set the right address and start the register read operation
|
|
enc28j60Write(MIREGADR, address);
|
|
enc28j60Write(MICMD, MICMD_MIIRD);
|
|
|
|
// wait until the PHY read completes
|
|
while(enc28j60Read(MISTAT) & MISTAT_BUSY);
|
|
|
|
// quit reading
|
|
enc28j60Write(MICMD, 0x00);
|
|
|
|
// get data value
|
|
data = enc28j60Read(MIRDH);
|
|
data <<= 8;
|
|
data |= enc28j60Read(MIRDL);
|
|
|
|
// return the data
|
|
return data;
|
|
}
|
|
|
|
void enc28j60PhyWrite(uint8_t address, uint16_t data)
|
|
{
|
|
// set the PHY register address
|
|
enc28j60Write(MIREGADR, address);
|
|
|
|
// write the PHY data
|
|
enc28j60Write(MIWRL, data);
|
|
enc28j60Write(MIWRH, data>>8);
|
|
|
|
// wait until the PHY write completes
|
|
while(enc28j60Read(MISTAT) & MISTAT_BUSY);
|
|
}
|
|
|
|
void enc28j60Init(void)
|
|
{
|
|
/**
|
|
* Enable ENC28J560 Control ports
|
|
**/
|
|
// Enable CS and pull it high as CS is inverted
|
|
sbi(ENC28J60_CONTROL_DDR, ENC28J60_CONTROL_CS); // CS as output
|
|
sbi(ENC28J60_CONTROL_PORT, ENC28J60_CONTROL_CS); // CS high
|
|
|
|
// Enable Hard reset and pull it high as RESET is inverted
|
|
#ifndef ENC28J60_HARD_RESET_DISABLED
|
|
sbi(ENC28J60_CONTROL_DDR, ENC28J60_CONTROL_HRESET); // HR as output
|
|
cbi(ENC28J60_CONTROL_PORT, ENC28J60_CONTROL_HRESET); // HR low
|
|
#endif
|
|
|
|
/**
|
|
* setup SPI I/O pins
|
|
**/
|
|
sbi(ENC28J60_CONTROL_DDR, ENC28J60_SPI_SCK); // set SCK as output
|
|
cbi(ENC28J60_CONTROL_PORT, ENC28J60_SPI_SCK); // set SCK lo
|
|
sbi(ENC28J60_CONTROL_DDR, ENC28J60_SPI_MOSI); // set MOSI as output
|
|
cbi(ENC28J60_CONTROL_DDR, ENC28J60_SPI_MISO); // set MISO as input
|
|
|
|
sbi(ENC28J60_CONTROL_PORT, ENC28J60_SPI_SS); // SS must be output for Master mode to work
|
|
|
|
// master mode
|
|
sbi(SPCR, MSTR);
|
|
// select clock phase positive-going in middle of data
|
|
cbi(SPCR, CPOL);
|
|
// Data order MSB first
|
|
cbi(SPCR,DORD);
|
|
// switch to f/4 2X = f/2 bitrate
|
|
cbi(SPCR, SPR0);
|
|
cbi(SPCR, SPR1);
|
|
sbi(SPSR, SPI2X);
|
|
// enable SPI
|
|
sbi(SPCR, SPE);
|
|
delay(1);
|
|
|
|
#ifdef DEBUG_ENC_INIT
|
|
SPrintln_P(PSTR("SPI Enabled"));
|
|
#endif
|
|
// Reboot the ENC28J60
|
|
enc28j60Reboot();
|
|
|
|
#ifdef DEBUG_ENC_INIT
|
|
SPrintln_P(PSTR("PHY reboot done"));
|
|
#endif
|
|
|
|
#ifdef ENC28J60_LAMPS_MODE
|
|
SPrintln_P(PSTR("Custom lamps"));
|
|
enc28j60PhyWrite(PHLCON, ENC28J60_LAMPS_MODE);
|
|
#else
|
|
|
|
// Errata #9 correction
|
|
if (enc28j60Read(MACON3) & MACON3_FULDPX)
|
|
{
|
|
SPrintln_P(PSTR("Full duplex lamps"));
|
|
enc28j60PhyWrite(PHLCON, PHLCON_DEFAULT);
|
|
} else {
|
|
SPrintln_P(PSTR("Half duplex lamps"));
|
|
enc28j60PhyWrite(PHLCON, PHLCON_DEFAULT_HD);
|
|
}
|
|
#endif
|
|
|
|
#ifdef DEBUG_ENC_INIT
|
|
SPrintln_P(PSTR("Lamps set"));
|
|
#endif
|
|
// do bank 0 stuff
|
|
// initialize receive buffer
|
|
// 16-bit transfers, must write low byte first
|
|
|
|
// set receive buffer start address
|
|
NextPacketPtr = RXSTART_INIT;
|
|
enc28j60Write(ERXSTL, RXSTART_INIT&0xFF);
|
|
enc28j60Write(ERXSTH, RXSTART_INIT>>8);
|
|
|
|
// set receive pointer address
|
|
enc28j60Write(ERXRDPTL, RXSTART_INIT&0xFF);
|
|
enc28j60Write(ERXRDPTH, RXSTART_INIT>>8);
|
|
|
|
// set receive buffer end
|
|
// ERXND defaults to 0x1FFF (end of ram)
|
|
enc28j60Write(ERXNDL, RXSTOP_INIT&0xFF);
|
|
enc28j60Write(ERXNDH, RXSTOP_INIT>>8);
|
|
|
|
// set transmit buffer start
|
|
// ETXST defaults to 0x0000 (beginnging of ram)
|
|
enc28j60Write(ETXSTL, TXSTART_INIT&0xFF);
|
|
enc28j60Write(ETXSTH, TXSTART_INIT>>8);
|
|
|
|
// Needs register implementation
|
|
#ifdef ENC28J60_PACKET_FILTER_ENABLED
|
|
// do bank 1 stuff, packet filter:
|
|
// For broadcast packets we allow only ARP packtets
|
|
// All other packets should be unicast only for our mac (MAADR)
|
|
//
|
|
// The pattern to match on is therefore
|
|
// Type ETH.DST
|
|
// ARP BROADCAST
|
|
// 06 08 -- ff ff ff ff ff ff -> ip checksum for theses bytes=f7f9
|
|
// in binary these poitions are:11 0000 0011 1111
|
|
// This is hex 303F->EPMM0=0x3f,EPMM1=0x30
|
|
//enc28j60Write(ERXFCON, ERXFCON_UCEN|ERXFCON_CRCEN|ERXFCON_PMEN);
|
|
enc28j60Write(ERXFCON, ERXFCON_UCEN|ERXFCON_PMEN);
|
|
enc28j60Write(EPMM0, 0x3f);
|
|
enc28j60Write(EPMM1, 0x30);
|
|
enc28j60Write(EPMCSL, 0xf9);
|
|
enc28j60Write(EPMCSH, 0xf7);
|
|
#endif
|
|
|
|
// do bank 2 stuff
|
|
// enable MAC receive
|
|
enc28j60Write(MACON1, MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS);
|
|
// bring MAC out of reset
|
|
enc28j60Write(MACON2, 0x00);
|
|
// enable automatic padding and CRC operations
|
|
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN);
|
|
// enc28j60Write(MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN);
|
|
|
|
// set inter-frame gap (non-back-to-back)
|
|
enc28j60Write(MAIPGL, 0x12);
|
|
enc28j60Write(MAIPGH, 0x0C);
|
|
// set inter-frame gap (back-to-back)
|
|
enc28j60Write(MABBIPG, 0x12);
|
|
// Set the maximum packet size which the controller will accept
|
|
enc28j60Write(MAMXFLL, MAX_FRAMELEN&0xFF);
|
|
enc28j60Write(MAMXFLH, MAX_FRAMELEN>>8);
|
|
|
|
// do bank 3 stuff
|
|
// write MAC address
|
|
// NOTE: MAC address in ENC28J60 is byte-backward
|
|
enc28j60Write(MAADR5, ENC28J60_MAC0);
|
|
enc28j60Write(MAADR4, ENC28J60_MAC1);
|
|
enc28j60Write(MAADR3, ENC28J60_MAC2);
|
|
enc28j60Write(MAADR2, ENC28J60_MAC3);
|
|
enc28j60Write(MAADR1, ENC28J60_MAC4);
|
|
enc28j60Write(MAADR0, ENC28J60_MAC5);
|
|
|
|
// no loopback of transmitted frames
|
|
enc28j60PhyWrite(PHCON2, PHCON2_HDLDIS);
|
|
|
|
// switch to bank 0
|
|
enc28j60SetBank(ECON1);
|
|
// enable interrutps
|
|
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE|EIE_PKTIE);
|
|
// enable packet reception
|
|
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
|
|
|
|
#ifdef DEBUG_ENC_INIT
|
|
SPrintln_P(PSTR("Banks robbed"));
|
|
#endif
|
|
/*
|
|
enc28j60PhyWrite(PHLCON, 0x0AA2);
|
|
|
|
// setup duplex ----------------------
|
|
|
|
// Disable receive logic and abort any packets currently being transmitted
|
|
enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRTS|ECON1_RXEN);
|
|
|
|
{
|
|
uint16_t temp;
|
|
// Set the PHY to the proper duplex mode
|
|
temp = enc28j60PhyRead(PHCON1);
|
|
temp &= ~PHCON1_PDPXMD;
|
|
enc28j60PhyWrite(PHCON1, temp);
|
|
// Set the MAC to the proper duplex mode
|
|
temp = enc28j60Read(MACON3);
|
|
temp &= ~MACON3_FULDPX;
|
|
enc28j60Write(MACON3, temp);
|
|
}
|
|
|
|
// Set the back-to-back inter-packet gap time to IEEE specified
|
|
// requirements. The meaning of the MABBIPG value changes with the duplex
|
|
// state, so it must be updated in this function.
|
|
// In full duplex, 0x15 represents 9.6us; 0x12 is 9.6us in half duplex
|
|
//enc28j60Write(MABBIPG, DuplexState ? 0x15 : 0x12);
|
|
|
|
// Reenable receive logic
|
|
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
|
|
|
|
// setup duplex ----------------------
|
|
*/
|
|
}
|
|
|
|
#define ETHERNET_MIN_PACKET_LENGTH 0x3C
|
|
#define ETHERNET_HEADER_LENGTH 0x0E
|
|
|
|
#define IP_TCP_HEADER_LENGTH 40
|
|
#define TOTAL_HEADER_LENGTH (IP_TCP_HEADER_LENGTH+ETHERNET_HEADER_LENGTH)
|
|
|
|
|
|
void enc28j60PacketSend(uint16_t len, uint8_t* packet)
|
|
{
|
|
/*
|
|
// dump packet
|
|
int i,j;
|
|
for (i=0;i<len;i+=16)
|
|
{
|
|
printf("%04x ",i);
|
|
for (j=0;j<16;j++)
|
|
printf("%02x ",(i+j) < len ? packet[i+j] : 0);
|
|
printf(" ");
|
|
for (j=0;j<16;j++)
|
|
printf("%c", (i+j) < len ? isprint(packet[i+j]) ? packet[i+j] : '.' : '.');
|
|
printf("\n");
|
|
}
|
|
*/
|
|
// Errata workaround #10 Transmit Logic
|
|
if (enc28j60Read(EIR) & EIR_TXERIF)
|
|
{
|
|
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST);
|
|
enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);
|
|
enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, EIR, EIR_TXERIF);
|
|
}
|
|
|
|
// Set the write pointer to start of transmit buffer area
|
|
enc28j60Write(EWRPTL, TXSTART_INIT);
|
|
enc28j60Write(EWRPTH, TXSTART_INIT>>8);
|
|
|
|
// Set the TXND pointer to correspond to the packet size given
|
|
enc28j60Write(ETXNDL, (TXSTART_INIT+len));
|
|
enc28j60Write(ETXNDH, (TXSTART_INIT+len)>>8);
|
|
|
|
// write per-packet control byte
|
|
enc28j60WriteOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00);
|
|
|
|
// TODO, fix this up
|
|
/*
|
|
if( uip_len <= TOTAL_HEADER_LENGTH )
|
|
{
|
|
// copy the packet into the transmit buffer
|
|
enc28j60WriteBuffer(len, packet);
|
|
}
|
|
else
|
|
{
|
|
len -= TOTAL_HEADER_LENGTH;
|
|
enc28j60WriteBuffer(TOTAL_HEADER_LENGTH, packet);
|
|
enc28j60WriteBuffer(len, (unsigned char *)uip_appdata);
|
|
}
|
|
*/
|
|
// copy the packet into the transmit buffer
|
|
enc28j60WriteBuffer(len, packet);
|
|
|
|
// send the contents of the transmit buffer onto the network
|
|
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
|
|
|
|
// if( (enc28j60Read(EIR) & EIR_TXERIF) ){
|
|
// enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRTS);
|
|
// }
|
|
}
|
|
|
|
uint16_t enc28j60PacketReceive(uint16_t maxlen, uint8_t* packet)
|
|
{
|
|
uint16_t rxstat;
|
|
uint16_t len;
|
|
|
|
// check if a packet has been received and buffered
|
|
if( !(enc28j60Read(EIR) & EIR_PKTIF) )
|
|
{
|
|
// Errata workaround #4, PKTIF is not reliable
|
|
// double check by looking at EPKTCNT
|
|
if (enc28j60Read(EPKTCNT) == 0)
|
|
return 0;
|
|
}
|
|
|
|
// Set the read pointer to the start of the received packet
|
|
enc28j60Write(ERDPTL, (NextPacketPtr));
|
|
enc28j60Write(ERDPTH, (NextPacketPtr)>>8);
|
|
|
|
// read the next packet pointer
|
|
NextPacketPtr = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
|
|
NextPacketPtr |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
|
|
|
|
// read the packet length
|
|
len = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
|
|
len |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
|
|
|
|
// read the receive status
|
|
rxstat = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
|
|
rxstat |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
|
|
|
|
// limit retrieve length
|
|
// (we reduce the MAC-reported length by 4 to remove the CRC)
|
|
len = MIN(len, maxlen);
|
|
|
|
// copy the packet from the receive buffer
|
|
enc28j60ReadBuffer(len, packet);
|
|
|
|
// Move the RX read pointer to the start of the next received packet
|
|
// This frees the memory we just read out
|
|
// Errata workaround #11. Make sure ERXRDPT is odd
|
|
//
|
|
{
|
|
uint16_t rs,re;
|
|
rs = enc28j60Read(ERXSTH);
|
|
rs <<= 8;
|
|
rs |= enc28j60Read(ERXSTL);
|
|
re = enc28j60Read(ERXNDH);
|
|
re <<= 8;
|
|
re |= enc28j60Read(ERXNDL);
|
|
if (NextPacketPtr - 1 < rs || NextPacketPtr - 1 > re)
|
|
{
|
|
enc28j60Write(ERXRDPTL, (re));
|
|
enc28j60Write(ERXRDPTH, (re)>>8);
|
|
}
|
|
else
|
|
{
|
|
enc28j60Write(ERXRDPTL, (NextPacketPtr-1));
|
|
enc28j60Write(ERXRDPTH, (NextPacketPtr-1)>>8);
|
|
}
|
|
}
|
|
|
|
// decrement the packet counter indicate we are done with this packet
|
|
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
|
|
|
|
return len;
|
|
}
|
|
|
|
void enc28j60ReceiveOverflowRecover(void)
|
|
{
|
|
// receive buffer overflow handling procedure
|
|
|
|
// recovery completed
|
|
}
|
|
|
|
void enc28j60RegDump(void)
|
|
{
|
|
// unsigned char macaddr[6];
|
|
// result = ax88796Read(TR);
|
|
|
|
// SPrint_P(PSTR("Media State: "));
|
|
// if(!(result & AUTOD))
|
|
// SPrint_P(PSTR("Autonegotiation\r\n"));
|
|
// else if(result & RST_B)
|
|
// SPrint_P(PSTR("PHY in Reset \r\n"));
|
|
// else if(!(result & RST_10B))
|
|
// SPrint_P(PSTR("10BASE-T \r\n"));
|
|
// else if(!(result & RST_TXB))
|
|
// SPrint_P(PSTR("100BASE-T \r\n"));
|
|
|
|
SPrint_P(PSTR("RevID: ")); delay(5);
|
|
Serial.println(enc28j60Read(EREVID), HEX); delay(5);
|
|
|
|
SPrint_P(PSTR("Cntrl: ECON1 ECON2 ESTAT EIR EIE\r\n")); delay(5);
|
|
SPrint_P(PSTR(" ")); delay(5);
|
|
Serial.print(enc28j60Read(ECON1), HEX); delay(5);
|
|
SPrint_P(PSTR(" ")); delay(5);
|
|
Serial.print(enc28j60Read(ECON2), HEX); delay(5);
|
|
SPrint_P(PSTR(" ")); delay(5);
|
|
Serial.print(enc28j60Read(ESTAT), HEX); delay(5);
|
|
SPrint_P(PSTR(" ")); delay(5);
|
|
Serial.print(enc28j60Read(EIR), HEX); delay(5);
|
|
SPrint_P(PSTR(" ")); delay(5);
|
|
Serial.print(enc28j60Read(EIE), HEX); delay(5);
|
|
Serial.println(); delay(5);
|
|
|
|
SPrint_P(PSTR("MAC : MACON1 MACON2 MACON3 MACON4 MAC-Address\r\n")); delay(5);
|
|
SPrint_P(PSTR(" ")); delay(5);
|
|
Serial.print(enc28j60Read(MACON1), HEX); delay(5);
|
|
SPrint_P(PSTR(" ")); delay(5);
|
|
Serial.print(enc28j60Read(MACON2), HEX); delay(5);
|
|
SPrint_P(PSTR(" ")); delay(5);
|
|
Serial.print(enc28j60Read(MACON3), HEX); delay(5);
|
|
SPrint_P(PSTR(" ")); delay(5);
|
|
Serial.print(enc28j60Read(MACON4), HEX); delay(5);
|
|
SPrint_P(PSTR(" ")); delay(5);
|
|
Serial.print(enc28j60Read(MAADR5), HEX); delay(5);
|
|
Serial.print(enc28j60Read(MAADR4), HEX); delay(5);
|
|
Serial.print(enc28j60Read(MAADR3), HEX); delay(5);
|
|
Serial.print(enc28j60Read(MAADR2), HEX); delay(5);
|
|
Serial.print(enc28j60Read(MAADR1), HEX); delay(5);
|
|
Serial.print(enc28j60Read(MAADR0), HEX); delay(5);
|
|
Serial.println(); delay(5);
|
|
|
|
SPrint_P(PSTR("Rx : ERXST ERXND ERXWRPT ERXRDPT ERXFCON EPKTCNT MAMXFL\r\n")); delay(5);
|
|
SPrint_P(PSTR(" ")); delay(5);
|
|
Serial.print(enc28j60Read(ERXSTH), HEX); delay(5);
|
|
Serial.print(enc28j60Read(ERXSTL), HEX); delay(5);
|
|
SPrint_P(PSTR(" ")); delay(5);
|
|
Serial.print(enc28j60Read(ERXNDH), HEX); delay(5);
|
|
Serial.print(enc28j60Read(ERXNDL), HEX); delay(5);
|
|
SPrint_P(PSTR(" ")); delay(5);
|
|
Serial.print(enc28j60Read(ERXWRPTH), HEX); delay(5);
|
|
Serial.print(enc28j60Read(ERXWRPTL), HEX); delay(5);
|
|
SPrint_P(PSTR(" ")); delay(5);
|
|
Serial.print(enc28j60Read(ERXRDPTH), HEX); delay(5);
|
|
Serial.print(enc28j60Read(ERXRDPTL), HEX); delay(5);
|
|
SPrint_P(PSTR(" ")); delay(5);
|
|
Serial.print(enc28j60Read(ERXFCON), HEX); delay(5);
|
|
SPrint_P(PSTR(" ")); delay(5);
|
|
Serial.print(enc28j60Read(EPKTCNT), HEX); delay(5);
|
|
SPrint_P(PSTR(" ")); delay(5);
|
|
Serial.print(enc28j60Read(MAMXFLH), HEX); delay(5);
|
|
Serial.print(enc28j60Read(MAMXFLL), HEX); delay(5);
|
|
Serial.println(); delay(5);
|
|
|
|
SPrint_P(PSTR("Tx : ETXST ETXND MACLCON1 MACLCON2 MAPHSUP\r\n")); delay(5);
|
|
SPrint_P(PSTR(" ")); delay(5);
|
|
Serial.print(enc28j60Read(ETXSTH), HEX); delay(5);
|
|
Serial.print(enc28j60Read(ETXSTL), HEX); delay(5);
|
|
SPrint_P(PSTR(" ")); delay(5);
|
|
Serial.print(enc28j60Read(ETXNDH), HEX); delay(5);
|
|
Serial.print(enc28j60Read(ETXNDL), HEX); delay(5);
|
|
SPrint_P(PSTR(" ")); delay(5);
|
|
Serial.print(enc28j60Read(MACLCON1), HEX); delay(5);
|
|
SPrint_P(PSTR(" ")); delay(5);
|
|
Serial.print(enc28j60Read(MACLCON2), HEX); delay(5);
|
|
SPrint_P(PSTR(" ")); delay(5);
|
|
Serial.print(enc28j60Read(MAPHSUP), HEX); delay(5);
|
|
Serial.println(); delay(5);
|
|
|
|
//delay_ms(25); delay(5);
|
|
delay(25);
|
|
}
|
|
|
|
|
|
|