基于LPC2210的RTL8019AS以太网驱动系统设计(二)
---------------------------------------------------------
Author :tiger-john
WebSite :blog.csdn.net/tigerjb
Email :jibo.tiger@gmail.com
开发环境 硬件环境:LPC2200
操作系统:UC/OS-II操作系统
编译环境:ADS1.2
Tiger声明:本人鄙视直接复制本人文章而不加出处的个人或团体,
但不排斥别人转载tiger-john的文章,只是请您注明出处并和本人
联系或留言给我。3Q
---------------------------------------------------------
五.发送数据包模块
5.1发送数据包模块功能
发送数据包时,先将待发送数据包通过远程DMA写入芯片RAM,给出发送缓冲区首地址和数据包长度,即可实现RTL8019AS的数据发送。RTL8019AS会自动按以太网协议完成发送并将结果写入状态寄存器。
5.2发送数据包模快的数据结构
1>_pkst
struct _pkst{
struct _pkst *STPTR;//前一个结构数组
unsigned int length;//以太网帧报头长度长度14字节
unsigned char *DAPTR;//报头的指针
};
2>ipethernet
typedef struct {
uint8 DestMacId[6]; /*目的网卡地址*/
uint8 SourceMacId[6]; /*源网卡地址*/
int16 NextProtocal; /*下一层协议*/
} ipethernet;
3>定义数据结构:
struct _pkst * TxdData;
struct _pkst *ExPtr;
5.3发送数据包模块组成
第一部分:ARM LPC2210把数据写到RTL8019AS RAM中
该过程涉及以下几个寄存器:
Ø RBCR0,RBCR1:远程DMA数据字节技术器
Ø RSAR0,RSAR1:远程DMA起始地址
Ø CR:发出远程DMA开始命令
1>计算发送包帧的长度
2>设置远程DMA起始地址寄存器(RSAR0,RSAR1),使远程DMA起始地址寄存器为发送缓冲区首地址
3>设置远程DMA字节计数器寄存器为发送数据帧的长度
4>启动远程DMA写
设置CR命令寄存器使DMA开始远程写。
5>将数据写到远程DMA 0x10号寄存器处
6>清零远程DMA字节计数器为0,并终止远程DMA写
7>清除所有中断标志
第二部分:RTL8019AS将数据发送到以太网
在ARM LPC2210把数据通过远程DMA写到RTL8019AS RAM之后,RTL8019AS芯片通过本地DMA将数据发送到以太网。
该过程涉及以下寄存器:
Ø TPSR:设置传输数据包开始页面地址
Ø TBCR0,TBCR1:设置传输数据包的字节计数。
Ø CR:发出发送数据包的指令。
设置寄存器结束后,RTL8019AS会自动用本地DMA发数据。
1> 设置要发送包的起始页
配置TPSR(发送开始页寄存器):把发送缓冲区首地址赋值给TPSR.
2> 判断数据包长度,若小于60字节,补足60字节
3> 设置传输数据包的字节计数
设置TBCR0,TBCR1为数据包长度
4>发送数据前先清除所有中断源
5>启动本地DMA发送数据包
配置CR命令寄存器为3E发送数据包
6>包发送完后,判断是否出错,若发送错误则进行重发,但只重发六次
Ø 读取命令寄存器(CR)中的TXP位:判断数据包是否发送完毕。没有发送完,则循环等待包发送完。
Ø 读TSR(传输状态寄存器):判断PTX位是否为1,若为1说明传输正确,退出程序。否则启动DMA重新传输数据。
5.4发送数据包模块的接口
发送包模块调用了写数据子模块,读数据子模块和页面切换子模块
Ø 读数据子模块: 从RTL8019AS芯片中把数据读出。
Ø 写数据子模块:将数据写入RTL8019AS芯片中
Ø 页面切换子模块:可选择Page0,Page1,Page3三个页面。
5.5发送数据包模块程序
/****************************Copyright(c)********************
** 西安邮电学院
** graduate school
** XNMS实验室
** Author:冀博
** Time:2011年2月21日
** http://blog.csdn.net/tigerjb
**
**--------------FileInfo---------------------------------------------------------------------
****************************Copyright(c)******************** /
/***************************************************
**函数原型:void Send_Packet(struct _pkst *TxdData)
**入口参数:struct _pkst *TxdData :指向要发送数据的结构指针
**出口参数: 无
**说 明: 发送数据包,以太网底层驱动程序,所有的数据发送都要通过该程序
***************************************************/
void Send_Packet(struct _pkst *TxdData)//
{
static uint8 Tx_Buff_Sel=0;
struct _pkst *ExPtr;
uint8 *TEPTR;
union send_temp{
uint16 words;
uint8 bytes[2];
}send_buff;
uint16 ii,length=0;
//切换至第0页
page(0);
length=length+TxdData->length;
ExPtr=TxdData->STPTR;
//计算出要发送的数据的总长度
while(ExPtr!=NULL)
{
length=length+ExPtr->length;
ExPtr=ExPtr->STPTR;
}
ii=length;
//发送缓冲区的切换
Tx_Buff_Sel=Tx_Buff_Sel^1;
//设置远程DMA起始地址寄存器(RSAR0,RSAR1)
if(Tx_Buff_Sel)
{
WriteToNet(0x09,0x40);
}
else
{
WriteToNet(0x09,0x46);
}
WriteToNet(0x08,0x00);
//设置远程DMA字节计数器寄存器为发送数据帧的长度
WriteToNet(0x0b,ii>>8);
WriteToNet(0x0a,ii&0x00ff);
//启动远程DMA开始写
WriteToNet(0,0x12);
/*******将数据写到远程DMA 0x10号寄存器处*****/
//TEPTR指向IPthernet
TEPTR=TxdData->DAPTR;
//发送数据结构IPthernet数据,每次发送两个字节
for(ii=0;ii<(((TxdData->length)+1)/2);ii++)
{
send_buff.bytes[0]=*TEPTR;
TEPTR++;
send_buff.bytes[1]=*TEPTR;
TEPTR++;
WriteToNet(0x10,send_buff.words);
}
ExPtr=TxdData->STPTR;//把下一个结构体指针给Exptr
while(ExPtr!=NULL)
{
TEPTR=ExPtr->DAPTR;
for(ii=0;ii<((ExPtr->length+1)/2);ii++)
{
send_buff.bytes[0]=*TEPTR;
TEPTR++;
send_buff.bytes[1]=*TEPTR;
TEPTR++;
WriteToNet(0x10,send_buff.words);
}
ExPtr=ExPtr->STPTR;
}
//清零远程DMA字节计数器为0
WriteToNet(0x0b,0x00);
WriteToNet(0x0a,0x00);
//终止DMA写操作
WriteToNet(0x00,0x22);
//清除所有中断标志
WriteToNet(0x07,0xff);
//设置要发送包的起始页
if(Tx_Buff_Sel)
{
WriteToNet(0x04,0x40);
}
else
{
WriteToNet(0x04,0x46);
}
//判断数据包长度,若小于60字节,补足60字节
ii=length;
if(length<60)
{
//如果数据长度<60字节,设置长度为60字节
ii=60;
}
//设置TBCR0,TBCR1为数据包长度
WriteToNet(0x06,ii>>8);
WriteToNet(0x05,ii&0x00ff);
//发送数据前先清除所有中断标志
WriteToNet(0x07,0xff);
//启动本地DMA发送数据包
WriteToNet(0x00,0x3e);
//检测是否发错,若发错重发,但只重发六次
for(length=0;length<6;length++) //最多重发6次
{
for(ii=0;ii<1000;ii++)
{
if((ReadFromNet(0X00)&0x04)==0)
{
break;
}
}
if((ReadFromNet(0X04)&0x01)!=0)
{
break;
}
WriteToNet(0x00,0x3e); //to sendpacket;
}
}