enc28j60.c
来自「spi口的超小型网络连接器」· C语言 代码 · 共 575 行 · 第 1/2 页
C
575 行
#include <targets/lpc21xx.h>
#include "enc28j60.h"
#include "spi.h"
/******************************************************************************/
/** \file enc28j60.c
* \brief Driver code for enc28j60.
* \author Iain Derrington (www.kandi-electronics.com)
* \date 0.1 20/06/07 First Draft \n
* 0.2 11/07/07 Removed CS check macros. Fixed bug in writePhy
* 0.3 12.07/07 Altered for uIP 1.0
*/
/*******************************************************************************/
// define private variables
/** MAC address. Should be set using a function.*/
const u8_t bytMacAddress[6] = {0x00,0xa0,0xc9,0x14,0xc8,0x29};
TXSTATUS TxStatus;
// define private functions
static u8_t ReadETHReg(u8_t); // read a ETX reg
static u8_t ReadMacReg(u8_t); // read a MAC reg
static u16_t ReadPhyReg(u8_t); // read a PHY reg
static u16_t ReadMacBuffer(u8_t * ,u8_t); //read the mac buffer (ptrBuffer, no. of bytes)
static u8_t WriteCtrReg(u8_t,u8_t); // write to control reg
static u8_t WritePhyReg(u8_t,u16_t); // write to a phy reg
static u16_t WriteMacBuffer(u8_t *,u16_t); // write to mac buffer
static void ResetMac(void);
static u8_t SetBitField(u8_t, u8_t);
static u8_t ClrBitField(u8_t, u8_t);
static void BankSel(u8_t);
static void spitest(void);
//define usefull macros
/** MACRO for selecting or deselecting chip select for the ENC28J60. Some HW dependancy.*/
#define SEL_MAC(x) (x==TRUE) ? (IO0CLR=CS_ENC28J60) : (IO0SET =CS_ENC28J60)
/** MACRO for rev B5 fix.*/
#define ERRATAFIX SetBitField(ECON1, ECON1_TXRST);ClrBitField(ECON1, ECON1_TXRST);ClrBitField(EIR, EIR_TXERIF | EIR_TXIF)
/***********************************************************************/
/** \brief Initialise the MAC.
*
* Description: \n
* a) Setup SPI device. Assume Reb B5 for sub 8MHz operation \n
* b) Setup buffer ptrs to devide memory in In and Out mem \n
* c) Setup receive filters (accept only unicast).\n
* d) Setup MACON registers (MAC control registers)\n
* e) Setup MAC address
* f) Setup Phy registers
* \author Iain Derrington
* \date 0.1 20/06/07 First draft
*/
/**********************************************************************/
void initMAC(void)
{
u16_t test;
initSPI(); // initialise the SPI
ResetMac(); // erm. Resets the MAC.
// setup memory by defining ERXST and ERXND
BankSel(0); // select bank 0
WriteCtrReg(ERXSTL,(u8_t)( RXSTART & 0x00ff));
WriteCtrReg(ERXSTH,(u8_t)((RXSTART & 0xff00)>> 8));
WriteCtrReg(ERXNDL,(u8_t)( RXEND & 0x00ff));
WriteCtrReg(ERXNDH,(u8_t)((RXEND & 0xff00)>>8));
// Make sure Rx Read ptr is at the start of Rx segment
WriteCtrReg(ERXRDPTL, (u8_t)( RXSTART & 0x00ff));
WriteCtrReg(ERXRDPTH, (u8_t)((RXSTART & 0xff00)>> 8));
BankSel(1); // select bank 1
WriteCtrReg(ERXFCON,( ERXFCON_UCEN + ERXFCON_CRCEN + ERXFCON_BCEN));
// Initialise the MAC registers
BankSel(2); // select bank 2
SetBitField(MACON1, MACON1_MARXEN); // Enable reception of frames
WriteCtrReg(MACLCON2, 63);
WriteCtrReg(MACON3, MACON3_FRMLNEN + // Type / len field will be checked
MACON3_TXCRCEN + // MAC will append valid CRC
MACON3_PADCFG0); // All small packets will be padded
SetBitField(MACON4, MACON4_DEFER);
WriteCtrReg(MAMXFLL, (u8_t)( MAXFRAMELEN & 0x00ff)); // set max frame len
WriteCtrReg(MAMXFLH, (u8_t)((MAXFRAMELEN & 0xff00)>>8));
WriteCtrReg(MABBIPG, 0x12); // back to back interpacket gap. set as per data sheet
WriteCtrReg(MAIPGL , 0x12); // non back to back interpacket gap. set as per data sheet
WriteCtrReg(MAIPGH , 0x0C);
//Program our MAC address
BankSel(3);
WriteCtrReg(MAADR1,bytMacAddress[0]);
WriteCtrReg(MAADR2,bytMacAddress[1]);
WriteCtrReg(MAADR3,bytMacAddress[2]);
WriteCtrReg(MAADR4,bytMacAddress[3]);
WriteCtrReg(MAADR5,bytMacAddress[4]);
WriteCtrReg(MAADR6,bytMacAddress[5]);
// Initialise the PHY registes
WritePhyReg(PHCON1, 0x000);
test =ReadPhyReg(PHCON1);
WritePhyReg(PHCON2, PHCON2_HDLDIS);
WriteCtrReg(ECON1, ECON1_RXEN); //Enable the chip for reception of packets
}
/***********************************************************************/
/** \brief Writes a packet to the ENC28J60.
*
* Description: Writes ui_len bytes of data from ptrBufffer into ENC28J60.
* puts the necessary padding around the packet to make it a legit
MAC packet.\n \n
1) Program ETXST. \n
2) Write per packet control byte.\n
3) Program ETXND.\n
4) Set ECON1.TXRTS.\n
5) Check ESTAT.TXABRT. \n
* \author Iain Derrington
* \param ptrBuffer ptr to byte buffer.
* \param ui_Len Number of bytes to write from buffer.
* \return uint True or false.
*/
/**********************************************************************/
u16_t MACWrite()
{
volatile u16_t i;
volatile u16_t address = TXSTART;
u8_t bytControl;
bytControl = 0x00;
BankSel(0); // select bank 0
WriteCtrReg(ETXSTL,(u8_t)( TXSTART & 0x00ff)); // write ptr to start of Tx packet
WriteCtrReg(ETXSTH,(u8_t)((TXSTART & 0xff00)>>8));
WriteCtrReg(EWRPTL,(u8_t)( TXSTART & 0x00ff)); // Set write buffer to point to start of Tx Buffer
WriteCtrReg(EWRPTH,(u8_t)((TXSTART & 0xff00)>>8));
WriteMacBuffer(&bytControl,1); // write per packet control byte
address++;
address+=WriteMacBuffer(&uip_buf[0], UIP_LLH_LEN);
if(uip_len <= UIP_LLH_LEN + UIP_TCPIP_HLEN)
{
address+=WriteMacBuffer(&uip_buf[UIP_LLH_LEN], uip_len - UIP_LLH_LEN);
}
else
{
address+=WriteMacBuffer(&uip_buf[UIP_LLH_LEN], UIP_TCPIP_HLEN);
address+=WriteMacBuffer(uip_appdata, uip_len - UIP_TCPIP_HLEN - UIP_LLH_LEN);
}
WriteCtrReg(ETXNDL, (u8_t)( address & 0x00ff)); // Tell MAC when the end of the packet is
WriteCtrReg(ETXNDH, (u8_t)((address & 0xff00)>>8));
ClrBitField(EIR,EIR_TXIF);
SetBitField(EIE, EIE_TXIE |EIE_INTIE);
ERRATAFIX;
SetBitField(ECON1, ECON1_TXRTS); // begin transmitting;
do
{
}while (!(ReadETHReg(EIR) & (EIR_TXIF))); // kill some time. Note: Nice place to block? // kill some time. Note: Nice place to block?
ClrBitField(ECON1, ECON1_TXRTS);
BankSel(0); // read tx status bytes
address++; // increment ptr to address to start of status struc
WriteCtrReg(ERDPTL, (u8_t)( address & 0x00ff)); // Setup the buffer read ptr to read status struc
WriteCtrReg(ERDPTH, (u8_t)((address & 0xff00)>>8));
ReadMacBuffer(&TxStatus.v[0],7);
if (ReadETHReg(ESTAT) & ESTAT_TXABRT) // did transmission get interrupted?
{
if (TxStatus.bits.LateCollision)
{
ClrBitField(ECON1, ECON1_TXRTS);
SetBitField(ECON1, ECON1_TXRTS);
ClrBitField(ESTAT,ESTAT_TXABRT | ESTAT_LATECOL);
}
ClrBitField(EIR, EIR_TXERIF | EIR_TXIF);
ClrBitField(ESTAT,ESTAT_TXABRT);
return FALSE; // packet transmit failed. Inform calling function
} // calling function may inquire why packet failed by calling [TO DO] function
else
{
return TRUE; // all fan dabby dozy
}
}
/***********************************************************************/
/** \brief Tries to read a packet from the ENC28J60.
*
* Description: If a valid packet is available in the ENC28J60 this function reads the packet into a
* buffer. The memory within the ENC28J60 will then be released. This version of the
driver does not use interrupts so this function needs to be polled.\n \n
*
* 1) Read packet count register. If >0 then continue else return. \n
* 2) Read the current ERXRDPTR value. \n
* 3) Write this value into ERDPT. \n
* 4) First two bytes contain the ptr to the start of next packet. Read this value in. \n
* 5) Calculate length of packet. \n
* 6) Read in status byte into private variable. \n
* 7) Read in packet and place into buffer. \n
* 8) Free up memory in the ENC. \n
*
* \author Iain Derrington
* \param ptrBuffer ptr to buffer of bytes where the packet should be read into.
* \return u16_t, the number of complete packets in the buffer -1.
*/
/**********************************************************************/
u16_t MACRead()
{
volatile u16_t u16_t_pckLen,test;
volatile u16_t u16_t_rdptr,u16_t_wrtptr;
static u16_t nextpckptr = RXSTART;
volatile RXSTATUS ptrRxStatus;
volatile u8_t bytPacket;
BankSel(1);
bytPacket = ReadETHReg(EPKTCNT); // How many packets have been received
if(bytPacket == 0)
return bytPacket; // No full packets received
BankSel(0);
WriteCtrReg(ERDPTL,(u8_t)( nextpckptr & 0x00ff)); //write this value to read buffer ptr
WriteCtrReg(ERDPTH,(u8_t)((nextpckptr & 0xff00)>>8));
ReadMacBuffer((u8_t*)&ptrRxStatus.v[0],6); // read next packet ptr + 4 status bytes
nextpckptr = ptrRxStatus.bits.NextPacket;
uip_len=ptrRxStatus.bits.ByteCount;
ReadMacBuffer(uip_buf,uip_len); // read packet into buffer
// ptrBuffer should now contain a MAC packet
BankSel(0);
WriteCtrReg(ERXRDPTL,ptrRxStatus.v[0]); // free up ENC memory my adjustng the Rx Read ptr
WriteCtrReg(ERXRDPTH,ptrRxStatus.v[1]);
// decrement packet counter
SetBitField(ECON2, ECON2_PKTDEC);
return uip_len;
}
/*------------------------Private Functions-----------------------------*/
/***********************************************************************/
/** \brief ReadETHReg.
*
* Description: Reads contents of the addressed ETH reg over SPI bus. Assumes correct bank selected.
*
*
* \author Iain Derrington
* \param bytAddress Address of register to be read
* \return byte Value of register.
*/
/**********************************************************************/
static u8_t ReadETHReg(u8_t bytAddress)
{
u8_t bytData;
if (bytAddress > 0x1F)
return FALSE; // address invalid, [TO DO]
SEL_MAC(TRUE); // ENC CS low
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?