📄 arm.c
字号:
//--------------------------------------以太网驱动程序--------------------
#define HARDWARE_GLOBALS
#include "config.h"
#include "../include/cfg_net.h"
#define NET_RST 0X00000040//0x20000000//------复位控制信号的管脚名称为P0.6[0x40=(1000000)B]
//*-------------------------------------------------------复位脚的管脚号,它与硬件有关在EASY2200板上是P0.6脚,所以 NET_RST=0X00000040
#define NET_BASE_ADDR 0X83400000//0x20000000//------网卡基地址,特指实验室的开发板,教材P395有相关描述
//--------------------------------------------------------*它与硬件有关在EASY2200板上是0X83400000
//#include "rtl8019as.h"
EX_RAM uint16 iic=0;//------------------------------------????
union REC_BUFF_UNION REC_BUFF[MAX_REC_BUFF];//---------定义接受缓冲区数组
/****************************************************************************
* 名称:WriteToNet()
* 功能:把数据写入RTL8019AS
* 入口参数: ADDR 写入地址//------------------8位地址
WRITEDATA 写入数据//------------------16位数据
* 出口参数:无
****************************************************************************/
void WriteToNet(uint8 ADDR_16,uint16 WRITEDATA)//--------把数据写入ARM的NET_BASE_ADDR+ADDR_1的单元中,即RTL8019AS的的ADDR_1寄存器中
{
(*((volatile unsigned short *) NET_BASE_ADDR+ADDR_16))=WRITEDATA;//0x83400000//-----网卡寄存器是8位,为何用uint16的数据写入,尽管这样并不会产生问题,但这样是不是不严谨??????
//----------------------------------------------------------------------------------答:使用RTL8019AS的16位模式,故数据传送用16位更稳妥,不会因编译器不同,而使结果不同!
}
/****************************************************************************
* 名称:ReadFromNet()
* 功能:从RTL8019AS把数据读出
* 入口参数: ADDR 读出地址//------------------8位地址
* 出口参数: READDATA 读出数据//------------------16位数据
****************************************************************************/
uint16 ReadFromNet(uint8 ADDR_16)////-----网卡寄存器是8位,为何用uint16的数据写入,这样是不是不严谨??????
{
uint16 temp;
temp=(*((volatile unsigned short *) NET_BASE_ADDR+ADDR_16));//--------NET_BASE_ADDR=0x83400000//----unsigned short:16位
return (temp);
}
/**********************************************************************
**函数原型: void page(uchar pagenumber)
**入口参数:?uchar pagenumber: 要切换的页
**出口参数: 无
**返 回 值: 无
**说 明: 选择页,可选择0,1,2三页,第四页ne000兼容芯片保留
************************************************************************/
void page(uint8 pagenumber)//----此函数通过设置CR寄存器的Bit7~Bit6位选择pagenumber指定的页(即:页切换函数)
{
uint8 temp;
temp=ReadFromNet(0);//command register
//temp=temp&0x3f;-----------------------------若这样改会产问题,任何对TXP的置位都会引起数据位重发
temp=temp&0x3B ;//注意txp位不能要-------------原因见上,详细原因见相关文档使temp(=CR)的Bit7~Bit6位清零
pagenumber=pagenumber <<6;//------------------将pagenumber的值左移至Bit7~Bit6位
temp=temp | pagenumber;//---------------------将temp(=CR)的Bit7~Bit6位设置成指定的页
WriteToNet(0,temp);//-------------------------将CR的Bit7~Bit6位设置成指定的页
//-------------------一个疑问:WriteToNet(uint8,unit16)函数要求第二个参数是16位数据,但temp是unit8类型?????????
//----------------------------这样是不是不严谨,我认为应为
}
/**********************************************************************
**函数原型: void SetMacID()
**入口参数: *mac_ptr
**出口参数: 无
**返 回 值: 无
**说 明: 设置芯片物理地址,物理地址已经存储在程序空间内
************************************************************************/
void SetMacID(uint8 * mac_ptr)
{
//把MAC地址写入MY——MAC——ID中
page(1);
WriteToNet(1 , *mac_ptr);
mac_ptr++;
WriteToNet(2 , *mac_ptr);
mac_ptr++;
WriteToNet(3 , *mac_ptr);
mac_ptr++;
WriteToNet(4 , *mac_ptr);
mac_ptr++;
WriteToNet(5 , *mac_ptr);
mac_ptr++;
WriteToNet(6 , *mac_ptr);
page(0);//---------------------------------切换到0页
}
/**********************************************************************
**函数原型: void Send_Packet(struct _pkst *TxdData)
**入口参数: struct _pkst *TxdData :指向要发送数据的结构指针
**
**出口参数: 无
**返 回 值: 无
**说 明: 发送数据包,以太网底层驱动程序,所有的数据发送都要通过该程序
************************************************************************/
void Send_Packet(struct _pkst *TxdData)//------_pkst是一个结构体类型,其定义在cfg_net.h文件中
{
static uint8 Tx_Buff_Sel=0;//-----------------缓冲区编号,static类型,第一次运行时初始化为0,但以后每次调用均是上一次调用后的值
//--------------------------------------------此变量实现的功能是:记住网卡正在发送的页.
struct _pkst *ExPtr;
//uint16 i;
uint8 *TEPTR;
union send_temp{
uint16 words;
uint8 bytes[2];
}send_buff;
uint16 ii,length=0;//------------------ii用于记录要发送数据的总长度
//i=0;//记录发送是否小于60个字节
page(0);//切换至第0页
length=length+TxdData->length;//--------------------------------这两句可以合并成:
ExPtr=TxdData->STPTR;//-----------------TxdData的一个成员-------ExPtr=TxdData
while(ExPtr!=NULL)//计算出要发送的数据的总长度
{
length=length+ExPtr->length;
ExPtr=ExPtr->STPTR;
}
ii=length;
Tx_Buff_Sel=Tx_Buff_Sel^1;//发送缓冲区的切换--------------------发送缓冲送共有两个,第个六页.故缓冲区编号范围是:0~1
//--------------------------------------------------------------0^1=1;1^1=0.通过异或可实现缓冲区切换
if(Tx_Buff_Sel)//------------------//Tx_Buff_Sel==1时
{
WriteToNet(0x09,0x40); //设置发送页地址//------第一页:字节偏移量为:40~45
}
else//-----------------------------//Tx_Buff_Sel==0时
{
WriteToNet(0x09,0x46); //设置发送页地址//------第二页:字节偏移量为:46~51
}
WriteToNet(0x08,0x00); //写入RSAR0 DMA起始地址低位read page address low
WriteToNet(0x0b,ii>>8); //写入RSCR1 DMA 计数器高位read count high
WriteToNet(0x0a,ii&0x00ff); //写入RSCR0 DMA 计数器低位read count low;
WriteToNet(0,0x12); //启动DMA写write dma, page0
TEPTR=TxdData->DAPTR;//--------------------------字节类型指针TEPTR指向以太网头
for(ii=0;ii<(((TxdData->length)+1)/2);ii++)//----将以太网头写入网卡缓冲区
//-----------------------------------------------16位总线,一次要写一个16位字,故只要写(((TxdData->length)+1)/2)次
{
send_buff.bytes[0]=*TEPTR;//-----------------send_buff是send_temp类型(联合体),成员为两个:bytes,words
TEPTR++;
send_buff.bytes[1]=*TEPTR;
TEPTR++;
WriteToNet(0x10,send_buff.words);//---16位总线,所以一次要写一个16位字
}
ExPtr=TxdData->STPTR;
while(ExPtr!=NULL)//----------------------这样处理的原因是:以太网帧的数据并不是存放在一个数组中,而是存放在一个链表中
{//---------------------------------------一个疑问:如果长度是奇数,将多发送一个字节数据,如何处理这个问题????????
TEPTR=ExPtr->DAPTR;//------------------------字节类型指针TEPTR指向以太网数据
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;
}
//如果少于60
/***************************************/
//以下为终止DMA操作
WriteToNet(0x0b,0x00);
WriteToNet(0x0a,0x00);
WriteToNet(0x00,0x22); //结束或放弃DMA操作
WriteToNet(0x07,0xff);//-----------------------------------清除中断标志
if(Tx_Buff_Sel)//------------------//Tx_Buff_Sel==1时//----这是设置网卡发送数据起始地址的命令,与DMA传送命令不同
{
WriteToNet(0x04,0x40); //txd packet start;//---------第一页:字节偏移量为:40~45
}
else//-----------------------------//Tx_Buff_Sel==0时//----第二页:字节偏移量为:46~51
{
WriteToNet(0x04,0x46); //txd packet start;//----------这是设置网卡发送数据起始地址的命令,与DMA传送命令不同
}
ii=length;
if(length<60)
{
//如果数据长度<60字节,设置长度为60字节
ii=60;//-----------------------------------------------填充的内容是不确定的,在没有发生复位、溢出等特殊情况下,
//-----------------------------------------------------填充的内容是前两个数据包对应位置的数据
}
WriteToNet(0x06,ii>>8); //high byte counter
WriteToNet(0x05,ii&0x00ff);//low byte counter
WriteToNet(0x07,0xff);//-----------------------------------清除中断标志
WriteToNet(0x00,0x3e); //to sendpacket;
/***************************************/
//重发数据的处理
for(length=0;length<6;length++) //最多重发6次
{
for(ii=0;ii<1000;ii++)
{//检查CR寄存器的txp位是否为低,为1说明正在发送,为0说明发完或出错放弃
if((ReadFromNet(0X00)&0x04)==0)
{ break; }
}
if((ReadFromNet(0X04)&0x01)!=0)//表示发送成功,判断发送状态寄存器TSR,决定是否出错
//-------------------------------ReadFromNet(0X04)&0x01)=1则发送成功,跳出循环
{break;};
WriteToNet(0x00,0x3e); //to sendpacket;
}
/**************************************/
//OS_EXIT_CRITICAL();
}
/**********************************************************************
**函数原型: unsigned char * Rec_Packet()
**入口参数:?无
**出口参数: 返回数据指针 unsigned char *
**返 回 值: NULL 没有新数据包
** unsigned char * 接收到新数据包
**说 明: 查询是否有新数据包并接收进缓冲区
************************************************************************/
uint8 Rec_Packet() //-------------------通过RTL8019AS接收以太网包,调用Rec_Ethernet_Packed()处理以太网包
{
static uint8 REC_BUFF_NUM=0;
static uint8 bnry,curr; //?可否只做局部?
static uint16 tmp[2];
//static uint16 crt=0;
uint16 * REC_BUFF_PTR_WORDS;
uint8 * REC_BUFF_PTR_BYTES;
uint8 i;
uint16 ii,length;
OS_ENTER_CRITICAL();
rea1:
page(0);
i=ReadFromNet(0X07); //读取中断状态
if((i&0x90)!=0)//如果复位或益出就重新初试化
{
InitNic(0);
OS_EXIT_CRITICAL();
return(0);
}
bnry=ReadFromNet(0X03); //bnry page have read 读页指针//----------bnry:指向最后一个已读的页地址
page(1);
curr=ReadFromNet(0X07); //curr writepoint 8019写页指针//----------curr:指向当前即将写的页地址的后边一个页地址
page(0);
if(curr==0)//-----------------curr肯定大于0x40,因为SRAM的地址范围是:0x4000~0x7fff,大小为16K=84页(每页256K)
{
OS_EXIT_CRITICAL();
return(0); //读的过程出错
}
bnry++;//bnry=bnry+1;//-----------------------------------由于bnry指向当前已经读取的页,故本次执行要读的页地址是bnry+1
//--------------------------------------------------------下面的程序是基于bnry编写的,故在执行前使用bnry++
if(bnry>0x7f)//---------------curr肯定小于0x7f,因为SRAM的地址范围是:0x4000~0x7fff,大小为16K=84页(每页256K)
{
bnry=0x4c;//--------------------bnry返回到PStart,实现缓冲区的循环利用
//crt++;//统计内部16K循环了多少次(仿真器29次后出错)52、
}
if(bnry!=curr) //此时表示有新的数据包在缓冲区里
{ //在任何操作都最好返回page0
if(REC_BUFF_NUM==MAX_REC_BUFF)//接收缓冲区号清零
{
REC_BUFF_NUM=0;//---------------------------------实现以太太网包缓冲区的循环使用,有点类似网卡中发送缓冲区的使用方法
}
REC_BUFF_PTR_WORDS=REC_BUFF[REC_BUFF_NUM].words;//设定接收缓冲区的起始地址,REC_BUFF[REC_BUFF_NUM].words是一个数组的首地址,详见变量的定义
//----------------------------------REC_BUFF变量类型是REC_BUFF_UNION(以太网层的接收缓冲区数据结)
//----------------------------------每个缓冲区大小为1536字节/768字/384双字
//==============================================================================================
WriteToNet(0x09,bnry);//RSAR1写入读页地址的高字节 //-------------------
WriteToNet(0x08,0x00);//RSAR0写入读页地址的低字节 //--将要传送的数据---
WriteToNet(0x0b,0x00);//RSCR1写入读取字节计数高字节 //---的信息设置好----
WriteToNet(0x0a,18); //RSCR0写入读取字节计数高字节 //-------------------
WriteToNet(0x00,0x0a);//启动Remote DMA读操作//--------将上面设置的信息传给DMA,并启动DAM控制器,
//----------------------------------------------------也就是说下面指定次数(由RSCR1:RSCR0指定)的数据读写均由DMA负责传送
//----------------------------------------------------10H~17H的8个地址是一样的,都可以用来做DMA端口,只要用其中的一个就可以了
//----------------------------------------------------每次LPC2100向指定的DMA端口请求数据,网卡中的DMA控制器都会将数据发到指定端口
//读取一包的前4个字节:4字节的8019头部//---------------8019会在接收到的帧的前面加上四个字节的关于所接收帧的说明
//----------------------------------------------------每个字节的含义----0:接收状态;1:下一包的指针;2:本包长度低位;3:本包长度高位;
//----------------------------------------------------RSR中是它的一份拷贝,详见文档RTL8019AS使用方法.doc
for(i=0;i<2;i++)//------------------------------------将四个字节的帧的说明读到tmp[i]数组中
{
*REC_BUFF_PTR_WORDS=ReadFromNet(0x10);//----------10H~17H的8个地址是一样的,都可以用来做DMA端口,只要用其中的一个就可以了
//------------------------------------------------我的理解是:ReadFromNet(0x10)将第一个字字放到低位,第二个字节放到高位
tmp[i]=*REC_BUFF_PTR_WORDS;
REC_BUFF_PTR_WORDS++;
}//-----------------------------------------------每个字节的含义----0:接收状态;1:下一包的指针;2:本包长度低位;3:本包长度高位;
//----------------------------------------------------字节0在RSR寄存器中有一份挎贝RSR: Receive Status Register (0CH; Type=R in Page0),详细说明见8019的文档
//=======================================中止DMA操作
WriteToNet(0x0b,0x00); //RSCR1写入读取字节计数高字节
WriteToNet(0x0a,0x00); //RSCR0写入读取字节计数高字节
WriteToNet(0x00,0x22); //结束或放弃DMA操作
//=======================================
tmp[1]=tmp[1]-4;//去掉4个字节的CRC//------------------tmp[1]中是包的长度,实现将长度减4
//----------------------------------------------------???高低位是否颠倒???
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -