SMARTARM2200 ADS工程在IAR EWARM 5.3上的移植(7)-LwIP 1.2的移植(RTL8019AS驱动1)

实现LwIP与uCOSII的操作系统模拟层后,剩下重要的一部分就是网卡驱动了.SMARTARM2200用的网卡芯片是RTL8019AS.
RTL8019AS.有3种工作方式:
第一种为跳线方式,网卡的i/o和中断由跳线决定
第二种为即插即用方式,由软件进行自动配置plug and play
第三种为免跳线方式,网卡的i/o和中断由外接的93c46里的内容决定。

SMARTARM2200使用第一种方式即跳线方式.65脚JP为高电平时即为跳线模式.其基地址为300H,中断源为INT0(P0.9),操作地址为0x83400000~0x0x83400001F,该地址为CS3,A23,A22,A21通过ATF16LV8C译码而得.
更详细的信息可以参考我上传的工程http://download.csdn.net/source/1661278

由于很多涉及操作RTL8019AS寄存器,关于这方面更详细的内容请参考RTL8019AS的DataSheet.
RTL8019AS的驱动实现在2个文件里:
RTL8019.c:实现一些操作RTL8019AS的基本函数
ethernetif.c:实现LwIP与网卡接收发送的接口函数,主要是low_level_input和low_level_output以及中断处理函数
先讲RTL8019.c实现的一些函数:

1.定义读写寄存器的宏
//因为LPC2220的SAO~SA4与LPC2220的ADDRl~ADDR5相连,RTL8019AS工作在16位模式 #define RTL8019Addr (0x83400000>>1) #define Write8019Reg(addr, dat) *((volatile unsigned char *)((RTL8019Addr+addr)<<1)) = dat #define Read8019Reg(addr) *((volatile unsigned char *)((RTL8019Addr+addr)<<1))
2.页选择,RTL8019AS有4页寄存器,前3页与NE2000兼容,最后一页是自己的定义的,用来PNP,我们用不到,不用去设置
void page(unsigned char pagenumber) { unsigned char temp; temp = Read8019Reg(0x00) & 0x3B; //CR(00H)第6,7位PS1,PS0进行页选择 temp |= (pagenumber <<6); Write8019Reg(0x00, temp); }
3.GPIO初始化
void RTL8019AS_GPIOInit(void) { PINSEL0 |= 3<<18; //设置中断管脚连接,P0.9设置为EINT3 OSTimeDly(10); IO0DIR |= NET_RST;//set reset pin direction to output }
4.中断初始化
void RTL8019AS_InterruptInit(void) { //设置触发方式,上升沿触发 EXTMODE |= 0x08; EXTPOLAR |= 0x08; //EINT3清除中断状态 EXTINT = 1<<3; //配置LPC2220中断向量,并使能 VICIntSelect &= ~(1 << VIC_EINT3); /* Configure the Ethernet VIC interrupt source for IRQ */ VICVectCntl14 = 0x20 | VIC_EINT3; VICVectAddr14 = (CPU_INT32U)IRQ_Eint3; /* Set the vector address */ VICIntEnable = (1 << VIC_EINT3); /* Enable the VIC interrupt source, but no local sources */ }
5.复位网卡
static void RTL8019AS_Reset() //复位网卡 { IO0SET |= NET_RST; OSTimeDly(10); IO0CLR |= NET_RST; OSTimeDly(10); }
6.写MAC地址
static void RTL8019AS_WriteMAC(void) { page(1); Write8019Reg(0x01, My_hwaddr[0]); Write8019Reg(0x02, My_hwaddr[1]); Write8019Reg(0x03, My_hwaddr[2]); Write8019Reg(0x04, My_hwaddr[3]); Write8019Reg(0x05, My_hwaddr[4]); Write8019Reg(0x06, My_hwaddr[5]); page(0); }
7.准备好以上几个基本函数后,就可以进行RTL8019AS的初始化了
void RTL8019AS_Init(void) { unsigned char i; RTL8019AS_GPIOInit(); while(1) { //复位8019 RTL8019AS_Reset(); OSTimeDly(10); //使芯片处于停止模式,这时进行寄存器设置 停止模式下,将不会发送和接收数据包 Write8019Reg(0x00, 0x21); //延时10毫秒,确保芯片进入停止模式 OSTimeDly(10); i = Read8019Reg(0x00); //复位后,CR bit0(STP)应为1,芯片处于停止模式 if(i == 0x21) break; } page(0); Write8019Reg(0x0a, 0x00);//RBCR0 Write8019Reg(0x0b, 0x00);//RBCR1 Write8019Reg(0x0c, 0xe0);//RCR monitor mode (no packet receive) Write8019Reg(0x0d, 0xe2);//loop back mode 使芯片处于mon和loopback模式,跟外部网络断开 Write8019Reg(0x01, 0x4c);//PSTART 设置起始页 Write8019Reg(0x02, 0x80);//PSTOP 设置停止页 Write8019Reg(0x03, 0x4c);//BNRY 设置读缓冲指针 Write8019Reg(0x04, 0x40);//TPSR 设置发送包起始页 Write8019Reg(0x07, 0xff);//ISR 清除所有中断标志位 Write8019Reg(0x0f, 0x11);//IMR 禁止OVW PRX中断 Write8019Reg(0x0e, 0xc8);//DCR 8位dma方式 page(1); Write8019Reg(0x07, 0x4d);//CURR 设置接收包起始页 Write8019Reg(0x08, 0x00);//MAR0-7 多播地址(未使用设置为0) Write8019Reg(0x09, 0x00); Write8019Reg(0x0a, 0x00); Write8019Reg(0x0b, 0x00); Write8019Reg(0x0c, 0x00); Write8019Reg(0x0d, 0x00); Write8019Reg(0x0e, 0x00); Write8019Reg(0x0f, 0x00); Write8019Reg(0x00, 0x22);//CR 这时让芯片开始工作 RTL8019AS_WriteMAC();//将网卡MAC地址写入到mar寄存器 page(0); Write8019Reg(0x0c, 0xcc);//RCR 设置接收模式 Write8019Reg(0x0d, 0xe0);//TCR 将网卡设置成正常模式 Write8019Reg(0x00, 0x22);//CR 这时让芯片开始工作 Write8019Reg(0x07, 0xff);//ISR 清除所有中断标志位 }
8.发送数据包send_frame,该函数在ethernetif.c中的low_level_output被调用
void send_frame(unsigned char * outbuf, unsigned short len) { unsigned char i; unsigned short j; unsigned char temp; page(0); if(len<60)len=60;//长度最小为60字节 txd_buffer_select=!txd_buffer_select;//交换输出缓冲区 if(txd_buffer_select) Write8019Reg(0x09, 0x40); //txdwrite highaddress将远程DMA地址分为两个,40-45,46-4b。前面用于发送包。 else Write8019Reg(0x09, 0x46); //txdwrite highaddress后面用于构造端的包 Write8019Reg(0x08, 0x00);//RSAR 设置远程DMA起始地址 //read page address low Write8019Reg(0x0b, (unsigned char)(len>>8)); //read count high Write8019Reg(0x0a, (unsigned char)(len&0xff)); //read count low Write8019Reg(0x00, 0x12); //write dma, page0从远端DMA写到8019RAM中数据 for(j=0; j<len; j++) { Write8019Reg(0x10, *(outbuf+j)); } for(i=0;i<16;i++) //最多重发16次 { for(j=0;j<1000;j++) //检查txp为是否为低 { temp = Read8019Reg(0x00); if((temp&0x04)==0) break; } temp = Read8019Reg(0x04); if((temp&0x01)!=0) break; //表示发送成功,如果不成功,则执行reg00=3e,继续发送。 Write8019Reg(0x00, 0x3e); } Write8019Reg(0x07, 0xff); //清除所有中断标志位 if(txd_buffer_select) Write8019Reg(0x04, 0x40); //txd packet start; //设置发送开始页的地址 else Write8019Reg(0x04, 0x46); //txd packet start; Write8019Reg(0x06, (unsigned char)(len>>8)); //high byte counter要发送的包的字节数(长度) Write8019Reg(0x05, (unsigned char)(len&0xff)); //low byte counter Write8019Reg(0x07, 0xff); //清除所有中断 Write8019Reg(0x00, 0x3e); //to sendpacket; 从本地DMA中发送包 }
9.RTL8019AS_Query,查询是否有新数据包接收,这个函数在接收中断处理函数中被调用
char RTL8019AS_Query(void) { unsigned char my_bnry=0; unsigned char my_curr=0; page(0); my_bnry = Read8019Reg(0x03);//bnry page have read 读页指针 page(1); my_curr = Read8019Reg(0x07);//curr writepoint 8019写页指针 page(0); if ((my_curr==0)) return 0; my_bnry++; if (my_bnry>0x7f) my_bnry=0x4c; if (my_bnry!=my_curr)//此时表示有新的数据包在缓冲区里 { //complete dma page 0 //Remote DMA Write Write8019Reg(0x0b, 0x00); Write8019Reg(0x0a, 0x00); Write8019Reg(0x00, 0x22); return 1; } Write8019Reg(0x0b, 0x00); Write8019Reg(0x0a, 0x00); Write8019Reg(0x00, 0x22); return 0; }

下一篇介绍ethernetif.c中low_level_input,low_level_output及中断处理的实现

你可能感兴趣的:(工作,vector,query,buffer,input,output)