⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ethdrv_enc28j60.c

📁 enc28j60的驱动
💻 C
字号:
/******************************************************************************
 *
 * Copyright:
 *    (C) 2000 - 2005 Embedded Artists AB
 *
 * Description:
 *    Ethernet driver for Davicom DM9000E
 *
 *****************************************************************************/

/******************************************************************************
 * Includes 
 *****************************************************************************/

#include "general.h"
#include "ethdrv_enc28j60.h"
#include <lpc2xxx.h>
#include <string.h>

#include <printf_P.h>

/******************************************************************************
 * Local variables
 *****************************************************************************/

/* Ethernet address (MAC) */
static tU8 macAddr[6];

/******************************************************************************
 * Defines and typedefs
 *****************************************************************************/


#define m_eth_dis_int
#define m_eth_ena_int

#define m_nic_read(reg) encReadReg(reg)
#define m_nic_write(reg, data) encWriteReg(reg, data)
#define m_nic_read_data(len, buf) encReadBuff((len), (buf))
#define m_nic_write_data(len, buf) encWriteBuff((len), (buf))


// bit field set
#define m_nic_bfs(reg, data) encBitSet(reg, data)

// bit field clear
#define m_nic_bfc(reg, data) encBitClr(reg, data)

/*
 * Controller memory layout:
 *
 * 0x0000 - 0x0bff  3k bytes transmit buffer
 * 0x0c00 - 0x1fff  5k bytes receive buffer
 */
#define ENC_TX_BUF_START 0x0000
#define ENC_RX_BUF_START 0x0C00

/* maximum frame length */
#define ENC_MAX_FRM_LEN 1518


/******************************************************************************
 * External Function Prototypes
 *****************************************************************************/

void encWriteReg(tU8 regNo, tU8 data);
tU8  encReadReg(tU8 regNo);
void encReadBuff(tU16 length, tU8 *pBuff);
void encWriteBuff(tU16 length, tU8 *pBuff);
void encBitSet(tU8 regNo, tU8 data);
void encBitClr(tU8 regNo, tU8 data);

/******************************************************************************
 * Implementation of local functions
 *****************************************************************************/
void ethIf_init(tU8* pEthAddr);

/*****************************************************************************
 *
 * Description:
 *    Read PHY registers.
 *
 *    NOTE! This function will change to Bank 2.
 *
 * Params:
 *    [in] addr address of the register to read
 *
 * Returns:
 *    The value in the register
 *
 ****************************************************************************/
static tU16 
phyRead(tU8 addr)
{
  tU16 ret = 0;

  /* move to bank 2 */
  m_nic_bfc(CTL_REG_ECON1, ENC_ECON1_BSEL0);
  m_nic_bfs(CTL_REG_ECON1, ENC_ECON1_BSEL1);

  /* write address to MIREGADR */
  m_nic_write(CTL_REG_MIREGADR, addr);

  /* set MICMD.MIIRD */
  m_nic_write(CTL_REG_MICMD, ENC_MICMD_MIIRD);

  /* poll MISTAT.BUSY bit until operation is complete */
  while((m_nic_read(CTL_REG_MISTAT) & ENC_MISTAT_BUSY) != 0)
  {
    static int cnt = 0;

    if(cnt++ >= 1000)
    {
      printf("#");
      cnt = 0;
    }
  }


  /* clear MICMD.MIIRD */
  m_nic_write(CTL_REG_MICMD, 0);

  ret  = (m_nic_read(CTL_REG_MIRDH) << 8);
  ret |= (m_nic_read(CTL_REG_MIRDL) & 0xFF);

  return ret;
}

/*****************************************************************************
 *
 * Description:
 *    Get the next packet from the receive ring buffer. 
 *
 * Params:
 *    [in/out] pBuf - data is copied to this buffer
 *    [in]     len  - length of buffer
 *
 * Returns:
 *    number of copied bytes to the supplied buffer
 *
 ****************************************************************************/
static tU16
getPacket(tU8* pBuf, 
          tU16 len)
{
  tU8 nextpL = 0;
  tU8 nextpH = 0;
  tU16 nextPointer;

  tU16 count = 0;
  tU16 status = 0;
  tU16 cpyLen = 0;

tU8 buffer[20];

  // move to bank 0
  m_nic_bfc(CTL_REG_ECON1, (ENC_ECON1_BSEL1 | ENC_ECON1_BSEL0));

//printf("\nCTL_REG_ERDPT = 0x%x", (tU16)m_nic_read(CTL_REG_ERDPTL) | ((tU16)m_nic_read(CTL_REG_ERDPTH) << 8));
//printf("\nCTL_REG_ERXRDPT = 0x%x", (tU16)m_nic_read(CTL_REG_ERXRDPTL) | ((tU16)m_nic_read(CTL_REG_ERXRDPTH) << 8));

m_nic_read_data(6, buffer);
//printf("\nByte= [%x, %x, %x, %x, %x, %x, %x, %x, %x, %x]\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7], buffer[8], buffer[9]);
//printf("\nByte= [%x, %x, %x, %x, %x, %x, %x, %x, %x, %x]\n", buffer[10], buffer[11], buffer[12], buffer[13], buffer[14], buffer[15], buffer[16], buffer[17], buffer[18], buffer[19]);

#if 0
  /* read the next packet pointer */
  m_nic_read_data(1, &nextpL);
  m_nic_read_data(1, &nextpH);
printf("\nNextp = 0x%x\n", (tU16)nextpL | ((tU16)nextpH << 8));

  /* 
   * Get the receive byte count. The count includes destination and
   * source addresses, type/length, data, padding and CRC
   */
  m_nic_read_data(2, (tU8*)&count);
#endif
nextpL = buffer[0];
nextpH = buffer[1];
nextPointer = (tU16)nextpL | (tU16)nextpH << 8;
count = buffer[2];
count |= (tU16)buffer[3] << 8;
status = buffer[4];
status |= (tU16)buffer[5] << 8;



	// TODO: Remove this code.  In revision A0 beta silicon, a bug exists 
	// which can cause the receive buffer to become corrupt when moving the 
	// ERXRDPT value.  They do not update as a WORD, but rather as two 
	// separate BYTEs.  In future silicon revisions, receive buffer corruption
	// should never be possible.
	if(nextPointer > 0x1fff || 
	   nextPointer < ENC_RX_BUF_START ||
	   count > 1518)
	{
		// Reset the part.  We've gotten corrupt.
		ethIf_init(macAddr);
printf("\n\nEth reset!!!\n\n");
    return 0;
	}


//  printf("getPacket: count = %d\n", count);

  /* read rest of status vector (2 bytes) bits [23:16][31:24]*/
//  m_nic_read_data(2, (tU8*)&status);

//  printf("getPacket: status = %x, Ok = %d\n", status, ((status & 0x0080) != 0));


  if(pBuf != NULL)
  {
    if(count <= len)
      cpyLen = count;
    else
      cpyLen = len;
  }

  /* read data into buffer */
  m_nic_read_data(cpyLen, pBuf);

  /* skip any remaining data */
  m_nic_read_data((count-cpyLen), NULL);

  /* free buffer space */

  // move to bank 0
  m_nic_bfc(CTL_REG_ECON1, ENC_ECON1_BSEL1);
  m_nic_bfc(CTL_REG_ECON1, ENC_ECON1_BSEL0);
  

  /*
   * Set to next packet pointer
   */
  m_nic_write(CTL_REG_ERXRDPTL, nextpL);
  m_nic_write(CTL_REG_ERXRDPTH, nextpH);
m_nic_write(CTL_REG_ERDPTL, nextpL);
m_nic_write(CTL_REG_ERDPTH, nextpH);

  /* decrease packet counter */
  m_nic_bfs(CTL_REG_ECON2, ENC_ECON2_PKTDEC);

  return cpyLen;

}

/******************************************************************************
 * Implementation of public functions
 *****************************************************************************/

/*****************************************************************************
 *
 * Description:
 *    Resets the NIC and initializes all required hardware registers. 
 *
 * Params:
 *    [in] pEthAddr - the ethernet address (MAC) that should be assigned to 
 *                    the driver. 
 *
 ****************************************************************************/
void
ethIf_init(tU8* pEthAddr)
{
  tU16 phid1 = 0;
  tU16 phid2 = 0;

  memcpy(macAddr, pEthAddr, 6);

  /* 
   * Setup the buffer space. Only start pointer is needed since the default
   * value of the end pointer (ERXND) is 0x1fff.
   */  
  m_nic_write(CTL_REG_ERXSTL, (ENC_RX_BUF_START & 0xFF));
  m_nic_write(CTL_REG_ERXSTH, (ENC_RX_BUF_START >> 8));
m_nic_write(CTL_REG_ERDPTL, (ENC_RX_BUF_START & 0xFF));
m_nic_write(CTL_REG_ERDPTH, (ENC_RX_BUF_START >> 8));

  /*
   * For tracking purposes, the ERXRDPT registers should be programmed with 
   * the same value. This is the read pointer.
   */
  m_nic_write(CTL_REG_ERXRDPTL, (ENC_RX_BUF_START & 0xFF));
  m_nic_write(CTL_REG_ERXRDPTH, (ENC_RX_BUF_START >> 8));

  /* Setup receive filters. */

  // move to bank 1
  m_nic_bfc(CTL_REG_ECON1, ENC_ECON1_BSEL1);
  m_nic_bfs(CTL_REG_ECON1, ENC_ECON1_BSEL0);

  // OR-filtering, Unicast, CRC-check and broadcast
  m_nic_write(CTL_REG_ERXFCON, (ENC_RFR_UCEN|ENC_RFR_CRCEN|ENC_RFR_BCEN));

  /* Wait for Oscillator Start-up Timer (OST). */

  while((m_nic_read(CTL_REG_ESTAT) & ENC_ESTAT_CLKRDY) == 0)
  {
    static int cnt = 0;

    if(cnt++ >= 1000)
    {
      printf(".");
      cnt = 0;
    }
  }



  /* verify identification */
  phid1 = phyRead(PHY_REG_PHID1);
  phid2 = phyRead(PHY_REG_PHID2);

  if(phid1 != ENC_PHID1_VALUE 
     || (phid2 & ENC_PHID2_MASK) != ENC_PHID2_VALUE)
  {
    printf("ERROR: failed to identify controller\n");
    printf("phid1 = %x, phid2 = %x\n", phid1, (phid2&ENC_PHID2_MASK));
    printf("should be phid1 = %x, phid2 = %x\n", ENC_PHID1_VALUE, ENC_PHID2_VALUE);
  }

  //
  // --- MAC Initialization ---
  //

  /* Pull MAC out of Reset */

  // switch to bank 2
  m_nic_bfc(CTL_REG_ECON1, ENC_ECON1_BSEL0);
  m_nic_bfs(CTL_REG_ECON1, ENC_ECON1_BSEL1);
  // clear MARTST
  m_nic_write(CTL_REG_MACON2, 0);

  /* enable MAC to receive frames */
  m_nic_write(CTL_REG_MACON1, ENC_MACON1_MARXEN);

  /* configure pad, tx-crc and duplex */ 
  // TODO maybe enable FRMLNEN
  m_nic_write(CTL_REG_MACON3, (ENC_MACON3_PADCFG0|ENC_MACON3_TXCRCEN));

  /* set maximum frame length */
  m_nic_write(CTL_REG_MAMXFLL, (ENC_MAX_FRM_LEN & 0xff));
  m_nic_write(CTL_REG_MAMXFLH, (ENC_MAX_FRM_LEN >> 8));

  /* 
   * Set MAC back-to-back inter-packet gap. Recommended 0x12 for half duplex
   * and 0x15 for full duplex.
   */
  m_nic_write(CTL_REG_MABBIPG, 0x12);

  /* Set (low byte) Non-Back-to_Back Inter-Packet Gap. Recommended 0x12 */
  m_nic_write(CTL_REG_MAIPGL, 0x12);
  
  /* 
   * Set (high byte) Non-Back-to_Back Inter-Packet Gap. Recommended 
   * 0x0c for half-duplex. Nothing for full-duplex
   */
  m_nic_write(CTL_REG_MAIPGH, 0x0C);

  /* set MAC address */

  // switch to bank 3
  m_nic_bfs(CTL_REG_ECON1, (ENC_ECON1_BSEL0|ENC_ECON1_BSEL1));

  m_nic_write(CTL_REG_MAADR0, macAddr[5]);
  m_nic_write(CTL_REG_MAADR1, macAddr[4]);
  m_nic_write(CTL_REG_MAADR2, macAddr[3]);
  m_nic_write(CTL_REG_MAADR3, macAddr[2]);
  m_nic_write(CTL_REG_MAADR4, macAddr[1]);
  m_nic_write(CTL_REG_MAADR5, macAddr[0]);

  //
  // Receive settings
  //

  /* auto-increment RX-pointer when reading a received packet */
  m_nic_bfs(CTL_REG_ECON2, ENC_ECON2_AUTOINC);

  // TODO interrupts can be enabled EIE.PKTIE, EIE.INTIE

  
  /* enable reception */
  m_nic_bfs(CTL_REG_ECON1, ENC_ECON1_RXEN);


  m_eth_ena_int;
}

/*****************************************************************************
 *
 * Description:
 *    Send an ethernet packet. 
 *
 * Params:
 *    [in] pData - the data to send
 *    [in] len   - length of the data to send
 *
 ****************************************************************************/
void
ethIf_send(tU8* pData, 
           tU16 len)
{
  tU8 byteVal = 0;
//printf("\nEnter ethIf_send()");
  // TODO wait for ECON1.TXRTS to be cleared ????
while ((m_nic_read(CTL_REG_ECON1) & 0x08) == 0x08)
  printf("?");

  /* move to bank 0 */
  m_nic_bfc(CTL_REG_ECON1, (ENC_ECON1_BSEL1 | ENC_ECON1_BSEL0));

  /* set start of transmit buffer */
  m_nic_write(CTL_REG_EWRPTL, (ENC_TX_BUF_START & 0xff));
  m_nic_write(CTL_REG_EWRPTH, (ENC_TX_BUF_START >> 8));
  m_nic_write(CTL_REG_ETXSTL, (ENC_TX_BUF_START & 0xff));
  m_nic_write(CTL_REG_ETXSTH, (ENC_TX_BUF_START >> 8));

  /* set end of transmit buffer, data + control byte */
  m_nic_write(CTL_REG_ETXNDL, ((ENC_TX_BUF_START+len) & 0xff));
  m_nic_write(CTL_REG_ETXNDH, ((ENC_TX_BUF_START+len) >> 8));

  /* write control byte */
  byteVal = 0x0E;
  m_nic_write_data(1, &byteVal);

  /* write data */
  m_nic_write_data(len, pData);

  /* clear transmit interrupt flag */
  m_nic_bfc(CTL_REG_EIR, ENC_EIR_TXIF);

  // TODO set EIE.TXIE o EIE:INTIE if interrupts...

  /* start transmission */
  m_nic_bfs(CTL_REG_ECON1, ENC_ECON1_TXRTS);
//printf("... and start transmission!!!\n");
}


/*****************************************************************************
 *
 * Description:
 *    Poll the driver
 *
 * Params:
 *    [in] pBuf - allocated buffer to which data will be copied
 *    [in] len  - length of buffer
 *
 * Returns:
 *    Number of copied bytes to the supplied buffer
 *
 ****************************************************************************/
tU16
ethIf_poll(tU8* pBuf, 
           tU16 len)
{
  tU16 recvLen = 0;
  tU8 eir = 0;

  eir = m_nic_read(CTL_REG_EIR);

  /* receive error */
  if(eir & ENC_EIR_RXERIF)
  {
    printf("ethIf_poll: Receive Error\n");
    m_nic_bfc(CTL_REG_EIR, ENC_EIR_RXERIF);
  }

  /* transmit error */
  if(eir & ENC_EIR_TXERIF)
  {
    printf("ethIf_poll: Transmit Error\n");
    m_nic_bfc(CTL_REG_EIR, ENC_EIR_TXERIF);
  }

  /* wake-up on LAN */
  if(eir & ENC_EIR_WOLIF)
  {
    printf("ethIf_poll: Wake-up on LAN\n");
  }

  /* Transmit interrupt -> a packet has been sent. */
  if((eir & ENC_EIR_TXIF) != 0)
  {
    printf("ethIf_poll: Transmit done\n");
    m_nic_bfc(CTL_REG_EIR, ENC_EIR_TXIF);
    
    
  }

  /* Link change */
  if((eir & ENC_EIR_LINKIF) != 0)
  {
    printf("\nethIf_poll: Link Change\n");
    m_nic_bfc(CTL_REG_EIR, ENC_EIR_LINKIF);
  }

  /* DMA completed */
  if((eir & ENC_EIR_DMAIF) != 0)
  {
    printf("\nethIf_poll: DMA Completed\n");
    m_nic_bfc(CTL_REG_EIR, ENC_EIR_DMAIF);
  }

  /* a packet has been received */
  if((eir & ENC_EIR_PKTIF) != 0)
  {
    recvLen = getPacket(pBuf, len);
    printf("ethIf_poll: Packet received\n");
  }

  return recvLen;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -