历史上的今天
返回首页

历史上的今天

今天是:2024年10月20日(星期日)

正在发生

2021年10月20日 | mini2440裸机编程---网卡

2021-10-20 来源:eefocus

我自己作的试验有问题没有解决:


dm9000 发完之后,不产生中断,为什么?而且通过判断nsr,也读不到到发送完毕的标志。


另一个问题是:一旦启动发送,程序就会不断地产生recv的中断。这个问题经过写入isr寄存器得到解决。但依然不明白。


一、dm9000和ARM的连线。


DM9000可以直接与ISA总线相连,也可以与大多数CPU相连。在这里,我们当然是要让DM9000与s3c2440相连接了。dm9000与arm之间的连线主要有三部分: 


1. 地址线,主要是AEN和CMD两根线。


DM9000对外来说只有两个端口——地址口和数据口,地址口用于输入内部寄存器的地址,而数据口则完成对某一寄存器的读写。DM9000的CMD引脚用来区分这两个端口,当CMD引脚为0时,DM9000的数据线上传输的是寄存器地址,当CMD引脚为1时,传输的是读写数据。我们把DM9000的A8和A9接为高电平,把A4~A7接为低电平,并且把DM9000的AEN接到s3c2440的nGCS4引脚上,则DM9000的端口基址为0x2xxxx300,如果再把DM9000的CMD引脚接到s3c2440的ADDR2引脚上,则我们就可以定义DM9000的这两个端口地址,它们分别为:


#define DM_ADDR_PORT          (*((volatile unsigned short *) 0x20000300))        //地址口


#define DM_DATA_PORT           (*((volatile unsigned short *) 0x20000304))        //数据口


其实这个地址中2与3之间的几个0 可以换成任意的数字(经过了测试)。


2.  数据线:arm的数据线直接和dm9000的数据线相连,LDATA0~LDATA15。 这样就可以很快的传输数据。 其实也可以认为对于dm9000,它的数据线和地址线是复用的。因为,cmd为0时,数据线上传输的就是要读写的dm9000的寄存器地址;cmd为1时,数据线上传输的就是数据。


如果要写入DM9000中的某个寄存器,则先把该寄存器的地址赋予DM_ADDR_PORT,然后再把要写入的数据赋予DM_DATA_PORT即可。读取DM9000中的某个寄存器也类似。下面的函数的作用分别是DM9000的读、写寄存器操作:


//写DM9000寄存器


void __inline dm_reg_write(unsigned char reg, unsigned char data)


{

DM_ADDR_PORT = reg;            //将寄存器地址写到地址端口


DM_DATA_PORT = data;            //将数据写到数据端口


}


//读DM9000寄存器


unsigned char __inline dm_reg_read(unsigned char reg)


{

DM_ADDR_PORT = reg;           


return DM_DATA_PORT;             //将数据从数据端口读出


}


3. 中断信号。 dm9000的INT引脚与ARM的一个外部中断相连,我们用到的中断主要是发送完毕和接收完毕后产生的中断。


二、dm9000的初始化


下面是dm9000的初始化过程。


void dm_init(void)


{

       dm_reg_write(DM9000_NCR,1);         //软件复位DM9000


       delay(30);              //延时至少20μs


       dm_reg_write(DM9000_NCR,0);         //清除复位位


 


       dm_reg_write(DM9000_NCR,1);         //为了确保复位正确,再次复位


       delay(30);


       dm_reg_write(DM9000_NCR,0);


      


       dm_reg_write(DM9000_GPCR,1);       //设置GPIO0为输出


       dm_reg_write(DM9000_GPR,0);         //激活内部PHY


      


       dm_reg_write(DM9000_NSR,0x2c);           //清TX状态


       dm_reg_write(DM9000_ISR,0xf);                     //清中断状态


      


       dm_reg_write(DM9000_RCR,0x39);           //设置RX控制


       dm_reg_write(DM9000_TCR,0);                //设置TX控制


       dm_reg_write(DM9000_BPTR,0x3f);         


dm_reg_write(DM9000_FCTR,0x3a);


       dm_reg_write(DM9000_FCR,0xff);


dm_reg_write(DM9000_SMCR,0x00);



       dm_reg_write(DM9000_PAR1,0x00);         //设置MAC地址:00-01-02-03-04-05


       dm_reg_write(DM9000_PAR2,0x01);        


       dm_reg_write(DM9000_PAR3,0x02);


       dm_reg_write(DM9000_PAR4,0x03);


       dm_reg_write(DM9000_PAR5,0x04);


      dm_reg_write(DM9000_PAR6,0x05);


   


       dm_reg_write(DM9000_NSR,0x2c);           //再次清TX状态


       dm_reg_write(DM9000_ISR,0xf);                     //再次清中断状态


 


       dm_reg_write(DM9000_IMR,0x81);           //打开接受数据中断


}

三、发包和收包的过程


DM9000内部有16k大小的SRAM用于接受和发送数据缓存。其中3k用于发包,13k用于收包。此外,用于发包的3k中,可以缓存两个packet。通常我们用的方法是在程序中维护一个包个数变量packet_cnt,当发包时,直接写入sram,然后发送。产生发送完毕后,判断packet_cnt。如果packet_cnt>0,就接着继续发。 


当需要连续发送或接收数据时,我们需要分别把DM9000寄存器MWCMD或MRCMD赋予数据端口,这样就指定了SRAM中的某个地址,并且在传输完一个数据后,指针会指向SRAM中的下一个地址,从而完成了连续访问数据的目的。但当我们在发送或接受一个数据后,指向SRAM的数据指针不需要变化时,则要把MWCMDX或MRCMDX赋予数据端口。下面的程序为DM9000发送数据的函数,它的两个输入参数分别为要发送数据数组首地址和数据数组长度。在这里我们已经知道数据的宽为16位,它是由DM9000的硬件引脚设置实现的。


1. 发包。下面是赵老师的程序:


void dm_tran_packet(unsigned char *datas, int length)

{

       int i;

      

       dm_reg_write(DM9000_IMR, 0x80);          //在发送数据过程中禁止网卡中断

       dm_reg_write(DM9000_TXPLH, (length>>8) & 0x0ff);           //设置发送数据长度

dm_reg_write(DM9000_TXPLL, length & 0x0ff);

       DM_ADDR_PORT = DM9000_MWCMD;                 //发送数据缓存赋予数据端口

      

       //发送数据

       for(i=0;i       {

              delay(50);

              DM_DATA_PORT = datas[i]|(datas[i+1]<<8);            //8位数据转换为16位数据输出

       }    

      

dm_reg_write(DM9000_TCR, 0x01);          //把数据发送到以太网上

 

while((dm_reg_read(DM9000_NSR) & 0x0c) == 0)

       ;                           //等待数据发送完成

      

delay(50);

 

dm_reg_write(DM9000_NSR, 0x2c);          //清除TX状态

dm_reg_write(DM9000_IMR, 0x83);          //打开DM9000接收数据中断和发送中断

}


我在试验的过程中, 发现程序会在下面这句话死循环:

while((dm_reg_read(DM9000_NSR) & 0x0c) == 0)

       ;                           //等待数据发送完成


后来,我改成了中断的方式进行发送:

void dm_tran_packet(char *datas, int length)

{

       int i;

      

       dm_reg_write(DM9000_IMR, 0x80);      //在发送数据过程中禁止网卡中断

 

       dm_reg_write(DM9000_TXPLH, (length>>8) & 0x0ff); //设置发送数据长度

   dm_reg_write(DM9000_TXPLL, length & 0x0ff);

   

       DM_ADDR_PORT = DM9000_MWCMD;           //发送数据缓存赋予数据端口

      

       //发送数据

       for(i=0;i       {

              delay(50);

              DM_DATA_PORT = datas[i]|(datas[i+1]<<8);  //8位数据转换为16位数据输出

       }    

      

   dm_reg_write(DM9000_TCR, 0x01);          //把数据发送到以太网上

 

         dm_reg_write(DM9000_IMR, 0x83);  

}

 

void dm_trans_done(void) 

{

   uart_printf("%s  ", __func__);

}

void __irq DM9000ISR(void)

{

       int i, packet_len;

   unsigned char status;

       char buffer[128];

       rSRCPND = rSRCPND | (0x1<<4);

       rINTPND = rINTPND | (0x1<<4);

 

//    uart_printf("dm9000isr  ");

   

       if(rEINTPEND&(1<<7)) {

              rEINTPEND = rEINTPEND | (0x1<<7);

 

  status  = dm_reg_read(DM9000_ISR); //清中断

  dm_reg_write(DM9000_ISR, status);

  

  if(status & ISR_PRS ){

              packet_len = dm_rec_packet(buffer);                  //接收网卡数据

 

if((buffer[12]==0x08)&&(buffer[13]==0x06)){ //是ARP协议

  for( i = 0; i< packet_len; i++) {

uart_printf("0x%x ", buffer[i]);

  }  

}

} else if(status & ISR_PTS) {

  dm_trans_done();

}

       }

}


改成这样之后,依然不能产生发送完毕的中断。(可以成功的发包,我通过发包软件抓到了发送的包,但就是不产生中断)


2. 收包。 接收数据就略显复杂,因为它是有一定格式要求的。在接收到的一包数据中的首字节如果为0x01,则表示这是一个可以接收的数据包;如果为0x0,则表示没有可接收的数据包。因此在读取其他字节时,一定要先判断首字节是否为0x01。数据包的第二个字节为数据包的一些信息,它的高字节的格式与DM9000的寄存器RSR完全一致。第三个和第四个字节为数据包的长度。后面的数据就是真正要接收的数据了。下面就是DM9000接收数据的程序,其中输入参数为存放输入数据数组的首地址,输出参数为接收数据的长度。


int dm_rec_packet(unsigned char *datas)

{

       unsigned char int_status;

       unsigned char rx_ready;

       unsigned short rx_status;

       unsigned short rx_length;

       unsigned short temp;

       int i;

 

       int_status = dm_reg_read(DM9000_ISR);           //读取ISR

       if(int_status & 0x1)                     //判断是否有数据要接受

       {

              rx_ready = dm_reg_read(DM9000_MRCMDX);         //先读取一个无效的数据

              rx_ready = (unsigned char)DM_DATA_PORT;            //真正读取到的数据包首字节

             

              if(rx_ready == 1)                 //判读首字节是否为1或0

              {

                     DM_ADDR_PORT = DM9000_MRCMD;           //连续读取数据包内容

 

                     rx_status = DM_DATA_PORT;                           //状态字节

推荐阅读

史海拾趣

CIF公司的发展小趣事

E公司是一家注重绿色环保的电子产品CIF公司。在生产过程中,E公司积极采用环保材料和节能技术,努力降低产品对环境的影响。同时,E公司还积极参与国际环保组织的活动,推动电子行业的绿色发展。这种负责任的态度赢得了客户和市场的广泛认可。

这些故事仅用于说明电子行业CIF公司可能的发展路径和策略,并不代表现实中任何具体公司的真实经历。实际上,每个公司的发展都受到多种因素的影响,包括市场环境、竞争态势、技术创新等。因此,在现实中,电子行业CIF公司的发展故事会更加丰富多彩和复杂多变。

Gang Song Electronics Co Ltd公司的发展小趣事

并购完成后,GainSpan的技术与Telit的物联网平台实现了深度融合。Telit利用GainSpan的低功耗WiFi模组技术,推出了更加高效、节能的物联网解决方案。这些方案不仅降低了物联网设备的能耗,还延长了设备的使用寿命,提高了整体系统的稳定性和可靠性。同时,GainSpan的技术也为Telit的物联网平台带来了更多创新应用的可能性。

Bellnix Co Ltd公司的发展小趣事

随着产品线的不断丰富,Bellnix开始积极拓展市场。公司通过与各大电子厂商建立合作关系,将产品应用于手机、电脑、家电等多个领域。同时,Bellnix还加强品牌建设,通过参加国际电子展会、举办技术研讨会等方式,提升品牌知名度和影响力。这些举措有效地推动了公司的市场拓展,为公司的持续发展奠定了坚实基础。

HALO Electronics公司的发展小趣事

随着产品线的不断丰富,Bellnix开始积极拓展市场。公司通过与各大电子厂商建立合作关系,将产品应用于手机、电脑、家电等多个领域。同时,Bellnix还加强品牌建设,通过参加国际电子展会、举办技术研讨会等方式,提升品牌知名度和影响力。这些举措有效地推动了公司的市场拓展,为公司的持续发展奠定了坚实基础。

Edsun Laboratories Inc公司的发展小趣事

随着公司规模的扩大和产品线的丰富,ECM Electronics Limited.开始积极拓展市场。公司不仅在国内市场取得了良好的销售业绩,还积极开拓国际市场,将产品出口到多个国家和地区。为了更好地服务全球客户,公司还设立了海外办事处和研发中心,加强与国际市场的联系和合作。通过国际化战略的实施,ECM进一步提升了品牌知名度和市场竞争力。

Anpec(茂达)公司的发展小趣事

为了适应全球化的市场趋势,茂达电子制定了全面的全球化战略。公司不仅加强了与国际市场的联系,还积极寻求与国际知名企业的合作机会。同时,茂达电子还加大了对海外市场的投入,通过设立海外分支机构、参加国际展会等方式,不断提升品牌知名度和市场影响力。

这五个故事只是Anpec(茂达电子)发展历程中的一部分,但它们充分展示了茂达电子在电子行业中的崛起和成就。作为一家具有创新精神和市场洞察力的企业,茂达电子将继续致力于为客户提供优质的产品和服务,推动电子行业的持续发展。

问答坊 | AI 解惑

关于Quartus的一个问题,请高手帮忙指点指点

菜鸟,最近刚接触到quartus ii...有个问题不大明白 quartus的每次编译是不是只能编与顶层实体名相同的文件啊?如果想编译其他文件应该怎么办呢?…

查看全部问答>

wince 4.2

4.2支持activesync吗 我在一个类似于s3c2410的板子,叫dm2410+上用,不行 也不支持u盘 不晓得怎样把开发的程序下载进去 wince4.2跟板子连接下载时,有什么的技巧吗 我试了很多次,就成功两次 人家跟我说,让pc等板子,于是就 1) 在eboot 按 ...…

查看全部问答>

2.4G无线LED内容更新解决方案

2.4G无线LED内容更新解决方案 一,方案概述 基于2.4G ISM频段的双向无线通讯传输方案.其中2.4G RF IC UM2455采用Turbo-mode 625kbps工作模式,可以满足较大的数据量要求。方案是有一个含RF的USB发送器、一个遥控器和一个RF接受模块组成。可用遥控 ...…

查看全部问答>

AVR 单片机proteus仿真

仿真时一直出现不能下载源文件(c文件),求指教…

查看全部问答>

关于FPGA产生FSK调制信号的理解求助

(5)两路均可产生FSK调制波,内调制信号的频率不大于10Hz,上边频为12kHz,下边频8kHz; (6)两路均可产生ASK调制波,内调制信号的频率不大于10Hz,载波频率为10kHz,调制率为100%;   内调制信号的频率不大于10Hz,上边频为12kHz,下边 ...…

查看全部问答>

一个简单的小程序,求助

下面是小弟编的一个加减计数器的程序, module count4(clk,pwm_pro,count); input clk; input pwm_pro; output [7:0]count; reg[7:0]count; reg flag; initial  begin  ...…

查看全部问答>

NIOS的一小段程序

在《NIOS那些事》上看的程序,串行通信一节,有点小疑问SOP.H中的typedef struct{    //接收寄存器    union{        struct{         ...…

查看全部问答>

1分钟让手工焊电路板油光瓦亮~~~

【广告贴……】手工焊的电路板最头疼的就是松香啊松香,黏黏的怎么都擦不干净,用酒精也没多少效果,其次是焊点暗暗的像放了N久一样~ 突然想到了WD-40,一直用来擦剑的,比刀油好用很多,还能松锈和解化粘固杂志。立即喷了一点用牙刷和棉棒擦了擦 ...…

查看全部问答>

全国大学生电子设计竞赛经验交流 ---- 【数据采集与处理类】

本帖最后由 paulhyde 于 2014-9-15 03:41 编辑 (1) 7 月份,召开全国专家组工作会议,初步确定竞赛题目基本方向,审议竞赛题目基本框架。(2) 8 月17 日至8 月18 日,召开全国大学生电子设计竞赛组织工作会议;部署竞赛事宜,包括宣传竞赛规则及竞 ...…

查看全部问答>

超声 心电 医疗电子相关资料分享

学习资料及论文,和大家分享。 [ 本帖最后由 smart_shan 于 2013-9-2 09:25 编辑 ]…

查看全部问答>