ChibiOS简介4/5
1. 源由
作为后续研读Ardupilot的ChibiOS的垫脚石,先了解下ChibiOS系统。
Ardupilot ChibiOS项目: https://github.com/ArduPilot/ChibiOS
Artery(AT32) porting项目: //Artery官网没有相关porting动作,不过开源github有相关项目。
2. ChibiOS基础知识4/5
2.13 Chapter 13 - RT Synchronous Messages
2.13.1 Basic concepts
-
Synchronous Messages are a unique feature of ChibiOS/RT that allows to create client/server architectures into an embedded system. RT implements in its inner scheduler layer a message-passing mechanism, when a context switch is performed a message is always passed between the thread being switched out and the one being switched in. The message is exchanged with almost no overhead. This inner mechanism is used to implement the Synchronous Messages high level functionality.
-
Client and Servers, When using synchronous messages there are two kind of threads: clients and servers.
Clients are threads that start a transaction by sending a message to a server thread then wait for a response message.
Servers are threads that wait for a transaction start from a client, once a message is received the server processes it and finally send a response message to the client. Servers are able to handle one message at time but can also handle multiple messages from different clients and to returns answers in an arbitrary order.
- Messages are always signed scalars with type msg_t. This type is guaranteed to be cast-able to/from data pointers. Clients can send simple encoded messages but also pointers to structures representing complex transactions.
There are three predefined messages used internally to the RT kernel:
- MSG_OK. Defined as 0 is a generic acknowledge message.
- MSG_TIMEOUT. Defined as -1 is the message sent in case of timeouts.
- MSG_RESET. Defined as -2 is the message sent to inform of an object reset condition.
Note: It is assumed that pointers with values 0, -1 and -2 to not be valid pointers. Also note that there are no dedicated objects involved, the exchange is done directly between threads, each thread has its own queue of incoming messages.
- Message Passing, In this scenario there are multiple threads in the system that never share data, everything is done by exchanging messages. Each thread represents a service, the other threads can request the service by sending a message.
2.13.2 APIs
Function Name | Description |
---|---|
chMsgSend() | Sends a message to the specified thread. |
chMsgWait() | Waits for a message and returns a pointer to the sender thread. |
chMsgGet() | Retrieves the message after exiting from chMsgWait(). |
chMsgRelease() | Returns an answer to the specified sender and releases it. |
chMsgIsPendingI() | Evaluates to true if there is a message waiting in the queue. |
2.14 Chapter 14 - RT Events
2.14.1 Basic concepts
2.14.1.1 Events
- Event Sources are the objects that broadcast events to system.
- Event Flags, Events also carry information, the information is encoded as Event Flags, a mask of flags of type eventflags_t are broadcasted by sources together with the event itself.
- Event Listeners, On each event source one or more event listeners can be registered, each event listener is linked to a single thread.
- Events Masks, A set of pending events at thread level is called an Events Mask and has type eventmask_t, this type has must not be confused with event flags.
2.14.1.2 Operations
- Registering
The register operation is performed by a thread in order to become a listener of an event source, the association is mediated by an event listener object as follow:
PROCEDURE register(source, listener, events, wflags)
LET listener.flags = 0
LET listener.wflags = wflags
LET listener.events = events
LET listener.thread = current_thread
source.listeners = source.listeners + listener
END
- Waiting for Events
The wait operation allows a thread to check for pending events or wait for them if none:
FUNCTION wait(events)
LET current_thread.ewmask = events
IF current_thread.epending AND current_thread.ewmask = 0
WAIT
END
RETURN current_thread.epending AND current_thread.ewmask
END
- Broadcasting
The broadcast operation notifies all the registered threads that an event occurred on an Event Source, it is quite complex:
PROCEDURE broadcast(source, flags)
FOR EACH source.listeners AS listener
LET listener.flags = listener.flags OR flags
IF (listener.flags AND listener.wflags) <> 0
LET listener.thread.epending = listener.thread.epending OR listener.events
IF listener.thread.epending AND listener.thread.ewmask <> 0
WAKEUP listener.thread
END
END
END
END
- Simplified Events
There is also another way to use events without recurring to event sources and listeners. A thread can directly signal another thread. In this scenario there is no decoupling between sources and threads, specific threads or ISRs signal specific threads with a mask of event flags. The targeted object is directly the thread handling the event.
PROCEDURE signal(thread, events)
LET thread.epending = thread.epending OR events
IF thread.epending AND thread.ewmask <> 0
WAKEUP thread
END
END
2.14.2 APIs
Function Name | Description |
---|---|
EVENTSOURCE_DECL() | Event sources static initializer |
EVENT_MASK() | Translates from an event identifier to an event mask |
chEvtObjectInit() | Initializes an event source object of type event_source_t |
chEvtRegister() | Registers the current thread on an event source by assigning it an event identifier |
chEvtRegisterMask() | Registers the current thread on an event source by assigning it a mask of events |
chEvtRegisterMaskWithFlags() | Registers the current thread on an event source by assigning it a mask of events and a set of flags |
chEvtUnregister() | Unregisters the current thread from an event source |
chEvtGetAndClearEvents() | Returns the events pending for the current thread |
chEvtAddEvents() | Adds a mask of events to the current thread |
chEvtSignal() | Adds a mask of events to the specified thread |
chEvtSignalI() | Adds a mask of events to the specified thread (I-Class variant) |
chEvtBroadcast() | Performs the broadcast operation on an event source with no flags |
chEvtBroadcastI() | Performs the broadcast operation on an event source with no flags (I-Class variant) |
chEvtBroadcastFlags() | Performs the broadcast operation on an event source and adds the specified flags to event listeners |
chEvtBroadcastFlagsI() | Performs the broadcast operation on an event source and adds the specified flags to event listeners (I-Class variant) |
chEvtGetAndClearFlags() | Returns the event flags pending in the specified event listener |
chEvtGetAndClearFlagsI() | Returns the event flags pending in the specified event listener (I-Class variant) |
chEvtWaitOne() | Waits for exactly one of the specified events |
chEvtWaitAny() | Waits for any of the specified events |
chEvtWaitAll() | Waits for all the specified events |
chEvtWaitOneTimeout() | Waits for exactly one of the specified events with timeout |
chEvtWaitAnyTimeout() | Waits for any of the specified events with timeout |
chEvtWaitAllTimeout() | Waits for all the specified events with timeout |
chEvtIsListeningI() | Verifies if there is at least one listener registered on the event source (I-Class variant) |
chEvtDispatch() | Calls the functions associated with an events mask |
2.15 Chapter 15 - RT Debug
ChibiOS/RT provides a comprehensive set of debug options meant to assist the developer during the system implementation and debug phase. All the debug options are reachable into the kernel configuration file chconf.h, each project has its own copy of this file.
2.15.1 Compile Time Checks
Configuration errors are, by design, detected at compile time, the system headers include logic checks that result in compilation errors in case of a wrong configuration.
2.15.2 Runtime Checks
Most debug options operate at runtime in order to catch design or programming errors. If a problem is detected then the system is stopped into the function chSysHalt()
and the global variable ch.dbg_panic_msg
points to an error message string.
2.15.3 Kernel Statistics
The debug option CH_DBG_STATISTICS enables support for kernel statistics. Statistics include:
- Number of served IRQs.
- Number of context switches.
- Time measurement of thread-level critical sections: best, worst, last cases are stored.
- Time measurement of ISR-level critical sections: best, worst, last cases are stored.
- For each thread the following counters are kept:
- Longest execution time.
- Shortest execution time.
- Last execution time.
- Cumulative execution time.
Times are measured using the realtime counter and are clock cycle accurate. The ChibiOS/RT Eclipse plugin is able to show the runtime statistics of the application under debug.
2.15.4 System State Checks
The debug option CH_DBG_SYSTEM_STATE_CHECK
enables an unique ChibiOS/RT, the System State Checker. This option is able to detect any call protocol violation, calling OS APIs out of the proper context is one of the greatest sources of hard to detect problems and random crashes.
2.15.5 Functions Parameters Checks
The debug option CH_DBG_ENABLE_CHECKS
enables the parameters checks at API level. This option is able to detect application errors causing the application to pass invalid parameters to the RTOS, a typical example are NULL
pointers passed where a reference to a valid object is expected. It is advisable to keep this option enabled through the whole development process. Safety concerns may require to keep this kind of checks in place also in the final code as a defensive measure.
2.15.6 System Assertions
The debug option CH_DBG_ENABLE_ASSERTS
enables system-wide integrity checks on the RTOS data structures. The system is also checked for unexpected runtime situations. It is advisable to keep this option enabled through the whole development process. Safety concerns may require to keep this kind of checks in place also in the final code as a defensive measure.
2.15.7 Trace Buffer
The option CH_DBG_TRACE_MASK
is an “or” of various option flags, each option selects an event to be traced:
CH_DBG_TRACE_MASK_NONE
. No events traced by default (but tracing can be activated at runtime for any event).CH_DBG_TRACE_MASK_SWITCH
. Context switches are traced by default.CH_DBG_TRACE_MASK_ISR
. ISR enter and leave events are traced by default.CH_DBG_TRACE_MASK_HALT
. The halt event is traced, of course it is the last event recorded.CH_DBG_TRACE_MASK_USER
. User events are recorded. Application code can trace events using the chDbgWriteTrace() API.CH_DBG_TRACE_MASK_SLOW
. All events are enabled except IRQ-related ones.CH_DBG_TRACE_MASK_ALL
. All events are enabled.CH_DBG_TRACE_MASK_DISABLED
. The trace subsystem is removed entirely from the OS image.
The trace buffer stores the last N context switch operations. It can be used to determine the sequence of operations that lead to an halt condition. The option CH_DBG_TRACE_BUFFER_SIZE
allows to change the size of the trace buffer, the default is 128 entries.
2.15.8 Stack Overflow Checks
The debug option CH_DBG_ENABLE_STACK_CHECK
enables checks on stack overflow conditions. The implementation of the detection is port-dependent and can be implemented differently in each port or even be not supported at all. The most common implementation is to check the stack position when a context switch is about to be performed, if the calculated new stack position overflows the stack limit then the system is halted. Safety concerns may require to keep this kind of checks in place also in the final code as a defensive measure.
2.15.9 Working Area Fill
The debug option CH_DBG_FILL_THREADS
fills the threads working area with a fixed 0x55 pattern before the thread is executed, this allows to calculate the effective stack usage by the various threads. The ChibiOS/RT Eclipse plugin is able to calculate the unused stack size for each thread if this option is enabled. Optimizations of the unused stacks should only be performed:
- At development end.
- With all other debug options disabled or in their final settings.
- Using the final compiler version.
- Using the final compiler options.
Use case in optimizing stacks because different compiler options or compiler version can change stack sizes dramatically and there is the risk of introducing errors not easily detected in the final code (with checks disabled).
2.15.10 Threads Profiling
The debug option CH_DBG_THREADS_PROFILING
enables a system tick counter in each thread, after a long execution time relative values of the counters indicate the relative “weight” of all threads. This option has been superseded by CH_DBG_STATISTICS and is not compatible with the tick-less mode.
3. 参考资料
【1】ArduPilot开源飞控系统之简单介绍
【2】Ardupilot开源飞控之ChibiOS简介
【3】 ChibiOS官方文档