📄 cs8900if.c
字号:
/** @file * * Ethernet network driver for IP *//* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * 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. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels <adam@sics.se> * *//* This file is part of the lwIP TCP/IP stack. * * This is a device driver for the Crystal Semiconductor CS8900 * chip in combination with the lwIP stack. * * This is work under development. Please coordinate changes * and requests with Leon Woestenberg <leon.woestenberg@axon.tv> * * 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: * * cs8900_*() are low level, cs8900 hardware specific functions. * These are declared static in the device driver source and * SHOULD NOT need to be called from outside this source. * * cs8900if_*() are the lwIP network interface functions. * * cs8900_interrupt() is an early interrupt service routine (ISR). * It merely sets a flag to indicate the cs8900 needs servicing. * (This function MAY be tied to an interrupt vector, IF present). * * cs8900_service() is the actual interrupt event service routine. * It must be called whenever the cs8900 needs servicing. It MAY * be polled safely (so, you do NOT NEED interrupt support.) * * cs8900_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(). * * cs8900_input() transfers a received packet from the chip. * Function is called from cs8900if_input(). * * cs8900_output() transfers a packet to the chip for transmission. * Function is called from cs8900if_output(). * * cs8900if_init() initializes the lwIP network interface, and * calls cs8900_init() to initialize the hardware. * Function is called from lwIP. * * cs8900if_service() is the service routine, which must be called * upon the need for service, or on a regular basis, in order to * service the Ethernet chip. * * cs8900if_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(). * * cs8900if_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模式,采用中断方式收发数据 * 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. * * 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 */#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"//LPC2138头文件#include "LPC2294.h"#include "cs8900if.h"#include "cs8900a.h"/* Define those to better describe your network interface. */#define IFNAME0 'e'#define IFNAME1 '0'struct cs8900if { struct eth_addr *ethaddr; /* Add whatever per-interface state that is needed here. */};//CS8900A引脚宏定义#define IOR (1 << 19) #define IOW (1 << 23)#define SEL0 (1 << 21)#define SEL1 (1 << 22)#define A3_1 (7 << 16)#define D15_10 (0x3f << 25)#define D9_0 (0x3ff <<14)// typedefs:对cs8900a寄存器的访问先写入地址再写入数据typedef struct { u16_t addr; //CS8900A寄存器地址 u16_t data; //要写入寄存器的数据} TInitSeq;/** * Dependend on physical layer. This is a safe minimum for 802.3 10base5/T. * @sa RFC1042 */#define ETH_MIN_FRAME_LEN 76static const struct eth_addr ethbroadcast = {{0xffU,0xffU,0xffU,0xffU,0xffU,0xffU}};//定义MAC地址#define ETHADDR0 0x00#define ETHADDR1 0x01#define ETHADDR2 0x02#define ETHADDR3 0x03#define ETHADDR4 0x04#define ETHADDR5 0x05//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 *cs8900if_netif;//向cs8900a内部寄存器地址写入一个16位半字,访问方式为小端模式static void cs8900a_write(u16_t addr, u16_t data){ u32_t addr32 = 0,data32 = 0; addr32 = (u32_t)addr; data32 = (u32_t)data;/* CS8900的片先低有效 */ IO1SET = SEL0; //禁止CS8900A0 IO1CLR = SEL1; //使能CS8900A1 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-addressstatic u16_t cs8900a_read(u16_t addr){ u32_t value; u16_t tmp; u32_t addr32; addr32 = (u32_t)addr; /* CS8900的片先低有效 */ IO1SET = SEL0; //禁止CS8900A0 IO1CLR = SEL1; //使能CS8900A1 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 cs8900a_skip_frame(void){ // No space avaliable, skip a received frame and try again cs8900a_write(ADD_PORT, PP_RxCFG); cs8900a_write(DATA_PORT, cs8900a_read(DATA_PORT) | SKIP_1);}static sys_sem_t rxSem = NULL;/* 我建立了一个接收进程来处理网络数据包的接收,也可以用轮询的方式,前者更符合lwip的设计原则,并且 工作效率更高。此进程的优先级应该更高,不至于使数据丢失,但系统繁忙时可能需要更多的内存。 * */void cs8900a_rxThread(void *pdata){ u16_t irq_status = 0x0000U; pdata = pdata; /* Block for ever. */ rxSem = sys_sem_new(0); while(1) { //接收到信号量 sys_sem_wait(rxSem); //读取8900的中断状态寄存器判断中断来源 irq_status = cs8900a_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 */ cs8900if_input(cs8900if_netif); } else cs8900a_skip_frame(); } /* read ISQ register */ irq_status = cs8900a_read(ISQ_PORT); } }}/*u16_t ptr[1024];u16_t cs8900a_rev_test(){ u16_t len = 0; u16_t i = 0; // Check receiver event register to see if there are any valid frames avaliable cs8900a_write(ADD_PORT, PP_RxEvent); if ((cs8900a_read(DATA_PORT) & 0xd00) == 0) return 0; // Read frame length len = cs8900a_read(RX_FRAME_PORT); len = cs8900a_read(RX_FRAME_PORT); for(i = 0 ;i < (len/2); ++i) { ptr[i] = cs8900a_read(RX_FRAME_PORT); } return len;}*//** * cs8900a的接收中断服务程序 * * 接收到数据包时触发,用信号量通知接收子进程把数据提交给上层。 * * * * 千杯不醉 2007.1.30 */void cs8900a_rxIsr(void){ OS_ENTER_CRITICAL(); //cs8900a_rev_test(); if((EXTINT & 0x04) == 0x04) { sys_sem_signal(rxSem); // 通知接收任务 } EXTINT |= 0x04; //清除中断源,电平模式下当电平无效时执行 VICVectAddr = 0; // 通知中断控制器中断结束 OS_EXIT_CRITICAL();}// cs8900_init()//// initializes the CS8900A chipvoidcs8900a_init(struct netif *netif){ struct cs8900if *cs8900if; // u16_t dummy; u8_t i = 0; // the meaning of "netif->state" can be defined in drivers, here for MAC address! cs8900if = netif->state; /* maximum transfer unit */ netif->mtu = 1500; /* broadcast capability */ netif->flags = NETIF_FLAG_BROADCAST; /* hardware address length */ netif->hwaddr_len = 6; /* make up an MAC address. */ cs8900if->ethaddr->addr[0] = (u8_t)ETHADDR0; cs8900if->ethaddr->addr[1] = (u8_t)ETHADDR1; cs8900if->ethaddr->addr[2] = (u8_t)ETHADDR2; cs8900if->ethaddr->addr[3] = (u8_t)ETHADDR3; cs8900if->ethaddr->addr[4] = (u8_t)ETHADDR4; cs8900if->ethaddr->addr[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 ************************** */ PINSEL0 |= 0x0000c000; //cs8900's INTRQ1 active high //EXTMODE |= 0x04; //INT2边沿触发 EXTMODE = 0x00; EXTPOLAR |= 0x04; PINSEL1 = 0x00000000; PINSEL2 |= 0x04; IO0DIR |= D15_10 | D9_0; IO1DIR |= IOR | IOW | SEL0 | SEL1 | A3_1; IO1SET = SEL0 | SEL1 | IOR | IOW; //以太网控制器cs8900a1的中断:外部中断2 //VICVectAddr10 = (u32_t)cs8900a_rxIsr; //VICVectCntl10 = (0x20 | 0x10); //VICIntEnable |= 1 << 16; IO1SET = SEL0; //禁止CS8900A0 IO1CLR = SEL1; //使能CS8900A1 /**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -