robert-burger / libethercat

EtherCAT master library. This library is used to build a deterministic fieldbus network with EtherCAT components.
https://www.dlr.de/rm
Other
20 stars 4 forks source link

Sync manager configuration #2

Closed marcfir closed 4 months ago

marcfir commented 4 months ago

I have an EL6080 in my test setup and an automatic configuration of the sync manager by reading the configuration via coe does not work. Using a manual configuration setting sm_set_by_user and the sm structs works fine.

While debugging with automatic configuration I found out that ec_slave_generate_mapping' jumps toec_coe_generate_mapping'. But reading the 0x1C12 or 0x1C13 register with ec_coe_sdo_read(pec, slave, 0x1C12,...) returns 0.

Is this a problem with the Eeprom? How does TwinCAT handle this?

Any ideas?

robert-burger commented 4 months ago

There's only a field in EEPROM which identifies if the slave supports mailbox/protocols. In your case it seems to report CoE support and according to the Beckhoff documentation (https://infosys.beckhoff.com/content/1033/el6080/2454368267.html?id=4352996004428320181) this seems right. So the EEPROM should not be the problem.

libethercat then tries to generate a valid process-data-mapping while switching form PREOP to SAFEOP. It first tries CoE and SoE mailbox protocols, if they are not supported it falls back to EEPROM (https://github.com/robert-burger/libethercat/blob/0253bc4898853ef1a1e311b46b7da71b2185a8c3/src/slave.c#L655).

What do you exactly mean with "ec_coe_sdo_read(pec, slave, 0x1C12,...) returns 0." ? The return value of the function is 0, or reading sub_index 0 returns 0 in buf ? I assume you mean the second one. So contrary to the documentation there's no pdo mapping existing in the mailbox (which wouldn't surprise me) and you have to configure that in the PREOP state. You have to send something like this (and always check return values and abort_code ;-) ):

osal_uint32_t abort_code = 0;
osal_uint8_t cnt = 0;
osal_uint16_t pdo = 0x1600;
ec_coe_sdo_write(pec, slave, 0x1C12, 0, 0, (osal_uint8_t *)cnt, sizeof(cnt), &abort_code); 
ec_coe_sdo_write(pec, slave, 0x1C12, 1, 0, (osal_uint8_t *)pdo, sizeof(cnt), &abort_code); 
cnt = 1;
ec_coe_sdo_write(pec, slave, 0x1C12, 0, 0, (osal_uint8_t *)cnt, sizeof(cnt), &abort_code); 

cnt = 0;
osal_uint16_t pdo = 0x1A00;
ec_coe_sdo_write(pec, slave, 0x1C13, 0, 0, (osal_uint8_t *)cnt, sizeof(cnt), &abort_code); 
ec_coe_sdo_write(pec, slave, 0x1C13, 1, 0, (osal_uint8_t *)pdo, sizeof(cnt), &abort_code); 
cnt = 1;
ec_coe_sdo_write(pec, slave, 0x1C13, 0, 0, (osal_uint8_t *)cnt, sizeof(cnt), &abort_code); 

How exactly did you configure the sync managers with "sm_set_by_user" ?

TwinCAT in most cases does not use online values (live data from slave) for the mailbox information. It reads the ESI/XML slave description files and uses this information for configuration/operation. The sad thing about this is, that there's is a need of providing those files. libethercat currently does not read them, but that's a point we could think about.

A last thing to mention is that there might also be a very small PDO configuration present in the structure section of the EEPROM. So we could implement a fallback if mailbox mapping generation fails or maps nothing.

marcfir commented 4 months ago

Thank you for the detailed explanation.

What do you exactly mean with "ec_coe_sdo_read(pec, slave, 0x1C12,...) returns 0." ? The return value of the function is 0, or reading sub_index 0 returns 0 in buf ?

Yeah, I mean the buf. So testing the slave with the following shows that the CoE works, but the `0x1C12' registers are not set to default.

void read_and_print(ec_t *pec, uint16_t slave, uint16_t idx, uint8_t sub_idx)
{
    uint8_t buf[200] = {0};
    size_t buf_len = sizeof(buf);
    int ret_c = 0;
    uint32_t abort_code = 0;
    ret_c = ec_coe_sdo_read(pec, slave, idx, sub_idx, 0, buf, &buf_len, &abort_code);
    printf("r=%u a=%u len=%lu: ", ret_c, abort_code, buf_len);
    for (int i = 0; i < buf_len; i++)
    {
        printf("%u ", buf[i]);
    }
    printf("\n");
};

read_and_print(&ec, 1, 0x1000, 0);
read_and_print(&ec, 1, 0x1008, 0);
read_and_print(&ec, 1, 0x1C00, 0);
read_and_print(&ec, 1, 0x1C12, 0);
read_and_print(&ec, 1, 0x1C12, 1);
read_and_print(&ec, 1, 0x1C12, 2);

read_and_print(&ec, 1, 0x1C13, 0);
read_and_print(&ec, 1, 0x1C13, 1);
read_and_print(&ec, 1, 0x1C13, 2);

// This returns
// r=0 a=0 len=4: 137 19 0 0 
// r=0 a=0 len=6: 69 76 54 48 56 48 
// r=0 a=0 len=1: 4 
// r=0 a=0 len=1: 0 

I have configured the Sync Manager as follows. I took the adr and len from TwinCAT. I set the flags to what I found while debugging. I didn't find out how this field is used.

ec.slaves[1].sm_set_by_user = 1;
// Mailbox Out
ec.slaves[1].sm[0].adr = 0x2E00;
ec.slaves[1].sm[0].len = 256;
ec.slaves[1].sm[0].flags = 65574;
// Mailbox In
ec.slaves[1].sm[1].adr = 0x2F00;
ec.slaves[1].sm[1].len = 256;
ec.slaves[1].sm[1].flags = 65570;
// Out
ec.slaves[1].sm[2].adr = 0x1000;
ec.slaves[1].sm[2].len = 2;
ec.slaves[1].sm[2].flags = 65572;
// In
ec.slaves[1].sm[3].adr = 0x1F00;
ec.slaves[1].sm[3].len = 2;
ec.slaves[1].sm[3].flags = 65568;

Looking at the ENI file of TwinCAT I don't see any CoE init commands. But there are the general init commands for all state transitions with the fpwr commands and so on. But I don't see any PDO configuration or am I missing something?

image

PI,BI,SI,OI|cmd=2|adp=65535|ado=288|data=1,1,0,0|set device state to INIT
PI,SI,OI|cmd=1|adp=65535|ado=304|data=0,0,0,0|check device state for INIT
BI|cmd=1|adp=65535|ado=304|data=0,0,0,0|check device state for INIT
IP,IB|cmd=2|adp=65535|ado=288|data=1,1,0,0|set device state to INIT
IP,IB|cmd=1|adp=65535|ado=304|data=0,0,0,0|check device state for INIT
IP|cmd=2|adp=65535|ado=1280|data=0,0|assign EEPROM to ECAT
IP|cmd=2|adp=65535|ado=1282|data=0,0,0,1,0,8,0,0,0,0,0,0|check vendor id
IP|cmd=1|adp=65535|ado=1288|data=0,0,0,0,0,0,0,0|check vendor id
IP|cmd=2|adp=65535|ado=1282|data=0,0,0,1,0,10,0,0,0,0,0,0|check product code
IP|cmd=1|adp=65535|ado=1288|data=0,0,0,0,0,0,0,0|check product code
IP,IB|cmd=2|adp=65535|ado=16|data=14,10,0,3|set physical address
IP,IB,PI,SI,OI|cmd=5|adp=1002|ado=2048|data=0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0|clear sm 0/1 (mailbox out/in)
BI|cmd=2|adp=65535|ado=2048|data=0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0|clear sm 0/1 (mailbox out/in)
IP|cmd=5|adp=1002|ado=2048|data=0,0,2,14,0,0,0,1,2,6,0,0,0,1,0,0|set sm 0 (mailbox out)
IP|cmd=5|adp=1002|ado=2056|data=0,0,2,15,0,0,0,1,2,2,0,0,0,1,0,0|set sm 1 (mailbox in)
IB|cmd=5|adp=1002|ado=2048|data=0,0,1,8,1,4,0,2,2,6,0,0,0,1,0,0|set sm 0 (bootstrap out)
IB|cmd=5|adp=1002|ado=2056|data=1,4,1,10,1,4,0,2,2,2,0,0,0,1,0,0|set sm 1 (bootstrap in)
SP,OP|cmd=5|adp=1002|ado=288|data=1,2,0,0|set device state to PREOP
IP,SP,SI,OP,OI|cmd=5|adp=1002|ado=2064|data=0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0|clear sms
PS|cmd=5|adp=1002|ado=2064|data=0,0,1,0,0,2,0,0,2,4,0,0,0,1,0,0|set sm 2 (outputs)
PS|cmd=5|adp=1002|ado=2072|data=0,0,1,15,0,2,0,0,2,0,0,0,0,1,0,0|set sm 3 (inputs)
PS|cmd=5|adp=1002|ado=1536|data=0,0,0,0,0,0,0,1,0,2,0,0,0,0,0,7,0,0,1,0,0,0,0,2,0,1,0,0,0,0,0,0|set fmmu 0 (outputs)
PS|cmd=5|adp=1002|ado=1552|data=0,0,0,0,0,0,0,1,0,2,0,0,0,0,0,7,0,0,1,15,0,0,0,1,0,1,0,0,0,0,0,0|set fmmu 1 (inputs)
IP,IB|cmd=5|adp=1002|ado=1568|data=0,0,0,0,0,0,0,9,0,1,0,0,0,0,0,0,0,13,0,8,0,0,0,1,0,1,0,0,0,0,0,0|set fmmu 2 (mailbox state)
OS|cmd=5|adp=1002|ado=288|data=0,4,0,0|set device state to SAFEOP
SP,SI,OP,OI|cmd=5|adp=1002|ado=1536|data=0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0|clear fmmu 0
SP,SI,OP,OI|cmd=5|adp=1002|ado=1552|data=0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0|clear fmmu 1
PI,BI,SI,OI|cmd=5|adp=1002|ado=1568|data=0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0|clear fmmu 2
SP,OP|cmd=4|adp=1002|ado=304|data=0,0,0,0,0,0,0,0,0,0,0,0|check device state for PREOP
IP,IB|cmd=5|adp=1002|ado=1280|data=0,1|assign EEPROM to PDI
II|cmd=2|adp=65535|ado=1280|data=0,0|assign EEPROM back to ECAT
IP|cmd=5|adp=1002|ado=288|data=1,2,0,0|set device state to PREOP
IP|cmd=4|adp=1002|ado=304|data=0,0,0,0,0,0,0,0,0,0,0,0|check device state for PREOP
IP,BI|cmd=2|adp=65535|ado=1280|data=0,0|assign EEPROM back to ECAT
IB|cmd=5|adp=1002|ado=288|data=1,3,0,0|set device state to BOOT
IB|cmd=4|adp=1002|ado=304|data=0,0,0,0,0,0,0,0,0,0,0,0|check device state for BOOT
PS|cmd=5|adp=1002|ado=288|data=0,4,0,0|set device state to SAFEOP
PS|cmd=4|adp=1002|ado=304|data=0,0,0,0,0,0,0,0,0,0,0,0|check device state for SAFEOP
OS|cmd=4|adp=1002|ado=304|data=0,0,0,0,0,0,0,0,0,0,0,0|check device state for SAFEOP
SO|cmd=5|adp=1002|ado=288|data=0,8,0,0|set device state to OP
SO|cmd=4|adp=1002|ado=304|data=0,0,0,0,0,0,0,0,0,0,0,0|check device state for OP

el6080_eni.zip

Reading the ENI file sounds like a proper and stable way.

robert-burger commented 4 months ago

I set the flags to what I found while debugging. I didn't find out how this field is used.

Flags is a 32-bit value consisting of "Control", "Status", "Activate", "PDI Control" of the sync manager regsiters. See https://download.beckhoff.com/download/Document/io/ethercat-development-products/ethercat_esc_datasheet_sec2_registers_3i0.pdf on page 60.

robert-burger commented 4 months ago

And yes it looks like that the slave is happy with a static/fixed sync manager configuration for inputs and output. Imho this is a faulty behavior of the slave as it should be compliant to the ethercat specs.

marcfir commented 4 months ago

Thanks for explaining the flags.