<div dir="auto">Hi Gavin,<div dir="auto"><br></div><div dir="auto">I'm finally getting it. What you said makes perfect sense. The code is working beautifully now. Thank you for your help! I hope this thread helps other new user get their projects up and running.</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Apr 5, 2017 12:00 AM, "Gavin Lambert" <<a href="mailto:gavinl@compacsort.com">gavinl@compacsort.com</a>> wrote:<br type="attribution"><blockquote class="quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div lang="EN-NZ" link="blue" vlink="purple"><div class="m_-8802185563873307026WordSection1"><p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Calibri",sans-serif">Unless your slave device is a Beckhoff EL3102, that name is going to confuse you later.  You should use a more accurate name, or just specify the values directly instead of using a #define.<u></u><u></u></span></p><p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Calibri",sans-serif"><u></u> <u></u></span></p><p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Calibri",sans-serif">Similarly, you haven’t changed AnaInSlavePos from its previous value of 0,2 which specifies that the slave is the third device in the network, which is probably not correct for your network.<u></u><u></u></span></p><p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Calibri",sans-serif"><u></u> <u></u></span></p><p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Calibri",sans-serif">You should probably spend some time reading the documentation for the library and understand what all of these tables and values actually mean, based on the documentation for the APIs they are passed to and EtherCAT networks in general.<u></u><u></u></span></p><p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Calibri",sans-serif"><u></u> <u></u></span></p><p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Calibri",sans-serif">(Also note that while it’s ok to call printf from your real-time loop while you’re experimenting, you’ll have to remove it for a real application.  printf is blocking and too slow to maintain a stable real-time loop; you have to be very careful what code you put in there.)<u></u><u></u></span></p><p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Calibri",sans-serif"><u></u> <u></u></span></p><div style="border:none;border-left:solid blue 1.5pt;padding:0cm 0cm 0cm 4.0pt"><div><div style="border:none;border-top:solid #e1e1e1 1.0pt;padding:3.0pt 0cm 0cm 0cm"><p class="MsoNormal"><b><span lang="EN-US" style="font-size:11.0pt;font-family:"Calibri",sans-serif">From:</span></b><span lang="EN-US" style="font-size:11.0pt;font-family:"Calibri",sans-serif"> Justin Hunt [mailto:<a href="mailto:jphunt3@asu.edu" target="_blank">jphunt3@asu.edu</a>] <br><b>Sent:</b> Wednesday, 5 April 2017 13:32<br><b>To:</b> Gavin Lambert <<a href="mailto:gavin.lambert@compacsort.com" target="_blank">gavin.lambert@compacsort.com</a>><br><b>Cc:</b> <a href="mailto:etherlab-users@etherlab.org" target="_blank">etherlab-users@etherlab.org</a><br><b>Subject:</b> Re: [etherlab-users] Beginner: Modifying the example code "user"<u></u><u></u></span></p></div></div><div class="elided-text"><p class="MsoNormal"><u></u> <u></u></p><div><div><div><p class="MsoNormal" style="margin-bottom:12.0pt">Hi Gavin,<u></u><u></u></p></div><p class="MsoNormal" style="margin-bottom:12.0pt">Thank you for the reply, I really appreciate your time. I worked today to implement your instructions. Here is what I did:<u></u><u></u></p></div><div><p class="MsoNormal" style="margin-bottom:12.0pt">1) I changed the original definition "#define Beckhoff_EL3102 0x00000002, 0x0c1e3052" to include the vendor ID and product code of my sensor, which I got from using Konsole command "ethercat slaves -v." So now it reads "#define Beckhoff_EL3102 0x00000732, 0x26483052"<u></u><u></u></p></div><div><p class="MsoNormal" style="margin-bottom:12.0pt">2) I updated the domain1_regs to include only analog input from the index and sub index of the sensor force value I wish to read, like so:<br><br>const static ec_pdo_entry_reg_t domain1_regs[] = {<br>    {AnaInSlavePos,  Beckhoff_EL3102, 0x6000, 2, &off_ana_in_value},<br>    {}<u></u><u></u></p></div><div><p class="MsoNormal" style="margin-bottom:12.0pt">I am not sure if these two changes address your instructions correctly. I can however compile and run the code now. I tried to add the following line under cyclic_task() to see if I could stream the data to the Konsole, but it does not see to work:<br><br>printf("AnaIn: value %u\n", EC_READ_U32(domain1_pd + off_ana_in_value));<u></u><u></u></p></div><div><p class="MsoNormal"><u></u> <u></u></p></div><p class="MsoNormal" style="margin-bottom:12.0pt">included below is the complete code in case it is needed.<br><br> *****************************<wbr>******************************<wbr>*****************/<br><br>#include <errno.h><br>#include <signal.h><br>#include <stdio.h><br>#include <string.h><br>#include <sys/resource.h><br>#include <sys/time.h><br>#include <sys/types.h><br>#include <unistd.h><br><br>/*****************************<wbr>******************************<wbr>*****************/<br><br>#include "ecrt.h"<br><br>/*****************************<wbr>******************************<wbr>*****************/<br><br>// Application parameters<br>#define FREQUENCY 100<br>#define PRIORITY 1<br><br>// Optional features<br>#define CONFIGURE_PDOS  1<br>#define SDO_ACCESS      0<br><br>/*****************************<wbr>******************************<wbr>*****************/<br><br>// EtherCAT<br>static ec_master_t *master = NULL;<br>static ec_master_state_t master_state = {};<br><br>static ec_domain_t *domain1 = NULL;<br>static ec_domain_state_t domain1_state = {};<br><br>static ec_slave_config_t *sc_ana_in = NULL;<br>static ec_slave_config_state_t sc_ana_in_state = {};<br><br>// Timer<br>static unsigned int sig_alarms = 0;<br>static unsigned int user_alarms = 0;<br><br>/*****************************<wbr>******************************<wbr>*****************/<br><br>// process data<br>static uint8_t *domain1_pd = NULL;<br><br>#define BusCouplerPos  0, 0 //#define assigns 0, 0 to the name BusCouplerPos<br>#define DigOutSlavePos 0, 2<br>#define AnaInSlavePos  0, 3<br>#define AnaOutSlavePos 0, 4<br><br>#define Beckhoff_EK1100 0x00000002, 0x044c2c52<br>//#define Beckhoff_EL2004 0x00000002, 0x07d43052<br>#define Beckhoff_EL2032 0x00000002, 0x07f03052<br>#define Beckhoff_EL3152 0x00000002, 0x0c503052<br>//#define Beckhoff_EL3102 0x00000002, 0x0c1e3052<br>#define Beckhoff_EL3102 0x00000732, 0x26483052<br>#define Beckhoff_EL4102 0x00000002, 0x10063052<br>//test<br>// offsets for PDO entries<br>static unsigned int off_ana_in_status;<br>static unsigned int off_ana_in_value;<br>//static unsigned int off_ana_out;<br>//static unsigned int off_dig_out;<br><br>const static ec_pdo_entry_reg_t domain1_regs[] = {<br>    {AnaInSlavePos,  Beckhoff_EL3102, 0x6000, 2, &off_ana_in_value},<br>    {}<br>};<br><br>static unsigned int counter = 0;<br>static unsigned int blink = 0;<br><br>/*****************************<wbr>******************************<wbr>******************/<br><br>#if CONFIGURE_PDOS<br><br><br>static ec_pdo_entry_info_t el3102_pdo_entries[] = {<br>    {0x7010, 1, 32}, /* Control 1 */<br>    {0x7010, 2, 32}, /* Control 2 */<br>    {0x6000, 1, 32}, /* Fx/Gage0 */<br>    {0x6000, 2, 32}, /* Fy/Gage1 */<br>    {0x6000, 3, 32}, /* Fz/Gage2 */<br>    {0x6000, 4, 32}, /* Tx/Gage3 */<br>    {0x6000, 5, 32}, /* Ty/Gage3 */<br>    {0x6000, 6, 32}, /* Tz/Gage3 */<br>    {0x6010, 0, 32}, /* SubIndex 000 */<br>    {0x6020, 0, 32}, /* SubIndex 000 */<br>};<br><br>static ec_pdo_info_t el3102_pdos[] = {<br>    {0x1601, 2, el3102_pdo_entries + 0}, /* DO RxPDO-Map */<br>    {0x1a00, 8, el3102_pdo_entries + 2}, /* DI TxPDO-Map */<br>};<br>ec_sync_info_t el3102_syncs[] = {<br>    {0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},<br>    {1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},<br>    {2, EC_DIR_OUTPUT, 1, el3102_pdos + 0, EC_WD_ENABLE},<br>    {3, EC_DIR_INPUT, 1, el3102_pdos + 1, EC_WD_DISABLE},<br>    {0xff}<br>};<br><br>#endif<br><br>/*****************************<wbr>******************************<wbr>******************/<br><br>#if SDO_ACCESS<br>static ec_sdo_request_t *sdo;<br>#endif<br><br>/*****************************<wbr>******************************<wbr>******************/<br><br>void check_domain1_state(void)<br>{<br>    ec_domain_state_t ds;<br><br>    ecrt_domain_state(domain1, &ds);<br><br>    if (ds.working_counter != domain1_state.working_counter)<br>        printf("Domain1: WC %u.\n", ds.working_counter);<br>    if (ds.wc_state != domain1_state.wc_state)<br>        printf("Domain1: State %u.\n", ds.wc_state);<br><br>    domain1_state = ds;<br>}<br><br>/*****************************<wbr>******************************<wbr>******************/<br><br>void check_master_state(void)<br>{<br>    ec_master_state_t ms;<br>    //printf("test");<br>    ecrt_master_state(master, &ms);<br><br>    if (ms.slaves_responding != master_state.slaves_<wbr>responding)<br>        printf("%u slave(s).\n", ms.slaves_responding);<br>    if (ms.al_states != master_state.al_states)<br>        printf("AL states: 0x%02X.\n", ms.al_states);<br>    if (ms.link_up != master_state.link_up)<br>    //printf("test");<br>        printf("Link is %s.\n", ms.link_up ? "up" : "down");<br>    master_state = ms;<br>    <br>}<br><br>/*****************************<wbr>******************************<wbr>******************/<br>//printf("enter");<br>void check_slave_config_states(<wbr>void)<br><br>{<br>    <br>    ec_slave_config_state_t s;<br><br>    ecrt_slave_config_state(sc_<wbr>ana_in, &s);<br>//printf("test");<br>    if (s.al_state != sc_ana_in_state.al_state)<br>        printf("AnaIn: State 0x%02X.\n", s.al_state);<br>    if (s.online != sc_ana_in_state.online)<br>        printf("AnaIn: %s.\n", s.online ? "online" : "offline");<br>    if (s.operational != sc_ana_in_state.operational)<br>        printf("AnaIn: %soperational.\n",<br>                s.operational ? "" : "Not ");<br><br>    sc_ana_in_state = s;<br>}<br><br>/*****************************<wbr>******************************<wbr>******************/<br><br>#if SDO_ACCESS<br>void read_sdo(void)<br>{<br>    switch (ecrt_sdo_request_state(sdo)) {<br>        case EC_REQUEST_UNUSED: // request was not used yet<br>            ecrt_sdo_request_read(sdo); // trigger first read<br>            break;<br>        case EC_REQUEST_BUSY:<br>            fprintf(stderr, "Still busy...\n");<br>            break;<br>        case EC_REQUEST_SUCCESS:<br>            fprintf(stderr, "SDO value: 0x%04X\n",<br>                    EC_READ_U32(ecrt_sdo_request_<wbr>data(sdo)));<br>            ecrt_sdo_request_read(sdo); // trigger next read<br>            break;<br>        case EC_REQUEST_ERROR:<br>            fprintf(stderr, "Failed to read SDO!\n");<br>            ecrt_sdo_request_read(sdo); // retry reading<br>            break;<br>    }<br>}<br>#endif<br><br>/*****************************<wbr>******************************<wbr>*****************/<br><br>void cyclic_task()<br>{<br>  <br>    // receive process data<br>    ecrt_master_receive(master);<br>    ecrt_domain_process(domain1);<br><br>    // check process data state (optional)<br>    check_domain1_state();<br>    printf("AnaIn: value %u\n", EC_READ_U32(domain1_pd + off_ana_in_value));<br>    if (counter) {<br>        counter--;<br>    } else { // do this at 1 Hz<br>        counter = FREQUENCY;<br><br>        // calculate new process data<br>        blink = !blink;<br>      //printf("test");<br>        // check for master state (optional)<br>        //check_master_state();<br>//printf("test1");<br>        // check for islave configuration state(s) (optional)<br>        check_slave_config_states();<br><br>#if SDO_ACCESS<br>        // read process data SDO<br>        read_sdo();<br>#endif<br><br>    }<br><br>#if 0<br>    // read process data<br>    // printf("test2");<br>    printf("AnaIn: state %u value %u\n",<br>            EC_READ_U8(domain1_pd + off_ana_in_status),<br>            EC_READ_U32(domain1_pd + off_ana_in_value));<br>#endif<br><br>// #if 1<br>//     // write process data<br>//     EC_WRITE_U8(domain1_pd + off_dig_out, blink ? 0x06 : 0x09);<br>// #endif<br><br>    // send process data<br>    ecrt_domain_queue(domain1);<br>    ecrt_master_send(master);<br>}<br><br>/*****************************<wbr>******************************<wbr>*****************/<br><br>void signal_handler(int signum) {<br>    switch (signum) {<br>        case SIGALRM:<br>            sig_alarms++;<br>            break;<br>    }<br>}<br><br>/*****************************<wbr>******************************<wbr>*****************/<br><br>int main(int argc, char **argv)<br>{<br>    ec_slave_config_t *sc;<br>    struct sigaction sa;<br>    struct itimerval tv;<br><br>    master = ecrt_request_master(0);<br>    if (!master)<br>        return -1;<br><br>    domain1 = ecrt_master_create_domain(<wbr>master);<br>    if (!domain1)<br>        return -1;<br><br>    if (!(sc_ana_in = ecrt_master_slave_config(<br>                    master, AnaInSlavePos, Beckhoff_EL3102))) {<br>        fprintf(stderr, "Failed to get slave configuration.\n");<br>        return -1;<br>    }<br><br>#if SDO_ACCESS<br>    fprintf(stderr, "Creating SDO requests...\n");<br>    if (!(sdo = ecrt_slave_config_create_sdo_<wbr>request(sc_ana_in, 0x6000, 2, 2))) {<br>        fprintf(stderr, "Failed to create SDO request.\n");<br>        return -1;<br>    }<br>    ecrt_sdo_request_timeout(sdo, 500); // ms<br>#endif<br><br>#if CONFIGURE_PDOS<br>    printf("Configuring PDOs...\n");<br>    if (ecrt_slave_config_pdos(sc_<wbr>ana_in, EC_END, el3102_syncs)) {<br>        fprintf(stderr, "Failed to configure PDOs.\n");<br>        return -1;<br>    }<br><br>//     if (!(sc = ecrt_master_slave_config(<br>//                     master, AnaOutSlavePos, Beckhoff_EL4102))) {<br>//         fprintf(stderr, "Failed to get slave configuration.\n");<br>//         return -1;<br>//     }<br>// <br>//     if (ecrt_slave_config_pdos(sc, EC_END, el4102_syncs)) {<br>//         fprintf(stderr, "Failed to configure PDOs.\n");<br>//         return -1;<br>//     }<br>// <br>//     if (!(sc = ecrt_master_slave_config(<br>//                     master, DigOutSlavePos, Beckhoff_EL2032))) {<br>//         fprintf(stderr, "Failed to get slave configuration.\n");<br>//         return -1;<br>//     }<br><br>//     if (ecrt_slave_config_pdos(sc, EC_END, el2004_syncs)) {<br>//         fprintf(stderr, "Failed to configure PDOs.\n");<br>//         return -1;<br>//     }<br>#endif<br><br>    // Create configuration for bus coupler<br>    sc = ecrt_master_slave_config(<wbr>master, BusCouplerPos, Beckhoff_EL3102);<br>    if (!sc)<br>        return -1;<br><br>    if (ecrt_domain_reg_pdo_entry_<wbr>list(domain1, domain1_regs)) {<br>        fprintf(stderr, "PDO entry registration failed!\n");<br>        return -1;<br>    }<br><br>    printf("Activating master...\n");<br>    if (ecrt_master_activate(master))<br>        return -1;<br><br>    if (!(domain1_pd = ecrt_domain_data(domain1))) {<br>        return -1;<br>    }<br><br>#if PRIORITY<br>    pid_t pid = getpid();<br>    if (setpriority(PRIO_PROCESS, pid, -19))<br>        fprintf(stderr, "Warning: Failed to set priority: %s\n",<br>                strerror(errno));<br>#endif<br><br>    sa.sa_handler = signal_handler;<br>    sigemptyset(&sa.sa_mask);<br>    sa.sa_flags = 0;<br>    if (sigaction(SIGALRM, &sa, 0)) {<br>        fprintf(stderr, "Failed to install signal handler!\n");<br>        return -1;<br>    }<br><br>    printf("Starting timer...\n");<br>    tv.it_interval.tv_sec = 0;<br>    tv.it_interval.tv_usec = 100000 / FREQUENCY;<br>    tv.it_value.tv_sec = 0;<br>    tv.it_value.tv_usec = 1000;<br>    if (setitimer(ITIMER_REAL, &tv, NULL)) {<br>        fprintf(stderr, "Failed to start timer: %s\n", strerror(errno));<br>        return 1;<br>    }<br><br>    printf("Started.\n");<br>    while (1) {<br>      //printf("test");<br>        pause();<br><br>#if 0<br>        struct timeval t;<br>        gettimeofday(&t, NULL);<br>        printf("%u.%06u\n", t.tv_sec, t.tv_usec);<br>#endif<br>    <br>        while (sig_alarms != user_alarms) {<br>            cyclic_task();<br>        //fprintf("t");<br>            user_alarms++;<br>        }<br>    }<br><br>    return 0;<br>}<br><br>/*****************************<wbr>******************************<wbr>*****************/<u></u><u></u></p><div><div><p class="MsoNormal" style="margin-bottom:12.0pt"><u></u> <u></u></p></div></div></div><div><p class="MsoNormal"><u></u> <u></u></p><div><p class="MsoNormal">On Mon, Apr 3, 2017 at 7:10 PM, Gavin Lambert <<a href="mailto:gavinl@compacsort.com" target="_blank">gavinl@compacsort.com</a>> wrote:<u></u><u></u></p><blockquote style="border:none;border-left:solid #cccccc 1.0pt;padding:0cm 0cm 0cm 6.0pt;margin-left:4.8pt;margin-right:0cm"><div><div><p class="MsoNormal" style="margin-left:16.8pt"><span style="font-size:11.0pt;font-family:"Calibri",sans-serif">You’re halfway there.  You also need to update the </span>domain1_regs<span style="font-size:11.0pt;font-family:"Calibri",sans-serif"> to reflect the layout of your network (type and position of all slave devices) and to define variables to receive the offsets into domain memory to use for transferring the corresponding PDOs.</span><u></u><u></u></p></div></div></blockquote></div></div></div></div></div></div></blockquote></div><br></div>