[etherlab-users] Beckhoff 6731-0010 initialization
Thomas Paoloni
thomas at digithom.it
Mon Sep 17 10:17:03 CEST 2012
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,¶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 at etherlab.org
>> http://lists.etherlab.org/mailman/listinfo/etherlab-users
More information about the Etherlab-users
mailing list