📄 lib_emac.c
字号:
//*------------------------------------------------------------------------------------------------
//* 文件名 : 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 + -