Template C code used to produce target Ethercat C code
Copyright (C) 2011-2014: Laurent BESSARD, Edouard TISSERANT
Distributed under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
See COPYING file for copyrights details.
#include <native/timer.h>
#include "iec_types_all.h"
// declaration of interface variables
%(located_variables_declaration)s
uint8_t *domain1_pd = NULL;
%(used_pdo_entry_offset_variables_declaration)s
const static ec_pdo_entry_reg_t domain1_regs[] = {
%(used_pdo_entry_configuration)s
// Distributed Clock variables;
unsigned long long comp_period_ns = 500000ULL;
#define DC_FILTER_CNT 1024
// EtherCAT slave-time-based DC Synchronization variables.
static uint64_t dc_start_time_ns = 0LL;
static uint64_t dc_time_ns = 0;
static uint8_t dc_started = 0;
static int32_t dc_diff_ns = 0;
static int32_t prev_dc_diff_ns = 0;
static int64_t dc_diff_total_ns = 0LL;
static int64_t dc_delta_total_ns = 0LL;
static int dc_filter_idx = 0;
static int64_t dc_adjust_ns;
static int64_t system_time_base = 0LL;
static uint64_t dc_first_app_time = 0LL;
unsigned long long frame_period_ns = 0ULL;
uint64_t system_time_ns(void);
RTIME system2count(uint64_t time);
void sync_distributed_clocks(void);
void update_master_clock(void);
RTIME calculate_sleeptime(uint64_t wakeup_time);
uint64_t calculate_first(void);
/*****************************************************************************/
%(pdos_configuration_declaration)s
long long wait_period_ns = 100000LL;
static ec_master_t *master = NULL;
static ec_domain_t *domain1 = NULL;
#define SLOGF(level, format, args...)\
int slen = snprintf(sbuf , sizeof(sbuf) , format , ##args);\
LogMessage(level, sbuf, slen);\
/* EtherCAT plugin functions */
int __init_%(location)s(int argc,char **argv)
master = ecrt_request_master(%(master_number)d);
SLOGF(LOG_CRITICAL, "EtherCAT master request failed!");
if(!(domain1 = ecrt_master_create_domain(master))){
SLOGF(LOG_CRITICAL, "EtherCAT Domain Creation failed!");
// slaves PDO configuration
if (ecrt_domain_reg_pdo_entry_list(domain1, domain1_regs)) {
SLOGF(LOG_CRITICAL, "EtherCAT PDO registration failed!");
ecrt_master_set_send_interval(master, common_ticktime__);
%(slaves_initialization)s
// configure DC SYNC0/1 Signal
// select reference clock
ret = ecrt_master_select_reference_clock(master, slave0);
fprintf(stderr, "Failed to select reference clock : %%s\n",
// extracting default value for not mapped entry in output PDOs
%(slaves_output_pdos_default_values_extraction)s
if (ecrt_master_activate(master)){
SLOGF(LOG_CRITICAL, "EtherCAT Master activation failed");
if (!(domain1_pd = ecrt_domain_data(domain1))) {
SLOGF(LOG_CRITICAL, "Failed to map EtherCAT process data");
SLOGF(LOG_INFO, "Master %(master_number)d activated.");
ecrt_release_master(master);
void __cleanup_%(location)s(void)
ecrt_release_master(master);
void __retrieve_%(location)s(void)
ecrt_master_receive(master);
ecrt_domain_process(domain1);
static RTIME _last_occur=0;
static RTIME _last_publish=0;
static inline RTIME max(RTIME a,RTIME b){return a>b?a:b;}
void __publish_%(location)s(void)
ecrt_domain_queue(domain1);
RTIME current_time = rt_timer_read();
// Limit spining max 1/5 of common_ticktime
RTIME maxdeadline = current_time + (common_ticktime__ / 5);
RTIME deadline = _last_occur ?
_last_occur + common_ticktime__ :
current_time + _max_jitter;
if(deadline > maxdeadline) deadline = maxdeadline;
_current_lag = deadline - current_time;
RTIME period = current_time - _last_publish;
if(period > common_ticktime__ )
_max_jitter = max(_max_jitter, period - common_ticktime__);
_max_jitter = max(_max_jitter, common_ticktime__ - period);
_last_publish = current_time;
_last_occur = current_time;
while(current_time < deadline) {
_last_occur = current_time; //Drift backward by default
current_time = rt_timer_read();
if( _max_jitter * 10 < common_ticktime__ && _current_lag < _max_jitter){
//Consuming security margin ?
_last_occur = current_time; //Drift forward
sync_distributed_clocks();
ecrt_master_send(master);
if (comp_count == comp_count_max)
/* Test Function For Parameter (SDO) Set */
uint32_t abort_code, test_value;
if (ecrt_master_sdo_upload(master, 0, 0x1000, 0x0, (uint8_t *)value, 4, &result_size, &abort_code)) {
SLOGF(LOG_CRITICAL, "EtherCAT failed to get SDO Value");
test_value = EC_READ_S32((uint8_t *)value);
SLOGF(LOG_INFO, "SDO Value %%d", test_value);
master = ecrt_open_master(0);
SLOGF(LOG_CRITICAL, "EtherCAT master request failed!");
void ReleaseMasterData(void){
ecrt_release_master(master);
uint32_t GetSDOData(uint16_t slave_pos, uint16_t idx, uint8_t subidx, int size){
uint32_t abort_code, return_value;
if (ecrt_master_sdo_upload(master, slave_pos, idx, subidx, (uint8_t *)value, size, &result_size, &abort_code)) {
SLOGF(LOG_CRITICAL, "EtherCAT failed to get SDO Value %%d %%d", idx, subidx);
return_value = EC_READ_S32((uint8_t *)value);
//SLOGF(LOG_INFO, "SDO Value %%d", return_value);
/*****************************************************************************/
frame_period_ns = common_ticktime__;
if (frame_period_ns <= comp_period_ns) {
comp_count_max = comp_period_ns / frame_period_ns;
/* Set the initial master time */
dc_start_time_ns = system_time_ns();
dc_time_ns = dc_start_time_ns;
dc_first_app_time = dc_start_time_ns;
* Attention : The initial application time is also used for phase
* calculation for the SYNC0/1 interrupts. Please be sure to call it at
* the correct phase to the realtime cycle.
ecrt_master_application_time(master, dc_start_time_ns);
/****************************************************************************/
* Get the time in ns for the current cpu, adjusted by system_time_base.
* \attention Rather than calling rt_timer_read() directly, all application
* time calls should use this method instead.
uint64_t system_time_ns(void)
RTIME time = rt_timer_read(); // wkk
if (unlikely(system_time_base > (SRTIME) time)) {
fprintf(stderr, "%%s() error: system_time_base greater than"
" system time (system_time_base: %%ld, time: %%llu\n",
__func__, system_time_base, time);
return time - system_time_base;
/****************************************************************************/
// Convert system time to Xenomai time in counts (via the system_time_base).
RTIME system2count(uint64_t time)
if ((system_time_base < 0) &&
((uint64_t) (-system_time_base) > time)) {
fprintf(stderr, "%%s() error: system_time_base less than"
" system time (system_time_base: %%I64d, time: %%ld\n",
__func__, system_time_base, time);
ret = time + system_time_base;
return (RTIME) rt_timer_ns2ticks(ret); // wkk
/*****************************************************************************/
// Synchronise the distributed clocks
void sync_distributed_clocks(void)
RTIME prev_app_time = dc_time_ns;
// get reference clock time to synchronize master cycle
if(!ecrt_master_reference_clock_time(master, &ref_time)) {
dc_diff_ns = (uint32_t) prev_app_time - ref_time;
// call to sync slaves to ref slave
ecrt_master_sync_slave_clocks(master);
// set master time in nano-seconds
dc_time_ns = system_time_ns();
ecrt_master_application_time(master, dc_time_ns);
/*****************************************************************************/
* Return the sign of a number
* ie -1 for -ve value, 0 for 0, +1 for +ve value
* \ret val the sign of the value
({ typeof (val) _val = (val); \
((_val > 0) - (_val < 0)); })
/*****************************************************************************/
* Update the master time based on ref slaves time diff
* called after the ethercat frame is sent to avoid time jitter in
* sync_distributed_clocks()
void update_master_clock(void)
// calc drift (via un-normalised time diff)
int32_t delta = dc_diff_ns - prev_dc_diff_ns;
prev_dc_diff_ns = dc_diff_ns;
// normalise the time diff
dc_diff_ns = dc_diff_ns >= 0 ?
((dc_diff_ns + (int32_t)(frame_period_ns / 2)) %%
(int32_t)frame_period_ns) - (frame_period_ns / 2) :
((dc_diff_ns - (int32_t)(frame_period_ns / 2)) %%
(int32_t)frame_period_ns) - (frame_period_ns / 2) ;
// only update if primary master
dc_diff_total_ns += dc_diff_ns;
dc_delta_total_ns += delta;
if (dc_filter_idx >= DC_FILTER_CNT) {
dc_adjust_ns += dc_delta_total_ns >= 0 ?
((dc_delta_total_ns + (DC_FILTER_CNT / 2)) / DC_FILTER_CNT) :
((dc_delta_total_ns - (DC_FILTER_CNT / 2)) / DC_FILTER_CNT) ;
// and add adjustment for general diff (to pull in drift)
dc_adjust_ns += sign(dc_diff_total_ns / DC_FILTER_CNT);
// limit crazy numbers (0.1%% of std cycle time)
if (dc_adjust_ns < -1000) {
if (dc_adjust_ns > 1000) {
// add cycles adjustment to time base (including a spot adjustment)
system_time_base += dc_adjust_ns + sign(dc_diff_ns);
dc_started = (dc_diff_ns != 0);
#if DC_ENABLE && DEBUG_MODE
fprintf(stderr, "First master diff: %%d\n", dc_diff_ns);
// record the time of this initial cycle
dc_start_time_ns = dc_time_ns;
/*****************************************************************************/
* Calculate the sleeptime
RTIME calculate_sleeptime(uint64_t wakeup_time)
RTIME wakeup_count = system2count (wakeup_time);
RTIME current_count = rt_timer_read();
if ((wakeup_count < current_count) || (wakeup_count > current_count + (50 * frame_period_ns))) {
fprintf(stderr, "%%s(): unexpected wake time! wc = %%lld\tcc = %%lld\n", __func__, wakeup_count, current_count);
/*****************************************************************************/
* Calculate the sleeptime
uint64_t calculate_first(void)
uint64_t dc_remainder = 0LL;
uint64_t dc_phase_set_time = 0LL;
dc_phase_set_time = system_time_ns()+ frame_period_ns * 10;
dc_remainder = (dc_phase_set_time - dc_first_app_time) %% frame_period_ns;
return dc_phase_set_time + frame_period_ns - dc_remainder;
/*****************************************************************************/