Good morning, my name is Eduardo and I am a member of a work group from a
university in Mexico and we are exploring ethercat technology, we use a NUC
and an EPOS4 with the IgH library, we have many problems with Syncronia, we
even managed to solve it in partly by using some codes within our project,
we noticed the critical failures when we made movements with motors, having
emergency exits and stopping the trajectory, it was when we explored the
error and defined it by 2 parts by means of grep and by EPOS4 records, We
return to the beginning of the development and we use the dc_user again and
again we find the same error, if you could help us I would greatly
appreciate it.


[ 2028.813557] EtherCAT ERROR 0-0: AL status message 0x001A:
"Synchronization error".

The kernel and patch from Xenomai are
https://source.denx.de/Xenomai/linux-dovetail //dovetail 5.10.76 patch

20.04编译Linux5.10.76+Xenomai-3.2.1

We used a generic ethernet port from NUC and we are planning to use a Dual
Port Gigabit Ethernet card.

This is the IgH configuration that has been selected.

sudo ./configure --with-module-dir=/lib/modules/5.10.76-xenomai
--enable-eoe=no --enable-generic=si --enable-8139too=no --enable-e1000e
--enable-cycles --enable-hrtimer --with-xenomai-dir=/usr/xenomai
--prefix=/opt/etherlab

Grep from the console before running the code.

rtlinux@rtlinux-NUC7i7BNH:~/xenomai/ethercat-e1000e-5.10$ dmesg | grep -i
ether

[ 1335.760859] EtherCAT: Master driver 1.5.2 unknown
[ 1335.760921] EtherCAT: 1 master waiting for devices.
[ 1335.767208] ec_generic: EtherCAT master generic Ethernet device module
1.5.2 unknown
[ 1335.767214] EtherCAT: Accepting 94:C6:91:AD:1D:92 as main device for
master 0.
[ 1335.786391] EtherCAT 0: Starting EtherCAT-IDLE thread.
[ 1335.786429] EtherCAT 0: Link state of ecm0 changed to UP.
[ 1335.790455] EtherCAT 0: 1 slave(s) responding on main device.
[ 1335.790456] EtherCAT 0: Slave states on main device: INIT.
[ 1335.791004] EtherCAT 0: Scanning bus.
[ 1335.971731] EtherCAT 0: Bus scanning completed in 180 ms.
[ 1335.971732] EtherCAT 0: Using slave 0 as DC reference clock.
[ 1335.975743] EtherCAT 0: Slave states on main device: PREOP.

Grep from the console after running the code.

rtlinux@rtlinux-NUC7i7BNH:~/xenomai/ethercat-e1000e-5.10$ dmesg | grep -i
ether

 1335.767208] ec_generic: EtherCAT master generic Ethernet device module
1.5.2 unknown
[ 1335.767214] EtherCAT: Accepting 94:C6:91:AD:1D:92 as main device for
master 0.
[ 1335.786391] EtherCAT 0: Starting EtherCAT-IDLE thread.
[ 1335.786429] EtherCAT 0: Link state of ecm0 changed to UP.
[ 1335.790455] EtherCAT 0: 1 slave(s) responding on main device.
[ 1335.790456] EtherCAT 0: Slave states on main device: INIT.
[ 1335.791004] EtherCAT 0: Scanning bus.
[ 1335.971731] EtherCAT 0: Bus scanning completed in 180 ms.
[ 1335.971732] EtherCAT 0: Using slave 0 as DC reference clock.
[ 1335.975743] EtherCAT 0: Slave states on main device: PREOP.
[ 2022.370620] EtherCAT: Requesting master 0...
[ 2022.370623] EtherCAT: Successfully requested master 0.
[ 2022.370645] EtherCAT 0: Domain0: Logical address 0x00000000, 2 byte,
expected working counter 1.
[ 2022.370646] EtherCAT 0:   Datagram domain0-0-main: Logical offset
0x00000000, 2 byte, type LWR.
[ 2022.372689] EtherCAT 0: Master thread exited.
[ 2022.372691] EtherCAT 0: Starting EtherCAT-OP thread.
[ 2024.375379] EtherCAT WARNING 0: 4 datagrams UNMATCHED!
[ 2024.380714] EtherCAT WARNING: Datagram 00000000047a0a66 (domain0-0-main)
was SKIPPED 2 times.
[ 2027.593324] EtherCAT WARNING 0-0: Slave did not sync after 5000 ms.
[ 2027.605534] EtherCAT 0: Domain 0: Working counter changed to 1/1
[ 2027.907634] EtherCAT 0: Slave states on main device: OP.
[ 2028.374763] EtherCAT WARNING 0: 12 datagrams UNMATCHED!
[ 2028.396512] EtherCAT WARNING: Datagram 00000000047a0a66 (domain0-0-main)
was SKIPPED 6 times.
[ 2028.604830] EtherCAT 0: Releasing master...
[ 2028.608678] EtherCAT 0: Master thread exited.
[ 2028.608688] EtherCAT 0: Starting EtherCAT-IDLE thread.
[ 2028.608831] EtherCAT 0: Released.
[ 2028.608843] EtherCAT 0: 0 slave(s) responding on main device.
[ 2028.612972] EtherCAT 0: 1 slave(s) responding on main device.
[ 2028.612975] EtherCAT 0: Slave states on main device: SAFEOP + ERROR.
[ 2028.613588] EtherCAT 0: Scanning bus.
[ 2028.614191] EtherCAT WARNING 0-0: Slave has state error bit set (SAFEOP
+ ERROR)!
[ 2028.624296] EtherCAT WARNING: Datagram 00000000a2dc8bb0 (master-fsm) was
SKIPPED 1 time.
[ 2028.805082] EtherCAT 0: Bus scanning completed in 192 ms.
[ 2028.805084] EtherCAT 0: Using slave 0 as DC reference clock.
[ 2028.813557] EtherCAT ERROR 0-0: AL status message 0x001A:
"Synchronization error".
[ 2028.815031] EtherCAT 0-0: Acknowledged state SAFEOP.
[ 2028.826964] EtherCAT 0: Slave states on main device: PREOP.

Code dc_user.cpp

/*****************************************************************************
 *
 *  Copyright (C) 2007-2022  Florian Pose, Ingenieurgemeinschaft IgH
 *
 *  This file is part of the IgH EtherCAT Master.
 *
 *  The IgH EtherCAT Master is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License version 2,
as
 *  published by the Free Software Foundation.
 *
 *  The IgH EtherCAT Master is distributed in the hope that it will be
useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General
 *  Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with the IgH EtherCAT Master; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
 USA
 *
 *  ---
 *
 *  The license mentioned above concerns the source code only. Using the
 *  EtherCAT technology and brand is only permitted in compliance with the
 *  industrial property and similar rights of Beckhoff Automation GmbH.
 *
 ****************************************************************************/

#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <time.h>
#include <sys/mman.h>
#include <malloc.h>
#include <sched.h> /* sched_setscheduler() */

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

#include "ecrt.h"

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

// Application parameters
#define FREQUENCY 1000
#define CLOCK_TO_USE CLOCK_MONOTONIC
#define MEASURE_TIMING
#define NUMBER_OF_SAMPLE 1000

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

#define NSEC_PER_SEC (1000000000L)
#define PERIOD_NS (NSEC_PER_SEC / FREQUENCY)
#define SHIFT0 (PERIOD_NS/2)

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

#define TIMESPEC2NS(T) ((uint64_t) (T).tv_sec * NSEC_PER_SEC + (T).tv_nsec)

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

// EtherCAT
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 = {};

int slave_working = 0;

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

// process data
static uint8_t *domain1_pd = NULL;

#define BusCouplerPos    0, 0


#define EPOS4 0x000000fb , 0x61500000


// offsets for PDO entries
static int controlworld;

static unsigned int counter = 0;
static unsigned int blink = 0;
static unsigned int sync_ref_counter = 0;
const struct timespec cycletime = {0, PERIOD_NS};

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

struct timespec timespec_add(struct timespec time1, struct timespec time2)
{
    struct timespec result;

    if ((time1.tv_nsec + time2.tv_nsec) >= NSEC_PER_SEC) {
        result.tv_sec = time1.tv_sec + time2.tv_sec + 1;
        result.tv_nsec = time1.tv_nsec + time2.tv_nsec - NSEC_PER_SEC;
    } else {
        result.tv_sec = time1.tv_sec + time2.tv_sec;
        result.tv_nsec = time1.tv_nsec + time2.tv_nsec;
    }

    return result;
}

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

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);
if (ds.wc_state == 2)
  {
    slave_working = 1;
  }
    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 cyclic_task()
{
    struct timespec wakeupTime, time;
    uint32_t sample_no = 0;
#ifdef MEASURE_TIMING
    struct timespec startTime, endTime, lastStartTime = {};
    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

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

  //  while(1)
      while(sample_no < NUMBER_OF_SAMPLE){
        wakeupTime = timespec_add(wakeupTime, cycletime);
        clock_nanosleep(CLOCK_TO_USE, TIMER_ABSTIME, &wakeupTime, NULL);

        // Write application time to master
        //
        // It is a good idea to use the target time (not the measured time)
as
        // application time, because it is more stable.
        //
        ecrt_master_application_time(master, TIMESPEC2NS(wakeupTime));

#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;

        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

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

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


    if (slave_working)
    {
      // output timing stats
      sample_no++;
    }


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

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

#ifdef MEASURE_TIMING
            // 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",
                    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;
             printf("sample_no     %10u \n",
                    sample_no);
#endif

            // calculate new process data
            blink = !blink;
        }

        // write process data
        EC_WRITE_U8(domain1_pd + controlworld, blink ? 0x66 : 0x99);


        if (sync_ref_counter) {
            sync_ref_counter--;
        } else {
            sync_ref_counter = 1; // sync every cycle

            clock_gettime(CLOCK_TO_USE, &time);
            ecrt_master_sync_reference_clock_to(master, TIMESPEC2NS(time));
        }
        ecrt_master_sync_slave_clocks(master);

        // send process data
        ecrt_domain_queue(domain1);
        ecrt_master_send(master);

#ifdef MEASURE_TIMING
        clock_gettime(CLOCK_TO_USE, &endTime);
#endif
    }
}

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

int main(int argc, char **argv)
{
    ec_slave_config_t *sc;

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

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

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

    // Create configuration for bus coupler
    sc = ecrt_master_slave_config(master, BusCouplerPos, EPOS4);
    if (!sc)
        return -1;


    controlworld = ecrt_slave_config_reg_pdo_entry(sc, 0x6040, 0x00,
domain1, NULL);
    if (controlworld < 0)
        return -1;


    // configure SYNC signals for this slave
    ecrt_slave_config_dc(sc, 0x0300, PERIOD_NS, SHIFT0, 0, 0);

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

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

    /* Set priority */

    struct sched_param param = {};
    param.sched_priority = sched_get_priority_max(SCHED_FIFO);

    printf("Using priority %i.", param.sched_priority);
    if (sched_setscheduler(0, SCHED_FIFO, &param) == -1) {
        perror("sched_setscheduler failed");
    }

    printf("Starting cyclic function.\n");
    cyclic_task();
    ecrt_release_master(master);
    return 0;
}

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

Dr. Eduardo Rodríguez Orozco
-- 
Etherlab-users mailing list
Etherlab-users@etherlab.org
https://lists.etherlab.org/mailman/listinfo/etherlab-users

Reply via email to