打印
[ZLG-ARM]

抛砖引玉一把!本人对RTL8019AS的编程心得!

[复制链接]
2914|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
火光|  楼主 | 2009-4-13 19:31 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本人花了半个多月的时间,对RTL8019AS上的控制状态寄存器进行了仔细的琢磨,终于有了点心得体会,在这里和大家共享!
本人是在周立功的EASYARM2200上做的实验的:
下面是RTL8019AS的相关源代码:
---------------------------------------------------------------------

#include "config.h"
#include "LPC2294.h"
#include "general.h"

#define    INT_N            0x00000080
#define    NET_RST           0x00000040
#define    NET_BASE_ADDR   0x83400000

//{0x52,0x54,0x4c,0x19,0xf7,0x44}

#define    The_PAR0        0x52
#define    The_PAR1        0x54
#define    The_PAR2        0x4C
#define    The_PAR3        0x19
#define    The_PAR4        0xF7
#define    The_PAR5        0x44

uint8    Tx_Buff_Page    = 0x46;

void WriteToNet(uint8 ADDR_16, uint16 WRITEDATA)
{
    (*((volatile unsigned short *)NET_BASE_ADDR + ADDR_16)) = WRITEDATA;    //0x83400000
    
    return;    
}

uint16 ReadFromNet(uint8 ADDR_16)
{
    uint16 temp_uint16;

    temp_uint16    = (*((volatile unsigned short *)NET_BASE_ADDR + ADDR_16));    //0x83400000

    return    temp_uint16;
}

void SetPage(uint8 pagenumber)  
{
    uint8 temp_uint8;

    temp_uint8    = ReadFromNet(0);        //command register
    temp_uint8    = temp_uint8 & 0x3B;    //注意txp位不能要
    pagenumber    = pagenumber << 6;
    temp_uint8    = temp_uint8 | pagenumber;
    WriteToNet(0, temp_uint8);

    return;
}

void InitNic(void)  
{
    int    temp_i;
    
    PINSEL0    = PINSEL0 & ~0x0000F000;
    IO0DIR    = (IO0DIR & ~INT_N) | NET_RST;
    
    IO0CLR    = NET_RST;
    for (temp_i = 0; temp_i < 40000; temp_i++);

    IO0SET    = NET_RST;
    for (temp_i = 0; temp_i < 40000; temp_i++);

    IO0CLR    = NET_RST;
    for (temp_i = 0; temp_i < 40000; temp_i++);

    WriteToNet(0x1F, 0x00);     
    for (temp_i = 0; temp_i < 40000; temp_i++);
    
    WriteToNet(0x00, 0x21);                                //使芯片处于停止模式,这时进行寄存器设置    
    for (temp_i = 0; temp_i < 40000; temp_i++);

    SetPage(0);
    /////////////////////////////////////////////
    WriteToNet(0x0F, 0x00);
    WriteToNet(0x07, 0xFF);
    ///////////////////////////////////
    WriteToNet(0x0E, 0xCB);                                //DCR ???
    //WriteToNet(0x0E, 0xDB);
    WriteToNet(0x0C, 0xE0);                                //RCR ???
    WriteToNet(0x0D, 0xE0);                                //TCR ???
    ///////////////////////////////////
    WriteToNet(0x01, 0x4C);
    WriteToNet(0x02, 0x80);
    WriteToNet(0x03, 0x4C);

    WriteToNet(0x09, 0x40);
    WriteToNet(0x08, 0x00);
    WriteToNet(0x0B, 0x00);
    WriteToNet(0x0A, 0x00);

    WriteToNet(0x04, 0x40);
    WriteToNet(0x06, 0x00);
    WriteToNet(0x05, 0x00);
    /////////////////////////////////////////////
    SetPage(1);
    /////////////////////////////////////////////
    //||判断是否错误的计数???||
    //WriteToNet(0x07, 0x4D);
    WriteToNet(0x07, 0x4C);
    //||************************||
    ///////////////////////////////////
    WriteToNet(0x01, The_PAR0);
    WriteToNet(0x02, The_PAR1);
    WriteToNet(0x03, The_PAR2);
    WriteToNet(0x04, The_PAR3);
    WriteToNet(0x05, The_PAR4);
    WriteToNet(0x06, The_PAR5);
    ///////////////////////////////////
    WriteToNet(0x08, 0x00);
    WriteToNet(0x09, 0x00);
    WriteToNet(0x0A, 0x00);
    WriteToNet(0x0B, 0x00);
    WriteToNet(0x0C, 0x00);
    WriteToNet(0x0D, 0x00);
    WriteToNet(0x0E, 0x00);
    WriteToNet(0x0F, 0x00);
    /////////////////////////////////////////////
    SetPage(0);
    WriteToNet(0x0C, 0xC4);                                //RCR ???
    WriteToNet(0x07, 0xFF);
    WriteToNet(0x00, 0x22);

    Tx_Buff_Page    = 0x46;

    return;                
}

void Send_Packet(uint16 * buf, uint32 len)  
{
    uint32    temp_len;
    int        temp_i, temp_j;

    if (len < 60)
        len = 60;
    if (len & 1)
        len++;
    temp_len = len >> 1;
    if (Tx_Buff_Page == 0x40)
        Tx_Buff_Page =  0x46;
    else
        Tx_Buff_Page =  0x40;

    SetPage(0);                                //切换至第0页

    WriteToNet(0x09, Tx_Buff_Page);            //设置发送页地址    
    WriteToNet(0x08, 0x00);                 //写入RSAR0
    WriteToNet(0x0b, len >> 8);                //写入RSCR1
    WriteToNet(0x0a, len & 0xFF);            //写入RSCR0
    WriteToNet(0x00, 0x12);                    //启动DMA写write dma, page0

    for (temp_i = 0; temp_i < temp_len; temp_i++)
        WriteToNet(0x10, *buf++);
    
    //||判断是否是多余的操作???||
    //WriteToNet(0x0b, 0x00); 
    //WriteToNet(0x0a, 0x00);
    //WriteToNet(0x00, 0x22);                    //结束或放弃DMA操作
    //||**************************||
    
    WriteToNet(0x04, Tx_Buff_Page);            //txd packet start;    
    WriteToNet(0x06, len >> 8);                //high byte counter
    WriteToNet(0x05, len & 0xFF);            //low byte counter

    WriteToNet(0x07, 0xFF);
    
    //||是否有多余的位???||
    //WriteToNet(0x00, 0x3E);                    //to sendpacket;
    WriteToNet(0x00, 0x26);
    //||********************||
    
    for (temp_i = 0; temp_i < 6; temp_i++)            //最多重发6次
    {
        for (temp_j = 0; temp_j < 1000; temp_j++)
        {
            if ((ReadFromNet(0) & 0x04) == 0)        //检查CR寄存器的txp位是否为低,为1说明正在发送,为0说明发完或出错放弃 
                break;
        }

        if (ReadFromNet(0x04) & 0x01)                //表示发送成功,判断发送状态寄存器TSR,决定是否出错
            break;

        //||是否有多余的位???||
        //WriteToNet(0x00,0x3E);                        //to sendpacket;
        WriteToNet(0x00, 0x26);
        //||********************||
    }
    
    WriteToNet(0x07, 0xFF);
    
    return;
}

int    Rec_Packet(uint16 * buf) 
{
    uint8    temp_BNRY, temp_CURR;
    uint16    temp_buf0, temp_buf1;
    uint32    temp_len;
    uint8    temp_uint8;
    int        temp_i;

    SetPage(0);
    
    /*
    temp_uint8    = ReadFromNet(0x07);                //读取中断状态
    if (temp_uint8 & 0xAC)
    {
        InitNic();
        return -1;
    }
    */

    temp_BNRY    = ReadFromNet(0x03);                //bnry page have read 读页指针
    SetPage(1);
    temp_CURR    = ReadFromNet(0x07);                //curr writepoint 8019写页指针
    SetPage(0);

    //||判断是否多余的操作???||
    //temp_BNRY++;                                    //bnry++;
    //if (temp_BNRY > 0x7F)
    //      temp_BNRY = 0x4C;
    //||************************||
    
    if (temp_BNRY != temp_CURR)                        //此时表示有新的数据包在缓冲区里
       {
        WriteToNet(0x09, temp_BNRY);                //RSAR1写入读页地址的高字节
        WriteToNet(0x08, 0x00);                        //RSAR0写入读页地址的低字节
        WriteToNet(0x0b, 0x00);                        //RSCR1写入读取字节计数高字节
        WriteToNet(0x0a, 0x04);                        //RSCR0写入读取字节计数低字节
        WriteToNet(0x00, 0x0a);                        //启动Remote DMA读操作

        temp_buf0    = ReadFromNet(0x10);
        temp_buf1    = ReadFromNet(0x10);

        //||判断是否是多余的操作???||
        //WriteToNet(0x0b,0x00);                        //RSCR1写入读取字节计数高字节
        //WriteToNet(0x0a,0x00);                        //RSCR0写入读取字节计数高字节
        //WriteToNet(0x00,0x22);                        //结束或放弃DMA操作
        //||**************************||

        temp_buf1    = temp_buf1 - 4;
        if (((temp_buf0 & 0x0001) == 0) || 
            ((temp_buf0 & 0xFF00) <  0x4C00) ||
            ((temp_buf0 & 0xFF00) >  0x7F00) ||
            ( temp_buf1 > 0x0600))
        {
            SetPage(1);
            temp_CURR    = ReadFromNet(0x07);        //page1读取CURR的值
            SetPage(0);                                //切换回page0
            
            //||判断是否多余的操作???||
            //temp_BNRY    = temp_CURR - 1;            //把bnry恢复为下16K中的空余部分
            //if (temp_BNRY < 0x4C) 
            //      temp_BNRY = 0x7F;
            temp_BNRY    = temp_CURR;
            //||************************||
            
            WriteToNet(0x03, temp_BNRY);            //把BNRY恢复到指向下一帧write to bnry        
            WriteToNet(0x07, 0x7F);                    //清除中断标志

            return -1;
        }
        else                                        //表示数据包是完好的.读取剩下的数据
        {
            if (temp_buf1 & 1)
                temp_buf1++;
            temp_len = temp_buf1 >> 1;

            WriteToNet(0x09, temp_BNRY);            //RSAR1写入读页地址的高字节//read page address high
            WriteToNet(0x08, 0x04);                    //RSAR0写入读页地址的低字节//read page address low
            WriteToNet(0x0b, temp_buf1 >> 8);        //RSCR1写入读取字节计数高字节//read count high
            WriteToNet(0x0a, temp_buf1 &  0xFF);    //RSCR0写入读取字节计数低字节//read count low;
            WriteToNet(0x00, 0x0a);                    //启动Remote DMA读操作
            
            for (temp_i = 0; temp_i < temp_len; temp_i++)
                *buf++    = ReadFromNet(0x10);

            //||判断是否是多余的操作???||
            //WriteToNet(0x0b,0x00);                    //RSCR1写入读取字节计数高字节//read count high   
            //WriteToNet(0x0a,0x00);                    //RSCR0写入读取字节计数高字节//read count low;
            //WriteToNet(0x00,0x22);                    //结束或放弃DMA操作//结束或放弃DMA
            //||**************************||

            //||判断是否是多余的操作???||
            //temp_BNRY    = (temp_buf0 >> 8) - 1;
            //if (temp_BNRY < 0x4C)
            //      temp_BNRY = 0x7F;
            temp_BNRY    = (temp_buf0 >> 8);
            //||**************************||
                
            WriteToNet(0x03, temp_BNRY);
            WriteToNet(0x07, 0x7F);

            return temp_buf1;
        }
    }
    else
        return 0;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////
int    Rec_Packet_0(uint16 * buf) 
{
    uint8    temp_BNRY, temp_CURR;
    uint16    temp_buf0, temp_buf1;
    uint32    temp_len;
    uint8    temp_uint8;
    int        temp_i;

    SetPage(0);
    
    /*
    temp_uint8    = ReadFromNet(0x07);                //读取中断状态
    if (temp_uint8 & 0xAC)
    {
        InitNic();
        return -1;
    }
    */

    temp_BNRY    = ReadFromNet(0x03);                //bnry page have read 读页指针
    SetPage(1);
    temp_CURR    = ReadFromNet(0x07);                //curr writepoint 8019写页指针
    SetPage(0);

    //||判断是否多余的操作???||
    //temp_BNRY++;                                    //bnry++;
    //if (temp_BNRY > 0x7F)
    //      temp_BNRY = 0x4C;
    //||************************||
    
    if (temp_BNRY != temp_CURR)                        //此时表示有新的数据包在缓冲区里
       {
           //WriteToNet(0x0B, 0x0F);
           WriteToNet(0x00, 0x1A);
       
       
        //WriteToNet(0x09, temp_BNRY);                //RSAR1写入读页地址的高字节
        //WriteToNet(0x08, 0x00);                        //RSAR0写入读页地址的低字节
        //WriteToNet(0x0b, 0x00);                        //RSCR1写入读取字节计数高字节
        //WriteToNet(0x0a, 0x04);                        //RSCR0写入读取字节计数低字节
        //WriteToNet(0x00, 0x0a);                        //启动Remote DMA读操作

        temp_buf0    = ReadFromNet(0x10);
        temp_buf1    = ReadFromNet(0x10);

        //||判断是否是多余的操作???||
        //WriteToNet(0x0b,0x00);                        //RSCR1写入读取字节计数高字节
        //WriteToNet(0x0a,0x00);                        //RSCR0写入读取字节计数高字节
        //WriteToNet(0x00,0x22);                        //结束或放弃DMA操作
        //||**************************||

        //temp_buf1    = temp_buf1 - 4;
        
        if (((temp_buf0 & 0x0001) == 0) || 
            ((temp_buf0 & 0xFF00) <  0x4C00) ||
            ((temp_buf0 & 0xFF00) >  0x7F00) ||
            ( temp_buf1 > 0x0600))
        {
            WriteToNet(0x0b,0x00);                        //RSCR1写入读取字节计数高字节
            WriteToNet(0x0a,0x00);                        //RSCR0写入读取字节计数高字节
            WriteToNet(0x00,0x22);                        //结束或放弃DMA操作
        
            SetPage(1);
            temp_CURR    = ReadFromNet(0x07);        //page1读取CURR的值
            SetPage(0);                                //切换回page0
            
            //||判断是否多余的操作???||
            //temp_BNRY    = temp_CURR - 1;            //把bnry恢复为下16K中的空余部分
            //if (temp_BNRY < 0x4C) 
            //      temp_BNRY = 0x7F;
            temp_BNRY    = temp_CURR;
            //||************************||
            
            WriteToNet(0x03, temp_BNRY);            //把BNRY恢复到指向下一帧write to bnry        
            WriteToNet(0x07, 0xFF);                    //清除中断标志

            return -1;
        }
        else                                        //表示数据包是完好的.读取剩下的数据
        {
            if (temp_buf1 & 1)
                temp_buf1++;
            temp_len = temp_buf1 >> 1;

            //WriteToNet(0x09, temp_BNRY);            //RSAR1写入读页地址的高字节//read page address high
            //WriteToNet(0x08, 0x04);                    //RSAR0写入读页地址的低字节//read page address low
            //WriteToNet(0x0b, temp_buf1 >> 8);        //RSCR1写入读取字节计数高字节//read count high
            //WriteToNet(0x0a, temp_buf1 &  0xFF);    //RSCR0写入读取字节计数低字节//read count low;
            //WriteToNet(0x00, 0x0a);                    //启动Remote DMA读操作
            
            for (temp_i = 0; temp_i < temp_len; temp_i++)
                *buf++    = ReadFromNet(0x10);

            //||判断是否是多余的操作???||
            //WriteToNet(0x0b,0x00);                    //RSCR1写入读取字节计数高字节//read count high   
            //WriteToNet(0x0a,0x00);                    //RSCR0写入读取字节计数高字节//read count low;
            //WriteToNet(0x00,0x22);                    //结束或放弃DMA操作//结束或放弃DMA
            //||**************************||

            //||判断是否是多余的操作???||
            //temp_BNRY    = (temp_buf0 >> 8) - 1;
            //if (temp_BNRY < 0x4C)
            //      temp_BNRY = 0x7F;
            //temp_BNRY    = (temp_buf0 >> 8);
            //||**************************||
                
            //WriteToNet(0x03, temp_BNRY);
            WriteToNet(0x07, 0xFF);

            return temp_buf1;
        }
    }
    else
        return 0;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////

---------------------------------------------------------------------

相关帖子

沙发
火光|  楼主 | 2009-4-13 19:51 | 只看该作者

接着说!

上面的程序主要是对周立功的程序做了一些改进:

一.BNRYCURR寄存器内容的理解问题
   在周的程序里,对RTL8019AS进行初始化的时候,BNRY = 0X4C,CURR = 0X4D
   在收包程序里也相应地使BNRY落后CURR一页,其实这个看来是多余的,我反复测试过,对于接收缓冲区来,BNRYCURR这二个读写指针还是和我们平时理解的一样的:当BNRY == CURR时,接收缓冲为空;当BNRY在CURR下一页的时候,接收缓冲为满.
二.读写REMOTE DMA问题
   在对REMOTE DMA进行读写后,是没有必要进行终止DMA操作的
            //WriteToNet(0x0b,0x00);                    //RSCR1写入读取字节计数高字节//read count high   
            //WriteToNet(0x0a,0x00);                    //RSCR0写入读取字节计数高字节//read count low;
            //WriteToNet(0x00,0x22);                    //结束或放弃DMA操作//结束或放弃DMA

这样的代码完全是多余的.
但结束放弃DMA终究有什么用呢?
我认为在使用SEND PACKET命令的时候才是有必要的,见上面的Rec_Packet_0()函数,如果对DMA的读写命令发起后,需要中途终止,,,才是用"WriteToNet(0x00,0x22);"的时候,如果DMA读写过程是正常结束的,,,那是没有必要的


使用特权

评论回复
板凳
火光|  楼主 | 2009-4-13 19:59 | 只看该作者

继续...

三.发送以太包的命令
   如果要NIC发送以太网包,,,   
   只要用 WriteToNet(0x00, 0x26);
   没有必要用WriteToNet(0x00, 0x3E);
   后者中的一些位是多余的

四.编写了一个用SEND PACKET实现读包的函数Rec_Packet_0; 其实它是和Rec_Packet功能一致的.                        

使用特权

评论回复
地板
火光|  楼主 | 2009-4-13 20:14 | 只看该作者

困惑的地方!

虽然本人对RTL8019AS的大部分功能,但也继续不清楚的啊!

1.当本人故意让接收缓冲区溢出,这时ISR中的OVWRST位就会置起来了,,
  本人把接收区中的包全部读出来,使的CURR == BNRY,然后用 ISR = 0XFF的办法去清除ISR中的OVW标志,但始终不能成功,只有当网线上再来一个或者多个以太包,使得ISR的RXE标志起来,,,才能用ISR = 0XFF去清除ISR中的OVW标志,无限困惑啊!!!

2.ISR中的RST位也不会"读出一个包以后自动清0"的,这个和OVW情况类似的
  反正,如果一旦OVW标志起来,你要把它清除掉,可不太容易了...
  这实在让人不痛快啊!

3.TSR中的OWCCDHCRS位的意义不太清楚,,,

4.CSR中的DFR位也不太明白

使用特权

评论回复
5
火光|  楼主 | 2009-4-13 20:23 | 只看该作者

继续...

网上看了许多的**,发现对CURRBNRY寄存器的理解都是不妥当的,那样的程序,跑跑也是能跑的,但不能说精密,对不对?

使用特权

评论回复
6
zcying| | 2009-4-14 10:43 | 只看该作者

单片机跑TCP/IP,一般就用这个芯片

使用特权

评论回复
7
火光|  楼主 | 2009-4-14 15:28 | 只看该作者

呵呵

我说的是:DP8390的资料上讲得含糊,许多寄存器的位的含义,没有说明白.比如说ISRRSRTSR上的某些位,,,让人困惑的很!
 
尤其是美国国立半导体的那份有关"DP8390D/NS32490D NIC Network Interface Controller"**,看了让人头痛的紧...

RTL8019AS说是和NE2000兼容的,那它上面有没有美国国立半导体说的古怪特性的呢?

使用特权

评论回复
8
胡刚| | 2009-4-14 15:42 | 只看该作者

英文的

使用特权

评论回复
9
chen_mickey| | 2010-7-1 11:36 | 只看该作者
周立功?

使用特权

评论回复
10
hotpower| | 2010-7-4 00:24 | 只看该作者
关注

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

19

主题

75

帖子

0

粉丝