Chinaunix首页 | 论坛 | 博客
  • 博客访问: 416654
  • 博文数量: 55
  • 博客积分: 167
  • 博客等级: 入伍新兵
  • 技术积分: 1167
  • 用 户 组: 普通用户
  • 注册时间: 2012-08-28 10:20
个人简介

一个算是正常的中国码农!

文章分类

全部博文(55)

文章存档

2014年(1)

2013年(31)

2012年(23)

我的朋友

分类:

2013-09-26 08:24:24

    Lwip是一个非常优秀的开源协议栈,本人成功地把它移植到两款ARM7芯片上,移植过程中使用了众多大虾的成果,在此感谢他们的无私奉献!俗话说滴水之恩当涌泉相报,我反CS8900A的驱动程序张贴出来,希望对大家有利用价值。
    网上有不少CS8900A的驱动程序,但大多是使之工作于Memory模式,Memory模式占用较多的地址口,适用于有EMI接口的芯片,而对于没有 EMI接口的芯片(在低端嵌入式应用场合比较常见),IO模式因占用较少的地址线而得到广泛的应用。本驱动程序工作于16位IO模式,并在 Lwip1.1.1上能够很好地工作,底层操作系统采用uCOS-II。

/** @file:cs8900if0.c
*
* Ethernet network driver for CS8900A
*/

/*
*
* This is a device driver for the Crystal Semiconductor CS8900
* chip in combination with the lwIP stack.
*
* The Swedish Institute of Computer Science and Adam Dunkels
* are specifically granted permission to redistribute this
* source code under any conditions they seem fit.
*
* A quick function roadmap:
*
* cs8900a0_*() are low level, cs8900a hardware specific functions.
* These are declared static in the device driver source and
* SHOULD NOT need to be called from outside this source.
*
* cs8900if0_*() are the lwIP network interface functions.
*
* cs8900if0_rxIsr() is an early interrupt service routine (ISR).
* It merely post a semaphore to indicate the cs8900 needs servicing.
*
* cs8900if0_rxThread() is the actual interrupt event service routine.
* It must be called whenever the cs8900 signal a interrupt semaphore.
* It MAY be polled safely (so, you do NOT NEED interrupt support.)
* 把所有的接收工作都放在这个函数中是为了尽量使ISR简捷。
*
* cs8900a0_init() sets up the cs8900, using its register set. When
* using the driver on your particular hardware platform, make sure
* the register setups match.
* Function is called from cs8900if_init().
*
* cs8900a0_input() transfers a received packet from the chip.
* Function is called from cs8900if_input().
*
* cs8900a0_output() transfers a packet to the chip for transmission.
* Function is called from cs8900if_output().
*
* cs8900if0_init() initializes the lwIP network interface, and
* calls cs8900_init() to initialize the hardware.
* Function is called from lwIP.
*
* cs8900if0_input() calls cs8900_input() to get a received packet
* and then forwards the packet to protocol(s) handler(s).
* Function is called from cs8900_service().
*
* cs8900if0_output() resolves the hardware address, then
* calls cs8900_output() to transfer the packet.
* Function is called from lwIP.
*
* Future development:
*
* Split the generic Ethernet functionality (a lot of the
* cs8900if_*() functions) and the actual cs8900a dependencies.
*
* Enhance the interrupt handler to service the Ethernet
* chip (to decrease latency); support early packet
* inspection (during reception) to early drop unwanted
* packets, minimize chip buffer use and maximize throughput.
*
* Statistics gathering, currently under development.
* SNMP support, currently under development.
*
*/

/*
*        今天终于找出了取数据(DataAbort)出错的问题,原因是CS8900A的外部中断引起的。先用轮询法读取数据。
                2007.2.24 千杯不醉
*/


  
/*
*    cs8900a驱动程序,工作于16位I/O模式,采用中断方式收发数据
*   
* INT1--------P0.3
*    INT2--------P0.7
*    IOR---------P1.19
*    IOW---------P1.23
* A3-A1-------P1.18-P1.16
*    SEL0--------P1.21    :active low
*    SEL1--------P1.22
*    D15-D10-----P0.30-P0.25
*    D9-D0-------P0.23-P0.14
*
*    千杯不醉 2007.1.20
*
* 注意:本驱动中所有涉及到IO1SET = SEL1;    //禁止CS8900A1
*                                    IO1CLR = SEL0;    //使能CS8900A0
*        的语句是因为双网卡的缘故.
*/

#include "lwip/debug.h"

#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/stats.h"
#include "lwip/sys.h"

#include "netif/etharp.h"
#include "arch/sys_arch.h"

#include "netif/cs8900if.h"

/* Define those to better describe your network interface. */
#define IFNAME0 'e'
#define IFNAME1 '1'

//定义MAC地址
#define ETHADDR0 0x00
#define ETHADDR1 0x01
#define ETHADDR2 0x02
#define ETHADDR3 0x03
#define ETHADDR4 0x04
#define ETHADDR5 0x06

//cs8900a的配置信息,寄存器地址和写入值成对出现
static TInitSeq InitSeq[] =
{    
    {PP_IA,       ETHADDR0 | (ETHADDR1 << 8)},     // set MAC Address
    {PP_IA + 2,   ETHADDR2 | (ETHADDR3 << 8)},
    {PP_IA + 4,   ETHADDR4 | (ETHADDR5 << 8)},
    {PP_TestCTL, 0x0099},                                        //Test Control:DisableLT XXX OBS
    /*
    *    enable:receiver,transmitter   
    */
    {PP_LineCTL, 0x0013U | 0x0080U/*SerTxOn*/ | 0x0040U/*SerRxOn*/},
    /*
    *    accept valid unicast or broadcast frames
    */
    {PP_RxCTL,    0x0005U | 0x0800U | 0x0400U | 0x0100U},
    {PP_RxCFG,        0x0003U | 0x0100U},        // enable receive interrupt
    {PP_TxCFG,        0x0007U | 0},                    // disable transmit interrupt (is default)
    {PP_CS8900_ISAINT,        0x0000U},                            // use interrupt number 0
   
    /* generate interrupt event on:
        - the RxMISS counter reaches 0x200, or
       - a received frame is lost
       */
    {PP_BufCFG,        0x000bU},
   
    {PP_BusCTL,        0x0017U | 0x8000U}// enable interrupt generation
};


static struct netif *cs8900if0;

//向cs8900a内部寄存器地址写入一个16位半字,访问方式为小端模式
static void cs8900a0_write(u16_t addr, u16_t data)
{
    u32_t addr32 = 0,data32 = 0;
    addr32 = (u32_t)addr;
    data32 = (u32_t)data;
/* CS8900的片先低有效    */
    IO1SET = SEL1;    //禁止CS8900A1
IO1CLR = SEL0;    //使能CS8900A0

IO0DIR |= D15_10 | D9_0;                              // Data port to output

IO1SET = IOR | IOW | ((addr32<<15) & A3_1);                        // Put address on bus
IO1CLR = (~(addr32<<15)) & A3_1;                  
  
IO0SET = ((data32<<14) & D9_0) | ((data32<<15) & D15_10);        //put 16bit data on data bus
IO0CLR = ((~(data32<<14)) & D9_0) | ((~(data32<<15)) & D15_10);
IO1CLR = IOW;
  
IO1SET = IOW;
}

// Reads a word in little-endian byte order from a specified port-address
static u16_t cs8900a0_read(u16_t addr)
{
u32_t value;
u16_t tmp;
u32_t addr32;
    addr32 = (u32_t)addr;
  
/* CS8900的片先低有效    */
    IO1SET = SEL1;    //禁止CS8900A1
IO1CLR = SEL0;    //使能CS8900A0

    IO0DIR &= ~(D15_10 | D9_0);        // data port to input
   
                            
     IO1SET = IOR | IOW | ((addr32<<15) & A3_1);        // Put address on bus
IO1CLR = (~(addr32<<15)) & A3_1;                  

IO1CLR = IOR;                            // IOR-signal low
  
value = IO0PIN;
  
IO1SET = IOR;
  
tmp = (u16_t)(((value & D9_0)>>14) | ((value & D15_10)>>15));
  
return tmp;
}

/**----------------------------------------*
* 说明:    SKIP_1:when set,this bit causes the last committed revieved frame to be
*            deleted from the receive buffer.并且一置位就立即执行(Act at once)。
**---------------------------------------*/
static void cs8900a0_skip_frame(void)
{
    //read RxStatus and RxLen
    cs8900a0_read(RX_FRAME_PORT);
    cs8900a0_read(RX_FRAME_PORT);
    // skip received frame    
    cs8900a0_write(ADD_PORT,PP_RxCFG);
    cs8900a0_write(DATA_PORT,cs8900a0_read(DATA_PORT) | 0x0040U/*Skip_1*/ );
}


static sys_sem_t rxSem0 = NULL;

/* 我建立了一个接收进程来处理网络数据包的接收,也可以用轮询的方式,前者更符合lwip的设计原则,并且
工作效率更高。此进程的优先级应该更高,不至于使数据丢失,但系统繁忙时可能需要更多的内存。
*
*/
void cs8900if0_rxThread(void *pdata)
{
    u16_t irq_status = 0x0000U;
    pdata = pdata;   
   
    /* Block for ever. */
rxSem0 = sys_sem_new(0);
   
    while(1)
    {
        //接收到信号量
        sys_sem_wait(rxSem0);
        //读取8900的中断状态寄存器判断中断来源   
           irq_status = cs8900a0_read(ISQ_PORT);
        /* ISQ interrupt event, and allowed to service in this loop? */
         while (irq_status != 0x0000U)
        {
            /* investigate event */
            if ((irq_status & 0x003fU) == 0x0004U/*Receiver Event*/)
            {
                  /* correctly received frame, either broadcast or individual address */
                  /* TODO: think where these checks should appear: here or in cs8900_input() */
                  if ((irq_status & 0x0100U/*RxOK*/) && (irq_status & 0x0c00U/*Broadcast | Individual*/))
                  {                
                    /* read the frame from the cs8900a */
                    cs8900if0_input(cs8900if0);
                  }
                  else cs8900a0_skip_frame();
            }

            /* read ISQ register */
                irq_status = cs8900a0_read(ISQ_PORT);
        }
    }
}

/**
*         cs8900a的接收中断服务程序
*
*         接收到数据包时触发,用信号量通知接收子进程把数据提交给上层。
*
*
*
*        千杯不醉        2007.1.30
*/

void cs8900if0_rxIsr(void)
{   
   
    //#if OS_CRITICAL_METHOD == 3          /* Allocate storage for CPU status register */
    //    OS_CPU_SR cpu_sr = 0;
    //#endif
   // OS_ENTER_CRITICAL();   
   if((EXTINT & 0x02) == 0x02)
    {   
      sys_sem_signal(rxSem0);
    }
    EXTINT |= 0x02;    //清除中断源,电平模式下当电平无效时执行
    VICVectAddr = 0;            // 通知中断控制器中断结束
    
   // OS_EXIT_CRITICAL();
}

// cs8900_init()
//
// initializes the CS8900A chip
static struct netif *
cs8900a0_init(struct netif *netif)
{
u8_t i = 0;
  
/* maximum transfer unit */
//以太网最大传输单元是1500B
netif->mtu = 1500;

/* broadcast capability */
netif->flags = NETIF_FLAG_BROADCAST;

/* hardware address length */
netif->hwaddr_len = 6;
  
/* make up an MAC address. */
netif->hwaddr[0] = (u8_t)ETHADDR0;
netif->hwaddr[1] = (u8_t)ETHADDR1;
netif->hwaddr[2] = (u8_t)ETHADDR2;
netif->hwaddr[3] = (u8_t)ETHADDR3;
netif->hwaddr[4] = (u8_t)ETHADDR4;
netif->hwaddr[5] = (u8_t)ETHADDR5;

/**    初始化cs8900a引脚配置和中断控制器   
*******INT1***INT2****
*
* INT1--------P0.3
*    INT2--------P0.7
*
*********GPIO*********
*    IOR---------P1.19
*    IOW---------P1.23
* A3-A1-------P1.18-P1.16
*    SEL0--------P1.21    :active low
*    SEL1--------P1.22
*    D15-D10-----P0.30-P0.25
*    D9-D0-------P0.23-P0.14
**************************
*/

PINSEL1 |= 0x00000000;
PINSEL2 |= 0x04;
//配置相关引脚为输出
IO0DIR |= D15_10 | D9_0;  
IO1DIR |= IOR | IOW | SEL0 | SEL1 | A3_1;
  
IO1SET = SEL0 | SEL1 | IOR | IOW;
   
IO1SET = SEL1;    //禁止CS8900A0
IO1CLR = SEL0;    //使能CS8900A1

   /**
* Reset the CS8900A chip-wide using a soft reset
*
* @note You MUST wait 30 ms before accessing the CS8900
* after calling this function.
*/
cs8900a0_write(ADD_PORT, PP_SelfCTL);
cs8900a0_write(DATA_PORT, POWER_ON_RESET);
    
/* 电平的跳变使CS8900A进入16位模式。After a hardware or a software reset,the CS8900A will be in 8-bit mode.Provide a HIGH
*    to LOW and then LOW to HIGH transition on the /SBHE signal before any 16-bit IO or Memory access is done
*    to the CS8900A.
*/
IO1SET = SEL0;
IO1CLR = SEL0;
IO1SET = SEL0;
IO1CLR = SEL0;
   // Wait until chip-reset is done   
cs8900a0_write(ADD_PORT, PP_SelfST);
// INITD bit still clear?
while ((cs8900a0_read(DATA_PORT) & INIT_DONE) == 0) ;

// Configure the CS8900A
for (i = 0; i < sizeof(InitSeq) / sizeof (TInitSeq); ++i)
    {
      cs8900a0_write(ADD_PORT, InitSeq[i].addr);
      cs8900a0_write(DATA_PORT, InitSeq[i].data);
    }

   //返回此网络接口给一个全局变量,接收线程通过此网络接口传递数据
   return netif;
}

/*-----------------------------------------------------------------------------------*/
/*
* cs8900a0_output():
* @return error code
* - ERR_OK: packet transferred to hardware
* - ERR_CONN: no link or link failure
* - ERR_IF: could not transfer to link (hardware buffer full?)
*
*
* Should do the actual transmission of the packet. The packet is
* contained in the pbuf that is passed to the function. This pbuf
* might be chained.
*
*    我想在数据接收和发送的过程中应该用信号量来保证数据的完整性。
*/
/*-----------------------------------------------------------------------------------*/

static err_t
cs8900a0_output(struct netif *netif, struct pbuf *p)
{
    struct pbuf *q;
int tries = 0;
err_t result;

// exit if link has failed
    cs8900a0_write(ADD_PORT,PP_LineST);
    if ((cs8900a0_read(DATA_PORT) & 0x0080U/*LinkOK*/) == 0) return ERR_CONN; // no Ethernet link
   
result = ERR_OK;  
     
// issue 'transmit' command to CS8900
cs8900a0_write(TX_CMD_PORT, TX_START_ALL_BYTES);
/* send length (in bytes) of packet to send, but at least minimum frame length */
cs8900a0_write(TX_LEN_PORT, (p->tot_len < MIN_PACKET_SIZE? MIN_PACKET_SIZE: p->tot_len));

    cs8900a0_write(ADD_PORT,PP_BusST);
// not ready for transmission and still within 50 retries?
//如果当前缓冲区满不能发送,在50次后清空接收数据
while (((cs8900a0_read(DATA_PORT) & 0x0100U/*Rdy4TxNOW*/) == 0) && (tries++ < 50))
{
    // throw away the last committed received frame
    cs8900a0_skip_frame();

    cs8900a0_write(ADD_PORT,PP_BusST);
}
  
//drop the padding word
#if ETH_PAD_SIZE
    pbuf_header(p,-ETH_PAD_SIZE);
#endif
  
// ready to transmit?如果准备好则发送数据
if ((cs8900a0_read(DATA_PORT) & 0x0100U/*Rdy4TxNOW*/) != 0)
{
    unsigned long sent_bytes = 0;
    /* q traverses through linked list of pbuf's
     * This list MUST consist of a single packet ONLY */

    for (q = p; q != NULL; q = q->next)
    {
      u16_t i;
      u16_t *ptr = (u16_t *)q->payload;
      /* Send the data from the pbuf to the interface, one pbuf at a
       * time. The size of the data in each pbuf is kept in the ->len
       * variable.
       可能有多个缓冲区中的数据要发送,我们争取全部把它们发送出去
       */
      for (i = 0; i < q->len; i += 2)
      {
        /** TODO: this routine assumes 16-bit boundary pbufs... */
        cs8900a0_write(TX_FRAME_PORT,*ptr++);
        sent_bytes += 2;
        
      }
    }
    /* provide any additional padding to comply with minimum Ethernet
     * frame length (RFC10242)如果数据过短就补充0,达到以太网最小的数据包 */
    while (sent_bytes < MIN_PACKET_SIZE)
    {
      cs8900a0_write(TX_FRAME_PORT,0x0000);
      sent_bytes += 2;
    }
}
else
{
    // { not ready to transmit!? }
    /* return not connected */
    result = ERR_IF;
}
  
//reclaim the padding word
#if ETH_PAD_SIZE
    pbuf_header(p,-ETH_PAD_SIZE);
#endif
#if LINK_STATS
        lwip_stats.link.xmit++;
    #endif /* LINK_STATS */
   
return result;
}
/*-----------------------------------------------------------------------------------*/
/*
* cs8900a0_input():
*
* Should allocate a pbuf and transfer the bytes of the incoming
* packet from the interface into the pbuf.
*
* Move a received packet from the cs8900 into a new pbuf.
*
* Must be called after reading an ISQ event containing the
* "Receiver Event" register, before reading new ISQ events.
*
* This function copies a frame from the CS8900A.
* It is designed failsafe:
* - It does not assume a frame is actually present.
* - It checks for non-zero length
* - It does not overflow the frame buffer
*/
/*-----------------------------------------------------------------------------------*/
static struct pbuf *
cs8900a0_input(struct netif *netif)
{
    struct pbuf *p = NULL, *q = NULL;
    u16_t len = 0;
    u16_t i;
    u16_t *ptr = NULL;

    // read RxStatus.由于在cs8900if0_rxThread()已经对接收到的数据进行判断,故discard it以提高效率
    cs8900a0_read(RX_FRAME_PORT);

    // read RxLength
    len = cs8900a0_read(RX_FRAME_PORT);
    LWIP_DEBUGF(NETIF_DEBUG, ("cs8900_input: packet len %u\n", len));
    // positive length?
    if (len > 0)
    {
      // allocate a pbuf chain with total length 'len'
      p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
      if (p != NULL)
      {
      #if ETH_PAD_SIZE
            pbuf_header(p, -ETH_PAD_SIZE);            /* drop the padding word */
        #endif
        for (q = p; q != 0; q = q->next)
            {
                  LWIP_DEBUGF(NETIF_DEBUG, ("cs8900_input: pbuf @%p tot_len %u len %u\n", q, q->tot_len, q->len));
                ptr = q->payload;
          // TODO: CHECK: what if q->len is odd? we don't use the last byte?
              for (i = 0; i < (q->len + 1) / 2; i++)
              {
                *ptr = cs8900a0_read(RX_FRAME_PORT);
                ptr++;
              }
        }
    #if ETH_PAD_SIZE
        pbuf_header(p, ETH_PAD_SIZE);            /* reclaim the padding word */
    #endif
      }
      // could not allocate a pbuf
      else
      {
        // skip received frame
        // TODO: maybe do not skip the frame at this point in time?
        cs8900a0_skip_frame();
        len = 0;
        
        #if LINK_STATS
                lwip_stats.link.memerr++;
                lwip_stats.link.drop++;
                #endif /* LINK_STATS */   
      }
    }
    // length was zero
    else
    {
    }
return p;
}

/**
* cs8900if0_input():
*
* Read a received packet from the CS8900.
*
* This function should be called when a packet is received by the CS8900
* and is fully available to read. It moves the received packet to a pbuf
* which is forwarded to the IP network layer or ARP module. It transmits
* a resulting ARP reply or queued packet.
*
* @param netif The lwIP network interface to read from.
*
* @internal Uses cs8900_input() to move the packet from the CS8900 to a
* newly allocated pbuf.
*
*
* This function should be called when a packet is ready to be read
* from the interface. It uses the function low_level_input() that
* should handle the actual reception of bytes from the network
* interface.
*
*/
/*-----------------------------------------------------------------------------------*/
void
cs8900if0_input(struct netif *netif)
{
struct eth_hdr *ethhdr;
struct pbuf *p;

/* move received packet into a new pbuf */
p = cs8900a0_input(netif);
/* no packet could be read */
if (p == NULL) {
    /* silently ignore this */
    return;
}
/* points to packet payload, which starts with an Ethernet header */
ethhdr = p->payload;

#if LINK_STATS
lwip_stats.link.recv++;
#endif /* LINK_STATS */

switch (htons(ethhdr->type)) {
/* IP packet? */
case ETHTYPE_IP:
    /* update ARP table */
    etharp_ip_input(netif, p);
    /* skip Ethernet header */
    pbuf_header(p, -sizeof(struct eth_hdr));
    /* pass to network layer */
    netif->input(p, netif);
    break;
      
    case ETHTYPE_ARP:
      /* pass p to ARP module */
      etharp_arp_input(netif, (struct eth_addr *)&(netif->hwaddr[0]), p);
      break;
    default:
      pbuf_free(p);
      p = NULL;
      break;
}
}

/**
* cs8900if0_output():
*
* Writing an IP packet (to be transmitted) to the CS8900.
*
* Before writing a frame to the CS8900, the ARP module is asked to resolve the
* Ethernet MAC address. The ARP module might undertake actions to resolve the
* address first, and queue this packet for later transmission.
*
* @param netif The lwIP network interface data structure belonging to this device.
* @param p pbuf to be transmitted (or the first pbuf of a chained list of pbufs).
* @param ipaddr destination IP address.
*
* @return ERR_OK if the packet was sent or queued. There is no way to
* find out if a packet really makes it onto the network link.
*
* @internal It uses the function cs8900_input() that should handle the actual
* reception of bytes from the network interface.
*
* This function is called by the TCP/IP stack when an IP packet
* should be sent. It calls the function called low_level_output() to
* do the actual transmission of the packet.
*
*/
err_t
cs8900if0_output(struct netif *netif, struct pbuf *p,
      struct ip_addr *ipaddr)
{  
/* resolve hardware address, then send (or queue) packet */
return etharp_output(netif, ipaddr, p);
}


/**
* arp_timer.
*/
static void arp_timer(void *arg)
{
etharp_tmr();
sys_timeout(ARP_TMR_INTERVAL, (sys_timeout_handler)arp_timer, NULL);
}


//void cs8900a0_send_test(void);
/**
* cs8900if0_init():
* Initialize the CS8900 Ethernet MAC/PHY and its device driver.
*
* @param netif The lwIP network interface data structure belonging to this device.
* MAY be NULL as we do not support multiple devices yet.
*
* Should be called at the beginning of the program to set up the
* network interface. It calls the function low_level_init() to do the
* actual setup of the hardware.
*
*/

err_t
cs8900if0_init(struct netif *netif)
{
struct cs8900if *cs8900if;
  
//协议栈有自己的内存管理机制
cs8900if = mem_malloc(sizeof(struct cs8900if));
if (cs8900if == NULL)
{
    LWIP_DEBUGF(NETIF_DEBUG, ("cs8900if0_init: out of memory\n"));
    return ERR_MEM;
}
// initialize cs8900 specific interface state data pointer
netif->state = cs8900if;
netif->name[0] = IFNAME0;
netif->name[1] = IFNAME1;
netif->output = cs8900if0_output;
netif->linkoutput = cs8900a0_output;
  
//initialize cs8900 specific interface state field
cs8900if->state = NETIFUSED;
  
// intialize the cs8900a chip
cs8900if0 = cs8900a0_init(netif);
  
etharp_init();
  
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
  
//cs8900a0_send_test();
  
return ERR_OK;
}
/*-----------------------------------------------------------------------------------*/
/**
*        这是一个不依赖于Lwip的驱动测试程序,发送一个ARP请求包。
*       
*/
#if 0
static const u8_t arpdata[60] =
{
     0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x01,0x02,0x03,0x04,0x06,0x08,0x06,0x00,0x01,
     0x08,0x00,0x06,0x04,0x00,0x01,0x00,0x01,0x02,0x03,0x04,0x06,0xd2,0x1d,0x68,0x08,
     0x00,0x00,0x00,0x00,0x00,0x00,0xd2,0x1d,0x68,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,
     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
void cs8900a0_send_test(void)
{
     u16_t u;

// Transmit command
cs8900a0_write(TX_CMD_PORT, TX_START_ALL_BYTES);
cs8900a0_write(TX_LEN_PORT, 60);

// Maximum number of retries
u = 8;
for (;;)
    {
      // Check for avaliable buffer space
      cs8900a0_write(ADD_PORT, PP_BusST);
      if (cs8900a0_read(DATA_PORT) & READY_FOR_TX_NOW)
        break;
      if (u -- == 0)
        return;

      // No space avaliable, skip a received frame and try again
      cs8900a0_skip_frame();
    }
  
// Send uip_len bytes of header
for (u = 0; u < 60; u += 2)
    {
    cs8900a0_write(TX_FRAME_PORT,*(u16_t *)&arpdata[u]);
     
    }
}
#endif
阅读(2437) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~