Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The sync0 signals of 2 slaves cannot be aligned #618

Closed
ChenHades666 opened this issue May 30, 2022 · 8 comments
Closed

The sync0 signals of 2 slaves cannot be aligned #618

ChenHades666 opened this issue May 30, 2022 · 8 comments

Comments

@ChenHades666
Copy link

my app code:

SOEM_Task.txt

Question 1

When I use the ecx_configdc function in the original ethercatdc.c file, I will use it in the application code

ec_FPRD(ec_slave[2].configadr, ECT_REG_DCSYSDIFF, sizeof(diff_time_2), &diff_time_2, EC_TIMEOUTRET);

When I read a large value, it is about 1.2 seconds in seconds, so I had to rewrite the ecx_configdc function as follows:

boolean ecx_configdc(ecx_contextt *context)
{
   uint16 i, slaveh, parent, child;
   uint16 parenthold = 0;
   uint16 prevDCslave = 0;
   int32 ht, dt1, dt2, dt3;
   int64 hrt;
   uint8 entryport;
   int8 nlist;
   int8 plist[4];
   int32 tlist[4];
   ec_timet mastertime;
   uint64 mastertime64;

   context->slavelist[0].hasdc = FALSE;
   context->grouplist[0].hasdc = FALSE;
   ht = 0;

   ecx_BWR(context->port, 0, ECT_REG_DCTIME0, sizeof(ht), &ht, EC_TIMEOUTRET);  /* latch DCrecvTimeA of all slaves */

	mastertime = osal_current_time();
	//mastertime.sec -= 946684800UL;  /* EtherCAT uses 2000-01-01 as epoch start instead of 1970-01-01 */
	mastertime.sec += 694310400UL; //Since the lower computer cannot obtain the standard time, it is assumed that the boot time is 0:00 on January 1, 2022
	mastertime64 = (((uint64)mastertime.sec * 1000000) + (uint64)mastertime.usec) * 1000;

	//add by cxj in 2022-04-13
	//Reduce the time between 2 acquisitions of DCSOF to reduce the offset difference
	for (i = 1; i <= *(context->slavecount); i++){
		if (context->slavelist[i].hasdc){
			slaveh = context->slavelist[i].configadr;
			/* 64bit latched DCrecvTimeA of each specific slave */
			(void)ecx_FPRD(context->port, slaveh, ECT_REG_DCSOF, sizeof(hrt), &hrt, EC_TIMEOUTRET);
			/* use it as offset in order to set local time around 0 + mastertime */
			hrt = htoell(-etohll(hrt) + mastertime64);
			/* save it in the offset register */
			(void)ecx_FPWR(context->port, slaveh, ECT_REG_DCSYSOFFSET, sizeof(hrt), &hrt, EC_TIMEOUTRET);
		}
	}

   for (i = 1; i <= *(context->slavecount); i++)
   {
      context->slavelist[i].consumedports = context->slavelist[i].activeports;
      if (context->slavelist[i].hasdc)
      {
         if (!context->slavelist[0].hasdc)
         {
            context->slavelist[0].hasdc = TRUE;
            context->slavelist[0].DCnext = i;
            context->slavelist[i].DCprevious = 0;
            context->grouplist[context->slavelist[i].group].hasdc = TRUE;
            context->grouplist[context->slavelist[i].group].DCnext = i;
         }
         else
         {
            context->slavelist[prevDCslave].DCnext = i;
            context->slavelist[i].DCprevious = prevDCslave;
         }
         /* this branch has DC slave so remove parenthold */
         parenthold = 0;
         prevDCslave = i;
         slaveh = context->slavelist[i].configadr;
         (void)ecx_FPRD(context->port, slaveh, ECT_REG_DCTIME0, sizeof(ht), &ht, EC_TIMEOUTRET);
         context->slavelist[i].DCrtA = etohl(ht);
//         /* 64bit latched DCrecvTimeA of each specific slave */
//		 (void)ecx_FPRD(context->port, slaveh, ECT_REG_DCSOF, sizeof(hrt), &hrt, EC_TIMEOUTRET);
//		 /* use it as offset in order to set local time around 0 + mastertime */
//		 hrt = htoell(-etohll(hrt) + mastertime64);
//		 /* save it in the offset register */
//		 (void)ecx_FPWR(context->port, slaveh, ECT_REG_DCSYSOFFSET, sizeof(hrt), &hrt, EC_TIMEOUTRET);
         (void)ecx_FPRD(context->port, slaveh, ECT_REG_DCTIME1, sizeof(ht), &ht, EC_TIMEOUTRET);
         context->slavelist[i].DCrtB = etohl(ht);
         (void)ecx_FPRD(context->port, slaveh, ECT_REG_DCTIME2, sizeof(ht), &ht, EC_TIMEOUTRET);
         context->slavelist[i].DCrtC = etohl(ht);
         (void)ecx_FPRD(context->port, slaveh, ECT_REG_DCTIME3, sizeof(ht), &ht, EC_TIMEOUTRET);
         context->slavelist[i].DCrtD = etohl(ht);

         ...//Omit the middle part of the code
      }
      else
      {
         context->slavelist[i].DCrtA = 0;
         context->slavelist[i].DCrtB = 0;
         context->slavelist[i].DCrtC = 0;
         context->slavelist[i].DCrtD = 0;
         parent = context->slavelist[i].parent;
         /* if non DC slave found on first position on branch hold root parent */
         if ( (parent > 0) && (context->slavelist[parent].topology > 2))
            parenthold = parent;
         /* if branch has no DC slaves consume port on root parent */
         if ( parenthold && (context->slavelist[i].topology == 1))
         {
            ecx_parentport(context, parenthold);
            parenthold = 0;
         }
      }
   }

   return context->slavelist[0].hasdc;
}

After modification, a relatively small diff_time can be read in the application code, about within 50ns

Question 2

When I use the same sync_shift, there is a phase difference of about 700ns between the sync0 signals of the two slave stations. The phase difference can only be achieved by manually adjusting the sync_shift of different slave stations, as shown in the following figure:

tek00010
新建文件1

I wonder if this is reasonable? Is there a way to make it align itself while setting the same sync0 shift? In addition, I can see in the packet capture file of TwinCAT that the value set by TwinCAT for the sync0 start time of the two slave stations is exactly the same

@ChenHades666
Copy link
Author

Forgot to say, my slaves are 2 LAN9252 demo boards with STM32F7 as MCU

@ArthurKetels
Copy link
Contributor

What are the values of ec_slave[cnt].pdelay? The calculated propagation delay of each slave is added to the slave clock, independent of the clock offset. Wrong calculations of pdelay might cause the observed sync0 shift.

I have tested the sync code with many slaves and never found a large sync0 shift (always +-25ns).

Although not critical but might I suggest a different order for slave synchronization?
#487 (comment)
#520

@ChenHades666
Copy link
Author

The value of ec_slave[cnt].pdelay of 2 slaves is 0. I don't know if this is reasonable. Assuming that the propagation speed of electromagnetic waves in twisted pair is 2x10^8m/s, the length of my cable It is about 1.5 meters, so it takes 7.5ns, but the ec_slave[cnt].pdelay calculated each time is 0.

#487 (comment) helped me a lot, I made changes to my program by referring to it before

I will try to continue modifying according to #520, looking forward to good results

@ArthurKetels
Copy link
Contributor

Could you test your set-up with an unmodified SOEM slaveinfo? It shows the propagation delay for each slave. I have tested this with a set of LAN9252 and they yield exactly 700ns propagation delay between two slaves.

The propagation delay measurement algorithm in SOEM is not perfect and could be improved. But even as-is you can measure cable delays quite accurately. For cat5e cable I find an average delay of around 4.7ns/m. The biggest influence on variable delay is still the PHY. By design the delay can be +- one symbol at 25Msymbols/s for ethernet 100TX. On the other hand there are very few applications that require better accuracy.

@ChenHades666
Copy link
Author

From what you said, I tried adjusting the order of the slave syncs, but I didn't get good results, or even worse - sometimes there is no sync0 signal output.

I ran slaveinfo and got the following prints, I even started to suspect that my slave was the problem.
LogPrint_2022-06-01_1
LogPrint_2022-06-01_2

This is the ESI file I use to configure LAN9252
noya-LAN9252-TempHumi.zip

@ChenHades666
Copy link
Author

There is also a very strange problem. In the process of debugging, I can occasionally measure the delay of slave2 to be 740ns because I hit a breakpoint. This result should be reasonable, but if I run directly without a breakpoint, The measured delay is always 0ns.

The environment where I run SOEM is ZYNQ7015, and the underlying MAC communication is transplanted by myself. I don't have enough confidence to ensure that my MAC communication is no problem, but it seems that the communication should be no problem at present.

@ArthurKetels
Copy link
Contributor

Just to make things clear, you have unexplained behaviour with SOEM and yourself programmed MAC driver. When something does not work properly, do you suspect SOEM or your driver?

It is not simple to make a robust packet driver, mistakes are easily made.

The propagation delay calculation is simple and robust, it just reads data directly from ESC hardware. When this fails then there is most likely a communication failure between SOEM and the slave. Therefore I suspect either your driver or the cabling.

I would suggest to test your code on a standard Linux system with unmodified SOEM. Then you can also see the results with Wireshark. When that works transfer the code to your ZYNQ system and work out the bugs.

@ChenHades666
Copy link
Author

Yes, in the Windows environment, I use the unmodified SOEM to execute slavainfo, and I can correctly get the delay of slave2 to be 720ns. I think there is a problem with my MAC driver, thank you for your reply, you provided me with an excellent idea to solve the problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants