📄 enc28j60.c
字号:
/*********************************************
* vim:sw=8:ts=8:si:et
* To use the above modeline in vim you must have "set modeline" in your .vimrc
* Author: Guido Socher
* Copyright: GPL V2
* http://www.gnu.org/licenses/gpl.html
*
* Based on the enc28j60.c file from the AVRlib library by Pascal Stang.
* For AVRlib See http://www.procyonengineering.com/
* Used with explicit permission of Pascal Stang.
*
* Title: Microchip ENC28J60 Ethernet Interface Driver
* Chip type : ATMEGA88 with ENC28J60
*********************************************/
/*****************************************************/
/* EasyLPC2103 Study Broad + ENC28J60 Module */
/* http://www.OurEDA.cn */
/*****************************************************/
/* Modified By OurEDA.CN */
/*****************************************************/
#include <LPC2103.H>
#include "enc28j60.h"
#define AT_ARM
#define uint8_t unsigned char
#define uint16_t unsigned short
static uint8_t Enc28j60Bank;
static uint16_t NextPacketPtr;
#ifdef AT_ARM
#define ENC_SPI_CH (0)
#define waitspi()
/*
Send data to slave or receive data from slave
*/
unsigned short SAMspiSend(unsigned char ch, unsigned short data) {
S0SPDR = data;
while( 0==(S0SPSR&0x80));
data = S0SPDR;
return(data);
}
/*
initialize the contorl logic of /CS pin
*/
static void enc28j60CSinit(void) {
/* 实际功能已经完成 */
}
/*
enable enc28j60, /CS = Low
*/
static void CSACTIVE(void) {
IOCLR |= (1<<7);
}
/*
disable enc28j60, /CS = High
*/
static void CSPASSIVE(void) {
IOSET |= (1<<7);
}
/*
set ENC28J60 SPI SCK freq, MAX 10MHz
*/
static void enc28j60SetSCK(void) {
/* 实际功能已经完成 */
}
void delay_ms(unsigned char ms) {
unsigned int t1, t2;
for(t1=0;t1<ms;t1++) {
for(t2=0;t2<100;t2++);
}
}
void _delay_us(unsigned char us) {
unsigned char len = 20;
for (;us > 0; us --) {
for (;len > 0; len --);
len = 20;
}
}
/*
ENC28J60 HW RST
*/
static void enc28j60HWRST(void) {
/* 实际功能已经完成 */
}
#endif
uint8_t enc28j60ReadOp(uint8_t op, uint8_t address) {
uint8_t dat = 0;
CSACTIVE();
dat = op | (address & ADDR_MASK);
SAMspiSend(ENC_SPI_CH, dat);
dat = SAMspiSend(ENC_SPI_CH, 0);
// do dummy read if needed (for mac and mii, see datasheet page 29)
if(address & 0x80) {
dat = SAMspiSend(ENC_SPI_CH, 0);
}
CSPASSIVE();
return dat;
}
void enc28j60WriteOp(uint8_t op, uint8_t address, uint8_t data) {
uint8_t dat = 0;
CSACTIVE();
// issue write command
dat = op | (address & ADDR_MASK);
SAMspiSend(ENC_SPI_CH, dat);
// write data
dat = data;
SAMspiSend(ENC_SPI_CH, dat);
CSPASSIVE();
}
void enc28j60ReadBuffer(uint16_t len, uint8_t* data) {
CSACTIVE();
// issue read command
SAMspiSend(ENC_SPI_CH, ENC28J60_READ_BUF_MEM);
while(len) {
len--;
// read data
*data = (uint8_t)SAMspiSend(ENC_SPI_CH, 0);
data++;
}
*data='\0';
CSPASSIVE();
}
void enc28j60WriteBuffer(uint16_t len, uint8_t* data) {
CSACTIVE();
// issue write command
SAMspiSend(ENC_SPI_CH, ENC28J60_WRITE_BUF_MEM);
while(len) {
len--;
// write data
SAMspiSend(ENC_SPI_CH, *data);
data++;
}
CSPASSIVE();
}
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);
}
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) {
_delay_us(15);
}
}
void enc28j60clkout(uint8_t clk) {
//setup clkout: 2 is 12.5MHz:
enc28j60Write(ECOCON, clk & 0x7);
}
void enc28j60Init(uint8_t* macaddr) {
// initialize I/O
enc28j60CSinit();
CSPASSIVE();
enc28j60SetSCK();
enc28j60HWRST();
// perform system RST
enc28j60WriteOp(ENC28J60_SOFT_RST, 0, ENC28J60_SOFT_RST);
delay_ms(250);
// check CLKRDY bit to see if RST is complete
// The CLKRDY does not work. See Rev. B4 Silicon Errata point. Just wait.
//while(!(enc28j60Read(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;
// Rx start
enc28j60Write(ERXSTL, RXSTART_INIT&0xFF);
enc28j60Write(ERXSTH, RXSTART_INIT>>8);
// set receive pointer address
enc28j60Write(ERXRDPTL, RXSTART_INIT&0xFF);
enc28j60Write(ERXRDPTH, RXSTART_INIT>>8);
// RX end
enc28j60Write(ERXNDL, RXSTOP_INIT&0xFF);
enc28j60Write(ERXNDH, RXSTOP_INIT>>8);
// TX start
enc28j60Write(ETXSTL, TXSTART_INIT&0xFF);
enc28j60Write(ETXSTH, TXSTART_INIT>>8);
// TX end
enc28j60Write(ETXNDL, TXSTOP_INIT&0xFF);
enc28j60Write(ETXNDH, TXSTOP_INIT>>8);
// 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(EPMM0, 0x3f);
enc28j60Write(EPMM1, 0x30);
enc28j60Write(EPMCSL, 0xf9);
enc28j60Write(EPMCSH, 0xf7);
// do bank 2 stuff
// enable MAC receive
enc28j60Write(MACON1, MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS);
// bring MAC out of RST
enc28j60Write(MACON2, 0x00);
// enable automatic padding to 60bytes and CRC operations
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN|MACON3_FULDPX);
// 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
// Do not send packets longer than MAX_FRAMELEN:
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, macaddr[0]);
enc28j60Write(MAADR4, macaddr[1]);
enc28j60Write(MAADR3, macaddr[2]);
enc28j60Write(MAADR2, macaddr[3]);
enc28j60Write(MAADR1, macaddr[4]);
enc28j60Write(MAADR0, macaddr[5]);
enc28j60PhyWrite(PHCON1, PHCON1_PDPXMD);
// 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);
}
// read the revision of the chip:
uint8_t enc28j60getrev(void) {
return(enc28j60Read(EREVID));
}
void enc28j60PacketSend(uint16_t len, uint8_t* packet) {
// Set the write pointer to start of transmit buffer area
enc28j60Write(EWRPTL, TXSTART_INIT&0xFF);
enc28j60Write(EWRPTH, TXSTART_INIT>>8);
// Set the TXND pointer to correspond to the packet size given
enc28j60Write(ETXNDL, (TXSTART_INIT+len)&0xFF);
enc28j60Write(ETXNDH, (TXSTART_INIT+len)>>8);
// write per-packet control byte (0x00 means use macon3 settings)
enc28j60WriteOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00);
// 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);
// RST the transmit logic problem. See Rev. B4 Silicon Errata point 12.
if((enc28j60Read(EIR) & EIR_TXERIF)) {
enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRTS);
}
}
// Gets a packet from the network receive buffer, if one is available.
// The packet will by headed by an ethernet header.
// maxlen The maximum acceptable length of a retrieved packet.
// packet Pointer where packet data should be stored.
// Returns: Packet length in bytes if a packet was retrieved, zero otherwise.
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) ){
// The above does not work. See Rev. B4 Silicon Errata point 6.
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 (see datasheet page 43)
len = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
len |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
len-=4; //remove the CRC count
// read the receive status (see datasheet page 43)
rxstat = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
rxstat |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
// limit retrieve length
if (len>maxlen-1) {
len=maxlen-1;
}
// check CRC and symbol errors (see datasheet page 44, table 7-3):
// The ERXFCON.CRCEN is set by default. Normally we should not
// need to check this.
if ((rxstat & 0x80)==0) {
// invalid
len=0;
}else {
// 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
enc28j60Write(ERXRDPTL, (NextPacketPtr));
enc28j60Write(ERXRDPTH, (NextPacketPtr)>>8);
// decrement the packet counter indicate we are done with this packet
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
return(len);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -