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

synchronous RPDOs lost #23

Closed
amacintyre opened this issue Feb 14, 2017 · 4 comments
Closed

synchronous RPDOs lost #23

amacintyre opened this issue Feb 14, 2017 · 4 comments

Comments

@amacintyre
Copy link

I’m using CANopenNode for an actuator project. Asynchronous RPDOs work fine. However, I noticed that some synchronous RPDO commands were getting lost. It looks like CO_RPDO_process() clears the CANrxNew flags every time it is called, rather than just when the sync flag is set and the RPDO processed. The main loop calls CO_process_SYNC_RPDO() once every one millisecond tick. If the sync message arrives once every 10ms and the RPDO arrives at some random time between syncs, there would be a 90% chance of the function resetting the new flag without processing the RPDO. I’m wondering if this is a bug or I’ve misunderstood something. Thanks.

@CANopenNode
Copy link
Owner

The standard says:
"The data of synchronous RPDOs received after the occurrence of the SYNC is passed to the
application with the occurrence of the following SYNC, independent of the transmission rate
specified by the transmission type. The data of event-driven RPDOs is passed directly to the
application."

Synchronous PDOs shall be transmitted inside sync window, otherwise they are ignored. They are passed to application immediately after the next SYNC message.
You can set RPDO to event driven (transmission type is 254 or 255), even if TPDO in transmitting device is set to synchronous. Or you can set synchronous windows.

However, this part is quite new and is not deeply tested.

@amacintyre
Copy link
Author

For this application, the sync window is disabled (OD_synchronousWindowLength=0), so I would expect a synchronous RPDO received a few milliseconds after a sync message to be processed on the following sync for any time interval, assuming no other RPDO arrives before the sync. (In this case, the sync interval is 30ms) However, CO_process_SYNC_RPDO calls CO_RPDO_process once per millisecond between syncs with syncWas=0. This clears the RPDO CANrxNew flag before the next sync, and the RPDO does not get passed to the application. If the RPDO happens to arrive in the millisecond before the sync, it does get passed to the application. RPDOs configured as event driven are always processed.

@amacintyre
Copy link
Author

The following code change in CO_PDO.c fixed the problem for me.

void CO_RPDO_process(CO_RPDO_t *RPDO, bool_t syncWas){
if(!RPDO->valid || !(*RPDO->operatingState == CO_NMT_OPERATIONAL))
{
RPDO->CANrxNew[0] = RPDO->CANrxNew[1] = false;
}
else if(!RPDO->synchronous || syncWas)
{
...
}
}

@CANopenNode
Copy link
Owner

I checked it and there was a bug (race conditions):
function CO_process_SYNC_RPDO() (from CANopen.c) calls CO_SYNC_process() and then calls CO_RPDO_process() for each RPDO. CAN messages are received from interrupt, which has higher priority than CO_process_SYNC_RPDO().

Following situation was problematic:

  • CO_SYNC_process() was called, no SYNC detected.
  • From CAN bus comes the train with SYNC and PDOs, which was immediately processed by CAN receive interrupt.
  • CO_process_SYNC_RPDO() was interrupted in the middle and now continues with CO_RPDO_process() calls. In that case RPDOs were deleted.

Stack is now updated with the change from above. Operational RPDOs are not supposed to be deleted in any case. (CO_CANclearPendingSyncPDOs() only clears TPDOs outside window.)

Thank you.

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