原创 RTL8019AS资料搜集

2009-5-12 15:24 3067 7 8 分类: 通信

用户终端硬件结构及RTL8019的配置

1、用户终端结构硬件结构图如图2所示:系统由两块单片机组成,一块负责五表读
数、安防红外遥控器及安防信号的采集工作,另一块负责驱动RTL8019通讯、家电
控制,并响应键盘及驱动液晶显示。两块MCU之间通过串口交换数据。

图2 用户终端结构图(略)

2、RTL8019的配置
RTL8019是一款高度集成的以太网控制芯片,它有两种工作模式:一种是跳线模式
jumper,一种是非跳线模式 jumperless,后者也支持Plug and Play。在单片机中
一般都采用跳线模式选项。I/O端口的基地址IO_BASE_ADDRESS由单片机和8019之间
的接线决定。此外8019还具有8个IRQ接口,本系统中没用到IRQ,采用查询方式。

8019输入输出地址共32个,地址偏移量为00H――1FH:
其中00H--0FH共16个地址,为寄存器地址,寄存器分成4页PAGE0――PAGE3,与
NE2000兼容的寄存器只有3页(Page0-Page2),为了保证驱动程序对所有Ne2000的
网卡有效,不要去操作第四页的寄存器。

10H--17H共8个地址,为DMA地址。
18H--1FH共8个地址,为软复位端口。8019的硬件复位很简单,只需在上电时对
RSTDRV输出一高电平就可以了。8019复位的过程将执行一些操作,比如将93c46读
入,将内部寄存器初始化等,至少需要2毫秒的时间。推荐等待更久的时间之后才
对网卡操作,比如100毫秒之后才对它操作,以确保完全复位。

ICS16B=LOW时采用8位DMA操作模式,上面的地址中只有18个是有用的: 00H--
0FH共16个寄存器地址。10H DMA地址 (10H--17H的8个地址是一样的,都可以用
来做DMA端口,只要用其中的一个就可以了)。1FH 复位地址(18H到1FH共8个地址
都是复位地址,每个地址的功能都是一样的,只要其中的一个就可以了,但实际上
只有18H、1AH、1CH、1EH这几个复位端口是有效的,其他不要使用,有些兼容卡不
支持19H、1BH、1DH等奇数地址的复位)。 


网卡驱动及TCP/IP协议栈的简化

从程序员的角度来说,对8019的操作是比较简单的,驱动程序只需要将要发送的数
据按一定的格式写入芯片并启动发送命令,8019会自动添加接收状态、下一页指针
、以太网帧长度和校验FCS段,并将数据包转换成物理帧格式在物理信道上传输。
反之,8019收到物理信号后将其还原成数据,按指定格式存放在芯片RAM中以便主
机程序取用。简言之就是8019完成数据包和电信号之间的相互转换:数据包<===>
电信号。以太网协议由芯片硬件自动完成,对程序员透明。驱动程序有3种功能:
芯片初始化、收包、发包。发送数据包是先将待发送的数据包通过DMA写操作存入
网卡芯片RAM,并给出发送缓冲区首地址(TPSR0、TPSR1)和数据包长度(TBCR0,
TBCR1),启动发送命令,网卡芯片会自动按以太网协议完成发送并将结果写入状态
寄存器。接收数据包时,采用查询的方式,根据CURR==BNRY+1?可以判断是否收
到新的数据包,如果有则通过DMA读操作从网卡芯片RAM读出数据。发送、接收子程
序如下所示:

1发送子程序
bit Transmit(void)
{
CardCopyDown();
XBYTE[IO_BASE_ADDRESS + NIC_COMMAND] = CR_NO_DMA|CR_STOP|CR_PAGE0;//停止
8019
XBYTE[IO_BASE_ADDRESS + NIC_INTR_STATUS] = 0xFF;//清中断标志
XBYTE[IO_BASE_ADDRESS + NIC_XMIT_START] = XMIT_START;//设置发送开始地址
XBYTE[IO_BASE_ADDRESS + NIC_XMIT_CONFIG] = TCR_NO_LOOPBACK;//设置为一般
模式
XBYTE[IO_BASE_ADDRESS+NIC_DATA_CONFIG]=DCR_FIFO_8_BYTE|DCR_NORMAL|DCR_BY
TE_WIDE;//设置8位DMA模式
XBYTE[IO_BASE_ADDRESS + NIC_XMIT_COUNT_LSB] = 100;//设置发送数据长度
XBYTE[IO_BASE_ADDRESS + NIC_XMIT_COUNT_MSB] = 0;
XBYTE[IO_BASE_ADDRESS + NIC_COMMAND] = CR_START|CR_XMIT|CR_PAGE0;//启动
8019
return (TRUE);

2接收子程序
bit Receive(void)
{
uint TempShort;
uchar Temp;
uchar CURR;
uchar BNRY;
uint i;
//停止网卡
XBYTE[IO_BASE_ADDRESS + NIC_COMMAND] = CR_STOP|CR_NO_DMA|CR_PAGE1;
//读取当前CURRENT的值
CURR= XBYTE[IO_BASE_ADDRESS + NIC_CURRENT];
//读取当前BOUNDARY的值
XBYTE[IO_BASE_ADDRESS + NIC_COMMAND] = CR_STOP|CR_NO_DMA|CR_PAGE0;
BNRY= XBYTE[IO_BASE_ADDRESS + NIC_BOUNDARY];
if(CURR==0)
return (FAULSE);
if((++BNRY)> PAGE_STOP)
BNRY=PAGE_START;
if(CURR!=BNTY)//表示有包收到
{
//设置远端DMA地址和长度
XBYTE[IO_BASE_ADDRESS + NIC_RMT_ADDR_LSB] = 0x00;
XBYTE[IO_BASE_ADDRESS + NIC_RMT_ADDR_MSB] = BOUNDARY;
XBYTE[IO_BASE_ADDRESS+NIC_RMT_COUNT_LSB]=__dread&0xFF;
XBYTE[IO_BASE_ADDRESS + NIC_RMT_COUNT_MSB] = (__dread>>8)&0xFF;
//设置DMA读
XBYTE[IO_BASE_ADDRESS + NIC_COMMAND] = CR_START|CR_DMA_READ|CR_PAGE0;
//重复读DMA端口
for (i=0;i<__dread;i++)
{
Receive_data = XBYTE[IO_BASE_ADDRESS + NIC_RACK_NIC];
}
//等待DMA停止
TempShort = 0xFFFF;
while(TempShort)
{
Temp = XBYTE[IO_BASE_ADDRESS + NIC_INTR_STATUS];
if (Temp&ISR_DMA_DONE) break;
TempShort --;
}
return (TRUE);
}
else
return(FAULSE);
}

3协议栈的精简

单片机中TCP/IP的实现与PC机不同,在PC里可支持比较完整的TCP/IP协议组,但在
单片机里无法做到,这是因为单片机根本没有足够的代码空间来支持这些协议。一
般在单片机里实现与需要有关的部分,而不使用的协议则一概不支持。例如文件共
享SMB协议,在UNIX、WINDOWS都支持,但单片机上却没有必要。一般只能在单片机
中实现:ARP、IP,ICMP、TCP/UDP这些协议,而更高层的协议,HTTP、SMTP、FTP
一般是不需要支持的。虽然有些单片机例如AVR上网方案实现了这些协议,但实用
性不大。因为单片机应用的TCP/IP协议大多是为了完成数据采集和数据传输,而不
是网页浏览、文件传输这些功能。另外由于单片机资源的有限性,对某一协议而言
,也有可能要作简化。本系统中实现的协议只有ARP、IP、ICMP、UDP。在选择传输
层协议时我们放弃了面向链接的TCP,因为TCP为了保证数据的可靠性采用一问一答
的方式,这在数据量并不大的嵌入式系统中,反而增加了网络的负担;另外TCP的
很多机制,如分段机制、窗口机制等都适合于数据量大、处理能力强的PC机网络,
并不适合于嵌入式系统。UDP虽然不提供面向链接的、可靠的服务,但是协议简单
,实时性更强,应用层也可以做相应的定时等待、重发处理等辅助性的操作来弥补
它的缺陷。

a.ARP:ARP的本质就是实现IP地址到MAC地址的转换,抓住了这一点实现就比较简
单。嵌入式系统中没有必要实现PC机网络中地址表的更新功能,只需完成地址转换
。管理中心机在初始化CDT时发送ARP请求,CDT只需响应中心对它的ARP请求,但不
主动发送ARP请求。

b.ICMP:ICMP的种类很多,在本系统中只要实现ICMP信息回显功能。管理中心在
执行PING命 令 时,发送ICMP请求信息,CDT中只需实现ICMP回应信息。

c.IP:IP包最大可达65k,单片机中无法存放如此大的数据包,因此一般不支持分
段,以发送小数据的方式来避免分段。另外IP层的选项功能都可以完全忽略,IP层
只需要根据协议类型分包。
d.应用层:应用层采用自己的数据协议格式为:

头部+命令字段+布防字段+报警字段+五表参数字段+五表读数字段+家电控制
字段
接收方根据命令段的含义来分别实现布防、报警、五表参数设置、五表读书、家电
控制等功能。


结束语

本文以基于TCP/IP技术的智能小区家庭智能终端系统的研究为例,详细讲述了
RTL8019网卡芯片的驱动方法,并给出了单片机中TCP/IP协议的精简方案。本系统
已经成功地运用于多个小区,其可行性、可靠性和灵活性已经得到证实,并且基于
以太网智能小区系统低廉的造价、简洁的布线更使得基于TCP/IP的以太网技术成为
了替代传统现场总线技术的一种重要手段。

 
 
另外我在用LPC2214的外部中断时,经常引起JTAG口没反应,使仿真器挂起,需要烧录另外一个好的程序启动一下,再用仿真器就又可以了,不知道你们有没有遇到这种情况。


 


============================================================


======================另外一例================================


==============================================================


*******************************************************************************
 *  Copyright (C) 2005 Ben Ning
 *  rtl8019.c: Send & Receive Implementation for RTL8019AS 
 *
 *******************************************************************************/
#pragma LARGE ORDER NOPRINT OPTIMIZE(2)

#include <stdlib.h>
#include <stdio.h>

#include <absacc.h>
#include <string.h>

#include "NetAPI.h"
#include "NET.H"
//#include "SERIAL.H" 
#include "w78e58.h"
#include "rtl8019.h"

//-----------------------------------------------------------------------------
// select RTL8019AS register page
//-----------------------------------------------------------------------------
void rtl8019_page(UCHAR page_num)
{
        UCHAR data temp;

        temp = CR; //command register
        temp=temp&0x3B ; // 0011 1011 bit2 = 0 for to disabel TXP 
        page_num = page_num << 6;
        temp=temp | page_num;
        CR = temp;
}


//-----------------------------------------------------------------------------
// reset RTL8019AS chip
//-----------------------------------------------------------------------------

void rtl8019_reset()
{
        UCHAR i, j, temp;
        
        // hardware reset
        RTL8019_RESET = 1;
        for (i=0; i<100; i++) for (j=0; j<255; j++);
        RTL8019_RESET = 0;
        for (i=0; i<100; i++) for (j=0; j<255; j++);
        
        // software reset
        temp = REST_PORT;
        for (i=0; i<100; i++) for (j=0; j<255; j++);
        REST_PORT = temp;
        for (i=0; i<100; i++) for (j=0; j<255; j++);
}

//-----------------------------------------------------------------------------
// Initialize the RTL8019AS chip
//-----------------------------------------------------------------------------
extern UCHAR xdata my_hwaddr[6]; 

void rtl8019_init(void)
{
        UCHAR i, j;

//        for (i=0; i<255; i++);
        rtl8019_reset();

        CR = 0x21; // stop mode for setting registers and select page 0

        for (i=0; i<10; i++) 
                for (j=0; j<255; j++);        // delay about 10ms
                
        DCR = 0xc8; // byte dma 8 bit dma mode

        RBCR0 = 0x00;
        RBCR1 = 0x00;
        TCR = 0x02;

//        RCR = 0xcc; //monitor mode (no packet receive)
        RCR = 0xe0; //monitor mode (no packet receive)

        PSTART        = RXSTART_INIT;
//        PSTOP        = 0x80; // for 16 bit mode 
        PSTOP        = RXSTOP_INIT; // for 8 bit mode
        BNRY        = RXSTART_INIT;

        TPSR = TXSTART_INIT;
        ISR = 0xff; // clear all interrupt flags
        IMR        = 0x00; // disable all interrupt


        CR = 0x61;                // select page 1
        CURR = RXSTART_INIT;

//        CR = 0x22; // Let chip to work
//        TCR = 0xe0;
//        CR = 0x62;

        // set Mac address 
        PAR0 = my_hwaddr[0];
        PAR1 = my_hwaddr[1];
        PAR2 = my_hwaddr[2];
        PAR3 = my_hwaddr[3];
        PAR4 = my_hwaddr[4];
        PAR5 = my_hwaddr[5];

        // set muticast address 
        MAR0 = 0xFF;
        MAR1 = 0xFF;
        MAR2 = 0xFF;
        MAR3 = 0xFF;
        MAR4 = 0xFF;
        MAR5 = 0xFF;
        MAR6 = 0xFF;
        MAR7 = 0xFF;
        
        CR = 0x21; // select page 0

        RCR = 0xcc; // normal mode
        TCR = 0xe0;
        CR = 0x22;  // Normal work
        ISR = 0xff; // clear all interrupt flags

}

//-----------------------------------------------------------------------------
// This functions checks RTL8019AS status then sends an ethernet frame to it. 
//-----------------------------------------------------------------------------
void rtl8019_send_frame(UCHAR xdata * outbuf, UINT len)
{
        UINT data i, j, n;

        rtl8019_page(0);

        if (len<60)        n = 60; else n = len;

        // set start address for sending
        RSAR1 = TXSTART_INIT; //  write dma address        -- high byte 
        RSAR0 = 0x00; //  write dma address -- low byte
        
        //        set the count of bytes that will be send out 
        RBCR1 = n >> 8;
        RBCR0 = n & 0xff;

        CR = 0x12; //write dma, page0
        
        // Write data to dma
        for (i=0; i<len; i++) DMA_PORT = *(outbuf+i);        

        // If necessary, to file some PAD bytes with 0x00
        for (i=len; i<n; i++) DMA_PORT = 0x00;        
        
        // Disable DMA OP
        RBCR1 = 0x00; // write count high
        RBCR0 = 0x00; // write count low;
        CR = 0x22;          //complete dma page 0
        
        for(i=0;i<16;i++)        // Try to resend 16 times
        { 
                for (j=0; j<1000; j++) {
                        if (!(CR & TXP)) break; // If has transmited, break.
                }

                if (TSR & PTX) break; // If sending has completed

                CR = 0x3e;
        }        

        ISR = 0xff;

        TPSR = TXSTART_INIT;        //txd packet start;
                
        TBCR1 = n >> 8;        //high byte counter
        TBCR0 = n & 0xff;        //low byte counter

        ISR = 0xff;
        CR = 0x3e; //to sendpacket;

        // Release memory for re-use
//        free(outbuf);
                  
}

//------------------------------------------------------------------------
// This function gets an incoming Ethernet frame from the RTL8019AS.
// There may be more than 1 waiting but just allocate memory for
// one and read one in.  Use the RTL8019AS to queue incoming packets.
//------------------------------------------------------------------------
//extern UCHAR idata rcve_buf_allocated;

UCHAR xdata * rtl8019_rcve_frame(void)
{
        UINT data len, i;
        UCHAR xdata * data buf;
        UCHAR xdata * data p;
        UCHAR data curr, bnry;
        UCHAR data status, next_page, len_l, len_h;
        
        rtl8019_page(0);

        status = ISR;
         // Check if buffer overflow
        if (status & 0x90)
                rtl8019_OverflowRecover();

        status = RSR;
        if (!(status & 0x01)) // no data received
                return NULL;

        bnry = BNRY; //bnry page have read
        rtl8019_page(1);
        curr = CURR; //curr write page

        rtl8019_page(0);

        if (bnry==curr) return NULL; // no arrived package
        
        CRDA1 = bnry;        // current read dma address high
        CRDA0 = 0x00;        // current read dma address low

        RBCR1 = 0x00;        // count high
        RBCR0 = 0x04;        // count low

        CR = 0x0a; // begin to read dma

        // read 8019 header
        status = DMA_PORT;
        next_page = DMA_PORT;
        len_l = DMA_PORT;
        len_h = DMA_PORT;

        RBCR1 = 0x00;        // to read a page (256 bytes)
        RBCR0 = 0x00;
        CR = 0x22; // DMA completed page0
        
        // if boundary pointer is invalid
//        if (!(status & 0x01) || (next_page>0x7f) || (next_page<0x4c) || (len_h>0x06) )
        if (!(status & 0x01) || (next_page>=RXSTOP_INIT) || (next_page<RXSTART_INIT) || (len_h>0x06) )
        {
                rtl8019_page(1);
                curr = CURR;
                rtl8019_page(0);
                bnry = curr;
                BNRY = bnry;
                ISR = 0xff;

                return NULL;
        }
        
        len = ((UINT) len_h << 8) | (UINT) len_l;
        len = len - 4; // subract 4 bytes for eth CRC

        // Allocate enough memory to hold the incoming frame
        buf = (UCHAR xdata *) malloc(len);


        if (buf == NULL) {
                 return NULL;
        }

        p = buf;

        CRDA1 = bnry;        // read DMA address high
        CRDA0 = 0x04;        // read DMA address low, skip 4 byte that is 8019 header

        RBCR1 = len >> 8;                // count high
        RBCR0 = len & 0x00ff;        // count low

        CR = 0x0a; // begin to read DMA

        for (i=0; i<len; i++) {
                *p++ = DMA_PORT;
        }

        RBCR1 = 0x00;        // to read a page (256 bytes)
        RBCR0 = 0x00;
        CR = 0x22; // DMA completed page0
        ISR = 0xff;

        BNRY = next_page; //bnry; // Update BNRY
                
        return (buf);
}

void rtl8019_OverflowRecover(void)
{
        UCHAR data data_L, resend;
        UCHAR idata i, j;

        data_L = CR;

        CR = 0x21; // stop mode for setting registers and select page 0

        for (i=0; i<10; i++) for (j=0; j<255; j++);        // delay about 10ms

        RBCR0 = 0x00;
        RBCR1 = 0x00;
                
        if (data_L & TXP) {
         data_L = ISR;
         if((data_L & 0x02) || (data_L & 0x08))
             resend = 0;
         else
             resend = 1;
        }
        else
                resend = 0;

        TCR = 0x02;

        CR = 0x22;
        BNRY = RXSTART_INIT;

    CR = 0x62;
    CURR = RXSTART_INIT;

    CR = 0x22;
    ISR = 0x10;
    TCR = TCR_INIT;
     
     if(resend)
         CR = 0x26;
 
     ISR = 0xFF;

}

PARTNER CONTENT

文章评论1条评论)

登录后参与讨论

tengjingshu_112148725 2009-5-12 18:02

谢谢分享
相关推荐阅读
用户540930 2011-07-13 09:36
压在手头的三件事情
1, APEX integration 2, Image mosaic.. 3, Gaianvwa...  ...
用户540930 2011-07-11 12:44
学习新雨师弟,一个月更新一次简历
某师弟一个月更新一次简历,每次我想到这一点就敬佩从心底里升起···· 认识这些人真是幸运的事...
用户540930 2011-06-10 01:00
以后继续皈依这里
以后继续皈依这里了··· 我在QQ空间里写了一段时间,所写所说都是感性之文,为的也是某个人能看到, 可是从来没有见过那样的足迹,我失望且绝望了。   我的心生疼生疼的,可是我必须忍受这种疼痛, 观察自...
用户540930 2009-08-18 17:58
比找配偶更重要的是找工作----第一天
最近好多XDJM都在找工作,虽然偶是撮人一个,正二八经的也只是在准备出国而已。但是对于这档子事儿还是有那么点点小经验。分享下攒人品,有好想法的欢迎拍砖哈。。去年这个时候,我混迹在无数04级找工作的大军...
用户540930 2009-08-13 11:39
自我管理
很难想象一个没有严肃的精神世界的人会有多大的成就我的严肃的精神世界正在慢慢的消融这一点让我有点恐惧 当你在做坏事的时候,心里的道德感不再去责问你,你还有什么来约束自己呢?好的习惯的养成是一个逆水行舟的...
用户540930 2009-07-29 01:08
核电资料小结
压水堆  压水堆  (pressurized water reactor)  使用加压轻水(即普通水)作冷却剂和慢化剂,且水在堆内不沸腾的核反应堆。燃料为加浓铀。20世纪80年代,被公认为是技术最成熟...
EE直播间
更多
我要评论
1
7
关闭 站长推荐上一条 /3 下一条