⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lib_emac.c

📁 uCOS-II下实现的lwip协议栈实现Ping功能
💻 C
📖 第 1 页 / 共 2 页
字号:
//*------------------------------------------------------------------------------------------------
//* 文件名				: lib_emac.c
//* 功能描述			: EMAC外设的函数库
//* 作者    			: yangzheyu@ict.ac.cn
//* 版本				: 0.1
//* 建立日期、时间		: 2010/10/24
//* 最近修改日期、时间	: 
//* 修改原因			: 
//*------------------------------------------------------------------------------------------------
//*------------------------------------------ 头文件 ----------------------------------------------
//#include	"includes.h"
#include	"lwip/opt.h"
#include	"lib_emac.h"
#include	"os_api.h"
//#include 	"2440addr.h"
#include 	"config.h"
#include	"err.h"

extern	OS_EVENT * hEthernetInput;
extern	OS_EVENT *  EthernetInput;

static INT8U	mac_addr[]={0x00,0x19,0x21,0xcb,0x60,0x0b};
static	INT16U	sendlengh=0;////发送数据包的长度统计
static U8 Int_States;
static struct 	buffer_pool		r_pool[RWIDE];
static struct	buffer_pool	* head_free=NULL;
static struct	buffer_pool	* head_used=NULL;
OS_STK MACPACKETS_STK[MACPACKETS_STK_LENGH ];
static OS_EVENT * hEMACInput=NULL;
//*-------------------------------------- 函数原型声明 --------------------------------------------
static void __CheckPHYID(void);/*	查看网卡芯片ID	*/
static void udelay(INT32U t);
static void dm9000_reg_write(INT16U reg, INT16U data);
static INT8U dm9000_reg_read(INT16U reg);
static INT16U dm9000_reg_read16(INT16U reg);
static void irqEMACISR(void);
static void IOSetInit(void);
static void PrintfDM9000Reg(void);
static void OpenDM9000Isr(void);
static void buffer_pool_init(void);
static void readthemacbuffer(void);
static void DM9000_init(void); 
void MACPackets(void *pada);
//*================================================================================================
//*                     函 数 区
//*================================================================================================

//*------------------------------------------------------------------------------------------------
//* 函数名称 : udelay
//* 功能描述 : 延时函数
//* 入口参数 : t 延时的时间长度
//* 出口参数 : 无
//*------------------------------------------------------------------------------------------------

static void udelay(INT32U t)
{
   INT32U i;
   for(;t>0;t--)
   {
     for(i=0;i<100;i++){}
   }
}
//*------------------------------------------------------------------------------------------------
//* 函数名称 : dm9000_reg_write
//* 功能描述 : 向DM9000寄存器写数据,先将寄存器的地址写进去 然后再写数据到相应的寄存器中
//* 入口参数 : reg 寄存器的地址	data 写入寄存器的值
//* 出口参数 : 无
//*------------------------------------------------------------------------------------------------

static void dm9000_reg_write(INT16U reg, INT16U data)
{  
//	udelay(20);		//之前定义的微妙级延时函数,这里延时20us
	DM_ADD = reg;	//将寄存器地址写到INDEX端口
//	udelay(20);
	DM_CMD = data;	//将数据写到DATA端口,即写进寄存器
}

//*------------------------------------------------------------------------------------------------
//* 函数名称 : dm9000_reg_read
//* 功能描述 : 向DM9000寄存器读数据,先将寄存器的地址写进去 然后再读数据,读取的数据虽然是16位,但是
//*	丢弃了前面的八位。不适合读数据包
//* 入口参数 : reg 寄存器的地址
//* 出口参数 : 寄存器的值
//*------------------------------------------------------------------------------------------------

static INT8U dm9000_reg_read(INT16U reg)
{
  //  udelay(20);
    DM_ADD = reg;
  //  udelay(20);
    return DM_CMD;//将数据从寄存器中读出	
}

//*------------------------------------------------------------------------------------------------
//* 函数名称 : dm9000_reg_read16
//* 功能描述 : 向DM9000寄存器读数据,先将寄存器的地址写进去 然后再读数据,读取的数据是16位
//* 入口参数 : reg 寄存器的地址
//* 出口参数 : 寄存器的值 16bit
//*------------------------------------------------------------------------------------------------

static INT16U dm9000_reg_read16(INT16U reg)
{
  //  udelay(20);
    DM_ADD = reg;
  //  udelay(20);
    return DM_CMD;//将数据从寄存器中读出	
}
//*------------------------------------------------------------------------------------------------
//* 函数名称 : OpenInt9
//* 功能描述 : 打开外部中断引脚  此函数在中断服务程序中被调用
//* 入口参数 : 
//* 出口参数 : 
//*------------------------------------------------------------------------------------------------

static void OpenInt7(void)
{
	//*	清除中断源	
	rEINTPEND |= 1<<9;
	ClearPending(BIT_EINT8_23);
	//*开启中断
	//*开外部中断屏蔽寄存器
	rEINTMASK = rEINTMASK & (~(0x01<<9));
	rINTMSK = rINTMSK & (~(BIT_EINT8_23));
}
//*------------------------------------------------------------------------------------------------
//* 函数名称 : ClosedInt9
//* 功能描述 : 关闭外部中断引脚  此函数在中断服务程序中被调用
//* 入口参数 : 
//* 出口参数 : 
//*------------------------------------------------------------------------------------------------

static void ClosedInt7(void)
{
	//*	关闭中断
	rINTMSK  |=BIT_EINT8_23;
	rEINTMASK|=(0x01<<9);
	//*	清除中断源	
	rEINTPEND |= 1<<9;
	ClearPending(BIT_EINT8_23);
}
//*------------------------------------------------------------------------------------------------
//* 函数名称 : __CheckPHYID
//* 功能描述 : 检查PHY ID是否为0x82010000,如果不是则表明PHY还没有就绪或者出现故障,函数将一直查询直至正确
//* 入口参数 : 无
//* 出口参数 : 无
//*------------------------------------------------------------------------------------------------
static void __CheckPHYID(void)
{
//*	如果能够正常读取出数据,那么说明时序是正确的
//*	注意这个时序和读取或者写入一个寄存器的值后的
//*	延时时间不是一样的含义。
    U32 id_val;
    id_val = 0;
    DM_ADD = DM9KS_PID_H;
    id_val = (DM_CMD & 0xff) << 8;
    
   // id_val = (uint8)DM_CMD;
    DM_ADD = DM9KS_PID_L;
    id_val+= (DM_CMD & 0xff);
    //id_val |= (uint8)DM_CMD<<8;
   // DM_ADD = DM9KS_PID_L;udelay(2);
    id_val = id_val << 16;
    DM_ADD = DM9KS_VID_H;
    id_val += (DM_CMD & 0xff) << 8;
    DM_ADD = DM9KS_VID_L;
    id_val += (DM_CMD & 0xff);
  Printf("DM9000AE ChipId is %x\n", id_val);
    if(id_val == DM9KS_ID)
        Printf("DM9000 ID correct\n");
    else
        Printf("DM9000 ID wrong\n");    
}

//*------------------------------------------------------------------------------------------------
//* 函数名称 : irqEMACISR
//* 功能描述 : EMAC发送和接收结束中断处理函数
//* 入口参数 : 无
//* 出口参数 : 无
//*	功能详细描述:DM9000在接受到数据之后通过INT9引脚发送中断到CPU,CPU响应中断,发送一个信号量,通过
//*	这个信号量来处理提出的中断,中断有两种,一是发送完成中断,一是接收完成中断。
//*------------------------------------------------------------------------------------------------
 static void irqEMACISR(void)
{
///*	这段在中断函数中的处理,系统调度停止了
//		extern LWIP_HANDLER hEthernetInput;/*	实际上这个就是一个事件控制器	因为此处要使用*/
	//Printf("enter in interrupt!\n");
	//*首先是关闭外部引脚中断
	ClosedInt7();
	Int_States = dm9000_reg_read(0xfe) ; 
	if(Int_States & 0x01)
	{
		OSAPISemSend(hEMACInput);
	}
	dm9000_reg_write(DM9000_ISR,  0x3f);    //清除所有中断标志位
	//*然后关闭网卡中断,此时网卡还是可以接受数据
    dm9000_reg_write(DM9000_IMR,0x80);////关闭网卡中断
	
	//*接受网卡缓冲中的数据并清除网卡中断状态标志
	//*这一步放在专门的任务中处理。这样便于不丢失数据包
	
	//* 向任务发送数据,这样任务过来取数据
	//OSAPISemSend(hEMACInput);
	
//	Printf("Int \n");
	//*打开外部中断
	OpenInt7();
	
	//*开启网卡中断,同时清除其中的中断状态寄存器
    dm9000_reg_write(DM9000_IMR, 0x81);     //中断使能
}

//*------------------------------------------------------------------------------------------------
//* 函数名称 : IOSetInit
//* 功能描述 : 初始化INT7引脚的中断
//* 入口参数 : 无
//* 出口参数 : 无
//*------------------------------------------------------------------------------------------------
 static void  IOSetInit(void)
{
	/*
	rGPFCON = (rGPFCON & (~(0x03<<14))) | (0x02<<14);	//GPF7设置为EINT7
	rEXTINT0 = (rEXTINT0 & (~(0x07<<28))) | (0x01<<28);
	//开外部中断屏蔽寄存器,小门
	rEINTMASK = rEINTMASK & (~(0x01<<7));
	//清除中断源
	rEINTPEND |= 1<<7;
	ClearPending(BIT_EINT4_7);
	//设置中断函数
	pISR_EINT4_7 = (U32)irqEMACISR;
	//打开外部中断屏蔽门,大门
	rINTMSK = rINTMSK & (~(BIT_EINT4_7));
	*/
	//GPG1设置为EINT9,DM9000的INT连接EINIT9 [3:2]=10
		rGPGCON = (rGPGCON & (~(0x03<<2))) | (0x02<<2);	       
		//rEXTINT0 = (rEXTINT0 & (~(0x07<<28))) | (0x01<<28);
		rEXTINT1 = (rEXTINT1 & (~(0x07<<4))) | (0x01<<4);
		//EINIT9中断使能
		rEINTMASK = rEINTMASK & (~(0x01<<9));         
		//rINTMOD |= 0x01<<5;
		//ChearPending()清除SCRPND和INTPND对应的位,rSRCPND = bit;rINTPND = bit;rINTPND;
		//清除中断源
		rEINTPEND |= 1<<9;
		ClearPending(BIT_EINT8_23);             //BIT_EINT4_7 (0x1<<4)                  
		//rSRCPND |= 0x1<<5;
		//rINTPND |= 0x1<<5 ;
		pISR_EINT8_23 = (U32)irqEMACISR;                
		rINTMSK = rINTMSK & (~(BIT_EINT8_23));
	
}

//*------------------------------------------------------------------------------------------------
//* 函数名称 : buffer_pool_init
//* 功能描述 : 接收数据缓冲池初始化,在EMAC初始化中被调用
//* 入口参数 : 无
//* 出口参数 : 无
//*------------------------------------------------------------------------------------------------

static void buffer_pool_init(void)
{
	INT8U i=0;
	head_free=r_pool;
	head_used=NULL;
	for(;i<RWIDE-1;i++)
	{
		r_pool[i].next=&r_pool[i+1];
		r_pool[i].leng=0;
	}
	r_pool[i].next=NULL;
	r_pool[i].leng=0;
}
//*------------------------------------------------------------------------------------------------
//* 函数名称 : get_dm900_data
//* 功能描述 : 得到DM9000中的数据 这个函数在中断函数中被调用,所以不需要进行临界保护
//* 入口参数 : 
//* 出口参数 : 无
//*------------------------------------------------------------------------------------------------
static void get_dm9000_data(void)
{
	char *pp;
	struct buffer_pool * temp;
	INT16S i=0,data,status,len;
//	if(head_free==NULL)
//	{
//		Printf("get_dm9000_data bug\n");
//		return;
//	}
	#if OS_CRITICAL_METHOD == 3                     
    OS_CPU_SR  		cpu_sr = 0;
	#endif	
	OS_ENTER_CRITICAL()
	temp=head_free;
	head_free=head_free->next;
	temp->next=NULL;
	pp=temp->data;
	
	DM_ADD = DM9000_MRCMD;
	
	status = DM_CMD;
	udelay(10);
    len = DM_CMD;
    temp->leng=len;
//    Printf("\nReceive the DM9000 data \n");
	for(;i<len;i+=2)
	{	
		data = DM_CMD;
    	pp[i] = data & 0x0ff;
    	pp[i + 1] = (data >> 8) & 0x0ff;
//    	Printf(" %x  %x",pp[i],pp[i+1]);
    }
//    Printf("\n***********\n");
    if(head_used==NULL)
    	head_used=temp;
    else
    {
    	temp->next=head_used;
    	head_used=temp;
    }
    OS_EXIT_CRITICAL()
}

//*此函数被中断函数调用,在这里设置了一个缓冲区主要是为了使得丢包的次数减少
//*在获取数据的时候一直往下面读,直到读取的数据是00则表示结束
static unsigned int count=0;
static void readthemacbuffer(void)
{
	INT16U	ready=0;
	INT8U err;
	extern OS_EVENT * hEthernetInput;
	//*堵塞获取一个信号,用在共享资源上面
	OSSemPend(hEthernetInput,0,&err);
    while(1){
    ready = dm9000_reg_read(DM9000_MRCMDX); // 第一次读取,一般读取到的是 00H
    if((ready & 0x0ff) != 0x01)
    {
        ready = dm9000_reg_read(DM9000_MRCMDX); // 第二次读取,总能获取到数据
        if((ready & 0x01) != 0x01)
         {
           
            if((ready & 0x01) != 0x00)      //若第二次读取到的不是 01H 或 00H ,则表示没有初始化成功
            {
                 dm9000_reg_write(DM9000_IMR, 0x80);//屏蔽网卡中断
                 DM9000_init();             //重新初始化
                 Printf("Init again\n"); /////////// 
                 return;
            }
            //*说明已经读到末尾了          
           else	 return;
         }
    }
    count++;
    //Printf("the %d mac buffer packet\n",count);
//    OSSchedLock();
    get_dm9000_data();
    OSAPISemSend(EthernetInput);
    //*释放这个共享资源

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -