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

📄 dm9000.c

📁 this is a driver for the davicom ethernet controller DM9000. this driver help in developing pc or em
💻 C
字号:
//
// Copyright (c) 2001, Adam Dunkels.
// Copyright (c) 2005, Invector Embedded Technologies
// All rights reserved. 
//
// Redistribution and use in source and binary forms, with or without 
// modification, are permitted provided that the following conditions 
// are met: 
// 1. Redistributions of source code must retain the above copyright 
//    notice, this list of conditions and the following disclaimer. 
// 2. Redistributions in binary form must reproduce the above copyright 
//    notice, this list of conditions and the following disclaimer in the 
//    documentation and/or other materials provided with the distribution. 
// 3. The name of the author may not be used to endorse or promote
//    products derived from this software without specific prior
//    written permission.  
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  

// ---------------------------------------------------------------------------//
// Module:			DM9000 ethernet routines for 8051 and SDCC port of Adam Dunkels' 
//              uIP v0.9 
// Filename:		DM9000.c
// Version:			0.1
// Date:			  30/MAR/2005
// Author:			Adam Dunkels, A.Pemberton, Pontus Oldberg
// Function:		DM9000 and other H/W definitions
//
// Change History:	
//              2006-03-15 PO Cleaned up code
//              2005-09-14 AP Basic DM9000 module - frills removed
//
// 
// ---------------------------------------------------------------------------

#include <stdio.h>
#include <string.h>
#include "dm9000.h"		  // Physical Layer

#define VERSION 1_1

//---------------------------------------------------------------------------------
// Static variables for DM9000
//---------------------------------------------------------------------------------

extern bit TX_EventPending;	// the DM9000 hardware receive event
extern bit ARP_EventPending;	// trigger the arp timer event

static u16_t RX_Length;	// Physical size of packet must be completely read!

//---------------------------------------------------------------------------------
// Local prototypes
//---------------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Write Command to NIC
//-----------------------------------------------------------------------------

void write_nicreg(u8_t IOaddr, u8_t val)
{
	NIC_REG = IOaddr;
	NIC_DAT = val;
}

//-----------------------------------------------------------------------------
// Write Data to NIC
//-----------------------------------------------------------------------------
void write_nicdata(u8_t val)
{
	NIC_DAT = val;
}

//-----------------------------------------------------------------------------
// Write Command or Data to already selected register
//-----------------------------------------------------------------------------
void set_nicreg(u8_t IOaddr)
{
	NIC_REG = IOaddr;
}

//-----------------------------------------------------------------------------
// Write Command to PHY
//-----------------------------------------------------------------------------

void PHY_write(u8_t IOaddr, u16_t val)
{
 	write_nicreg(DM9000_EPCR,0x0a);					// Set EEPROM & PHY Control Reg to write
 	write_nicreg(DM9000_EPAR,((IOaddr & 0x3f) | DM9000_PHY));	// Set PHY Address Reg to PHY Address
  write_nicreg(DM9000_EPDRH,(u8_t)(val >> 8));	// write high_byte of PHY data
  write_nicreg(DM9000_EPDRL,(u8_t)(val));			// write low_byte of PHY data
 	write_nicreg(DM9000_EPCR,0x00);					// Clear EEPCR
}

//--------------------------------------------------------------------------------
// Read Status from NIC
//--------------------------------------------------------------------------------
u8_t read_nicreg(u8_t IOaddr)
{
	NIC_REG = IOaddr;
	return (NIC_DAT);
}

//--------------------------------------------------------------------------------
// Read Data from NIC from preselected address
//--------------------------------------------------------------------------------
u8_t read_nicdata(void)
{
	return (NIC_DAT);
}

//-----------------------------------------------------------------------------
// Non-interrupt delay approx 1mS to 255mS
//-----------------------------------------------------------------------------
void _wait_ms(u16_t count)
{
	u16_t i;

  for ( ; count > 0; count--) {
		for ( i = 10000; i > 0; i--);
	}
}

//-----------------------------------------------------------------------------
// u8_t InitDM9000(void); 
//
// Init the PHY. If OK, return true
//-----------------------------------------------------------------------------
// Driver Initializing Steps

u8_t InitDM9000(void)
{

  //1. If the internal PHY is required, the following steps are to active the internal PHY:
  // The default status of the DM9000 is to power down the internal PHY by setting the GPIO0.
  // Since the internal PHY have been powered down, the wakeup procedure will be needed to
  // enable the DM9000.
  write_nicreg(DM9000_GPCR, 0x07);    // Power PHY set the GPR to output
  write_nicreg(DM9000_GPR,  0x06);	  // Clear the GPIO lines (Led's off)
  _wait_ms(1);

  //2. Program NCR register. Choose normal mode by setting NCR (reg_00h) bit[2:1] = 00h. The
  // system designer can choose the network operation such as setting internal/external PHY,
  // enable wakeup event or choose the full-duplex mode. Please refer to the DM9000 datasheet
  // ch.6.1 about NCR register setting.
  // Reset DM9000 (twice)
  write_nicreg(DM9000_NCR, 0x03);	// Reset
  _wait_ms(1);
  write_nicreg(DM9000_NCR, 0x00);	// Normal mode
  _wait_ms(1);

  write_nicreg(DM9000_NCR, 0x03);
  _wait_ms(1);
  write_nicreg(DM9000_NCR, 0x00);
  _wait_ms(1);

  //3. Clear TX status by reading NSR register (reg_01h). Bit[2:3] and bit[5] will be automatically
  // cleared by reading or writing 1. Please refer to the DM9000 datasheet ch.6.2 about NSR
  // register setting.
  read_nicreg(DM9000_NSR);

  //4. Read EEPROM (No EEPROM available - use scratchpad instead) data if
  // valid or required. By default, the array will have hard MAC loaded.

  //5. Set Node address 6 bytes from in physical address register (reg_10h~15h).
 	write_nicreg(DM9000_MAC_REG,  uip_ethaddr.addr[0]);
 	write_nicreg(DM9000_MAC_REG+1,uip_ethaddr.addr[1]);
 	write_nicreg(DM9000_MAC_REG+2,uip_ethaddr.addr[2]);
 	write_nicreg(DM9000_MAC_REG+3,uip_ethaddr.addr[3]);
 	write_nicreg(DM9000_MAC_REG+4,uip_ethaddr.addr[4]);
 	write_nicreg(DM9000_MAC_REG+5,uip_ethaddr.addr[5]);

  //6. Set Hash table 8 bytes from multicast address register (reg_16h~1Dh).
 	write_nicreg(DM9000_MLC_REG,  0xff);
 	write_nicreg(DM9000_MLC_REG+1,0xff);
 	write_nicreg(DM9000_MLC_REG+2,0xff);
 	write_nicreg(DM9000_MLC_REG+3,0xff);
 	write_nicreg(DM9000_MLC_REG+4,0xff);
 	write_nicreg(DM9000_MLC_REG+5,0xff);
 	write_nicreg(DM9000_MLC_REG+6,0xff);
 	write_nicreg(DM9000_MLC_REG+7,0xff);

  //7. reset Internal PHY if desired
  //	PHY_write(DM9000_BMCR, 0x8000);	// PHY reset
  //	 _wait_ms(1000);
  //	PHY_write(DM9000_BMCR, 0x1200);	// Auto negotiation
  //	 _wait_ms(1000);


  //8. Set IMR register (reg_FFh) bit[7]=1 to enable the SRAM read/write pointer which is the
  // automatic return function of the memory R/W address pointer; also set the receive int mask.
 	write_nicreg(DM9000_IMR, 0x81);

  //9. Depend on OS and DDK of the system to handle NIC interrupts.
  // Not applicable since the DM9000 is polled

  //10. Program IMR register (reg_FFh) bit[1:0] to enable the TX/RX interrupt. Before doing this,
  // the system designer needs to register the interrupt handler routine. For example, if the driver
  // needs to generate the interrupt after a package is transmitted, the interrupt mask register IMR
  // bit[1]=1 will be set. If the interrupt is generated by the DM9000 after receiving a packet, IMR
  // bit[0] should be set to 1.
  // Not applicable since the DM9000 is polled

  //11. Program RXCR register to enable RX. The RX function is enabled by setting the RX control
  // register (reg_05h) bit[0]=1. The choice of the other bits bit[6:0] depends on the system design.
  // Please refer to the DM9000 datasheet ch.6.6 about RXCR register setting.
 	write_nicreg(DM9000_RXCR, 0x31);	// Only MAC-packets and RX enable - no multicast packets

  //12. NIC is being activated now.

  //13. Check Vendor ID is Davicom (0x0A46)
  if ((read_nicreg(DM9000_VID) + (read_nicreg(DM9000_VID+1) << 8)) != DM9000_VendID)
    return TRUE;		// No chip found

  if ((read_nicreg(DM9000_PID) + (read_nicreg(DM9000_PID+1) << 8)) != DM9000_ProdID)
    return TRUE;		// No chip found

  RX_Length = 0;	

  return FALSE;
}
// ---------------------------------------------------------------------------//							DM9000_receive()
//
//	This function will read an entire IP packet into the uip_buf.
//	If it must wait for more than 0.5 seconds, it will return with
//	the return value 0. Otherwise, when a full packet has been read
//	into the uip_buf buffer, the length of the packet is returned.
// 
// Checks Physical layer for incoming Data, if applicable, forewind
// to 1st IP-Byte
// (for DM9000: Drop Status, but keep and (Physical) length)
// ---------------------------------------------------------------------------u16_t DM9000_receive(void)
{    

  u8_t RX_ready;
  u16_t RX_status;
  int i;

  // Unless there is a transmit event pending, we loop here listening to the DM9000
  // If the following bits get set, we break out to transmit a packet
  do // continuously read DM9000 for incoming packet
  { 

    // read the packet ready flag
    // Check if bit[0]=PRS=1, RX OK, a frame has been received
	  read_nicreg(DM9000_MRCMDX); // Read the packet ready flag

    if ((RX_ready = read_nicdata()) & DM9000_PKT_RDY) // ready check: this byte must be 0 or 1
    { 

      // get (and check) the RX status and get RX length
      // Set memory read autoincrement pointer 
      set_nicreg(DM9000_MRCMD);

      // Now read the two first bytes of the packet
      // First byte is RX packet present - should be 0x01. If 0x00 then no packet follows. Otherwise it is an error
      RX_status = (read_nicdata() + (read_nicdata() << 8));

      // Now get the packet data length which will not include these four bytes
      RX_Length = (read_nicdata() + (read_nicdata() << 8));

      // Now read the RX packet data to the previously recorded length
      for (i = 0; i < RX_Length; i++) 
      {
        *(uip_buf + i) = read_nicdata();
      }
      write_nicreg(DM9000_ISR, DM9000_RX_INTR);// clear bit[0]=PRS latched in ISR
      return RX_Length;// Frame received - return number of bytes in frame
    }
    // If rx_ready is 0, a frame error has occurred - reset the PHY
    else if (RX_ready != 0x00) 
    {
      write_nicreg(DM9000_IMR, 0x80);   // Stop Interrupt Request
      write_nicreg(DM9000_ISR, 0x0F);   // Clear Interrupt Status
      write_nicreg(DM9000_RXCR, 0x00);  // Stop Receive function

      InitDM9000();			                // Error occured! Reset PHY
      return 0;                         // error
    }
    write_nicreg(DM9000_ISR, DM9000_RX_INTR);// clear bit[0]=PRS latched in ISR
  }
  while (!(TX_EventPending || ARP_EventPending));
  return 0;		// No Frame received
}

//-----------------------------------------------------------------------------
// 					DM9000_transmit(void)
//
// Send the packet in the uip_buf and uip_appdata buffers
// using the DM9000 ethernet chip.
// The uIP packet buffer. 
//
// The uip_buf array is used to hold incoming and outgoing packets.
// The device driver should place incoming data into this buffer.
// When sending data, the device driver should read the
// link level headers and the TCP/IP headers from this buffer.
// The size of the link level headers is configured by the
// UIP_LLH_LEN define.
//
//-----------------------------------------------------------------------------
void DM9000_transmit(void)
{
  static u16_t i;
  static u16_t j;
  u8_t *ptr; // general pointer for data

  //Step 1: Wait for current transmit to complete
  while (read_nicreg(DM9000_TCR) & 0x01);

  // while (read_nicreg(DM9000_NSR) & (4 | 8));

  write_nicreg(DM9000_ISR, DM9000_TX_INTR);

  //Step 2: write the data into TX SRAM byte mode with address autoincrement
  set_nicreg(DM9000_MWCMD);

  // Transfer header info to SRAM
  // 54 octets - header, etc. info
  ptr = &uip_buf[0];

  // Modified to allow for the TCP options field length if supplied
  // uip_buf[UIP_LLH_LEN + 9] is the header protocol octet
  // uip_buf[UIP_LLH_LEN + 32] is the TCP offset octet which determines where the TCP header ends and data begins

  if (uip_buf[UIP_LLH_LEN + 9] == UIP_PROTO_TCP) 
  {
    j = (UIP_LLH_LEN + UIP_TCPIP_HLEN + (((uip_buf[UIP_LLH_LEN + 32] >> 4) - 5) << 2));
  }
  else if (uip_buf[UIP_LLH_LEN + 9] == UIP_PROTO_ICMP) 
  {
    j = (UIP_LLH_LEN + UIP_TCPIP_HLEN);
  }
  else if (uip_buf[UIP_LLH_LEN + 9] == UIP_PROTO_UDP) 
  {
    j = (UIP_LLH_LEN + UIP_TCPIP_HLEN);
  }
  else 
    j = (UIP_LLH_LEN + UIP_TCPIP_HLEN);

  for (i = 0; i < j; i++) 
  {
    write_nicdata(*ptr++); // write header data to transmit SRAM
  }

  // reached the end of header, switch pointer to uip_appdata to be sent.
  // Write appdata to DM9000 - should include any offset
  if (i < uip_len) 
  {
    for (ptr = uip_appdata; (i < uip_len) ; i++) 
    {
      write_nicdata(*ptr++); // write data to transmit SRAM
    }
  }

  //Step 3: write the xmit  data length into MDRAL (reg_FCh) & MDRAH (reg_FDh)
  // write high_byte of the transmitted data length into MDRAH (reg_FDh)
  write_nicreg(DM9000_TXPLH,(u8_t)(i >> 8));
  // write low_byte of the transmitted data length into MDRAL (reg_FCh)
  write_nicreg(DM9000_TXPLL,(u8_t)(i));

  //Step 4: start to transmit a packet
  // Issue command for DM9000 to transmit packet from TX SRAM.
  write_nicreg(DM9000_TCR, 1);
}

//-----------------------------------------------------------------------------
// END

⌨️ 快捷键说明

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