EtherCAT主站实时性分析


一、实时性的意义

   在主从DC同步模式下,主站需要以非常精准的时间发送过程数据,如下图所示:

EtherCAT主站实时性分析_第1张图片



二、实时性的关键

    如下图所示,影响实时性的关键因素是操作系统和网卡驱动,前者需要将过程数据准时送出,后者需要优化网卡驱动,即"准时出发,路上不能耽误"。

EtherCAT主站实时性分析_第2张图片

操作系统的实时性体现在需要非常准时地调用EtherCAT主站协议栈的发送函数,例如SOEM的发送函数是ecx_send_processdata()

Etherlab的发送函数为ecrt_master_send()。

采用Linux系统时,需要打上实时补丁,如Xenomai、RTAI、OSADL等。

标准Linux下的网卡驱动是为通用的网络通信设计的,网络数据穿过TCP/IP协议栈是一个非常漫长的过程,其中包括各种安全性检查、路由、出入队列、分片和重组等等,这其中有很多的不确定性,所以在EtherCAT主站开发中需要优化网卡驱动,使EtherCAT数据

绕过TCP/IP协议栈。


三、移植网卡驱动

在Etherlab的说明文档中给出了改造标准网卡驱动的三个基本点,如下:

(1)禁用netif_*()

(2)禁用中断

(3)重复利用socket buffer

接下来以EtherLAB源码中移植好的网卡驱动RealTek RTL-8139为例进行说明。

1、禁用netif_*()

在网卡驱动程序中的接收函数rtl8139_rx()中,netif_receive_skb (skb)负责将数据包传递给TCP/IP协议栈,

将其改成由EtherCAT主站直接处理。

改造前:

//8139too-3.4-orig.c

static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp,
        int budget)
{

    ......

    netif_receive_skb (skb);//将数据包提交给TCP/IP协议栈处理

   ......

}


改造后:

//8139too-3.4-ethercat.c

static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp,
        int budget)
{

   ......

  if (tp->ecdev) {                                         //作为EtherCAT使用时直接交给EtherCAT协议栈处理,绕过TCP/IP协议栈
   ecdev_receive(tp->ecdev,
     &rx_ring[ring_offset + 4], pkt_size);
     dev->last_rx = jiffies;
     dev->stats.rx_bytes += pkt_size;
     dev->stats.rx_packets++;
   }

  else

  {

    ......

    netif_receive_skb (skb);

    ......

  }

}

2. 禁用中断

  Linux标准网卡驱动中,采用中断方式收发网络数据包,较新的网卡驱动中采用NAPI(中断和轮询相结合),而EtherCAT通信中,EtherCAT主站发出过程数据包后,主站非常清楚数据包什么时候返回主站,因此不需要采用中断的方式,而由主站直接查询和处理返回的过程数据包。

改造前:

//8139too-3.4-orig.c

static int rtl8139_open (struct net_device *dev)

{

     ......

    retval = request_irq (dev->irq, rtl8139_interrupt, IRQF_SHARED, dev->name, dev); //向内核注册中断

    ......

}


改造后:

//8139too-3.4-ethercat.c

static int rtl8139_open (struct net_device *dev)
{

   ......

 if (!tp->ecdev) {
  retval = request_irq(dev->irq, rtl8139_interrupt,        //作为普通网卡时才注册中断
   IRQF_SHARED, dev->name, dev);
  if (retval)
   return retval;
 }

  ......

}

void ec_poll(struct net_device *dev)
{
 rtl8139_interrupt(0, dev);
}

函数调用关系为:ec_poll()->rtl8139_interrupt()->rtl8139_rx()->ecdev_receive();


3. 重复利用Socket buffer

   Linux标准网卡驱动中,将数据包发送后将释放数据包所占用的内存,或者放回预先分配的内存池中,

而EtherCAT通信中,只需重复使用其中的一两个缓存即可,这样可以节省为数据包分配和释放内存的时间。

改造前:

//8139too-3.4-orig.c

static netdev_tx_t rtl8139_start_xmit (struct sk_buff *skb,
          struct net_device *dev)
{

  ......

  dev_kfree_skb(skb);//释放Socket buffer所占内存或将其放回内存池

  ......

}


改造后:

//8139too-3.4-ethercat.c

static netdev_tx_t rtl8139_start_xmit (struct sk_buff *skb,
          struct net_device *dev)
{

   ......

     if (!tp->ecdev) {      //只有作为普通网卡时才释放Socket buffer
   dev_kfree_skb(skb);
  }

   ......

}





你可能感兴趣的:(EtherCAT)