|
#include "etherdev.h"
/***************************基本宏定义***********************************/
#define ETH_CPU_CLOCK ETH_CPU_XTAL / 12 // 8051 clock rate (X1 mode)
// Delay routine timing parameters
#define ETH_DELAY_CONST 9.114584e-5 // Delay routine constant
#define ETH_DELAY_MULTPLR (unsigned char)(ETH_DELAY_CONST * ETH_CPU_CLOCK)
// X1 CPU mode timing parameters
#define ETH_T0_CLOCK ETH_CPU_XTAL / 12 // Timer 0 mode 1 clock rate
#define ETH_T0_INT_RATE 24 // Timer 0 intrupt rate (Hz)
#define ETH_T0_RELOAD 65536 - (ETH_T0_CLOCK / ETH_T0_INT_RATE)
// Packet transmit & receive buffer configuration
#define ETH_TX_PAGE_START 0x40 // 0x4000 Tx buffer is 6 * 256 = 1536 bytes
#define ETH_RX_PAGE_START 0x46 // 0x4600 Rx buffer is 26 * 256 = 6656 bytes
#define ETH_RX_PAGE_STOP 0x60 // 0x6000
#define ETH_ADDR_PORT_MASK 0x0F // 00001111y
#define ETH_DATA_PORT_MASK 0xFF // 11111111y
#define ETH_MIN_PACKET_LEN 0x3C
/************************私有函数*****************************/
static void etherdev_reg_write(unsigned short reg, unsigned short wr_data);
static unsigned short etherdev_reg_read(unsigned short reg);
static void etherdev_delay_ms(unsigned int count);
static unsigned int etherdev_poll(void);
static void cs8900_reset (void);
static void cs8900_reginit (void);
//static void etherdev_timer0_isr(void) interrupt 1 using 1;
/***********************全局变量********************************/
static unsigned char tick_count = 0;
/*************CS8900A寄存器写函数 I/O空间模式********************************/
static void etherdev_reg_write(unsigned short regno, unsigned short wr_data)
{
unsigned char regnol,regnoh,pdatah;
unsigned short pdatal;
//写寄存器低八位地址
regnol=regno&0xff;
ETH_ADDR_PORT= CS8900_PPTRL;
IOW = 0;
ETH_DATA_PORT= regnol;
IOW = 1;
//写寄存器高八位地址
regnoh=regno>>8;
ETH_ADDR_PORT= CS8900_PPTRH;
IOW = 0;
ETH_DATA_PORT= regnoh;
IOW = 1;
//写低八位数据
pdatal=wr_data&0xff;
ETH_ADDR_PORT= CS8900_PDATAL;
IOW = 0;
ETH_DATA_PORT= pdatal;
IOW = 1;
//写高八位数据
pdatah=wr_data>>8;
ETH_ADDR_PORT= CS8900_PDATAH;
IOW = 0;
ETH_DATA_PORT= pdatah;
IOW = 1;
ETH_DATA_PORT = ETH_DATA_PORT_MASK;
return;
}
/***********************CS8900A寄存器读函数 I/O空间模式******************/
static unsigned short etherdev_reg_read(unsigned short regno)
{
unsigned char regnol,regnoh;
unsigned short pdatal,pdatah,ppdata;
//写寄存器低八位地址
regnol=regno&0xff;
ETH_ADDR_PORT= CS8900_PPTRL;
IOW = 0;
ETH_DATA_PORT= regnol;
IOW = 1;
//写寄存器高八位地址
regnoh=regno>>8;
ETH_ADDR_PORT= CS8900_PPTRH;
IOW = 0;
ETH_DATA_PORT= regnoh;
IOW = 1;
//读寄存器低八位数据
ETH_ADDR_PORT= CS8900_PDATAL;
IOR = 0;
pdatal=ETH_DATA_PORT;
IOR = 1;
//读寄存器高八位数据
ETH_ADDR_PORT= CS8900_PDATAH;
IOR = 0;
pdatah=ETH_DATA_PORT;
IOR = 1;
ppdata=(pdatah<<8)|pdatal;
ETH_DATA_PORT = ETH_DATA_PORT_MASK;
return (unsigned short) ppdata;
}
/*************延时函数**********************************/
static void etherdev_delay_ms(unsigned int count)
{
for(count *= ETH_DELAY_MULTPLR; count > 0; count--) continue;
return;
}
/*************************定时器0****************************/
static void etherdev_timer0_isr(void) interrupt 1 using 1
{
// Reload timer/ counter 0 for 24Hz periodic interrupt.
TH0 = ETH_T0_RELOAD >> 8;
TL0 = ETH_T0_RELOAD;
// Increment 24ths of a second counter.
tick_count++;
return;
}
/****************************CS8900A***********************/
static void cs8900_reset (void)
{
unsigned short us;
//网卡重启
etherdev_reg_write (PP_SelfCTL, etherdev_reg_read (PP_SelfCTL) |0x0040);
//延时200ms
etherdev_delay_ms (200000);
//等待网卡重启结束
while (((us = etherdev_reg_read (PP_SelfSTAT)) & PP_SelfSTAT_InitD) == 0)
/* NOP*/;
}
/***************寄存器初始化**************************************/
static void cs8900_reginit (void)
{
//初始化RxCTL寄存器
etherdev_reg_write (PP_RxCTL, 0x1c00);
//初始化RxCFG寄存器
etherdev_reg_write (PP_RxCFG, 0);
//初始化TxCFG寄存器
etherdev_reg_write (PP_TxCFG, 0);
//初始化BufCFG寄存器
etherdev_reg_write (PP_BufCFG, 0);
//初始化RxCTL寄存器,允许接收和发送数据帧
etherdev_reg_write (PP_LineCTL, 0x00c0);
}
/**************公用函数接口******************************************/
/***************CS8900A初始化 返回值 1 成功 返回值0 失败************/
bit etherdev_init(void)
{
// Set IOR & IOW as they're active low.
IOR = 1;
IOW = 1;
// Set register data port as input.
ETH_DATA_PORT = ETH_DATA_PORT_MASK;
#ifdef ETH_DEBUG
init_sio_poll();
#endif /* ETH_DEBUG */
//验证网卡ID
if (etherdev_reg_read (PP_ChipID) != 0x630e) {
return 0;
}
//网卡重启
cs8900_reset ();
//写入网卡MAC地址
etherdev_reg_write (PP_IA + 0, UIP_ETHADDR0 | (UIP_ETHADDR1 << 8));
etherdev_reg_write (PP_IA + 2, UIP_ETHADDR2 | (UIP_ETHADDR3 << 8));
etherdev_reg_write (PP_IA + 4, UIP_ETHADDR4 | (UIP_ETHADDR5 << 8));
//初始化寄存器
cs8900_reginit ();
// Initialize Timer 0 to generate a periodic 24Hz interrupt.
// Stop timer/ counter 0.
TR0 = 0;
// Set timer/ counter 0 as mode 1 16 bit timer.
TMOD &= 0xF0;
TMOD |= 0x01;
// Preload for 24Hz periodic interrupt.
TH0 = ETH_T0_RELOAD >> 8;
TL0 = ETH_T0_RELOAD;
// Restart timer/ counter 0 running.
TR0 = 1;
// Enable timer/ counter 0 overflow interrupt.
ET0 = 1;
// Enable global interrupt.
EA = 1;
return 1;
}
/********************数据包发送函数************************************/
void etherdev_send(void)
{
unsigned int i;
unsigned char *ptr;
unsigned short s;
ptr = uip_buf;
retry:
//写发送命令低八位
ETH_ADDR_PORT= CS8900_TxCMDL;
IOW = 0;
ETH_DATA_PORT= 0xC0;
IOW = 1;
//写发送命令高八位
ETH_ADDR_PORT= CS8900_TxCMDH;
IOW = 0;
ETH_DATA_PORT= 0x00;
IOW = 1;
//写发送帧长度低八位
ETH_ADDR_PORT= CS8900_TxLENL;
IOW = 0;
ETH_DATA_PORT= uip_len&0xff;
IOW = 1;
//写发送帧长度高八位
ETH_ADDR_PORT= CS8900_TxLENH;
IOW = 0;
ETH_DATA_PORT= uip_len>>8;
IOW = 1;
if ((etherdev_reg_read (PP_BusSTAT) & PP_BusSTAT_TxRDY) == 0) {
etherdev_delay_ms (200000);
cs8900_reset ();
cs8900_reginit ();
goto retry;
}
for(i = 0; i < uip_len; i++)
{
if(i == 40 + UIP_LLH_LEN)
{
ptr = (unsigned char *)uip_appdata;
}
if(i%2==0)
{
ETH_ADDR_PORT= CS8900_RTDATAL;
IOW = 0;
ETH_DATA_PORT= *ptr++;
IOW = 1;
}
else
{
ETH_ADDR_PORT= CS8900_RTDATAH;
IOW = 0;
ETH_DATA_PORT= *ptr++;
IOW = 1;
}
}
// 等待发送完成
while ((s = etherdev_reg_read (PP_TER) & ~0x1F) == 0) continue;
return;
}
/*************************数据包接收函数**************************/
unsigned int etherdev_read(void)
{
unsigned int bytes_read;
/* tick_count threshold should be 12 for 0.5 sec bail-out
One second (24) worked better for me, but socket recycling
is then slower. I set UIP_TIME_WAIT_TIMEOUT 60 in uipopt.h
to counter this. Retransmission timing etc. is affected also. */
while ((!(bytes_read = etherdev_poll())) && (tick_count < 12)) continue;
tick_count = 0;
return bytes_read;
}
/*****************CS8900A接受合法数据包*************************/
static unsigned int etherdev_poll(void)
{
unsigned int len = 0,i;
unsigned short status,statusl,statush,rxlenl,rxlenh;
status = etherdev_reg_read (PP_RER);
if ((status & PP_RER_RxOK) == 0)//读取Receive Event寄存器,RxOk==0?
return 0; //没有数据帧接收,返回
//读取接收帧状态低八位
ETH_ADDR_PORT= CS8900_RTDATAL;
IOW = 0;
statusl=ETH_DATA_PORT;
IOW = 1;
//读取接收帧状态高八位
ETH_ADDR_PORT= CS8900_RTDATAH;
IOW = 0;
statush=ETH_DATA_PORT;
IOW = 1;
status=(statusl<<8)|statush;
//读取帧长度低八位
ETH_ADDR_PORT= CS8900_RTDATAL;
IOW = 0;
rxlenl=ETH_DATA_PORT;
IOW = 1;
//读取帧长度高八位
ETH_ADDR_PORT= CS8900_RTDATAH;
IOW = 0;
rxlenh=ETH_DATA_PORT;
IOW = 1;
len=(rxlenh<<8)|rxlenl;//读取帧长度
if(len>UIP_BUFSIZE)
return 0;
for(i = 0; i < len; i++)
{
if(i%2==0)
{
ETH_ADDR_PORT= CS8900_RTDATAL;
IOW = 0;
*(uip_buf + i)= ETH_DATA_PORT;
IOW = 1;
}
else
{
ETH_ADDR_PORT= CS8900_RTDATAH;
IOW = 0;
*(uip_buf + i)= ETH_DATA_PORT;
IOW = 1;
}
}
return len;
} |
|