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 + -
显示快捷键?