Sync Interrupt


XMP and ZMP series motion controllers have the ability to interrupt the host at a specified frequency, where the frequency is a multiple of the controller’s sample rate. This board-to-host interrupt is referred to as the Sync Interrupt and is explained in more detail below.

Common uses for the Sync Interrupt would be systems that need to synchronize with the controller and/or systems that need to process incoming SynqNet data from the controller and write data back to the controller before SynqNet transmission occurs.

The information below describes the low-level operation of the Sync Interrupt functionality. The hostService module in the apputil library provides a high level interface to this functionality. For more information see the HostService object.



The firmware on the XMP/ZMP controllers is made up of two tasks, commonly referred to as the foreground and background tasks. The foreground task has a higher priority than the background task and is started by the expiration of a timer. The background task is free running and executes whenever the foreground task is sleeping. For details, see Sample Rate.

At the start of the foreground task, code is executed, which determines if an interrupt should be sent to the host. The source of this interrupt can be a variety of things, such as motor limits to motion supervisor events. This interrupt can also come from a user configured Sync Interrupt.
The Sync Interrupt is an interrupt that occurs at a fixed frequency where the frequency is a multiple of the controller’s sample rate.


The Event Manager handles interrupts coming from the controller. The event manager code usually runs in a thread spawned by the apputil library’s service object. When the Event Manager service thread is woken up by an interrupt, it reads information from the controller to determine the source of the interrupt and then wakes the appropriate task waiting for that particular interrupt.

The Sync Interrupt code usually runs in a separate thread spawned by the apputil library’s hostService object. The Sync Interrupt is not the same as an interrupt generated by a motor limit or event. While the Sync Interrupt will wake the Event Manager, the Event Manager is not designed to deal with the Sync Interrupt and will not be able to identify it. The result is that the Event Manager will not wake any tasks and will just go back to sleep. However, the Event Manager service thread can still be used to process and distribute interrupts from motor limits and events while a Sync Interrupt service thread is active.

NOTE: To avoid CPU competition with the EventMgr service thread, it is important that the Sync Interrupt service thread is running at a higher priority than the EventMgr.

The reason for this design is that MEI wanted to supply the user with the ability to quickly wake a task so that any processing that the task may need to accomplish can be synchronized to the start of the controller’s cycle.

Using the Sync Interrupt


The Sync Interrupt can be easily configured. Just use the mpiControlConfigSet(...) function:


#define SYNC_PERIOD (1) /* Interrupt every sample */

MPIControlConfig mpiConfig;
MEIControlConfig meiConfig;

/* Configure sync interrupt */
if (returnValue == MPIMessageOK) {
        returnValue = mpiControlConfigGet(control,

        if (returnValue == MPIMessageOK) {
                meiConfig.syncInterruptPeriod = SYNC_PERIOD;
                returnValue = mpiControlConfigSet(control,

The above code will configure the Sync Interrupt to occur every sample. Define SYNC_PERIOD to be the number of controller samples between Sync Interrupt. For example 1 = every sample, 2 = every other sample, 3 = every third sample, etc. A SYNC_PERIOD defined as 0 will disable the Sync Interrupt. See the synqInterrupt.c sample application for more detail.


Setting up user code to sleep until the Sync Interrupt occurs can be done by using the mpiControlInterruptWait(...) function (this is the same function used by the Event Manager). The Event Manager is not needed (although it can be used in conjunction with mpiControlInterruptWait(...)). Any interrupt sent to the host by the controller will wake up the mpiControlInterruptWait(...) call. To determine if the interrupt source is the configured Sync Interrupt, some information must be read from the controller. Whenever the Sync Interrupt occurs, the firmware will set a flag that can be read by the host to determine if the source was the Sync Interrupt. The firmware will clear the flag on the next sample that does not send the Sync Interrupt.

The following code illustrates a simplified use of the mpiControlInterruptWait(...) function and how to check for the Sync Interrupt being the source. The code uses the mpiControlMemoryGet(...) function instead of a standard interface in order to bypass MPI overhead. This code also requires a control object and a “firmware” pointer. See the synqInterrupt.c sample app for more detail.


While(!done) {
   long synqFlag = 0;

   returnValue = mpiControlInterruptWait(control,                                          &interrupted,

   /* check to see if this is really a Sync interrupt */
   if (returnValue == MPIMessageOK) {
         returnValue = mpiControlMemoryGet(control,

         if ((returnValue == MPIMessageOK) && (syncFlag)) {

         /* Host Process */



Additional Sync Interrupt Features

Host Process Flag

For systems that need to synchronize with the controller and calculate data that needs to be sent every sample over SynqNet, the firmware has an additional flag. This flag is called the HostProcessFlag.

The HostProcessFlag can be used to tell the firmware that the host is processing data that is expected to be transmitted over the next SynqNet transmission.

The HostProcessFlag is set by the host after it is woken up by a Sync Interrupt and before the processing of its data/tasks. The HostProcessFlag is cleared by the host when all processing is done and before going back to sleep and waiting for the next Sync Interrupt.

The firmware checks the HostProcessFlag every foreground cycle just before starting SynqNet transmission. If the HostProcessFlag is still set when SynqNet transmission starts, then the firmware will set a status bit in the control object indicating that the host did not complete its tasks in time and that data transmitted over SynqNet may not have been complete. The controller does not consider this a catastrophic error and will not shutdown the SynqNet network. It is a warning available to the host. The host is responsible for dealing with the warning (MEIEventTypeCONTROL_HOST_PROCESS_TIME_EXCEEDED). The warning can be configured to send an interrupt to the host. See synqInterrupt.c (#define HOST_PROCESS_FLAG (1)) for more detail on how to set and clear the flag and how to use the Event Manager to be notified of the CONTROL_HOST_PROCESS_TIME_EXCEEDED event.

NOTE: The HostProcessFlag should only be used if the synq period is one and the host process is expected to complete before SynqNet transmission.

Host Process Time

Every foreground cycle, the firmware updates the HostProcessTime register. This register contains the number of clock ticks (at a 40MHz rate) between the beginning of the firmware’s foreground cycle and the start of SynqNet telegram transmission. This is also the time at which the HostProcessFlag is checked.

The HostProcessTime can be used by the host to determine approximately how much time within one sample it has to process data when using the HostProcessFlag.

Time (in uS) = HostProcessTime/40.


Here is an example of firmware interrupting the host every servo cycle (Texp) where the Host Task sets the HostProcessFlag at the beginning of its process and clears the HostProcessFlag at the end of its process. The firmware checks the HostProcessFlag to make sure that it is cleared before starting internal DMAs that set up the telegrams for transmission at TxTime.

The length of the foreground cycle will vary depending on the number of objects (motors, filters, axes, etc…) enabled. The more objects enabled, the longer the foreground cycle and the longer the HostProcessTime.

In this example TxTime is at 75%. It can be programmed to any value that places it after the HostProcessTime (plus a small amount of time for internal DMAs).


Data Structures



typedef struct {

/* Set by MPI, 0 = disabled, 1 = every sample,
2 = every other sample, etc... */

      long Period;

/* Set by host when processing data,
cleared by host when done */

      long HostProcessFlag;

/* Set by firmware, read by MPI:
1 = Heartbeat, 0 = not a heartbeat */

      long Flag;

/* Calculated by firmware for Host */
      long HostProcessTime;

/* Set by firmware – firmware use only */
      long Count;

} MEIXmpSyncInterrupt;

The MEIXmpSynqInterrupt is part of the SystemData structure. See the synqInterrupt.c app for more detail and code showing usage.



The only interface in the MPI for the Sync Interrupt feature is in the control object. It allows the user to set the Synq Period and therefore start (or stop) the Sync Interrupt feature.


typedef struct MEIControlConfig {
        char             userLabel[MEIObjectLabelCharMAX+1];
                             /* +1 for NULL terminator */
        long             preFilterCount;
        long             TxTime;
        long             syncInterruptPeriod;
        MEIXmpPreFilter  PreFilter[MEIXmpMAX_PreFilters];
        MEIXmpUserBuffer UserBuffer;
} MEIControlConfig;

By using mpiControlConfigGet(...) and mpiControlConfigSet(...) the user can set the syncInterruptPeriod. See Using the Sync Interrupt section above and the syncInterrupt.c app for more detail.


       Legal Notice  |  Tech Email  |  Feedback
Copyright ©
2001-2021 Motion Engineering