CANopenNode
Critical sections

CANopenNode is designed to run in different threads, as described in README.md. Threads are implemented differently in different systems. In microcontrollers threads are interrupts with different priorities, for example. It is necessary to protect sections, where different threads access to the same resource. In simple systems interrupts or scheduler may be temporary disabled between access to the shared resource. Otherwise mutexes or semaphores can be used. More...

Macros

#define CO_LOCK_CAN_SEND()
 Lock critical section in CO_CANsend()
 
#define CO_UNLOCK_CAN_SEND()
 Unlock critical section in CO_CANsend()
 
#define CO_LOCK_EMCY()
 Lock critical section in CO_errorReport() or CO_errorReset()
 
#define CO_UNLOCK_EMCY()
 Unlock critical section in CO_errorReport() or CO_errorReset()
 
#define CO_LOCK_OD()
 Lock critical section when accessing Object Dictionary.
 
#define CO_UNLOCK_OD()
 Unock critical section when accessing Object Dictionary.
 
#define CO_FLAG_READ(rxNew)   ((rxNew) != NULL)
 Check if new message has arrived.
 
#define CO_FLAG_SET(rxNew)   { __sync_synchronize(); rxNew = (void *)1L; }
 Set new message flag.
 
#define CO_FLAG_CLEAR(rxNew)   { __sync_synchronize(); rxNew = NULL; }
 Clear new message flag.
 

Detailed Description

CANopenNode is designed to run in different threads, as described in README.md. Threads are implemented differently in different systems. In microcontrollers threads are interrupts with different priorities, for example. It is necessary to protect sections, where different threads access to the same resource. In simple systems interrupts or scheduler may be temporary disabled between access to the shared resource. Otherwise mutexes or semaphores can be used.

Reentrant functions

Functions CO_CANsend() from C_driver.h, CO_errorReport() from CO_Emergency.h and CO_errorReset() from CO_Emergency.h may be called from different threads. Critical sections must be protected. Either by disabling scheduler or interrupts or by mutexes or semaphores.

Object Dictionary variables

In general, there are two threads, which accesses OD variables: mainline and timer. CANopenNode initialization and SDO server runs in mainline. PDOs runs in faster timer thread. Processing of PDOs must not be interrupted by mainline. Mainline thread must protect sections, which accesses the same OD variables as timer thread. This care must also take the application. Note that not all variables are allowed to be mapped to PDOs, so they may not need to be protected. SDO server protects sections with access to OD variables.

Synchronization functions for CAN receive

After CAN message is received, it is pre-processed in CANrx_callback(), which copies some data into appropriate object and at the end sets new_message flag. This flag is then pooled in another thread, which further processes the message. The problem is, that compiler optimization may shuffle memory operations, so it is necessary to ensure, that new_message flag is surely set at the end. It is necessary to use Memory barrier.

If receive function runs inside IRQ, no further synchronization is needed. Otherwise, some kind of synchronization has to be included. The following example uses GCC builtin memory barrier __sync_synchronize(). More information can be found here.