CANopenNode
CANopen protocol stack
Loading...
Searching...
No Matches
Critical sections
+ Collaboration diagram for Critical sections:

Macros

#define CO_LOCK_CAN_SEND(CAN_MODULE)   /**< Lock critical section in CO_CANsend() */
 Lock critical section in CO_CANsend()
 
#define CO_UNLOCK_CAN_SEND(CAN_MODULE)   /**< Unlock critical section in CO_CANsend() */
 Unlock critical section in CO_CANsend()
 
#define CO_LOCK_EMCY(CAN_MODULE)   /**< Lock critical section in CO_errorReport() or CO_errorReset() */
 Lock critical section in CO_errorReport() or CO_errorReset()
 
#define CO_UNLOCK_EMCY(CAN_MODULE)   /**< Unlock critical section in CO_errorReport() or CO_errorReset() */
 Unlock critical section in CO_errorReport() or CO_errorReset()
 
#define CO_LOCK_OD(CAN_MODULE)   /**< Lock critical section when accessing Object Dictionary */
 Lock critical section when accessing Object Dictionary.
 
#define CO_UNLOCK_OD(CAN_MODULE)   /**< Unock critical section when accessing Object Dictionary */
 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)
 Set new message flag.
 
#define CO_FLAG_CLEAR(rxNew)
 Clear new message flag.
 

Detailed Description

Protection of critical sections in multi-threaded operation.

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, and CO_error() 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. Lock/unlock macro is called with pointer to CAN module, which may be used inside.

Object Dictionary variables

In general, there are two threads, which accesses OD variables: mainline (initialization, storage, SDO access) and timer (PDO access). CANopenNode uses locking mechanism, where SDO server (or other mainline code) prevents execution of the real-time thread at the moment it reads or writes OD variable. CO_LOCK_OD(CAN_MODULE) and CO_UNLOCK_OD(CAN_MODULE) macros are used to protect:

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.