This commit is contained in:
Florian Pose
2019-01-02 11:26:50 +01:00
4 changed files with 94 additions and 80 deletions
+5 -10
View File
@@ -164,11 +164,12 @@ void run(long data)
struct timeval tv; struct timeval tv;
unsigned int sync_ref_counter = 0; unsigned int sync_ref_counter = 0;
count2timeval(nano2count(rt_get_real_time_ns()), &tv);
while (1) { while (1) {
t_last_cycle = get_cycles(); t_last_cycle = get_cycles();
count2timeval(nano2count(rt_get_real_time_ns()), &tv);
ecrt_master_application_time(master, EC_TIMEVAL2NANO(tv));
// receive process data // receive process data
rt_sem_wait(&master_sem); rt_sem_wait(&master_sem);
ecrt_master_receive(master); ecrt_master_receive(master);
@@ -214,18 +215,12 @@ void run(long data)
rt_sem_wait(&master_sem); rt_sem_wait(&master_sem);
tv.tv_usec += 1000;
if (tv.tv_usec >= 1000000) {
tv.tv_usec -= 1000000;
tv.tv_sec++;
}
ecrt_master_application_time(master, EC_TIMEVAL2NANO(tv));
if (sync_ref_counter) { if (sync_ref_counter) {
sync_ref_counter--; sync_ref_counter--;
} else { } else {
sync_ref_counter = 9; sync_ref_counter = 9;
ecrt_master_sync_reference_clock(master); count2timeval(nano2count(rt_get_real_time_ns()), &tv);
ecrt_master_sync_reference_clock_to(master, EC_TIMEVAL2NANO(tv));
} }
ecrt_master_sync_slave_clocks(master); ecrt_master_sync_slave_clocks(master);
ecrt_domain_queue(domain1); ecrt_domain_queue(domain1);
+64 -59
View File
@@ -57,7 +57,7 @@
#define PERIOD_NS (NSEC_PER_SEC / FREQUENCY) #define PERIOD_NS (NSEC_PER_SEC / FREQUENCY)
#define DIFF_NS(A, B) (((B).tv_sec - (A).tv_sec) * NSEC_PER_SEC + \ #define DIFF_NS(A, B) (((B).tv_sec - (A).tv_sec) * NSEC_PER_SEC + \
(B).tv_nsec - (A).tv_nsec) (B).tv_nsec - (A).tv_nsec)
#define TIMESPEC2NS(T) ((uint64_t) (T).tv_sec * NSEC_PER_SEC + (T).tv_nsec) #define TIMESPEC2NS(T) ((uint64_t) (T).tv_sec * NSEC_PER_SEC + (T).tv_nsec)
@@ -97,17 +97,17 @@ const struct timespec cycletime = {0, PERIOD_NS};
struct timespec timespec_add(struct timespec time1, struct timespec time2) struct timespec timespec_add(struct timespec time1, struct timespec time2)
{ {
struct timespec result; struct timespec result;
if ((time1.tv_nsec + time2.tv_nsec) >= NSEC_PER_SEC) { if ((time1.tv_nsec + time2.tv_nsec) >= NSEC_PER_SEC) {
result.tv_sec = time1.tv_sec + time2.tv_sec + 1; result.tv_sec = time1.tv_sec + time2.tv_sec + 1;
result.tv_nsec = time1.tv_nsec + time2.tv_nsec - NSEC_PER_SEC; result.tv_nsec = time1.tv_nsec + time2.tv_nsec - NSEC_PER_SEC;
} else { } else {
result.tv_sec = time1.tv_sec + time2.tv_sec; result.tv_sec = time1.tv_sec + time2.tv_sec;
result.tv_nsec = time1.tv_nsec + time2.tv_nsec; result.tv_nsec = time1.tv_nsec + time2.tv_nsec;
} }
return result; return result;
} }
/*****************************************************************************/ /*****************************************************************************/
@@ -134,7 +134,7 @@ void check_master_state(void)
ecrt_master_state(master, &ms); ecrt_master_state(master, &ms);
if (ms.slaves_responding != master_state.slaves_responding) if (ms.slaves_responding != master_state.slaves_responding)
printf("%u slave(s).\n", ms.slaves_responding); printf("%u slave(s).\n", ms.slaves_responding);
if (ms.al_states != master_state.al_states) if (ms.al_states != master_state.al_states)
printf("AL states: 0x%02X.\n", ms.al_states); printf("AL states: 0x%02X.\n", ms.al_states);
@@ -160,10 +160,17 @@ void cyclic_task()
// get current time // get current time
clock_gettime(CLOCK_TO_USE, &wakeupTime); clock_gettime(CLOCK_TO_USE, &wakeupTime);
while(1) { while(1) {
wakeupTime = timespec_add(wakeupTime, cycletime); wakeupTime = timespec_add(wakeupTime, cycletime);
clock_nanosleep(CLOCK_TO_USE, TIMER_ABSTIME, &wakeupTime, NULL); 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 #ifdef MEASURE_TIMING
clock_gettime(CLOCK_TO_USE, &startTime); clock_gettime(CLOCK_TO_USE, &startTime);
latency_ns = DIFF_NS(wakeupTime, startTime); latency_ns = DIFF_NS(wakeupTime, startTime);
@@ -191,20 +198,20 @@ void cyclic_task()
} }
#endif #endif
// receive process data // receive process data
ecrt_master_receive(master); ecrt_master_receive(master);
ecrt_domain_process(domain1); ecrt_domain_process(domain1);
// check process data state (optional) // check process data state (optional)
check_domain1_state(); check_domain1_state();
if (counter) { if (counter) {
counter--; counter--;
} else { // do this at 1 Hz } else { // do this at 1 Hz
counter = FREQUENCY; counter = FREQUENCY;
// check for master state (optional) // check for master state (optional)
check_master_state(); check_master_state();
#ifdef MEASURE_TIMING #ifdef MEASURE_TIMING
// output timing stats // output timing stats
@@ -222,34 +229,32 @@ void cyclic_task()
latency_min_ns = 0xffffffff; latency_min_ns = 0xffffffff;
#endif #endif
// calculate new process data // calculate new process data
blink = !blink; blink = !blink;
} }
// write process data // write process data
EC_WRITE_U8(domain1_pd + off_dig_out, blink ? 0x66 : 0x99); EC_WRITE_U8(domain1_pd + off_dig_out, blink ? 0x66 : 0x99);
EC_WRITE_U8(domain1_pd + off_counter_out, blink ? 0x00 : 0x02); EC_WRITE_U8(domain1_pd + off_counter_out, blink ? 0x00 : 0x02);
// write application time to master if (sync_ref_counter) {
clock_gettime(CLOCK_TO_USE, &time); sync_ref_counter--;
ecrt_master_application_time(master, TIMESPEC2NS(time)); } else {
sync_ref_counter = 1; // sync every cycle
if (sync_ref_counter) { clock_gettime(CLOCK_TO_USE, &time);
sync_ref_counter--; ecrt_master_sync_reference_clock_to(master, TIMESPEC2NS(time));
} else { }
sync_ref_counter = 1; // sync every cycle ecrt_master_sync_slave_clocks(master);
ecrt_master_sync_reference_clock(master);
}
ecrt_master_sync_slave_clocks(master);
// send process data // send process data
ecrt_domain_queue(domain1); ecrt_domain_queue(domain1);
ecrt_master_send(master); ecrt_master_send(master);
#ifdef MEASURE_TIMING #ifdef MEASURE_TIMING
clock_gettime(CLOCK_TO_USE, &endTime); clock_gettime(CLOCK_TO_USE, &endTime);
#endif #endif
} }
} }
/****************************************************************************/ /****************************************************************************/
@@ -258,10 +263,10 @@ int main(int argc, char **argv)
{ {
ec_slave_config_t *sc; ec_slave_config_t *sc;
if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) { if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
perror("mlockall failed"); perror("mlockall failed");
return -1; return -1;
} }
master = ecrt_request_master(0); master = ecrt_request_master(0);
if (!master) if (!master)
@@ -287,24 +292,24 @@ int main(int argc, char **argv)
if (off_dig_out < 0) if (off_dig_out < 0)
return -1; return -1;
if (!(sc = ecrt_master_slave_config(master, if (!(sc = ecrt_master_slave_config(master,
CounterSlavePos, IDS_Counter))) { CounterSlavePos, IDS_Counter))) {
fprintf(stderr, "Failed to get slave configuration.\n"); fprintf(stderr, "Failed to get slave configuration.\n");
return -1; return -1;
} }
off_counter_in = ecrt_slave_config_reg_pdo_entry(sc, off_counter_in = ecrt_slave_config_reg_pdo_entry(sc,
0x6020, 0x11, domain1, NULL); 0x6020, 0x11, domain1, NULL);
if (off_counter_in < 0) if (off_counter_in < 0)
return -1; return -1;
off_counter_out = ecrt_slave_config_reg_pdo_entry(sc, off_counter_out = ecrt_slave_config_reg_pdo_entry(sc,
0x7020, 1, domain1, NULL); 0x7020, 1, domain1, NULL);
if (off_counter_out < 0) if (off_counter_out < 0)
return -1; return -1;
// configure SYNC signals for this slave // configure SYNC signals for this slave
ecrt_slave_config_dc(sc, 0x0700, PERIOD_NS, 4400000, 0, 0); ecrt_slave_config_dc(sc, 0x0700, PERIOD_NS, 4400000, 0, 0);
printf("Activating master...\n"); printf("Activating master...\n");
if (ecrt_master_activate(master)) if (ecrt_master_activate(master))
@@ -324,7 +329,7 @@ int main(int argc, char **argv)
perror("sched_setscheduler failed"); perror("sched_setscheduler failed");
} }
printf("Starting cyclic function.\n"); printf("Starting cyclic function.\n");
cyclic_task(); cyclic_task();
return 0; return 0;
+4 -10
View File
@@ -193,16 +193,13 @@ void sync_distributed_clocks(void)
dc_time_ns = system_time_ns(); dc_time_ns = system_time_ns();
// set master time in nano-seconds
ecrt_master_application_time(master, dc_time_ns);
#if SYNC_MASTER_TO_REF #if SYNC_MASTER_TO_REF
// get reference clock time to synchronize master cycle // get reference clock time to synchronize master cycle
ecrt_master_reference_clock_time(master, &ref_time); ecrt_master_reference_clock_time(master, &ref_time);
dc_diff_ns = (uint32_t) prev_app_time - ref_time; dc_diff_ns = (uint32_t) prev_app_time - ref_time;
#else #else
// sync reference clock to master // sync reference clock to master
ecrt_master_sync_reference_clock(master); ecrt_master_sync_reference_clock_to(master, dc_time_ns);
#endif #endif
// call to sync slaves to ref slave // call to sync slaves to ref slave
@@ -368,6 +365,9 @@ void wait_period(void)
break; break;
} }
// set master time in nano-seconds
ecrt_master_application_time(master, wakeup_time);
// calc next wake time (in sys time) // calc next wake time (in sys time)
wakeup_time += cycle_ns; wakeup_time += cycle_ns;
} }
@@ -504,12 +504,6 @@ int main(int argc, char *argv[])
dc_start_time_ns = system_time_ns(); dc_start_time_ns = system_time_ns();
dc_time_ns = dc_start_time_ns; dc_time_ns = 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);
ret = ecrt_master_select_reference_clock(master, sc_ek1100); ret = ecrt_master_select_reference_clock(master, sc_ek1100);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "Failed to select reference clock: %s\n", fprintf(stderr, "Failed to select reference clock: %s\n",
+21 -1
View File
@@ -51,7 +51,27 @@ noinst_HEADERS = \
voe_handler.h voe_handler.h
libethercat_la_CFLAGS = -fno-strict-aliasing -Wall -I$(top_srcdir) libethercat_la_CFLAGS = -fno-strict-aliasing -Wall -I$(top_srcdir)
libethercat_la_LDFLAGS = -version-info 1:0:0
#
# http://www.gnu.org/software/libtool/manual/html_node/ ...
# Updating-version-info.html
#
# - If the library source code has changed at all since the last update, then
# increment revision (‘c:r:a’ becomes ‘c:r+1:a’).
# - If any interfaces have been added, removed, or changed since the last
# update, increment current, and set revision to 0.
# - If any interfaces have been added since the last public release, then
# increment age.
# - If any interfaces have been removed or changed since the last public
# release, then set age to 0.
#
# History
#
# 1:0.0
# ecrt_master_sync_reference_clock_to() added.
# 2:0:1
#
libethercat_la_LDFLAGS = -version-info 2:0:1
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------