Multi-tasking systems
This chapter describes the usage of the CANopen Library on multi-tasking systems. Multi-tasking systems include multi-tasking operating systems but also interrupt driven applications without any operating system i.e. application with timer triggered control loop.
Prepared solutions of the security mechanism for shared resources of the object dictionary are shown. Furthermore possible communication variants are discussed.
Figure 57: security mechanism for RTOS
A user application on a multi-tasking system consists of at least 2 processes: the application task and the CANopen communication task (Figure 57). The variables of the object dictionary should be accessible by both the application and the communication task. Therefore it is necessary to protect the object dictionary. This resource has to be allocated for each read or write access. The resource is blocked until the access is finished. Blocking of the resource during read/ write access for other processes ensures that the data are always consistent.
Sometimes it is useful to have shadow variable segments e.g. if certain parameters should become valid on command. In this case, it is only to ensure that in the moment of the data updating no access is possible. The update can be done by switching between the two data buffers (new pointer value assignment) or by copying data.
If more than one application task uses the services of the CANopen task, all CANopen services have to be protected because they are not reentrant. One possible way to use the CANopen functions was already discussed above: the direct usage (Figure 57). Another possibility is to use a message distributor. More options exist, but are not discussed.
Figure 58: message reception on RTOS
fehlende Grafik
The advantage of using a message distributor is the decoupling of application tasks from the CANopen Library. Only the message distributor programmer needs CANopen and the CANopen Library knowledge. All other application programmers can work with the commonly used mechanisms.
A further advantage is the easy switching to another communication system by replacing the distributor. So it is possible to support more than one field bus with one application software.
The message distributor is a process which uses the interprocess communication mechanism of the operating system to inform the application about new messages (Figure 59). For that purpose the application can read the new value from the object dictionary or the value can be sent via a queue mechanism. For data transmission the application task sends a message to the distributor. The distributor is responsible for the message handling to and from the CANopen Library. It manages all CANopen Library function calls and can schedule the message transmission order.
Figure 60: message transmission on RTOS
For resource protection a few different mechanisms are prepared within the CANopen Library by port. The following macro defines can be used to adapt the protection mechanism to your application and operating system needs.
CO_NEW_RX_MSG(CO_LINE)
CO_COM_PART_ALLOC(CO_LINE)
CO_COM_PART_RELEASE(CO_LINE)
CO_APPL_PART_ALLOC(CO_LINE)
CO_APPL_PART_RELEASE(CO_LINE)
The macros listed above use a #define for the current number of the used CAN line. For the single line version the CO_LINE define is empty. The task of the CO_NEW_RX_MSG macro is to inform the communication task that a new CAN message or a new error message is in the receive queue (waking up of CANopen task).
The other macros are necessary for allocating and releasing the object dictionary. The communication and application part can be protected separately. The Listing 32 shows this mechanism as an example of RTX51 for the multi-line version. For the single line version the parameter canLine is not necessary.
/* use semaphore for protection */
#define CO_SEMA_L0Â Â Â Â Â 13
#define CO_SEMA_L1Â Â Â Â Â 14
#define CO_APPL_PART_ALLOC(canLine) \
   if(canLine == 0)   \
       os_wait(K_MBX+CO_SEMA_L0, 0, NULL) \
   else \
       os_wait(K_MBX+CO_SEMA_L1, 0, NULL)
#define CO_APPL_PART_RELEASE(canLine)Â Â Â \
   if(canLine == 0)   \
       os_send_token(CO_SEMA_L0) \
   else \
       os_send_token(CO_SEMA_L1)Â
void resetActualVelocity(void)
{
   /* allocate OD application part */
   CO_APPL_PART_ALLOC(0);
   /* reset velocity value (CAN line 0)*/
   l0_actual_velocity = 0;
   /* release OD application part */
   CO_APPL_PART_RELEASE(0);
}
Listing 32: example for resource protection for RTX51
Between allocation and release of a resource only a few instructions should be made, in order to prevent unnecessary blocking of other tasks.
#define CO_SEMA_L0Â Â Â Â Â 13
#define CO_SEMA_L1Â Â Â Â Â 14
#define CO_NEW_RX_MSG(canLine)Â Â Â Â \
   if(canLine == 0)   \
       os_send_token(CO_SEMA_L0); \
   else \
       os_send_token(CO_SEMA_L1);
while (1)
{
   /* sleep while no new message on line
- if a new message is received
- if the CANopen timer is expired
in order to check all CANopen timers */
   os_wait(K_MBX+CO_SEMA_L0, 0, NULL);
   /* interpret message for line 0 or handle CANopen timers */
   FlushMbox(0);
}
Listing 33: example for process activation for RTX51
There are no prepared mechanisms of resource protection within the functions of the CANopen Library itself. The user is responsible for ensuring that these functions are not interrupted.
One relatively simple way to make a CANopen Library thread-safe is to create a single mutex, lock it upon each entry to the library, and unlock it upon each exit from the CANopen Library.
For single tasking systems, which use the same resources within the application and the interrupt service routines, equivalent protection mechanism have to be used. The easiest way is to disable the interrupt(s) in the allocation macros.
Â