dm9000初始化过程


 
drivers/dm9000x.c eth_init()函数
 
这里的初始化并不复杂,首先对dm9000进行复位
static void
dm9000_reset(void)
{
       DM9000_DBG("resetting/n");
       DM9000_iow(DM9000_NCR, NCR_RST);
       udelay(1000);              /* delay 1ms */
}
这里将NRC寄存器的第0位置1,之后要保持至少20us的延时。这里延时了1ms。
 
int
dm9000_probe(void)
{
       u32 id_val;
       id_val = DM9000_ior(DM9000_VIDL);
       id_val |= DM9000_ior(DM9000_VIDH) << 8;
       id_val |= DM9000_ior(DM9000_PIDL) << 16;
       id_val |= DM9000_ior(DM9000_PIDH) << 24;
       if (id_val == DM9000_ID) {
              printf("dm9000 i/o: 0x%x, id: 0x%x /n", CONFIG_DM9000_BASE,
                     id_val);
              return 0;
       } else {
              printf("dm9000 not found at 0x%08x id: 0x%08x/n",
                     CONFIG_DM9000_BASE, id_val);
              return -1;
       }
}
复位结束后到网卡的vendor ID寄存器和product ID寄存器读取id,检测此网卡是否是dm9000。
 
static void
identify_nic(void)
{
       struct board_info *db = &dmfe_info;       /* Point a board information structure */
       u16 phy_reg3;
       DM9000_iow(DM9000_NCR, NCR_EXT_PHY);
       phy_reg3 = phy_read(3);
       switch (phy_reg3 & 0xfff0) {
       case 0xb900:
              if (phy_read(31) == 0x4404) {
                     db->nic_type = HOMERUN_NIC;
                     program_dm9801(phy_reg3);
                     DM9000_DBG("found homerun NIC/n");
              } else {
                     db->nic_type = LONGRUN_NIC;
                     DM9000_DBG("found longrun NIC/n");
                     program_dm9802();
              }
              break;
       default:
              db->nic_type = FASTETHER_NIC;
              break;
       }
       DM9000_iow(DM9000_NCR, 0);
}
接着是检测网卡类型,是FASTETHER, HOMERUN或LONGRUN类型。这里主要是通过phy_read(3)和phy_read(31)读取PHY 寄存器的值并进行比较判断。读PHY寄存器的方法将在后面介绍。
 
DM9000_iow(DM9000_GPR, 0x00);
将GPR寄存器的第0位置0。激活内部PHY的功能。
 
The default status of the DM9000 is to power down the internal PHY by setting the GPIO0.
Since the internal PHY have been powered down, the wakeup procedure will be needed to
enable the DM9000
 
这是官方文档对这个设置的解释。因为其初始化状态是POWER DOWN。在power down模式下,除了MDC/MDIO管理接口,其他所有的发送、接收及MII接口功能都被禁止。
 
static void
set_PHY_mode(void)
{
       u16 phy_reg4 = 0x01e1, phy_reg0 = 0x1000;
       if (!(media_mode & DM9000_AUTO)) {
              switch (media_mode) {
              case DM9000_10MHD:
                     phy_reg4 = 0x21;
                     phy_reg0 = 0x0000;
                     break;
              case DM9000_10MFD:
                     phy_reg4 = 0x41;
                     phy_reg0 = 0x1100;
                     break;
              case DM9000_100MHD:
                     phy_reg4 = 0x81;
                     phy_reg0 = 0x2000;
                     break;
              case DM9000_100MFD:
                     phy_reg4 = 0x101;
                     phy_reg0 = 0x3100;
                     break;
              }
              phy_write(4, phy_reg4);  /* Set PHY media mode */
              phy_write(0, phy_reg0);  /*  Tmp */
       }
       DM9000_iow(DM9000_GPCR, 0x01);    /* Let GPIO0 output */
       DM9000_iow(DM9000_GPR, 0x00);       /* Enable PHY */
}
通过写PHY寄存器0和4即BMCR和ANAR来设置phy的工作模式。在我的这个板子上用的是默认的配置。通过写寄存器0使能了dm9000的auto-negotiation状态;通过写寄存器4设置该网卡支持IEEE 802.3 CSMA/CD和其他一些工作模式。
 
       DM9000_iow(DM9000_GPCR, 0x01);    /* Let GPIO0 output */
       DM9000_iow(DM9000_GPR, 0x00);       /* Enable PHY */
这最后两行又将PHY进行了一次重启。先将PHY设置为power down,再使能。
 
 
下面是对一些控制和状态寄存器的设置,具体含意可参考dm9000 datasheet.
       /* Program operating register */
       DM9000_iow(DM9000_NCR, 0x0);  /* only intern phy supported by now */
       DM9000_iow(DM9000_TCR, 0);      /* TX Polling clear */
       DM9000_iow(DM9000_BPTR, 0x3f);      /* Less 3Kb, 200us */
       DM9000_iow(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8)); /* Flow Control : High/Low Water */
       DM9000_iow(DM9000_FCR, 0x0);  /* SH FIXME: This looks strange! Flow Control */
       DM9000_iow(DM9000_SMCR, 0);   /* Special Mode */
       DM9000_iow(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);       /* clear TX status */
       DM9000_iow(DM9000_ISR, 0x0f);   /* Clear interrupt status */
 
 
 
       /* Set Node address */
       for (i = 0; i < 6; i++)
              ((u16 *) bd->bi_enetaddr)[i] = read_srom_word(i);
       printf("MAC: %02x:%02x:%02x:%02x:%02x:%02x/n", bd->bi_enetaddr[0],
              bd->bi_enetaddr[1], bd->bi_enetaddr[2], bd->bi_enetaddr[3],
              bd->bi_enetaddr[4], bd->bi_enetaddr[5]);
       for (i = 0, oft = 0x10; i < 6; i++, oft++)
              DM9000_iow(oft, bd->bi_enetaddr[i]);
       for (i = 0, oft = 0x16; i < 8; i++, oft++)
              DM9000_iow(oft, 0xff);
这段代码是设置dm9000的MAC地址,选是通过read_srom_word(i)到srom中读取MAC地址值,再分别写入板子信息数据结构bd中dm9000的MAC寄存器中,再将Multicast Address Register寄存器全部置1。
 
看一下read_srom_word这个函数
static u16
read_srom_word(int offset)
{
       DM9000_iow(DM9000_EPAR, offset);
       DM9000_iow(DM9000_EPCR, 0x4);
       udelay(200);
       DM9000_iow(DM9000_EPCR, 0x0);
       return (DM9000_ior(DM9000_EPDRL) + (DM9000_ior(DM9000_EPDRH) << 8));
}
这个函数是从srom中读一个word。首先把要读的那个寄存器的偏移地址offset写入EPAR寄存器,然后把读命令0x4写入EPCR寄存器,等待至少150us后,向EPCR寄存器写入0x0,清除读命令,最后从EPDRL和EPDRH寄存器中分别读出数据的低字节和高字节。EPAR是地址寄存器,存入要读/写的寄存器的偏移地址。EPCR是控制寄存器,通过命令控制读/写。读出的数据或要写入的数据放在PEDRL和EPDRH中。
 
       DM9000_iow(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);      /* RX enable */
       DM9000_iow(DM9000_IMR, IMR_PAR);       /* Enable TX/RX interrupt mask */
现在开始使能网卡的接收功能,设置中断屏蔽寄存器。这里IMR_PAR=1000 0000b,将IMR寄存器的位7置“1”,使内存数据读取地址的高字节为0ch,即Memory Data Read_address Register F5。这样设置使得接收的数据从内部内存地址0x0c00处开始存放。
 
       while (!(phy_read(1) & 0x20)) {    /* auto-negotiation complete bit */
              udelay(1000);
              i++;
              if (i == 10000) {
                     printf("could not establish link/n");
                     return 0;
              }
       }
读取phy寄存器1,判断auto-negotiation是否完成。我前面贴子说的起动时特别慢原因就在这里。if (i == 10000)
这里判断的次数太多,延长的等待时间。如果auto-negotiation完成的快,这里是多少也就无所谓了。
 
下面看一下phy_read(1)这个函数
 
static u16
phy_read(int reg)
{
       u16 val;
 
       /* Fill the phyxcer register into REG_0C */
       DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
       DM9000_iow(DM9000_EPCR, 0xc);      /* Issue phyxcer read command */
       udelay(100);              /* Wait read complete */
       DM9000_iow(DM9000_EPCR, 0x0);      /* Clear phyxcer read command */
       val = (DM9000_ior(DM9000_EPDRH) << 8) | DM9000_ior(DM9000_EPDRL);
 
       /* The read data keeps on REG_0D & REG_0E */
       DM9000_DBG("phy_read(%d): %d/n", reg, val);
       return val;
}
这段代码是从PHY寄存器中读取一个字。读取的方法和读srom是一样的。但在细节上有些差别。在写PHY寄存器地址时要保证EPAR的第7、6位的值为01b。这样就选中PHY模式。在往EPCR寄存器中写读命令时要保证其位3为1。这也是为了选中PHY模式。
 
最后       lnk = phy_read(17) >> 12;
       printf("operating at ");
       switch (lnk) {
       case 1:
              printf("10M half duplex ");
              break;
       case 2:
              printf("10M full duplex ");
              break;
       case 4:
              printf("100M half duplex ");
              break;
       case 8:
              printf("100M full duplex ");
              break;
       default:
              printf("unknown: %d ", lnk);
              break;
       }
       printf("mode/n");
       读PHY寄存器17,检测其工作模式。
到些网卡初始化结束。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
FreeRTOS DM9000是一个基于FreeRTOS操作系统的网络驱动程序,用于与DM9000网络芯片通信。DM9000是一款集成了以太网控制器和MAC(媒体接入控制器)功能的芯片,可以轻松地与嵌入式系统集成,实现网络通信功能。 FreeRTOS DM9000的主要功能包括初始化DM9000芯片、发送和接收数据包、处理中断和错误等。通过该驱动程序,用户可以方便地在FreeRTOS操作系统上实现网络连接和数据传输,而无需过多关注底层硬件细节。 在使用FreeRTOS DM9000时,我们可以按照以下步骤进行操作:首先,需进行初始化设置,包括配置DM9000芯片的寄存器和寄存器位的值,以便正确地启动芯片。接下来,可以使用发送函数将数据包发送到网络中,并使用接收函数来接收从网络上接收到的数据包。发送和接收函数会自动处理帧封装和解封装的操作。在数据发送和接收的过程中,我们还可以使用中断处理函数来处理硬件中断和错误,以提供更好的系统响应性能和稳定性。 FreeRTOS DM9000的使用使得嵌入式系统可以方便地实现网络通信功能,可满足通信需求,提高系统的可扩展性和灵活性。同时,该驱动程序也提供了一些额外功能,如自动流量控制和数据包过滤,进一步增强了系统的性能和安全性。 总结而言,FreeRTOS DM9000是一个用于在FreeRTOS操作系统上实现网络通信功能的驱动程序,通过与DM9000芯片集成,提供了方便、高效的网络数据传输解决方案。使用FreeRTOS DM9000可以使嵌入式系统具备网络连接能力,满足各种通信需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值