uIP 1.0 based webserver for LPC1114 + ENC28J60

Dependencies:   mbed TMP102

dev-enc28j60/enc28j60.cpp

Committer:
ban4jp
Date:
2014-06-30
Revision:
3:a2715e9c7737
Parent:
1:b4d28172cacd

File content as of revision 3:a2715e9c7737:

#include "mbed.h"

#include "enc28j60.h"
#include "uip-conf.h"

u8 Enc28j60Bank;
u16 NextPacketPtr;

ENC28J60::ENC28J60(SPI* _spi, PinName _cs, PinName _int):
	cs_pin(_cs), int_pin(_int)
{
	this->spi = _spi;
	
    this->spi->format(8,0);
    this->spi->frequency(8000000);

	cs_pin = 1;
}

u8 ENC28J60::readOp(u8 op, u8 address)
{
	u8 data;
   
	// assert CS
	cs_pin = 0;

	// issue read command
    spi->write(op | (address & ADDR_MASK));
	// read data
    data = spi->write(0x00);
	// do dummy read if needed
    if(address & 0x80)
    {
        data = spi->write(0x00);
    }

	// release CS
	cs_pin = 1;

	return data;
}

void ENC28J60::writeOp(u8 op, u8 address, u8 data)
{
	// assert CS
	cs_pin = 0;

	// issue write command
    spi->write(op | (address & ADDR_MASK));
	// write data
    spi->write(data);

	// release CS
	cs_pin = 1;
}

void ENC28J60::readBuffer(u16 len, u8* data)
{
	// assert CS
	cs_pin = 0;

	// issue read command
    spi->write(ENC28J60_READ_BUF_MEM);
    while(len--)
    {
		// read data
        *data++ = spi->write(0x00);
    }

	// release CS
	cs_pin = 1;
}

void ENC28J60::writeBuffer(u16 len, u8* data)
{
	// assert CS
	cs_pin = 0;

	// issue write command
    spi->write(ENC28J60_WRITE_BUF_MEM);
    while(len--)
    {
		// write data
        spi->write(*data++);
    }
	
	// release CS
	cs_pin = 1;
}

void ENC28J60::setBank(u8 address)
{
	// set the bank (if needed)
	if((address & BANK_MASK) != Enc28j60Bank)
	{
		// set the bank
		this->writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1|ECON1_BSEL0));
		this->writeOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK)>>5);
		Enc28j60Bank = (address & BANK_MASK);
	}
}

u8 ENC28J60::read(u8 address)
{
	// set the bank
	this->setBank(address);
	// do the read
	return this->readOp(ENC28J60_READ_CTRL_REG, address);
}

void ENC28J60::write(u8 address, u8 data)
{
	// set the bank
	this->setBank(address);
	// do the write
	this->writeOp(ENC28J60_WRITE_CTRL_REG, address, data);
}

u16 ENC28J60::phyRead(u8 address)
{
	u16 data;

	// Set the right address and start the register read operation
	this->write(MIREGADR, address);
	this->write(MICMD, MICMD_MIIRD);

	// wait until the PHY read completes
	while(this->read(MISTAT) & MISTAT_BUSY);

	// quit reading
	this->write(MICMD, 0x00);
	
	// get data value
	data  = this->read(MIRDL);
	data |= this->read(MIRDH);
	// return the data
	return data;
}

void ENC28J60::phyWrite(u8 address, u16 data)
{
	// set the PHY register address
	this->write(MIREGADR, address);
	
	// write the PHY data
	this->write(MIWRL, data);	
	this->write(MIWRH, data>>8);

	// wait until the PHY write completes
	while(this->read(MISTAT) & MISTAT_BUSY);
}

void ENC28J60::init(void)
{
	cs_pin = 1;			//Disable CS
	
	// perform system reset
	this->writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
	// check CLKRDY bit to see if reset is complete
	/* Fix Errata */
	wait_ms(1);
	while(!(this->read(ESTAT) & ESTAT_CLKRDY));

	// do bank 0 stuff
	// initialize receive buffer
	// 16-bit transfers, must write low byte first
	// set receive buffer start address
	NextPacketPtr = RXSTART_INIT;
	this->write(ERXSTL, RXSTART_INIT&0xFF);
	this->write(ERXSTH, RXSTART_INIT>>8);
	// set read pointer address
	//this->write(ERDPTL, 0);
	//this->write(ERDPTH, 0);
	// set receive pointer address
	this->write(ERXRDPTL, RXSTART_INIT&0xFF);
	this->write(ERXRDPTH, RXSTART_INIT>>8);
	// set receive buffer end
	// ERXND defaults to 0x1FFF (end of ram)
	this->write(ERXNDL, RXSTOP_INIT&0xFF);
	this->write(ERXNDH, RXSTOP_INIT>>8);
	// set transmit buffer start
	// ETXST defaults to 0x0000 (beginnging of ram)
	this->write(ETXSTL, TXSTART_INIT&0xFF);
	this->write(ETXSTH, TXSTART_INIT>>8);

	// do bank 2 stuff
	// enable MAC receive
	this->write(MACON1, MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS);
	// bring MAC out of reset
	this->write(MACON2, 0x00);
	// enable automatic padding and CRC operations
	this->writeOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN);
//	this->write(MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN);
	// set inter-frame gap (non-back-to-back)
	this->write(MAIPGL, 0x12);
	this->write(MAIPGH, 0x0C);
	// set inter-frame gap (back-to-back)
	this->write(MABBIPG, 0x12);
	// Set the maximum packet size which the controller will accept
	this->write(MAMXFLL, MAX_FRAMELEN&0xFF);	
	this->write(MAMXFLH, MAX_FRAMELEN>>8);

	// do bank 3 stuff
	// write MAC address
	// NOTE: MAC address in ENC28J60 is byte-backward
	this->write(MAADR5, UIP_ETHADDR0);
	this->write(MAADR4, UIP_ETHADDR1);
	this->write(MAADR3, UIP_ETHADDR2);
	this->write(MAADR2, UIP_ETHADDR3);
	this->write(MAADR1, UIP_ETHADDR4);
	this->write(MAADR0, UIP_ETHADDR5);

	// no loopback of transmitted frames
	this->phyWrite(PHCON2, PHCON2_HDLDIS);

	// switch to bank 0
	this->setBank(ECON1);
	// enable interrutps
	this->writeOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE|EIE_PKTIE);
	// enable packet reception
	this->writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
/*
	this->phyWrite(PHLCON, 0x0AA2);

	// setup duplex ----------------------

	// Disable receive logic and abort any packets currently being transmitted
	this->writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRTS|ECON1_RXEN);
	
	{
		u16 temp;
		// Set the PHY to the proper duplex mode
		temp = enc28j60PhyRead(PHCON1);
		temp &= ~PHCON1_PDPXMD;
		this->phyWrite(PHCON1, temp);
		// Set the MAC to the proper duplex mode
		temp = this->read(MACON3);
		temp &= ~MACON3_FULDPX;
		this->write(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
	//this->write(MABBIPG, DuplexState ? 0x15 : 0x12);	
	
	// Reenable receive logic
	this->writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);

	// setup duplex ----------------------
*/
}

void ENC28J60::packetSend(unsigned int len, unsigned char* packet)
{
	//Errata: Transmit Logic reset
	this->writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST);
	wait_us(10);
	this->writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);

	// Set the write pointer to start of transmit buffer area
	this->write(EWRPTL, TXSTART_INIT);
	this->write(EWRPTH, TXSTART_INIT>>8);
	// Set the TXND pointer to correspond to the packet size given
	this->write(ETXNDL, (TXSTART_INIT+len));
	this->write(ETXNDH, (TXSTART_INIT+len)>>8);

	// write per-packet control byte
	this->writeOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00);

	// copy the packet into the transmit buffer
	this->writeBuffer(len, packet);
	
	// send the contents of the transmit buffer onto the network
	this->writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
	
	while(this->readOp(ENC28J60_BIT_FIELD_SET, ECON1) & ECON1_TXRTS)
	{
		wait_us(10);
	}
}

void ENC28J60::packetSend2(unsigned int len1, unsigned char* packet1, unsigned int len2, unsigned char* packet2)
{
	//Errata: Transmit Logic reset
	this->writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST);
	this->writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);

	// Set the write pointer to start of transmit buffer area
	this->write(EWRPTL, TXSTART_INIT);
	this->write(EWRPTH, TXSTART_INIT>>8);
	// Set the TXND pointer to correspond to the packet size given
	this->write(ETXNDL, (TXSTART_INIT+len1+len2));
	this->write(ETXNDH, (TXSTART_INIT+len1+len2)>>8);

	// write per-packet control byte
	this->writeOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00);

	// copy the packet into the transmit buffer
	this->writeBuffer(len1, packet1);
	if(len2>0) this->writeBuffer(len2, packet2);
	
	// send the contents of the transmit buffer onto the network
	this->writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
}

unsigned int ENC28J60::packetReceive(unsigned int maxlen, unsigned char* packet)
{
	u16 rxstat;
	u16 len;

	// check if a packet has been received and buffered
	if( !(this->read(EIR) & EIR_PKTIF) )
	{
		if(this->read(EPKTCNT) == 0)
		{
			return 0;
		}
	}
	
	// Make absolutely certain that any previous packet was discarded	
	//if( WasDiscarded == FALSE)
	//	MACDiscardRx();

	// Set the read pointer to the start of the received packet
	this->write(ERDPTL, (NextPacketPtr));
	this->write(ERDPTH, (NextPacketPtr)>>8);
	// read the next packet pointer
	NextPacketPtr  = this->readOp(ENC28J60_READ_BUF_MEM, 0);
	NextPacketPtr |= this->readOp(ENC28J60_READ_BUF_MEM, 0)<<8;
	// read the packet length
	len  = this->readOp(ENC28J60_READ_BUF_MEM, 0);
	len |= this->readOp(ENC28J60_READ_BUF_MEM, 0)<<8;
	// read the receive status
	rxstat  = this->readOp(ENC28J60_READ_BUF_MEM, 0);
	rxstat |= this->readOp(ENC28J60_READ_BUF_MEM, 0)<<8;

	// limit retrieve length
	// (we reduce the MAC-reported length by 4 to remove the CRC)
	if(len>maxlen){
		len=maxlen;
	}

	// copy the packet from the receive buffer
	this->readBuffer(len, packet);

	// Move the RX read pointer to the start of the next received packet
	// This frees the memory we just read out
	/* Fix Errata */
	if(NextPacketPtr == RXSTART_INIT)
	{
		this->write(ERXRDPTL, (RXSTOP_INIT));
		this->write(ERXRDPTH, (RXSTOP_INIT)>>8);
	}
	else
	{
		this->write(ERXRDPTL, (NextPacketPtr));
		this->write(ERXRDPTH, (NextPacketPtr)>>8);
	}

	// decrement the packet counter indicate we are done with this packet
	this->writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
	wait_us(11);

	return len;
}

void ENC28J60::receiveOverflowRecover(void)
{
	// receive buffer overflow handling procedure

	// recovery completed
}

void ENC28J60::regDump(void)
{
	printf("RevID: 0x%x\n", this->read(EREVID));

	printf("Ctrl: ");
	printf("ECON1=%x ",this->read(ECON1));
	printf("ECON2=%x ",this->read(ECON2));
	printf("ESTAT=%x ",this->read(ESTAT));
	printf("EIR=%x ",this->read(EIR));
	printf("EIE=%x\n",this->read(EIE));

	printf("MAC:  ");
	printf("MACON1=%x ",this->read(MACON1));
	printf("MACON2=%x ",this->read(MACON2));
	printf("MACON3=%x ",this->read(MACON3));
	printf("MACON4=%x ",this->read(MACON4));
	printf("MAD=%x%x\n",
		this->read(MAADR5)*0x1000000+this->read(MAADR4)*0x10000+this->read(MAADR3)*0x100+this->read(MAADR2),
		this->read(MAADR1)*0x1000000+this->read(MAADR0)*0x10000+0xffff);

	printf("Rx:   ");
	printf("ERXST=%04x ",this->read(ERXSTH)*0x100+this->read(ERXSTL));
	printf("ERXND=%04x ",this->read(ERXNDH)*0x100+this->read(ERXNDL));
	printf("ERXWRPT=%x ",this->read(ERXWRPTH)*0x100+this->read(ERXWRPTL));
	printf("ERXRDPT=%x ",this->read(ERXRDPTH)*0x100+this->read(ERXRDPTL));
	printf("ERXFCON=%x ",this->read(ERXFCON));
	printf("EPKTCNT=%x ",this->read(EPKTCNT));
	printf("MAMXFL=%x\n",this->read(MAMXFLH)*0x100+this->read(MAMXFLL));

	printf("Tx:   ");
	printf("ETXST=%04x ",this->read(ETXSTH)*0x100+this->read(ETXSTL));
	printf("ETXND=%04x ",this->read(ETXNDH)*0x100+this->read(ETXNDL));
	printf("MACLCON1=%x ",this->read(MACLCON1));
	printf("MACLCON2=%x ",this->read(MACLCON2));
	printf("MAPHSUP=%x\n",this->read(MAPHSUP));
}