Hello,

First of all, thanks a lot for the very quick answer, I'm having much more help from this ml than from Beckhoff :-) I did basically the same thing in the same way except that I get the "magic" string sniffing with wireshark rather than grepping it from xml file, but I can't reach the OP state of the slave.
I can see this with dmesg


[83843.104993] EtherCAT 0: Starting EtherCAT-IDLE thread.
[83843.114523] EtherCAT 0: Link state changed to UP.
[83843.116794] EtherCAT 0: 6 slave(s) responding.
[83843.116808] EtherCAT 0: Slave states: PREOP.
[83843.117520] EtherCAT 0: Scanning bus.
[83843.120591] ADDRCONF(NETDEV_UP): eth0: link is not ready
[83843.124308] e100: eth0 NIC Link is Up 100 Mbps Full Duplex
[83843.124632] ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
[83844.128302] EtherCAT 0: Bus scanning completed in 1012 ms.
[83850.666172] EtherCAT: Requesting master 0...
[83850.666189] EtherCAT: Successfully requested master 0.
[83850.900986] EtherCAT 0: Domain0: Logical address 0x00000000, 3 byte, expected working counter 4. [83850.901003] EtherCAT 0: Datagram domain0-0: Logical offset 0x00000000, 3 byte, type LRW.
[83850.903482] EtherCAT 0: Master thread exited.
[83850.903503] EtherCAT 0: Starting EtherCAT-OP thread.
[83850.980790] RTAI/LXRT: Unknown srq #1014
[83850.988379] EtherCAT WARNING 0: No app_time received up to now, but master already active.
[83851.043722] EtherCAT 0: Domain 0: Working counter changed to 1/4.
[83851.235835] EtherCAT ERROR 0-5: SDO upload 0x1600:00 aborted.
[83851.235853] EtherCAT ERROR 0-5: SDO abort message 0x06020000: "This object does not exist in the object directory". [83851.235864] EtherCAT ERROR 0-5: Failed to read number of mapped PDO entries. [83851.235874] EtherCAT WARNING 0-5: Failed to read PDO entries for PDO 0x1600. [83851.235883] EtherCAT WARNING 0-5: Slave does not support changing the PDO mapping! [83851.235892] EtherCAT WARNING 0-5: Currently mapped PDO entries: (none). Entries to map: 0x7000:01/8 0x0000:00/8 [83851.273856] EtherCAT ERROR 0-5: Failed to set SAFEOP state, slave refused state change (PREOP + ERROR). [83851.275817] EtherCAT ERROR 0-5: AL status message 0x001D: "Invalid output configuration".
[83851.279859] EtherCAT 0-5: Acknowledged state PREOP.
[83851.284209] EtherCAT 0: Slave states: PREOP, OP.
[83852.044703] EtherCAT 0: Domain 0: 2 working counter changes - now 4/4.


Another question ...
How did you get the piece of code below ?
I have it for my slave, but I followed a bad way, I've detached the RJ45 cable after the node has been started from twincat and quickly plugged it on my master and read the config with "ethercat cstruct" command.
Which is the right way to have it ?


/*****************************************************************************/

/* Master 0, Slave 1, "EL6731-0010"
 * Vendor ID:       0x00000002
 * Product code:    0x1a4b3052
 * Revision number: 0x0011000a
 */

ec_pdo_entry_info_t slave_1_pdo_entries[] = {
    {0x7000, 0x01, 160},
    {0x6000, 0x01, 160},
    {0xa000, 0x01, 8},
    {0xf100, 0x02, 1},
    {0xa000, 0x02, 1},
    {0x0000, 0x00, 6},
};

ec_pdo_info_t slave_1_pdos[] = {
    {0x1600, 1, slave_1_pdo_entries + 0}, /* DPS RxPDO-Map Slave     */
    {0x1a00, 1, slave_1_pdo_entries + 1}, /* DPS TxPDO-Map Slave     */
    {0x1a80, 4, slave_1_pdo_entries + 2},
};

ec_sync_info_t slave_1_syncs[] = {
    {0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
    {1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
    {2, EC_DIR_OUTPUT, 1, slave_1_pdos + 0, EC_WD_DISABLE},
    {3, EC_DIR_INPUT, 2, slave_1_pdos + 1, EC_WD_DISABLE},
    {0xff}
};




Bye,
Thomas.


On 15/09/2012 10:22, Dr.-Ing. Wilhelm Hagemeister wrote:
Hello Thomas,

we follow a rather pragmatic way to bring those slaves to operational:

Do the configuration with TwinCat and make sure the Profibus
Slave/Master goes to work properly.
Export from TwinCat the configuration of the EtherCat slave (6731-xxxx)
to an xml-file.

Make the xml-file more readable with "xmllint --format".

Now how have to search manually (with an editor) for the configuration
SDO's of your slave.
You are looking for the objects:

0xf800: Master configuration

0x8000: Slave 1 config

0x8010: Slave 2 config

....

cut these out and put them into your C program, find below an example
for a program with a Profibus Master and a Profibus Slave talking to
each other.

Regards Wilhelm.


/*****************************************************************************
  *
  *  $Id: main.cpp,v 55c679db2375 2010/11/10 14:05:17 fp $
  *
  *  Copyright (C) 2010  Florian Pose, Ingenieurgemeinschaft IgH
  *  Modified by Wilhelm Hagemeister, Ingenieurgemeinschaft IgH
  *  Demo shows how to configure a Beckhoff profibus slave/master EL6731
(0010)
  *
  ****************************************************************************/

#include<errno.h>
#include<signal.h>
#include<stdio.h>
#include<string.h>
#include<time.h>
#include<sched.h>
#include<unistd.h>
#include<sys/mman.h>
#include<pthread.h>

/****************************************************************************/

#include<ecrt.h>

/****************************************************************************/

/** Task period in ns. */
#define PERIOD_NS       (1000000)
#define CLOCK_TO_USE    CLOCK_REALTIME
#define MEASURE_TIMING

/****************************************************************************/

#define NSEC_PER_SEC    (1000000000)

#define FREQUENCY (NSEC_PER_SEC / PERIOD_NS)

#define DIFF_NS(A, B) (((B).tv_sec - (A).tv_sec) * NSEC_PER_SEC + \
        (B).tv_nsec - (A).tv_nsec)

/****************************************************************************/

// EtherCAT

#define CouplerPos       0, 0
#define ProfiPosSlave    0, 1
#define ProfiPosMaster   0, 2


#define Beckhoff_EK1100  0x00000002, 0x044c2c52
#define Beckhoff_EL6731  0x00000002, 0x1a4b3052

static ec_master_t *master = NULL;
static ec_master_state_t master_state = {};

static ec_domain_t *domain1 = NULL;
static ec_domain_state_t domain1_state = {};

static ec_slave_config_t *sc = NULL;
static ec_slave_config_state_t sc_state = {};

/****************************************************************************/

/** Profibus configuration.
  * Stealed from TwinCAT configuration export.
  */


const char *pb_config_slave_0x8000 =
   "2d00020000000000000000000000a8010000f4"
   "f0000000000a02000000008801140b095f00800008d9e9";

/*----------------------*/

const char *pb_config_master_0xf800 =
   "11000109e8030b0020030910647e0401280004000000000000000000";

const char *pb_config_master_0x8000 =
   "2d00020001100000c0a8045a0202a8010000f4f00"
   "00000001602000000008801140b095f00c000080c"
   "8100000000c0a8045a0202d9e9";

// process data
static uint8_t *domain1_pd = NULL;

// offsets for PDO entries
static unsigned int off_out_slave;
static unsigned int off_in_slave;
static unsigned int off_out_master;
static unsigned int off_in_master;


const static ec_pdo_entry_reg_t domain1_regs[] = {
     {ProfiPosSlave, Beckhoff_EL6731, 0x7000, 1,&off_out_slave},
     {ProfiPosSlave, Beckhoff_EL6731, 0x6000, 1,&off_in_slave},
     {ProfiPosMaster, Beckhoff_EL6731, 0x7000, 1,&off_out_master},
     {ProfiPosMaster, Beckhoff_EL6731, 0x6000, 1,&off_in_master},
        {}
};

static unsigned int counter = 0;
unsigned int run = 1;

/*****************************************************************************/

/* Master 0, Slave 1, "EL6731-0010"
  * Vendor ID:       0x00000002
  * Product code:    0x1a4b3052
  * Revision number: 0x0011000a
  */

ec_pdo_entry_info_t slave_1_pdo_entries[] = {
     {0x7000, 0x01, 160},
     {0x6000, 0x01, 160},
     {0xa000, 0x01, 8},
     {0xf100, 0x02, 1},
     {0xa000, 0x02, 1},
     {0x0000, 0x00, 6},
};

ec_pdo_info_t slave_1_pdos[] = {
     {0x1600, 1, slave_1_pdo_entries + 0}, /* DPS RxPDO-Map Slave     */
     {0x1a00, 1, slave_1_pdo_entries + 1}, /* DPS TxPDO-Map Slave     */
     {0x1a80, 4, slave_1_pdo_entries + 2},
};

ec_sync_info_t slave_1_syncs[] = {
     {0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
     {1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
     {2, EC_DIR_OUTPUT, 1, slave_1_pdos + 0, EC_WD_DISABLE},
     {3, EC_DIR_INPUT, 2, slave_1_pdos + 1, EC_WD_DISABLE},
     {0xff}
};

/* Master 0, Slave 2, "EL6731"
  * Vendor ID:       0x00000002
  * Product code:    0x1a4b3052
  * Revision number: 0x0011000a
  */

ec_pdo_entry_info_t slave_2_pdo_entries[] = {
   { 0x7000, 1, 160 },                  /* 0 */
   { 0x6000, 1, 160 },                  /* 1 */
   { 0xA000, 1, 8 },                    /* 2 */
   { 0xF100, 1, 8 },                    /* 3 */
   { 0xF100, 3, 8 },                    /* 4 */
   { 0xF100, 2, 1 },                    /* 5 */
   { 0xA000, 2, 1 },                    /* 6 */
   { 0x0000, 0, 6 },
};

ec_pdo_info_t slave_2_pdos[] = {
     {0x1600, 1, slave_2_pdo_entries + 0}, /* DPS RxPDO-Map Slave     */
     {0x1a00, 1, slave_2_pdo_entries + 1}, /* DPS TxPDO-Map Slave     */
     {0x1a80, 6, slave_2_pdo_entries + 2},
};

ec_sync_info_t slave_2_syncs[] = {
     {0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
     {1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
     {2, EC_DIR_OUTPUT, 1, slave_2_pdos + 0, EC_WD_DISABLE},
     {3, EC_DIR_INPUT, 2, slave_2_pdos + 1, EC_WD_DISABLE},
     {0xff}
};


/*****************************************************************************/
/* Helper funktion, buffer has be allocated and big enough */
unsigned int strToCharArray(const char *str,unsigned char *buffer)
     {
         unsigned int i;
         unsigned char byteVal;
         //        const char *str = pb_config;
         //        unsigned char cf_data[256];
         size_t size = strlen(str);

         for (i = 0; i<  size; i++) {
             sscanf(str, "%2X",&byteVal);
             str += 2;
             buffer[i] = (uint8_t) byteVal;
         }
         return (size / 2);
     }

/*****************************************************************************/

void check_domain1_state(void)
{
     ec_domain_state_t ds;

     ecrt_domain_state(domain1,&ds);

     if (ds.working_counter != domain1_state.working_counter)
         printf("Domain1: WC %u.\n", ds.working_counter);
     if (ds.wc_state != domain1_state.wc_state)
         printf("Domain1: State %u.\n", ds.wc_state);

     domain1_state = ds;
}

/*****************************************************************************/

void check_master_state(void)
{
     ec_master_state_t ms;

     ecrt_master_state(master,&ms);

     if (ms.slaves_responding != master_state.slaves_responding)
         printf("%u slave(s).\n", ms.slaves_responding);
     if (ms.al_states != master_state.al_states)
         printf("AL states: 0x%02X.\n", ms.al_states);
     if (ms.link_up != master_state.link_up)
         printf("Link is %s.\n", ms.link_up ? "up" : "down");

     master_state = ms;
}

/*****************************************************************************/

void check_slave_config_states(void)
{
     ec_slave_config_state_t s;

     ecrt_slave_config_state(sc,&s);

     if (s.al_state != sc_state.al_state)
         printf("AnaIn: State 0x%02X.\n", s.al_state);
     if (s.online != sc_state.online)
         printf("AnaIn: %s.\n", s.online ? "online" : "offline");
     if (s.operational != sc_state.operational)
         printf("AnaIn: %soperational.\n",
                 s.operational ? "" : "Not ");

     sc_state = s;
}

/*****************************************************************************/

void cyclic_task()
{
     int i;
     uint8_t x, reset = 0;

     static uint8_t pcounter = 0;

     // receive process data
     ecrt_master_receive(master);
     ecrt_domain_process(domain1);

     // check process data state (optional)
     check_domain1_state();

     if (counter) {
         counter--;
     } else { // do this at 1 Hz
         counter = FREQUENCY;

         // check for master state (optional)
         check_master_state();

         // check for islave configuration state(s) (optional)
         check_slave_config_states();


         //write a byte to the master
         pcounter++;
         EC_WRITE_U8(domain1_pd + off_out_master + 1,pcounter);

         // read some bytes from the slave
         printf("\nSlave input data: ");
         for (i=0;i<16;i++)
           printf(" %d",EC_READ_U8(domain1_pd + off_in_slave +i));
         printf("\n");
     }
     // send process data
     ecrt_domain_queue(domain1);
     ecrt_master_send(master);
}

/****************************************************************************/

void signal_handler(int signum)
{
     switch (signum) {
         case SIGINT:
         case SIGTERM:
             run = 0;
             break;
     }
}

/****************************************************************************/

#define MAX_SAFE_STACK (8*1024)

void stack_prefault(void)
{
     unsigned char dummy[MAX_SAFE_STACK];
     memset(&dummy, 0, MAX_SAFE_STACK);
}

/****************************************************************************/

void *rt_thread_func(void *data)
{
     struct timespec wakeupTime;
     int ret;
#ifdef MEASURE_TIMING
     struct timespec startTime, endTime, lastStartTime = {}, lastOutputTime;
     uint32_t period_ns = 0, exec_ns = 0, latency_ns = 0,
              latency_min_ns = 0, latency_max_ns = 0,
              period_min_ns = 0, period_max_ns = 0,
              exec_min_ns = 0, exec_max_ns = 0;
#endif

     printf("rt_thread running.\n");

     // get current time
     clock_gettime(CLOCK_TO_USE,&wakeupTime);
     lastStartTime = wakeupTime;

     while (run) {
         wakeupTime.tv_nsec += PERIOD_NS;
         while (wakeupTime.tv_nsec>= NSEC_PER_SEC) {
             wakeupTime.tv_nsec -= NSEC_PER_SEC;
             wakeupTime.tv_sec++;
         }

         ret = clock_nanosleep(CLOCK_TO_USE, TIMER_ABSTIME,&wakeupTime,
NULL);
         if (ret) {
             printf("clock_nanosleep(): %s\n", strerror(ret));
         }

#ifdef MEASURE_TIMING
         clock_gettime(CLOCK_TO_USE,&startTime);
         latency_ns = DIFF_NS(wakeupTime, startTime);
         period_ns = DIFF_NS(lastStartTime, startTime);
         exec_ns = DIFF_NS(lastStartTime, endTime);
         lastStartTime = startTime;
         //printf("period_ns=%10u exec_ns=%5u\n", period_ns, exec_ns);
         if (latency_ns>  latency_max_ns) {
             latency_max_ns = latency_ns;
         }
         if (latency_ns<  latency_min_ns) {
             latency_min_ns = latency_ns;
         }
         if (period_ns>  period_max_ns) {
             period_max_ns = period_ns;
         }
         if (period_ns<  period_min_ns) {
             period_min_ns = period_ns;
         }
         if (exec_ns>  exec_max_ns) {
             exec_max_ns = exec_ns;
         }
         if (exec_ns<  exec_min_ns) {
             exec_min_ns = exec_ns;
         }
#endif

         cyclic_task();

#ifdef MEASURE_TIMING
         if (DIFF_NS(lastOutputTime, startTime)>= NSEC_PER_SEC) {
             // output timing stats
             printf("period     %10u ... %10u\n",
                     period_min_ns, period_max_ns);
             printf("exec       %10u ... %10u\n",
                     exec_min_ns, exec_max_ns);
             printf("latency    %10u ... %10u\n\n",
                     latency_min_ns, latency_max_ns);
             period_max_ns = 0;
             period_min_ns = 0xffffffff;
             exec_max_ns = 0;
             exec_min_ns = 0xffffffff;
             latency_max_ns = 0;
             latency_min_ns = 0xffffffff;
             lastOutputTime = startTime;
         }

         clock_gettime(CLOCK_TO_USE,&endTime);
#endif
     }

     pthread_exit(NULL);
}

/****************************************************************************/

int main(int argc, char **argv)
{
     struct sigaction sa;
     struct sched_param param;
     pthread_t rt_thread;
     int ret;

     int cnt;
     unsigned char pb_config_buf[256];

     sa.sa_handler = signal_handler;
     sigemptyset(&sa.sa_mask);
     sa.sa_flags = 0;
     if (sigaction(SIGTERM,&sa, 0)) {
         fprintf(stderr, "Failed to install signal handler!\n");
         return -1;
     }
     if (sigaction(SIGINT,&sa, 0)) {
         fprintf(stderr, "Failed to install signal handler!\n");
         return -1;
     }

     master = ecrt_request_master(0);
        if (!master)
                return -1;

     domain1 = ecrt_master_create_domain(master);
     if (!domain1)
         return -1;

     printf("Configuring PDOs...\n");

     /* EK1100 */
     if (!(sc = ecrt_master_slave_config(master, CouplerPos,
Beckhoff_EK1100))) {
         fprintf(stderr, "Failed to get slave configuration.\n");
         return -1;
     }

     /* EL6731 Slave*/
     if (!(sc = ecrt_master_slave_config(master, ProfiPosSlave,
Beckhoff_EL6731))) {
         fprintf(stderr, "Failed to get slave configuration.\n");
         return -1;
     }

     cnt = strToCharArray(pb_config_slave_0x8000,pb_config_buf);
     ecrt_slave_config_complete_sdo(sc, 0x8000, pb_config_buf, cnt);



     if (ecrt_slave_config_pdos(sc, EC_END, slave_1_syncs)) {
         fprintf(stderr, "Failed to configure PDOs.\n");
         return -1;
     }


     /* EL6731 Master*/
     if (!(sc = ecrt_master_slave_config(master, ProfiPosMaster,
Beckhoff_EL6731))) {
         fprintf(stderr, "Failed to get slave configuration.\n");
         return -1;
     }

     cnt = strToCharArray(pb_config_master_0xf800,pb_config_buf);
     ecrt_slave_config_complete_sdo(sc, 0xf800, pb_config_buf, cnt);

     cnt = strToCharArray(pb_config_master_0x8000,pb_config_buf);
     ecrt_slave_config_complete_sdo(sc, 0x8000, pb_config_buf, cnt);



     if (ecrt_slave_config_pdos(sc, EC_END, slave_2_syncs)) {
         fprintf(stderr, "Failed to configure PDOs (PB-Master).\n");
         return -1;
     }


     if (ecrt_domain_reg_pdo_entry_list(domain1, domain1_regs)) {
         fprintf(stderr, "PDO entry registration failed!\n");
                return -1;
     }


     printf("Activating master...\n");
     if (ecrt_master_activate(master))
         return -1;

     if (!(domain1_pd = ecrt_domain_data(domain1))) {
         return -1;
     }

     param.sched_priority = 80;
     if (sched_setscheduler(0, SCHED_FIFO,&param) == -1) {
         perror("sched_setscheduler failed");
         exit(-1);
     }

     if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
         perror("mlockall failed");
         exit(-2);
     }

     stack_prefault();

     printf("Starting timer...\n");

     ret = pthread_create(&rt_thread, NULL, rt_thread_func, NULL);
     if (ret<  0) {
         fprintf(stderr, "Failed to create realtime thread: %i.\n", ret);
         return ret;
     }

     while (run) {
         sleep(1);
     }

        return ret;
}

/****************************************************************************/


Am 15.09.2012 08:46, schrieb Thomas Paoloni:
Hi all,

I'm fighting with a Beckhoff 6731-0010 (Profibus slave to ethercat
bridge) which I'm not able to bring in OP state.
Nobody from Beckhoff is able to help me, they only seems to know their
twincat software, and nobody can explain how the same operations made by
twincat can be made trought SDO and C programming.
Even sniffing traffic with wireshark and trying to reproduce the same
with my code works because I can see some ADS packets which I can't
reproduce with Linux master.
Does anybody know more than me about this node, or maybe some other
network masters/slaves like CanOpen, Profibus, etc. that I think should
basically work in the same way ?

Thanks in advance,
Thomas.
_______________________________________________
etherlab-users mailing list
etherlab-users@etherlab.org
http://lists.etherlab.org/mailman/listinfo/etherlab-users

_______________________________________________
etherlab-users mailing list
etherlab-users@etherlab.org
http://lists.etherlab.org/mailman/listinfo/etherlab-users

Reply via email to