OpenEtherCATsociety / SOES

Simple Open Source EtherCAT Slave
Other
578 stars 249 forks source link

PDO mapping / length changing #44

Closed cainsbrainstem closed 5 years ago

cainsbrainstem commented 6 years ago

Hi there,

I have a PDO configured as an array of 256 bytes. I'd like to use the method reference in SOEM Slaves Configuration #94 by hefloryd to adjust the length of the PDO (up to a max length of 256 bytes). My understanding is that SOES only supports fixed PDO mappings?

I had a dig around in esc_coe.c in the SDO_download function. If I modify line 490:

copy2mbx (mbxdata, (objd + nsub)->data, size);

to be:

if ((objd + nsub)->data != NULL) {
 copy2mbx (mbxdata, (objd + nsub)->data, size);
} else {
 copy2mbx (mbxdata,  (uint32_t*)(&(objd + nsub)->value ), size);
}

and change the const SDO objects (ie SDO1601) to not be const, I can adjust the length by rewriting SDO1601 subindex 0 to my desired length. Running slaveinfo shows that "PDO mapping according to CoE :" changes from the default number of bytes to what I choose it to be.

This is a kludge - but is it a reasonable way of achieving this functionality? I'm also not certain as to whether simply rewriting the object list like this will actually have any affect on the ethercat device side. Can anyone confirm this?

Thanks very much!

nakarlsson commented 6 years ago

Why not simple add a uint32 * to ->data, that way you won’t need a COE change.

Also, to create a conformant slave you need to do more, update the ESI and EEPROM letting the Master/configurator know you support PdoConfiguration eg. that 1601 is dynamic.

cainsbrainstem commented 6 years ago

Hi,

I took a look at your suggestion - it looks better! I have a couple of questions / issues: (these might be a config issue on my end)

I can do a uint32* to ->data as per your suggestion. For my test case, I'm only altering the length of 0x1601. I added in uint32 pointers to ->data for addresses 0x1c12, subindex 0 and 2, and address 0x1601 subindex 0.
Rewriting SDO1601 subindex 0 to my desired length then works. However, if I do not write the config (from within my modified slaveinfo) the defaults will not be set from the object dictionary. Do I have to write the defaults from the object dictionary value into the ->data fields myself? At the moment I have to run slaveinfo twice in order to get the config to correctly write.

This is the output of the first slaveinfo: ./slaveinfo enp3s0 -map -sdo SOEM (Simple Open EtherCAT Master) Slaveinfo Starting slaveinfo ec_init on enp3s0 succeeded. Read at 0x1c12:0 => wkc: 1; data: 0x0 (0) [rxPDO:0] Read at 0x1c12:2 => wkc: 1; data: 0x00 (0) [rxPDO:2] Read at 0x1601:0 => wkc: 1; data: 0x0 (0) [rxPDO:2] Writing config. Write at 0x1c12:0 => wkc: 1; data: 0x0 {clear SM PDO} Write at 0x1601:0 => wkc: 1; data: 0x0 {clear RX PDO} Write at 0x1601:0 => wkc: 1; data: 0x8 {Set num PDO entries} Write at 0x1c12:2 => wkc: 1; data: 0x1601 {list entries in smpdo} Write at 0x1c12:0 => wkc: 1; data: 0x2 {Set num PDOs} Read at 0x1c12:0 => wkc: 1; data: 0x2 (2) [rxPDO:0] Read at 0x1c12:2 => wkc: 1; data: 0x1601 (5633) [rxPDO:2] Read at 0x1601:0 => wkc: 1; data: 0x8 (8) [rxPDO:2] 1 slaves found and configured. Calculated workcounter 1 Not all slaves reached safe operational state. Slave 1 State=12 StatusCode= 1d : Invalid output configuration

Slave:1 Name:arb_slaves Output size: 0bits Input size: 192bits State: 18 Delay: 0[ns] Has DC: 1 DCParentport:0 Activeports:1.0.0.0 Configured address: 1001 Man: 00000a43 ID: 00001001 Rev: 00000000 SM0 A:1000 L: 128 F:00010026 Type:1 SM1 A:1080 L: 128 F:00010022 Type:2 SM2 A:1100 L: 0 F:00000024 Type:3 SM3 A:1900 L: 24 F:00010020 Type:4 FMMU0 Ls:00000000 Ll: 24 Lsb:0 Leb:7 Ps:1900 Psb:0 Ty:01 Act:01 FMMUfunc 0:1 1:0 2:0 3:0 MBX length wr: 128 rd: 128 MBX protocols : 04 CoE details: 13 FoE details: 00 EoE details: 00 SoE details: 00 Ebus current: 0[mA] only LRD/LWR:0 PDO mapping according to CoE : SM2 outputs addr b index: sub bitl data_type name [0xFF9E3DE0.0] 0x7000:0x01 0x20 UNSIGNED32 id0 [0xFF9E3DE4.0] 0x7000:0x02 0x20 UNSIGNED32 id1 [0xFF9E3DE8.0] 0x7000:0x03 0x20 UNSIGNED32 id2 [0xFF9E3DEC.0] 0x7000:0x04 0x20 UNSIGNED32 control [0xFF9E3DF0.0] 0x7000:0x05 0x20 UNSIGNED32 fault [0xFF9E3DF4.0] 0x7001:0x01 0x08 UNSIGNED8 dout0 [0xFF9E3DF5.0] 0x7001:0x02 0x08 UNSIGNED8 dout1 [0xFF9E3DF6.0] 0x7001:0x03 0x08 UNSIGNED8 dout2 [0xFF9E3DF7.0] 0x7001:0x04 0x08 UNSIGNED8 dout3 [0xFF9E3DF8.0] 0x7001:0x05 0x08 UNSIGNED8 dout4 [0xFF9E3DF9.0] 0x7001:0x06 0x08 UNSIGNED8 dout5 [0xFF9E3DFA.0] 0x7001:0x07 0x08 UNSIGNED8 dout6 [0xFF9E3DFB.0] 0x7001:0x08 0x08 UNSIGNED8 dout7 SM3 inputs addr b index: sub bitl data_type name [0x0000.0] 0x6000:0x01 0x20 UNSIGNED32 status [0x0004.0] 0x6000:0x02 0x20 UNSIGNED32 fault [0x0008.0] 0x6001:0x01 0x08 UNSIGNED8 din0 [0x0009.0] 0x6001:0x02 0x08 UNSIGNED8 din1 [0x000A.0] 0x6001:0x03 0x08 UNSIGNED8 din2 [0x000B.0] 0x6001:0x04 0x08 UNSIGNED8 din3 [0x000C.0] 0x6001:0x05 0x08 UNSIGNED8 din4 [0x000D.0] 0x6001:0x06 0x08 UNSIGNED8 din5 [0x000E.0] 0x6001:0x07 0x08 UNSIGNED8 din6 [0x000F.0] 0x6001:0x08 0x08 UNSIGNED8 din7 [0x0010.0] 0x6001:0x09 0x08 UNSIGNED8 din8 [0x0011.0] 0x6001:0x0A 0x08 UNSIGNED8 din9 [0x0012.0] 0x6001:0x0B 0x08 UNSIGNED8 din10 [0x0013.0] 0x6001:0x0C 0x08 UNSIGNED8 din11 [0x0014.0] 0x6001:0x0D 0x08 UNSIGNED8 din12 [0x0015.0] 0x6001:0x0E 0x08 UNSIGNED8 din13 [0x0016.0] 0x6001:0x0F 0x08 UNSIGNED8 din14 [0x0017.0] 0x6001:0x10 0x08 UNSIGNED8 din15 End slaveinfo, close socket End program

And this is the output when I immediately run it again:

./slaveinfo enp3s0 -map -sdo SOEM (Simple Open EtherCAT Master) Slaveinfo Starting slaveinfo ec_init on enp3s0 succeeded. Read at 0x1c12:0 => wkc: 1; data: 0x2 (2) [rxPDO:0] Read at 0x1c12:2 => wkc: 1; data: 0x1601 (5633) [rxPDO:2] Read at 0x1601:0 => wkc: 1; data: 0x8 (8) [rxPDO:2] Writing config. Write at 0x1c12:0 => wkc: 1; data: 0x0 {clear SM PDO} Write at 0x1601:0 => wkc: 1; data: 0x0 {clear RX PDO} Write at 0x1601:0 => wkc: 1; data: 0x8 {Set num PDO entries} Write at 0x1c12:2 => wkc: 1; data: 0x1601 {list entries in smpdo} Write at 0x1c12:0 => wkc: 1; data: 0x2 {Set num PDOs} Read at 0x1c12:0 => wkc: 1; data: 0x2 (2) [rxPDO:0] Read at 0x1c12:2 => wkc: 1; data: 0x1601 (5633) [rxPDO:2] Read at 0x1601:0 => wkc: 1; data: 0x8 (8) [rxPDO:2] 1 slaves found and configured. Calculated workcounter 3

Slave:1 Name:arb_slaves Output size: 224bits Input size: 192bits State: 4 Delay: 0[ns] Has DC: 1 DCParentport:0 Activeports:1.0.0.0 Configured address: 1001 Man: 00000a43 ID: 00001001 Rev: 00000000 SM0 A:1000 L: 128 F:00010026 Type:1 SM1 A:1080 L: 128 F:00010022 Type:2 SM2 A:1100 L: 28 F:00010024 Type:3 SM3 A:1900 L: 24 F:00010020 Type:4 FMMU0 Ls:00000000 Ll: 28 Lsb:0 Leb:7 Ps:1100 Psb:0 Ty:02 Act:01 FMMU1 Ls:0000001c Ll: 24 Lsb:0 Leb:7 Ps:1900 Psb:0 Ty:01 Act:01 FMMUfunc 0:1 1:0 2:0 3:0 MBX length wr: 128 rd: 128 MBX protocols : 04 CoE details: 13 FoE details: 00 EoE details: 00 SoE details: 00 Ebus current: 0[mA] only LRD/LWR:0 PDO mapping according to CoE : SM2 outputs addr b index: sub bitl data_type name [0x0000.0] 0x7000:0x01 0x20 UNSIGNED32 id0 [0x0004.0] 0x7000:0x02 0x20 UNSIGNED32 id1 [0x0008.0] 0x7000:0x03 0x20 UNSIGNED32 id2 [0x000C.0] 0x7000:0x04 0x20 UNSIGNED32 control [0x0010.0] 0x7000:0x05 0x20 UNSIGNED32 fault [0x0014.0] 0x7001:0x01 0x08 UNSIGNED8 dout0 [0x0015.0] 0x7001:0x02 0x08 UNSIGNED8 dout1 [0x0016.0] 0x7001:0x03 0x08 UNSIGNED8 dout2 [0x0017.0] 0x7001:0x04 0x08 UNSIGNED8 dout3 [0x0018.0] 0x7001:0x05 0x08 UNSIGNED8 dout4 [0x0019.0] 0x7001:0x06 0x08 UNSIGNED8 dout5 [0x001A.0] 0x7001:0x07 0x08 UNSIGNED8 dout6 [0x001B.0] 0x7001:0x08 0x08 UNSIGNED8 dout7 SM3 inputs addr b index: sub bitl data_type name [0x001C.0] 0x6000:0x01 0x20 UNSIGNED32 status [0x0020.0] 0x6000:0x02 0x20 UNSIGNED32 fault [0x0024.0] 0x6001:0x01 0x08 UNSIGNED8 din0 [0x0025.0] 0x6001:0x02 0x08 UNSIGNED8 din1 [0x0026.0] 0x6001:0x03 0x08 UNSIGNED8 din2 [0x0027.0] 0x6001:0x04 0x08 UNSIGNED8 din3 [0x0028.0] 0x6001:0x05 0x08 UNSIGNED8 din4 [0x0029.0] 0x6001:0x06 0x08 UNSIGNED8 din5 [0x002A.0] 0x6001:0x07 0x08 UNSIGNED8 din6 [0x002B.0] 0x6001:0x08 0x08 UNSIGNED8 din7 [0x002C.0] 0x6001:0x09 0x08 UNSIGNED8 din8 [0x002D.0] 0x6001:0x0A 0x08 UNSIGNED8 din9 [0x002E.0] 0x6001:0x0B 0x08 UNSIGNED8 din10 [0x002F.0] 0x6001:0x0C 0x08 UNSIGNED8 din11 [0x0030.0] 0x6001:0x0D 0x08 UNSIGNED8 din12 [0x0031.0] 0x6001:0x0E 0x08 UNSIGNED8 din13 [0x0032.0] 0x6001:0x0F 0x08 UNSIGNED8 din14 [0x0033.0] 0x6001:0x10 0x08 UNSIGNED8 din15 End slaveinfo, close socket End program

The second output is the desired result! Can you offer any more advice on setting this up correctly?

Another possible issue: sizeOfPDO line 231

l = (uint8_t) objd->value; 

does not check to see if we are taking the number of entries in (say 0x1601) from data - where they could have been dynamically set. I altered this line to look to see if the number of entries might have been dynamically set:

if (objd->data) {
   l = *( (uint8_t*) objd->data );
} else {
   l = (uint8_t) objd->value;
}

I'll also make note to ensure the rest of my slave is conformant! Thanks again for your help

nakarlsson commented 6 years ago

Do you have a fork or something?

The issue is most likely that the size don’t match and since the second try works you need to trigger a sizeofPDO?

We’ve an upcoming release with dynamic configuration of 1C12, 1C13 in the loop, PdoAssign. Can’t give you a date yet but will try to prepare a fork.

cainsbrainstem commented 6 years ago

No, no fork I'm afraid. All this is based off the Git repo as of about a week ago, with basically no modification, except for what we have discussed.

sizeofPDO is being called after any write to 0x1c12 sub 0 in the objecthandler and its also being called at initialisation. At boot up, if I do not write anything from the master and only rely on the slave to initialise, I get a slaveinfo output as in the first output dump in my last message. I suspect initialisation data is not being taken from value (in the const object dictionary) and put into the data fields (When setting a uint32* to ->data).

I see the function initDefaultSyncMgrPara in esc_coe actually goes through and initialises from value to ->data (if data != NULL), but only for 1C3x and 10F1. Would it be worth extending this (or creating a new function) to do something similar for 1c12 and 1c13 etc?

Upcoming release sounds great! Thanks for your help

nakarlsson commented 6 years ago

That’s correct , I’ve added load PDO default.

cainsbrainstem commented 6 years ago

I’ve added load PDO default.

Is this something I can take a look at?

cainsbrainstem commented 6 years ago

I looked into this some more and wrote a function to load PDO defaults. Pretty quickly written and almost directly taken from COE_initDefaultSyncMgrPara. It looks like it works ok, but it may not be completely correct in the SOES scheme of things. Also, I still had to keep the modification to sizeOfPDO line 231 I mentioned earlier.

void initDefaultPDO (void)
{
   uint32_t i,j;
   const _objd *objd;
   const _objd *objsub;
   int32_t n = 0;
   int32_t addr = 0;

   /* 1C1x */
   for(i = 0x1C12; i <= 0x1C13; i ++)
   {
      /* Look if index is present */
      n = SDO_findobject(i);

      if(n < 0)
      {
         continue;
      }
      /* Load default values */
      objd = SDOobjects[n].objdesc;
      for(j = 0; j <= SDOobjects[n].maxsub; j++ )
      {
         if(objd[j].data != NULL)
         {
            *(uint32_t *)objd[j].data = objd[j].value;
         }
         /* Get the address it maps to and set it's default number of entries */
         if (j > 0) {         
            addr = SDO_findobject(objd[j].value);
            if (addr < 0) {
               continue;
            }

            objsub = SDOobjects[addr].objdesc;
            if(objsub[0].data != NULL)
            {
               *(uint32_t *)objsub[0].data = objsub[0].value;
            }
         }
         if(objd[j].subindex >= SDOobjects[n].maxsub)
         {
            break;
         }
      }
   }
}
nakarlsson commented 6 years ago

I tried to minimize the duplication of code and did some refactoring, if you do your own temp adoptions it shouldn’t matter that much in the end when we commit our solution.

We have also considered the dynamic No of subindexes in sizeof fore 1C1x.

In addition I’ve added an update data of the PDO mapping on reconfiguration of 1C1x.

nakarlsson commented 6 years ago

I've added an Alpha to my fork, https://github.com/nakarlsson/SOES

cainsbrainstem commented 6 years ago

Hiya,

I gave your fork a go - So far its working well! I found:

In esc_coe.h is

void COE_initSDODefault (uint16_t index);

declared incorrectly? Should it be:

void COE_initSDODefaultValue (uint16_t index);

Also, I'm aiming to set the number of variables to return in my PDOs (mentioned in my first message). To do this I'm writing the number of values I want to (eg) 0x1601, sub index 2. I found that I had to call COE_initSDODefaultValue(0x1601) after COE_initDefaultPDO() in the slave init function, before I calculated the PDO size. It looks like if I had 0x1601(subindex 2) as a uint32 to ->data in the object dictionary, COE_initDefaultPDO() would not copy the default value to the uint32 and the size would be calculated incorrectly.

Thanks again!

nakarlsson commented 6 years ago

Can you post your ObjectDictionary?

cainsbrainstem commented 6 years ago

Here you go: arb_arr_objectlist.c.txt

Note: I have the directions of my intended data flows backwards. For the sake of testing it's fine, but how embarrassing....

nakarlsson commented 6 years ago

It actually make sense to also default the SDOs in 1C12 and 1C13, check my updated fork. I did 2 squash/commits and forced a push so you might wanna re-clone the fork https://github.com/nakarlsson/SOES

I hope this solves the issue on 0x1601 not getting default data set

nakarlsson commented 5 years ago

Handled by SOES v3