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, ¶m) == -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