Example for Beckhoff DIO slaves

From Neuromeka Wiki
Jump to: navigation, search


Beckhoff EL1008 and EL2008 are EtherCAT slaves for digital input and output, each of eight channels. We will implement an application executing DIO on these devices using EtherCAT interfaces based on NRMK EtherCAT framework.


Generating EtherCAT slave configuration by ethercattool

  • By command ./ethercattool slaves one can identify the slaves on the bus with their alias and position. Note that there are three EL1008 slaves (at positions 2, 3, and 4) and four EL2008 slaves (at position 5, 6, 7, and 8).


Slave configurations of Beckhoff DIO modules

Slave configurations of Beckhoff DIO modules


  • By command ./ethercattool cstruct -p2 one can generate C interface file for an EL1008 slave (at position 2). This interface will be used to configure all three EL1008 slaves. Note that there are eight TxPDO mappings of indices from 0x1A00 to 0x1A07. All these should be transmitted to the master to get all DI signals.


C interface for Beckhoff EL1008 slave

C interface for Beckhoff EL1008 slave at position 2


  • Generate C interface file, named Beckhoff_EL1008_PDO.c and Beckhoff_EL1008_PDO.h. Note that each variable has been named to indicate the vendor and product directly.
#include "Beckhoff_EL1008_PDO.h" 

ec_pdo_entry_info_t Beckhoff_EL1008_pdo_entries[] = 
{ 
	{0x6000, 1, 1},	/* Input */
	{0x6010, 1, 1},	/* Input */
	{0x6020, 1, 1},	/* Input */
	{0x6030, 1, 1},	/* Input */
	{0x6040, 1, 1},	/* Input */
	{0x6050, 1, 1},	/* Input */
	{0x6060, 1, 1},	/* Input */
	{0x6070, 1, 1},	/* Input */
};

ec_pdo_info_t Beckhoff_EL1008_pdos[] = 
{ 
	{0x1a00, 1, Beckhoff_EL1008_pdo_entries + 0},	/* TxPDO TxPDO_Beckhoff_EL1008_0x1a00 */
	{0x1a01, 1, Beckhoff_EL1008_pdo_entries + 1},	/* TxPDO TxPDO_Beckhoff_EL1008_0x1a01 */
	{0x1a02, 1, Beckhoff_EL1008_pdo_entries + 2},	/* TxPDO TxPDO_Beckhoff_EL1008_0x1a02 */
	{0x1a03, 1, Beckhoff_EL1008_pdo_entries + 3},	/* TxPDO TxPDO_Beckhoff_EL1008_0x1a03 */
	{0x1a04, 1, Beckhoff_EL1008_pdo_entries + 4},	/* TxPDO TxPDO_Beckhoff_EL1008_0x1a04 */
	{0x1a05, 1, Beckhoff_EL1008_pdo_entries + 5},	/* TxPDO TxPDO_Beckhoff_EL1008_0x1a05 */
	{0x1a06, 1, Beckhoff_EL1008_pdo_entries + 6},	/* TxPDO TxPDO_Beckhoff_EL1008_0x1a06 */
	{0x1a07, 1, Beckhoff_EL1008_pdo_entries + 7},	/* TxPDO TxPDO_Beckhoff_EL1008_0x1a07 */
};

ec_sync_info_t Beckhoff_EL1008_syncs[] = 
{ 
	{0, EC_DIR_INPUT, 8, Beckhoff_EL1008_pdos + 0, EC_WD_ENABLE}, 
	{0xff} 
};
#pragma once 

// Ethercat Master---- 
#include "ecrt.h" 

// Vendor ID & Product Code 
#define Beckhoff 2 
#define Beckhoff_EL1008 0x03f03052 

extern ec_pdo_entry_info_t Beckhoff_EL1008_pdo_entries[]; 
extern ec_pdo_info_t  Beckhoff_EL1008_pdos[]; 
extern ec_sync_info_t   Beckhoff_EL1008_syncs[]; 


  • By command ./ethercattool cstruct -p5 one can generate C interface file for an EL2008 slave (at position 5).

This interface will be used to configure all four EL2008 slaves. Note that there are eight RxPDO mappings of indices from 0x1600 to 0x1607. All these should be transmitted to the master to set all DO signals.

C interface for Beckhoff EL1008 slave

C interface for Beckhoff EL2008 slave at position 5

  • Generate C interface file, named Beckhoff_EL2008_PDO.c and Beckhoff_EL2008_PDO.h. Note that each variable has been named to indicate the vendor and product directly.
#include "Beckhoff_EL2008_PDO.h" 

#include "Beckhoff_EL2008_PDO.h" 

ec_pdo_entry_info_t Beckhoff_EL2008_pdo_entries[] = 
{ 
	{0x7000, 1, 1},	/* Output */
	{0x7010, 1, 1},	/* Output */
	{0x7020, 1, 1},	/* Output */
	{0x7030, 1, 1},	/* Output */
	{0x7040, 1, 1},	/* Output */
	{0x7050, 1, 1},	/* Output */
	{0x7060, 1, 1},	/* Output */
	{0x7070, 1, 1},	/* Output */
};

ec_pdo_info_t Beckhoff_EL2008_pdos[] = 
{ 
	{0x1600, 1, Beckhoff_EL2008_pdo_entries + 0},	/* RxPDO RxPDO_Beckhoff_EL2008_0x1600 */
	{0x1601, 1, Beckhoff_EL2008_pdo_entries + 1},	/* RxPDO RxPDO_Beckhoff_EL2008_0x1601 */
	{0x1602, 1, Beckhoff_EL2008_pdo_entries + 2},	/* RxPDO RxPDO_Beckhoff_EL2008_0x1602 */
	{0x1603, 1, Beckhoff_EL2008_pdo_entries + 3},	/* RxPDO RxPDO_Beckhoff_EL2008_0x1603 */
	{0x1604, 1, Beckhoff_EL2008_pdo_entries + 4},	/* RxPDO RxPDO_Beckhoff_EL2008_0x1604 */
	{0x1605, 1, Beckhoff_EL2008_pdo_entries + 5},	/* RxPDO RxPDO_Beckhoff_EL2008_0x1605 */
	{0x1606, 1, Beckhoff_EL2008_pdo_entries + 6},	/* RxPDO RxPDO_Beckhoff_EL2008_0x1606 */
	{0x1607, 1, Beckhoff_EL2008_pdo_entries + 7},	/* RxPDO RxPDO_Beckhoff_EL2008_0x1607 */
};

ec_sync_info_t Beckhoff_EL2008_syncs[] = 
{ 
	{0, EC_DIR_OUTPUT, 8, Beckhoff_EL2008_pdos + 0, EC_WD_ENABLE}, 
	{0xff} 
};
#pragma once 

// Ethercat Master---- 
#include "ecrt.h" 

// Vendor ID & Product Code 
#define Beckhoff 2 
#define Beckhoff_EL2008 0x07d83052 

extern ec_pdo_entry_info_t Beckhoff_EL2008_pdo_entries[]; 
extern ec_pdo_info_t  Beckhoff_EL2008_pdos[]; 
extern ec_sync_info_t   Beckhoff_EL2008_syncs[]; 


Implementing EcatSlaveBase and EcatPDOBase

  • You have to include NRMK EtherCAT framework interface EtherCAT.h and C interface files for slave types.


#pragma once 
#include "EtherCAT.h" 

#include "Beckhoff_EL1008_PDO.h" 

namespace NRMKHelper
{
	// Implement your custom slave types

	// Implement your custom domain PDO types

	// Implement your custom domains and EtherCAT interface
}


  • Implement a custom slave type (within NRMKHelper namespace) by inheriting EcatSlaveBase.


class Slave_Beckhoff_EL1008 : public EcatSlaveBase 
{ 
public: 
	inline Slave_Beckhoff_EL1008() : EcatSlaveBase() 
	{ 
		setVendorProduct(Beckhoff, Beckhoff_EL1008); 
		setSyncManagers(Beckhoff_EL1008_syncs); 
	} 
}; 

class Slave_Beckhoff_EL2008 : public EcatSlaveBase 
{ 
public: 
	inline Slave_Beckhoff_EL2008() : EcatSlaveBase() 
	{ 
		setVendorProduct(Beckhoff, Beckhoff_EL2008); 
		setSyncManagers(Beckhoff_EL2008_syncs); 
	} 
};


  • Implement a custom domain PDO type (within NRMKHelper namespace) by inheriting EcatPDOBase.
    • Since one can access all eight bits by just one byte operation we only expose the first PDO mapping in the domain PDO definitions.
    • The application can interface these signals easily by DI or DO (of type UINT8).


#define NUM_OBJECTS_RxPDO_Beckhoff_EL2008_0x1600 1

struct RxPDO_Beckhoff_EL2008_0x1600 
	: public EcatPDOBase<NUM_OBJECTS_RxPDO_Beckhoff_EL2008_0x1600> 
{ 
	UINT8 DO; 

	inline RxPDO_Beckhoff_EL2008_0x1600() 
		: EcatPDOBase<NUM_OBJECTS_RxPDO_Beckhoff_EL2008_0x1600>(Beckhoff_EL2008_pdo_entries + 0, Beckhoff_EL2008_pdos + 0) 
	{ 
	}
};

#define NUM_OBJECTS_TxPDO_Beckhoff_EL1008_0x1a00 1

struct TxPDO_Beckhoff_EL1008_0x1a00 
	: public EcatPDOBase<NUM_OBJECTS_TxPDO_Beckhoff_EL1008_0x1a00> 
{ 
	UINT8 DI; 

	inline TxPDO_Beckhoff_EL1008_0x1a00() 
		: EcatPDOBase<NUM_OBJECTS_TxPDO_Beckhoff_EL1008_0x1a00>(Beckhoff_EL1008_pdo_entries + 0, Beckhoff_EL1008_pdos + 0) 
	{ 
	}
};


  • Implement a custom domains (within NRMKHelper namespace) by inheriting EcatDomainBase.
    • The main EtherCAT interface type is named EtherCAT_Beckhoff_DIO. It comprises all slaves, all domain PDO mappings and necessary domains.
    • For this interface we will separate RxPDOs and TxPDOs in each domain. So we will implement two domains (nested in the main EtherCAT interface type).
class EtherCAT_Beckhoff_DIO 
{ 
public: 
	enum 
	{ 
		NUM_BECKHOFF_EL1008_SLAVES = 3,
		NUM_BECKHOFF_EL2008_SLAVES = 4,

		NUM_RXDOMAIN_SLAVES = 4,
		NUM_RXDOMAIN_ENTRIES = 4,
				
		NUM_TXDOMAIN_SLAVES = 3,
		NUM_TXDOMAIN_ENTRIES = 3,
	};

	class RxDomain : public EcatDomainBase<NUM_RXDOMAIN_SLAVES, NUM_RXDOMAIN_ENTRIES> 
	{ 
	public: 
		inline void setPDOs(RxPDO_Beckhoff_EL2008_0x1600 * rxPDO) 
		{ 
			_rxPDO = rxPDO; 
		} 

	private: 
		virtual void _processSetData() 
		{ 
			for (int k = 0; k < NUM_RXDOMAIN_SLAVES; ++k)
			{
				EC_WRITE_U8(_domain_pd + _rxPDO[k].offset(0), _rxPDO[k].DO);
			}
		} 

	private: 
		RxPDO_Beckhoff_EL2008_0x1600 * _rxPDO; 

		using EcatDomainBase<NUM_RXDOMAIN_SLAVES, NUM_RXDOMAIN_ENTRIES>:: _domain_pd; 
	}; 

	class TxDomain : public EcatDomainBase<NUM_TXDOMAIN_SLAVES, NUM_TXDOMAIN_ENTRIES> 
	{ 
	public: 
		inline void setPDOs(TxPDO_Beckhoff_EL1008_0x1a00 * txPDO) 
		{ 
			_txPDO = txPDO; 
		} 

	private: 
		virtual void _processGetData() 
		{ 
			for (int k = 0; k < NUM_TXDOMAIN_SLAVES; ++k)
			{
				_txPDO[k].DI = EC_READ_U8(_domain_pd + _txPDO[k].offset(0));
			}
		} 

	private: 
		TxPDO_Beckhoff_EL1008_0x1a00 * _txPDO; 

		using EcatDomainBase<NUM_TXDOMAIN_SLAVES, NUM_TXDOMAIN_ENTRIES>:: _domain_pd; 
	}; 

public: 
	inline EtherCAT_Beckhoff_DIO(EcatMaster & master) : _master(master) 
	{ 
		_rxDomain.setPDOs(_rxPDO_RxDomain_RxPDO_Beckhoff_EL2008_0x1600); 
		_txDomain.setPDOs(_txPDO_TxDomain_TxPDO_Beckhoff_EL1008_0x1a00); 

		setSlavePosition(); 
	} 

	inline void setSlavePosition() 
	{ 
		 _beckhoff_EL1008_slaves[0].setAliasPosition(0, 2); 
		 _beckhoff_EL1008_slaves[1].setAliasPosition(0, 3); 
		 _beckhoff_EL1008_slaves[2].setAliasPosition(0, 4); 
		 _beckhoff_EL2008_slaves[0].setAliasPosition(0, 5); 
		 _beckhoff_EL2008_slaves[1].setAliasPosition(0, 6); 
		 _beckhoff_EL2008_slaves[2].setAliasPosition(0, 7); 
		 _beckhoff_EL2008_slaves[3].setAliasPosition(0, 8); 
	} 

	inline int setup() 
	{ 
		// Setup slaves 
		printf("Now trying to setup slaves...\n"); 
		for (int k=0; k < NUM_BECKHOFF_EL1008_SLAVES; k++ ) 
		{ 
			if (_beckhoff_EL1008_slaves[k].setup(_master) == -1) 
			{ 
				printf("Setting _beckhoff_EL1008_slaves[%d] failed...\n", k); 
				return -1; 
			} 
			else 
				_beckhoff_EL1008_slaves[k].checkState(); 
		} 

		for (int k=0; k < NUM_BECKHOFF_EL2008_SLAVES; k++ ) 
		{ 
			if (_beckhoff_EL2008_slaves[k].setup(_master) == -1) 
			{ 
				printf("Setting _beckhoff_EL2008_slaves[%d] failed...\n", k); 
				return -1; 
			} 
			else 
				_beckhoff_EL2008_slaves[k].checkState(); 
		} 

		// Create domain 
		if (_rxDomain.beginPDOEntryReg(_master) == -1) 
		{ 
			printf("Creating _rxDomain failed... \n"); 
			return -1; 
		} 

		if (_txDomain.beginPDOEntryReg(_master) == -1) 
		{ 
			printf("Creating _txDomain failed... \n"); 
			return -1; 
		} 

		// Setup domain registration list 
		printf("Now trying to register _rxDomain...\n"); 
		for (int k=0; k < NUM_BECKHOFF_EL2008_SLAVES; k++ ) 
		{ 
			_rxDomain.setPDOEntryReg(_beckhoff_EL2008_slaves[k], _rxPDO_RxDomain_RxPDO_Beckhoff_EL2008_0x1600[k]); 
		} 

		printf("Now trying to register _txDomain...\n"); 
		for (int k=0; k < NUM_BECKHOFF_EL1008_SLAVES; k++ ) 
		{ 
			_txDomain.setPDOEntryReg(_beckhoff_EL1008_slaves[k], _txPDO_TxDomain_TxPDO_Beckhoff_EL1008_0x1a00[k]); 
		} 

		// Then, finalize registration 
		// Every domain must be created before any registration 
		if (_rxDomain.finishPDOEntryReg() == -1) 
		{ 
			printf("Registering _rxDomain failed... \n"); 
			return -1; 
		} 

		if (_txDomain.finishPDOEntryReg() == -1) 
		{ 
			printf("Registering _txDomain failed... \n"); 
			return -1; 
		} 

		// Master should be activated (for cyclic task)
		// Then no configuration can change. 
		if (_master.activate() == -1) 
			return -1; 

		// Now, acquire the pointer to the domain data... 
		printf("Now trying to get the domain pointers...\n"); 
		if (_rxDomain.acquireDomainDataPtr() == -1) 
			return -1; 

		if (_txDomain.acquireDomainDataPtr() == -1) 
			return -1; 

		// Finally check the states. 
		_master.checkState(); 
		_rxDomain.checkState(); 
		_txDomain.checkState(); 

		return 0; 
	} 

	inline void cleanup() 
	{ 
		// TODO: Clear Data in PDO Entries 
		// _rxPDO[k].ControlWord = 0 
		for (unsigned int k = 0; k < NUM_BECKHOFF_EL2008_SLAVES; k++)
		{
			_rxPDO[k].DO = 0;
		}
	} 

	inline void readData() 
	{ 
		// TODO: Get Data from EtherCAT Master to domain 
		_txDomain.getData(_master);
	} 

	inline void writeData() 
	{ 
		// TODO: Write Data from domain to EtherCAT Master 
		_rxDomain.setData(_master);
	} 

	RxPDO_Beckhoff_EL2008_0x1600 & rxPDO_Beckhoff_EL2008_0x1600(int k) 
	{ 
		return _rxPDO[k]; 
	} 
	
	TxPDO_Beckhoff_EL1008_0x1a00 & txPDO_Beckhoff_EL1008_0x1a00(int k) 
	{ 
		return _txPDO[k]; 
	} 

private: 
	// PDOs 
	RxPDO_Beckhoff_EL2008_0x1600 _rxPDO[NUM_BECKHOFF_EL2008_SLAVES]; 
	TxPDO_Beckhoff_EL1008_0x1a00 _txPDO[NUM_BECKHOFF_EL1008_SLAVES]; 

	// Domains 
	RxDomain _rxDomain; 
	TxDomain _txDomain; 

	// Slaves 
	Slave_Beckhoff_EL1008 _beckhoff_EL1008_slaves[NUM_BECKHOFF_EL1008_SLAVES]; 
	Slave_Beckhoff_EL2008 _beckhoff_EL2008_slaves[NUM_BECKHOFF_EL2008_SLAVES]; 

	// Master instance 
	EcatMaster & _master; 
};

Creation of System Interface using the EtherCAT interface

  • System interface is a kind of abstraction layer which separates detailed device implementation from user applications.
  • Application can access the data and signals through system interface objects, rather than directly from EtherCAT interfaces.


 1 #pragma once 
 2 
 3 #include "SystemInterface_EtherCAT.h" 
 4 #include "EtherCAT_Beckhoff_DIO.h" 
 5 
 6 namespace NRMKHelper 
 7 { 
 8 	class SystemInterface_EtherCAT_Beckhoff_DIO : public SystemInterface_EtherCAT<EtherCAT_Beckhoff_DIO> 
 9 	{ 
10 	public: 
11 		enum 
12 		{ 
13 			NUM_BECKHOFF_EL1008_SLAVES = EtherCAT_Beckhoff_DIO::NUM_BECKHOFF_EL1008_SLAVES,
14 			NUM_BECKHOFF_EL2008_SLAVES = EtherCAT_Beckhoff_DIO::NUM_BECKHOFF_EL2008_SLAVES,
15 		};
16 
17 	public: 
18 		SystemInterface_EtherCAT_Beckhoff_DIO() 
19 		{ 
20 		} 
21 
22 		virtual void readByte(unsigned char * const data) 
23 		{ 
24 			_ecat->readData();
25 
26 			for(int k = 0; k < EtherCAT_Beckhoff_DIO::NUM_BECKHOFF_EL1008_SLAVES; ++k)
27 				data[k] = _ecat->txPDO_Beckhoff_EL1008_0x1a00(k).DI;
28 		} 
29 
30 		virtual void writeByte(unsigned char const * const data) 
31 		{ 
32 			for(int k = 0; k < EtherCAT_Beckhoff_DIO::NUM_BECKHOFF_EL2008_SLAVES; ++k)
33 				_ecat->rxPDO_Beckhoff_EL2008_0x1600(k).DO = data[k];
34 
35 			_ecat->writeData(); 
36 		} 
37 
38 		virtual void readData(float * const data) 
39 		{ 
40 		} 
41 
42 		virtual void writeData(float const * const data) 
43 		{ 
44 		} 
45 
46 	private: 
47 		using SystemInterface_EtherCAT<EtherCAT_Beckhoff_DIO>:: _ecat; 
48 	}; 
49 }

Application using EtherCAT interface

  • An example application reads all three DI channel, and sets blinking DOs.
  • Thanks to the system interface object the RT task handler can be implemented more or less independent of lower-level EtherCAT stuffs.


  1 #ifndef __XENO__
  2 #define __XENO__
  3 #endif
  4 
  5 #include <stdio.h>
  6 #include <stdlib.h>
  7 #include <signal.h>
  8 #include <unistd.h>
  9 #include <sys/mman.h>
 10 #include <string.h>		// string function definitions
 11 #include <fcntl.h>		// File control definitions
 12 #include <errno.h>		// Error number definitions
 13 #include <termios.h>	// POSIX terminal control definitions
 14 #include <time.h>		// time calls
 15 #include <sys/ioctl.h>
 16 #include <math.h>
 17 
 18 //-xenomai-///////////////////////////////////////////////////////////////
 19 #include <native/task.h>
 20 #include <native/timer.h>
 21 #include <native/mutex.h>
 22 #include <rtdk.h>		//The rdtk real-time printing library
 23 
 24 //EtherCAT Master ******************************************************************
 25 #include "ecrt.h"
 26 #include "SystemInterface_EtherCAT_Beckhoff_DIO.h"
 27 
 28 NRMKHelper::EcatMaster master;
 29 
 30 #define NUM_EL1008_SLAVES 3
 31 #define NUM_EL2008_SLAVES 4
 32 
 33 typedef NRMKHelper::SystemInterface_EtherCAT_Beckhoff_DIO SYSTEMINTERFACE_ECAT_DIO;
 34 SYSTEMINTERFACE_ECAT_DIO SystemInterface_DIO;
 35 
 36 unsigned char din[NUM_EL1008_SLAVES] = { 0 };
 37 unsigned char dout[NUM_EL2008_SLAVES] = { 0 };
 38 
 39 /****************************************************************************/
 40 
 41 RT_TASK DIO_task;
 42 unsigned int count = 0, hasstarted = 0;
 43 unsigned long fault_count = 0;
 44 long ethercat_time = 0, worst_time = 0, now, previous;
 45 
 46 // DIO task
 47 void DIO_run(void *arg)
 48 {
 49 	rt_task_set_periodic(NULL, TM_NOW, 1e6);
 50 
 51 	int i;
 52 	int working = 1;
 53 	unsigned int blink = 0;
 54 
 55 	while (working)
 56 	{
 57 		previous = rt_timer_read();
 58 
 59 		// Get data through SystemInterface
 60 		SystemInterface_DIO.readByte(din);
 61 
 62 		// Generate periodically blinking signals with phase-off
 63 		for (i = 0; i < NUM_EL2008_SLAVES; i += 2)
 64 		{
 65 			dout[i] = blink ? 0x0 : 0xFF;
 66 			dout[i + 1] = blink ? 0xFF : 0x0;
 67 		}
 68 
 69 		// Set data through SystemInterface
 70 		SystemInterface_DIO.writeByte(dout);
 71 
 72 		now = rt_timer_read();
 73 		ethercat_time = (long) now-previous;
 74 
 75 		if (hasstarted)
 76 		{
 77 			if (worst_time < ethercat_time)
 78 				worst_time = ethercat_time;
 79 		}
 80 
 81 		if (++count == 100)
 82 		{
 83 			blink ^=1;
 84 
 85 			if (hasstarted == 0)
 86 				hasstarted = 1;
 87 
 88 			for(i = 0; i < NUM_EL1008_SLAVES; ++i)
 89 			{
 90 				rt_printf("Drive %i: ", i);
 91 				rt_printf("value: 0x%x,  ", din[i]);
 92 			}
 93 
 94 			rt_printf("dt = %li, worst = %li\n", ethercat_time, worst_time);
 95 			count = 0;
 96 		}
 97 
 98 		rt_task_wait_period(NULL); //wait for next cycle
 99 	}
100 }
101 
102 void signal_handler(int signum = 0)
103 {
104 	rt_task_delete(&DIO_task);
105     	printf("Beckhoff EL1008 & EL2008 Stopped!\n");
106 
107     	SystemInterface_DIO.cleanup();
108     	master.release();
109 
110     	exit(1);
111 }
112 
113 /****************************************************************************/
114 int main(int argc, char **argv)
115 {
116 	// Perform auto-init of rt_print buffers if the task doesn't do so
117 	rt_print_auto_init(1);
118 	/* Avoids memory swapping for this program */
119 	mlockall(MCL_CURRENT|MCL_FUTURE);
120 
121 	signal(SIGINT, signal_handler);
122 	signal(SIGTERM, signal_handler);
123 
124 	// Acquire EtherCAT master instance
125 	master.request(0);
126 
127 	// Create EtherCAT Slaves
128 	NRMKHelper::EtherCAT_Beckhoff_DIO ecat_dio(master);
129 
130 	// ... and setup EtherCAT slaves
131 	if (ecat_dio.setup() == -1)
132 		printf("Failed to setup EtherCAT slaves...\n");
133 		
134 	// ... and system interface
135 	SystemInterface_DIO.setSlaveInfo(&ecat_dio);
136 
137 	rt_task_create(&DIO_task, "DIO test", 0, 99, 0);
138 	rt_task_start(&DIO_task, &DIO_run, NULL);
139 	pause();
140 
141 	signal_handler();
142     
143 	return 0;
144 }