Sitemap

TwinCAT3 EtherCAT Packet Capture | Technical Collection

9 min readMay 23, 2025

--

When testing the EtherCAT EOE (EtherCAT Over EtherCAT) functionality using TwinCAT, we often find that it is not possible to capture EtherCAT packets with Wireshark in normal operation. This article will guide you through the method of capturing EtherCAT packets.

Preparation Environment

Hardware:

● EtherKit Development Board(EtherKit)

● One Ethernet cable

● One Type-C USB cable

Software:

● TwinCAT3

● RT-Thread Studio

● Wireshark

Download the EtherCAT EOE Project

First, install the EtherKit SDK package in RT-Thread Studio. Then, create a new sample project named `etherkit_ethercat_eoe`, compile it, and upload the program to the device.

Connect one end of the Ethernet cable from the computer to EtherKit’s ETH0 port. Then, modify the Ethernet adapter’s IP address to ensure it is in the same subnet as the slave device’s IP address.

Observe the serial port status of the development board. At this point, you should see that the EOE application is running normally.

TwinCAT3 Simulation of EtherCAT Master Startup

During the startup process of TwinCAT3, it is also necessary to configure the ESI file and install the TwinCAT driver. You can refer to the EtherKit user manual for detailed instructions; these steps will not be elaborated here.

Next, the master scans for slave devices and activates the slave device:

After activating the slave device, you will see that the onboard Ethernet indicator on the EtherKit development board is functioning normally. Additionally, the default slave DC mode is set to SM-Synchron.

Configuring DC-Synchron in TwinCAT3

First, we need to enable Wireshark packet capture support. Right-click on the device, then in the Adapter settings, check the “Promiscuous Mode (use with Wireshark only)” option to enable promiscuous mode.

Next, we need to switch the DC mode from the default SM-Synchron mode to DC-Synchron mode.

Then, click on the top navigation bar: TwinCAT -> Restart TwinCAT (Config Mode).

Prompt: “Restart TwinCAT system in config mode,” click OK.

The shell will then prompt: “Load IO devices,” click OK.

Finally, click on “Activate.”

Next, we switch back to SM-Synchron mode and open Wireshark. Select the corresponding network interface device, and at this point, you will be able to see the ECAT message.

EtherCAT Data Frame Structure

EtherCAT data is transmitted directly using Ethernet frames, with a frame type of 0x88A4. An EtherCAT data packet consists of a 2-byte data header and 44 to 1498 bytes of data. The data section is composed of one or multiple EtherCAT subframes, each corresponding to an individual device or slave’s memory area.

EtherCAT Frame Structure Definition

EtherCAT Frame Structure Definition

Each EtherCAT subframe includes a subframe header, data field, and the corresponding Working Counter (WKC). The WKC records the number of times the subframe has been operated on by the slave. The master sets an expected WKC for each communication service subframe, with the initial value of the WKC in the transmitted subframe set to 0. After the slave correctly processes the subframe, the working counter increments by one. The master compares the returned WKC with the expected WKC to determine whether the subframe was processed correctly. The WKC is managed by the EtherCAT Slave Controller (ESC) during data frame processing, and different communication services have different methods of increasing the WKC.

EtherCAT Subframe Structure Definition

EtherCAT Packet Analysis

1. Request Packet

First, we set up a filter rule:

`ecat.cmd==BRD && ecat.ado==0x130`

We randomly capture a BRD packet, which is a packet sent from the master to the slave with an offset address of 0x130. This indicates a read operation of specific registers on the slave (such as device identifiers, status words, etc.). Such packets are commonly used during system initialization or status monitoring.

2. Response Packet

Slave startup process: The master sequentially sends commands to offset address 0x120 with values 1, 2, 4, 8, controlling the slave to enter Initialization (INIT), Pre-Operational (PRE-OP), Safe-Operational (SAFE-OP), and Operational (OP) modes:

`ecat.ado==0x120 && (ecat.adp==0x03e9 || ecat.adp==0xffff)`

Where `ecat.adp==0xffff` indicates a broadcast, meaning the master sends commands to all slaves; while `ecat.adp==0x03e9` (for example) specifies a specific slave address (which can be modified based on actual addresses).

3. Control Commands and EOE Packet Filtering

We use the following filter rules to capture EtherCAT control commands and Ethernet over EtherCAT (EOE) encapsulated packets:

`(ecat.ado==0x120 || ecat_mailbox.eoe) && (ecat.adp==0x03e9 || ecat.adp==0xffff)`

Explanation:

● `ecat.ado==0x120`: captures commands accessing the register at offset 0x120, which is the slave status control register. The master uses this to send mode switch commands (e.g., INIT, PRE-OP, SAFE-OP, OP) to the slave.

● `ecat_mailbox.eoe`: captures all Ethernet frames encapsulated with EOE protocol, which allows standard Ethernet frames (e.g., TCP/IP, UDP) to be transmitted over EtherCAT.

● `ecat.adp==0x03e9`: specifies a slave address of 0x03e9 (decimal 1001), used for point-to-point communication with a specific slave.

● `ecat.adp==0xffff`: indicates a broadcast command, where the master simultaneously initiates operations with all slaves.

Application Scenarios

This filtering rule can be used to simultaneously monitor:

● The master’s control over a specific slave (or all slaves) regarding their working mode;

● Data frames transmitted via EOE protocol (commonly used for EtherCAT slaves that communicate via TCP/IP, such as remote I/O modules with IP interfaces or industrial cameras).

Below is an example of actual Wireshark packet captures:

4. EtherCAT EOE Packet Capture TCP Messages

First, modify the `src/hal_entry.c` file located in the project directory by replacing its entire content with the following code:

   /*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-03-11 Wangyuqiang first version
*/
#include <rtthread.h>
#include "hal_data.h"
#include <rtdevice.h>
#include <board.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <finsh.h>
#define BUFSZ (1024)
static const char send_data[] = "This is TCP Server from RT-Thread.";
void hal_entry(void)
{
rt_kprintf("\nHello RT-Thread!\n");
rt_kprintf("==================================================\n");
rt_kprintf("This example project is an ethercat eoe routine!\n");
rt_kprintf("==================================================\n");
}
static void tcpserv(void *parameter)
{
char *recv_data; /* 用于接收的指针,后面会做一次动态分配以请求可用内存 */
socklen_t sin_size;
int sock, connected, bytes_received;
struct sockaddr_in server_addr, client_addr;
rt_bool_t stop = RT_FALSE; /* 停止标志 */
int ret;
recv_data = rt_malloc(BUFSZ + 1); /* 分配接收用的数据缓冲 */
if (recv_data == RT_NULL)
{
rt_kprintf("No memory\n");
return;
}
/* 一个socket在使用前,需要预先创建出来,指定SOCK_STREAM为TCP的socket */
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
/* 创建失败的错误处理 */
rt_kprintf("Socket error\n");
/* 释放已分配的接收缓冲 */
rt_free(recv_data);
return;
}
/* 初始化服务端地址 */
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(5000); /* 服务端工作的端口 */
server_addr.sin_addr.s_addr = INADDR_ANY;
rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
/* 绑定socket到服务端地址 */
if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
{
/* 绑定失败 */
rt_kprintf("Unable to bind\n");
/* 释放已分配的接收缓冲 */
rt_free(recv_data);
return;
}
/* 在socket上进行监听 */
if (listen(sock, 5) == -1)
{
rt_kprintf("Listen error\n");
/* release recv buffer */
rt_free(recv_data);
return;
}
rt_kprintf("\nTCPServer Waiting for client on port 5000...\n");
while (stop != RT_TRUE)
{
sin_size = sizeof(struct sockaddr_in);
/* 接受一个客户端连接socket的请求,这个函数调用是阻塞式的 */
connected = accept(sock, (struct sockaddr *)&client_addr, &sin_size);
/* 返回的是连接成功的socket */
if (connected < 0)
{
rt_kprintf("accept connection failed! errno = %d\n", errno);
continue;
}
/* 接受返回的client_addr指向了客户端的地址信息 */
rt_kprintf("I got a connection from (%s , %d)\n",
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
/* 客户端连接的处理 */
while (1)
{
/* 发送数据到connected socket */
ret = send(connected, send_data, strlen(send_data), 0);
if (ret < 0)
{
/* 发送失败,关闭这个连接 */
closesocket(connected);
rt_kprintf("\nsend error,close the socket.\r\n");
break;
}
else if (ret == 0)
{
/* 打印send函数返回值为0的警告信息 */
rt_kprintf("\n Send warning,send function return 0.\r\n");
}
/* 从connected socket中接收数据,接收buffer是1024大小,但并不一定能够收到1024大小的数据 */
bytes_received = recv(connected, recv_data, BUFSZ, 0);
if (bytes_received < 0)
{
/* 接收失败,关闭这个connected socket */
closesocket(connected);
break;
}
else if (bytes_received == 0)
{
/* 打印recv函数返回值为0的警告信息 */
rt_kprintf("\nReceived warning,recv function return 0.\r\n");
closesocket(connected);
break;
}
/* 有接收到数据,把末端清零 */
recv_data[bytes_received] = '\0';
if (strcmp(recv_data, "q") == 0 || strcmp(recv_data, "Q") == 0)
{
/* 如果是首字母是q或Q,关闭这个连接 */
closesocket(connected);
break;
}
else if (strcmp(recv_data, "exit") == 0)
{
/* 如果接收的是exit,则关闭整个服务端 */
closesocket(connected);
stop = RT_TRUE;
break;
}
else
{
/* 在控制终端显示收到的数据 */
rt_kprintf("RECEIVED DATA = %s \n", recv_data);
}
}
}
/* 退出服务 */
closesocket(sock);
/* 释放接收缓冲 */
rt_free(recv_data);
return ;
}
static int tcpserv_app(void)
{
rt_thread_t tcps = rt_thread_create("tcpserv", tcpserv, RT_NULL, 2048, 18, 10);
if(tcps != RT_NULL)
{
rt_thread_startup(tcps);
}
return 0;
}

After compiling, downloading, and reprogramming the device, and once the slave has successfully connected to the master, execute the `tcpserv_app` command to start a TCP server:

At the same time, open the TCP testing software and configure the TCP client with the following information:

Target IP: 192.168.10.100 (slave device IP)

Target Port: 5000

Also, open Wireshark and observe that TCP packets within the EtherCAT EOE network are successfully captured.

Appendix 1: EtherCAT Communication Service Commands

All EtherCAT subframe services are described from the master’s perspective. The data link layer defines the services for internal physical storage, reading, writing, and exchanging data within the slave device (reading data and immediately writing it back). The type of communication service of a subframe is jointly determined by the read/write operations and addressing mode, represented by the command byte in the subframe header:

When the master receives a response data frame, it inspects the WKC (Working Counter) within the subframe. If the WKC does not match the expected value, it indicates that the subframe was not processed correctly. The expected WKC value depends on the type of communication service and the addressing mode.

For a subframe processed by a single slave:

● If it is a read or write operation alone, WKC increments by 1 upon success.

● If it is a combined read/write operation:

● WKC increments by 1 if the read is successful.

● WKC increments by 2 if the write is successful.

● WKC increments by 3 when both read and write are completed successfully.

When multiple slaves process a single subframe, the WKC is the cumulative sum of the individual results from each slave.

Appendix 2: EtherCAT Status Codes

--

--

RT-Thread IoT OS
RT-Thread IoT OS

Written by RT-Thread IoT OS

An Open-Source Community-Powered Real-Time Operating System (RTOS) Project! Let’s develop, DIY, create, share, and explore this new IoT World together!

No responses yet