Skip to content
Snippets Groups Projects
Commit e70a2879 authored by Florian Pose's avatar Florian Pose
Browse files

Improved dc_user example.

parent 4b5ca525
No related branches found
No related tags found
No related merge requests found
...@@ -33,6 +33,6 @@ noinst_PROGRAMS = ec_dc_user_example ...@@ -33,6 +33,6 @@ noinst_PROGRAMS = ec_dc_user_example
ec_dc_user_example_SOURCES = main.c ec_dc_user_example_SOURCES = main.c
ec_dc_user_example_CFLAGS = -I$(top_srcdir)/include ec_dc_user_example_CFLAGS = -I$(top_srcdir)/include
ec_dc_user_example_LDFLAGS = -L$(top_builddir)/lib/.libs -lethercat ec_dc_user_example_LDFLAGS = -L$(top_builddir)/lib/.libs -lethercat -lrt
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
...@@ -35,6 +35,9 @@ ...@@ -35,6 +35,9 @@
#include <sys/time.h> #include <sys/time.h>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include <time.h>
#include <sys/mman.h>
#include <malloc.h>
/****************************************************************************/ /****************************************************************************/
...@@ -43,12 +46,20 @@ ...@@ -43,12 +46,20 @@
/****************************************************************************/ /****************************************************************************/
// Application parameters // Application parameters
#define FREQUENCY 100 #define FREQUENCY 1000
#define PRIORITY 1 #define CLOCK_TO_USE CLOCK_REALTIME
#define MEASURE_TIMING
// Optional features /****************************************************************************/
#define CONFIGURE_PDOS 1
#define NSEC_PER_SEC (1000000000L)
#define PERIOD_NS (NSEC_PER_SEC / FREQUENCY)
#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 // EtherCAT
...@@ -58,10 +69,6 @@ static ec_master_state_t master_state = {}; ...@@ -58,10 +69,6 @@ static ec_master_state_t master_state = {};
static ec_domain_t *domain1 = NULL; static ec_domain_t *domain1 = NULL;
static ec_domain_state_t domain1_state = {}; static ec_domain_state_t domain1_state = {};
// Timer
static unsigned int sig_alarms = 0;
static unsigned int user_alarms = 0;
/****************************************************************************/ /****************************************************************************/
// process data // process data
...@@ -81,10 +88,26 @@ static int off_counter_in; ...@@ -81,10 +88,26 @@ static int off_counter_in;
static int off_counter_out; static int off_counter_out;
static unsigned int counter = 0; static unsigned int counter = 0;
static unsigned int blink_counter = 0;
static unsigned int blink = 0; static unsigned int blink = 0;
static unsigned int sync_ref_counter = 0; static unsigned int sync_ref_counter = 0;
struct timeval app_time; 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;
}
/*****************************************************************************/ /*****************************************************************************/
...@@ -110,7 +133,7 @@ void check_master_state(void) ...@@ -110,7 +133,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);
...@@ -124,68 +147,108 @@ void check_master_state(void) ...@@ -124,68 +147,108 @@ void check_master_state(void)
void cyclic_task() void cyclic_task()
{ {
int i; struct timespec wakeupTime, time;
#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
// receive process data // get current time
ecrt_master_receive(master); clock_gettime(CLOCK_TO_USE, &wakeupTime);
ecrt_domain_process(domain1);
// check process data state (optional) while(1) {
check_domain1_state(); wakeupTime = timespec_add(wakeupTime, cycletime);
clock_nanosleep(CLOCK_TO_USE, TIMER_ABSTIME, &wakeupTime, NULL);
if (counter) { #ifdef MEASURE_TIMING
counter--; clock_gettime(CLOCK_TO_USE, &startTime);
} else { // do this at 1 Hz latency_ns = DIFF_NS(wakeupTime, startTime);
counter = FREQUENCY; period_ns = DIFF_NS(lastStartTime, startTime);
exec_ns = DIFF_NS(lastStartTime, endTime);
lastStartTime = startTime;
// calculate new process data if (latency_ns > latency_max_ns) {
blink = !blink; 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
// check for master state (optional) // receive process data
check_master_state(); 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();
#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;
#endif
if (blink_counter) { // calculate new process data
blink_counter--; blink = !blink;
} else { }
blink_counter = 9;
// calculate new process data // write process data
blink = !blink; EC_WRITE_U8(domain1_pd + off_dig_out, blink ? 0x66 : 0x99);
} EC_WRITE_U8(domain1_pd + off_counter_out, blink ? 0x00 : 0x02);
// write process data // write application time to master
EC_WRITE_U8(domain1_pd + off_dig_out, blink ? 0x66 : 0x99); clock_gettime(CLOCK_TO_USE, &time);
EC_WRITE_U8(domain1_pd + off_counter_out, blink ? 0x00 : 0x02); ecrt_master_application_time(master, timespec2u64(time));
app_time.tv_usec += 1000000 / FREQUENCY; if (sync_ref_counter) {
if (app_time.tv_usec >= 1000000) { sync_ref_counter--;
app_time.tv_usec -= 1000000; } else {
app_time.tv_sec++; sync_ref_counter = 1; // sync every cycle
} ecrt_master_sync_reference_clock(master);
ecrt_master_application_time(master, EC_TIMEVAL2NANO(app_time)); }
ecrt_master_sync_slave_clocks(master);
if (sync_ref_counter) { // send process data
sync_ref_counter--; ecrt_domain_queue(domain1);
} else { ecrt_master_send(master);
sync_ref_counter = 9;
ecrt_master_sync_reference_clock(master);
}
ecrt_master_sync_slave_clocks(master);
// send process data #ifdef MEASURE_TIMING
ecrt_domain_queue(domain1); clock_gettime(CLOCK_TO_USE, &endTime);
ecrt_master_send(master); #endif
} }
/****************************************************************************/
void signal_handler(int signum) {
switch (signum) {
case SIGALRM:
sig_alarms++;
break;
}
} }
/****************************************************************************/ /****************************************************************************/
...@@ -193,8 +256,11 @@ void signal_handler(int signum) { ...@@ -193,8 +256,11 @@ void signal_handler(int signum) {
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
ec_slave_config_t *sc; ec_slave_config_t *sc;
struct sigaction sa;
struct itimerval tv; if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
perror("mlockall failed");
return -1;
}
master = ecrt_request_master(0); master = ecrt_request_master(0);
if (!master) if (!master)
...@@ -237,7 +303,7 @@ int main(int argc, char **argv) ...@@ -237,7 +303,7 @@ int main(int argc, char **argv)
return -1; return -1;
// configure SYNC signals for this slave // configure SYNC signals for this slave
ecrt_slave_config_dc(sc, 0x0700, 10000000, 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))
...@@ -247,50 +313,15 @@ int main(int argc, char **argv) ...@@ -247,50 +313,15 @@ int main(int argc, char **argv)
return -1; return -1;
} }
#if PRIORITY
pid_t pid = getpid(); pid_t pid = getpid();
if (setpriority(PRIO_PROCESS, pid, -19)) if (setpriority(PRIO_PROCESS, pid, -19))
fprintf(stderr, "Warning: Failed to set priority: %s\n", fprintf(stderr, "Warning: Failed to set priority: %s\n",
strerror(errno)); strerror(errno));
#endif
sa.sa_handler = signal_handler; printf("Starting cyclic function.\n");
sigemptyset(&sa.sa_mask); cyclic_task();
sa.sa_flags = 0;
if (sigaction(SIGALRM, &sa, 0)) { return 0;
fprintf(stderr, "Failed to install signal handler!\n");
return -1;
}
printf("Starting timer...\n");
tv.it_interval.tv_sec = 0;
tv.it_interval.tv_usec = 1000000 / FREQUENCY;
tv.it_value.tv_sec = 0;
tv.it_value.tv_usec = 1000;
if (setitimer(ITIMER_REAL, &tv, NULL)) {
fprintf(stderr, "Failed to start timer: %s\n", strerror(errno));
return 1;
}
gettimeofday(&app_time, NULL);
printf("Started.\n");
while (1) {
pause();
#if 0
struct timeval t;
gettimeofday(&t, NULL);
printf("%u.%06u\n", t.tv_sec, t.tv_usec);
#endif
while (sig_alarms != user_alarms) {
cyclic_task();
user_alarms++;
}
}
return 0;
} }
/****************************************************************************/ /****************************************************************************/
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment