ChibiOS简介3/5
- 1. 源由
- 2. ChibiOS基础知识3/5
- 2.7 Chapter 7 - RT Time and Intervals
- 2.7.1 Basic concepts
- 2.7.2 APIs
- 2.8 Chapter 8 - RT Virtual Timers
- 2.8.1 Basic concepts
- 2.8.2 Tickless Mode
- 2.8.3 APIs
- 2.9 Chapter 9 - RT Scheduler
- 2.9.1 Basic concepts
- 2.9.2 System Class
- 2.9.3 Ready List
- 2.10 Chapter 10 - RT Threading
- 2.10.1 Basic concepts
- 2.10.2 APIs
- 2.11 Chapter 11 - RT Counter Semaphores
- 2.11.1 Basic concepts
- 2.11.2 APIs
- 2.12 Chapter 12 - RT Mutexes, Condition Variables and Monitors
- 2.12.1 Basic concepts
- 2.12.2 APIs
- 3. 参考资料
1. 源由
作为后续研读Ardupilot的ChibiOS的垫脚石,先了解下ChibiOS系统。
Ardupilot ChibiOS项目: https://github.com/ArduPilot/ChibiOS
Artery(AT32) porting项目: //Artery官网没有相关porting动作,不过开源github有相关项目。
- https://github.com/dron0gus/artery
- https://github.com/dron0gus/ChibiOS
2. ChibiOS基础知识3/5
2.7 Chapter 7 - RT Time and Intervals
2.7.1 Basic concepts
Handling of time is a fundamental mechanism in ChibiOS/RT, it is quite important to understand some basic concepts:
- System Tick, The system tick is the atomic unit of time in ChibiOS/RT, time is measured in ticks. The system tick increases the system time counter.
- System Time, System time is a counter of type systime_t increased by the System Tick, when the counter reaches its maximum value then it returns to zero, this does not affect functionality, the counter is meant to be able to wrap. The type systime_t is used for absolute time, specific instants in the system time domain.
- Time Intervals, A time interval is a time period measured in system ticks.
- Time units, A time units are used to define intervals using standard time units rather than system ticks. Time units have their own types:
time_secs_t
,time_msecs_t
andtime_usecs_t
. - Time Period, It is a couple of systime_t representing the “start time” and the “end time” of an absolute time period.
- System Time Counter, The system time is kept by a global counter of type systime_t which is incremented by the system tick.
- Tick-less mode, The system time is an HW counter within some system timer, no interrupts are required in order to increase the counter.
- High Resolution mode.
2.7.2 APIs
- System Time Access API
函数名 | 描述 |
---|---|
chVTGetSystemTime() | 返回当前系统时间。 |
chVTGetSystemTimeX() | 返回当前系统时间(X-Class变体)。该函数可以在任何上下文中调用,但在字长小于systime_t大小的体系结构上其原子性不能保证。 |
chVTTimeElapsedSinceX() | 返回自指定系统时间以来的间隔。 |
chVTIsSystemTimeWithin() | 如果当前系统时间在指定的时间段内,则返回true。 |
chVTIsSystemTimeWithinX() | 如果当前系统时间在指定的时间段内,则返回true(X-Class变体)。 |
- Time Utilities API
函数名 | 功能描述 |
---|---|
chTimeAddX() | 将时间间隔添加到系统时间,并返回新的系统时间。 |
chTimeDiffX() | 返回两个系统时间之间的时间间隔。 |
chTimeIsInRangeX() | 如果指定的系统时间在指定的时间段内,则返回true。 |
chTimeS2I() | 安全地将时间间隔从秒转换为滴答数。 |
chTimeMS2I() | 安全地将时间间隔从毫秒转换为滴答数。 |
chTimeUS2I() | 安全地将时间间隔从微秒转换为滴答数。 |
chTimeI2S() | 安全地将时间间隔从滴答数转换为秒。 |
chTimeI2MS() | 安全地将时间间隔从滴答数转换为毫秒。 |
chTimeI2US() | 安全地将时间间隔从滴答数转换为微秒。 |
TIME_S2I() | 不安全但更快的方式将时间间隔从秒转换为滴答数。 |
TIME_MS2I() | 不安全但更快的方式将时间间隔从毫秒转换为滴答数。 |
TIME_US2I() | 不安全但更快的方式将时间间隔从微秒转换为滴答数。 |
TIME_I2S() | 不安全但更快的方式将时间间隔从滴答数转换为秒。 |
TIME_I2MS() | 不安全但更快的方式将时间间隔从滴答数转换为毫秒。 |
TIME_I2US() | 不安全但更快的方式将时间间隔从滴答数转换为微秒。 |
2.8 Chapter 8 - RT Virtual Timers
2.8.1 Basic concepts
- RT Virtual Timers, Virtual Timers are an unique ChibiOS/RT feature. It is a software system able to provide an “unlimited” number of one-shot timers with the same resolution of the system tick.
- One Shot Timers, Virtual timers are one-shot timers that can be started, stopped prematurely or trigger a callback after their programmed time is expired.
- Callbacks, Timers callbacks are always invoked from ISR context, this means that the API that can be utilized from a timer callback is subject to the same restrictions applicable to ISRs. By re-arming a virtual timer from the callback it is possible to implement periodic or aperiodic timers as well.
2.8.2 Tickless Mode
- Common RTOS kernels are triggered by a periodic interrupt, called system tick, driving the internal timings-relate mechanisms. In ChibiOS/RT the system tick is handled efficiently however it can still limits the system in several ways:
- CPU usage is increased by the frequent IRQ servicing, the problem gets worse at higher frequencies.
- The system tick limits the resolution of the virtual timers and of the system time because a too high frequency would negatively affect the system performance.
- The system jitter is worsened by the continuous interruptions.
- Frequent interrupts can prevent the system from entering deeper sleep modes. This affects negatively the system power usage.
- ChibiOS/RT implements a unique tickless mode in its virtual timers subsystem. When the tickless mode is activated the system timer is no more generating periodic interrupts but is programmed to generate an interrupt only when the system has some scheduled activity to execute, usually a virtual timer expiration. This approach has several positive aspects:
- Lower power consumption thanks to the use of deeper sleep modes not continuously interrupted by a system tick.
- Better overall jitter in ISR servicing.
- Higher resolution for system time and virtual timers because the timer frequency is no more constrained.
- There are some things to consider:
- A new ChibiOS/RT port is more complex if the tickless mode has to be implemented.
- A special timer must be present in HW and dedicated to the tickless mode. It must be an up-counter with a comparator register. A 16 bits counter is sufficient however a 32 bits counter is recommended.
- The behavior of the system time within critical sections is slightly different, in tick mode the system time is not incremented, in tickless mode the time is always incremented because the timer counter register is used and it is not affected by the critical section.
- Slightly larger kernel image.
2.8.3 APIs
- Virtual Timers API
函数名 | 描述 |
---|---|
virtual_timer_t | 虚拟定时器对象的类型。 |
chVTObjectInit() | 初始化虚拟定时器对象 virtual_timer_t 。 |
chVTSet() | 启动或重新启动虚拟定时器。 |
chVTSetI() | 启动或重新启动虚拟定时器(I-Class变体)。 |
chVTReset() | 停止,如果虚拟定时器处于活动状态。 |
chVTResetI() | 停止,如果虚拟定时器处于活动状态(I-Class变体)。 |
chVTIsArmedI() | 如果定时器已启用,则返回true。 |
chVTDoSetI() | 启动虚拟定时器,定时器必须尚未启用。稍微比 chVTSetI() 快一点。 |
chVTDoResetI() | 停止虚拟定时器,定时器必须已经启用。稍微比 chVTResetI() 快一点。 |
2.9 Chapter 9 - RT Scheduler
2.9.1 Basic concepts
- RT Scheduler, ChibiOS/RT implements a strictly priority-based scheduling strategy, the module responsible for threads scheduling is called the scheduler. In this module are also defined the data structures used globally by the RTOS.
- Scheduler Module, The ChibiOS/RT scheduler is the module responsible for threads scheduling, it also exports a low level API that is used by the other modules in order to implement synchronization primitives of any kind.
2.9.2 System Class
- The System Class, ChibiOS/RT is designed to be upgrade-able to a multi-core capable RTOS. Because of this all the internal data structures are encapsulated into a single system class. In a single core implementation there is a single system object. When multi core MCUs will become common multiple system instances will be possible.
2.9.3 Ready List
- The ready list is probably the most important data structure in ChibiOS/RT. It is a closed bidirectional priority-ordered list of threads representing the threads eligible for execution.
- Idle thread has the lowest priority level in the system (one), and is executed only when no other thread is ready for execution. The purpose of the idle thread is to define what the system does when there is nothing to do, usually it is an empty loop or a loop containing a single, architecture-dependent, “Wait for Interrupt” instruction that stops the CPU until a interrupt is detected. Stopping the CPU can reduce during idle times can reduce the system power consumption. One important details is that the idle thread can only be in the READY or CURRENT states, it is not allowed to go in any of the sleeping states nor to terminate. The idle thread is automatically created on system initialization and lasts until the system is shut down.
2.10 Chapter 10 - RT Threading
2.10.1 Basic concepts
- RT Threading, The threading module is responsible for operations related to static threads. One important concept is the current thread, some functions inherently operate or the thread executing the function. The services of the threading module are:
- Declaration.
- Life Cycle.
- Delays.
- Threads References.
- Threads Queues.
- Thread Time.
- Priority Management.
- Round Robin.
2.10.2 APIs
- Threads Declaration API
Function | Description |
---|---|
THD_WORKING_AREA() | Statically allocates a working area for a thread. |
THD_FUNCTION() | Declares a thread function hiding eventual compiler-specific keywords. |
- Threads Management API
Function | Description |
---|---|
chThdGetSelfX() | Returns a pointer to the current thread. |
chThdCreateStatic() | Creates and starts a static thread. |
chThdCreateI() | Creates a thread without starting it. |
chThdStart() | Starts a thread previously created using chThdCreateI() . |
chThdStartI() | Starts a thread previously created using chThdCreateI() . |
chThdExit() | Terminates the current thread returning a message. |
chThdExitS() | Terminates the current thread returning a message. |
chThdWait() | Waits for the specified thread to terminate then returns its exit message. The thread can be again created if necessary. |
chThdTerminate() | Sets the termination flag in the destination thread. The thread is not deleted but just asked to exit. The termination is cooperative. |
chThdShouldTerminateX() | Returns true if the current thread has the termination flag set. |
chThdTerminatedX() | Returns true if the specified thread is terminated. |
- Delays API
Thread delays are characterized by:
- The achievable resolution depends on the system tick frequency, if the frequency is 1000Hz then the delays resolution is 1mS.
- The time spent into a delays is used to run other threads, there is not busy waiting involved.
Function | Description |
---|---|
chThdSleep() | Inserts a delay specified as number of system ticks, the delay is approximated to the next tick boundary. |
chThdSleepSeconds() | Inserts a delay specified in seconds, the delay is approximated to the next tick boundary. |
chThdSleepMilliseconds() | Inserts a delay specified in milliseconds. Note that the real resolution depends on system tick, the delay is approximated to the next tick boundary. |
chThdSleepMicroseconds() | Inserts a delay specified in microseconds. Note that the real resolution depends on system tick, the delay is approximated to the next tick boundary. |
chThdSleepUntil() | Sleeps until the system time counter reaches the specified value. |
chThdSleepUntilWindowed() | Special case of chThdSleepUntil() where a time window is specified. |
- Threads References API
There are two possible operations:
- Suspend, makes a NULL reference point to a thread.
- Resume, wakes up a waiting thread resetting the reference to NULL again.
Function | Description |
---|---|
chThdSuspendS() | Suspends the invoking thread on a reference variable. |
chThdSuspendTimeoutS() | Suspends the invoking thread on a reference variable with a timeout specification. |
chThdResume() | Resumes a suspended thread. |
chThdResumeI() | Resumes a suspended thread (I-Class variant). |
chThdResumeS() | Resumes a suspended thread (S-Class variant). |
- Threads Queues API
Thread queues are a special kind of FIFO object, the following operations are defined:
- Enqueue, a thread enqueues itself and goes to sleep.
- Dequeue Next, wakes up the next thread in the queue if any.
- Dequeue All, wakes up all threads in the queue.
Function | Description |
---|---|
chThdQueueObjectInit() | Initializes a thread queue object. |
chThdQueueIsEmptyI() | Returns true if the queue is empty. |
chThdEnqueueTimeoutS() | Enqueues the calling thread in the queue. |
chThdDoDequeueNextI() | Dequeues the next thread in the queue, the queue is assumed to contain at least one element. |
chThdDequeueNextI() | Dequeues the next thread in the queue, if any. |
chThdDequeueAllI() | Dequeues all thread in the queue, if any. |
- Priority Management API
Function | Description |
---|---|
chThdGetPriorityX() | Returns the priority of the current thread. |
chThdSetPriority() | Changes the thread priority level, returns the old priority. |
- Round Robin API
Round robin scheduling can work in two distinct ways:
- Preemptive Round Robin. This mode is activated by setting CH_CFG_TIME_QUANTUM to a value greater than zero. In this mode the thread using the CPU is preempted by its peers after its time slot has been used.
- Cooperative Round Robin. This mode is activated by setting CH_CFG_TIME_QUANTUM to zero. In this mode the switch between threads at the same priority level is always cooperative. Cooperative mode is preferable because the kernel becomes slightly more efficient because it does not have to handle time slots.
Function | Description |
---|---|
chThdYield() | The current thread relinquishes its time slice to the next thread in the round robin chain. |
2.11 Chapter 11 - RT Counter Semaphores
2.11.1 Basic concepts
Counting semaphores have an internal signed counter variable, the value of the variable is the semaphore internal state. The meaning of the counter is:
- N < 0. The semaphore is taken and there are -N threads queued.
- N == 0. The semaphore is taken but there are no threads queued.
- N > 0. The semaphore is not taken and can be taken N times.
ChibiOS/RT implements an extended version of the Dijkstra semaphores, there are several enhancements over the initial definition:
- Reset Operation. In addition to the classic Wait and Signal operations a new Reset operation has been added. This operation is able to reset a semaphore counter to any non-negative value, all waiting threads are dequeued, if any.
- Timeouts. The Wait operation has an optional timeout parameter, a queued thread is able to be dequeued if a Signal or Reset is not performed within the specified time interval.
- Message. The Wait operation returns a message code indicating the way the thread has been signaled:
MSG_OK. The thread has taken the resource normally.
MSG_RESET. The thread was queued and a Reset operation has been performed on the semaphore. This is the default message, a variant of the reset operation can send any message code.
MSG_TIMEOUT. The thread was queued and a timeout occurred.
- Atomic Signal and Wait. A Signal operation is performed on a semaphore and a Wait operation is performed on another semaphore atomically.
2.11.2 APIs
Function | Description |
---|---|
semaphore_t | Type of a counter semaphore object. |
SEMAPHORE_DECL() | Semaphore static initializer. |
chSemObjectInit() | Initializes a semaphore object of type semaphore_t. |
chSemWait() | Performs a Wait operation on the semaphore. |
chSemWaitS() | Performs a Wait operation on the semaphore (S-Class variant). |
chSemWaitTimeout() | Performs a Wait operation on the semaphore with timeout specification. |
chSemWaitTimeoutS() | Performs a Wait operation on the semaphore with timeout specification (S-Class variant). |
chSemSignal() | Performs a Signal operation on the semaphore. |
chSemSignalI() | Performs a Signal operation on the semaphore (I-Class variant). |
chSemReset() | Performs a Reset operation on the semaphore. |
chSemResetI() | Performs a Reset operation on the semaphore (I-Class variant). |
chSemResetWithMessage() | Performs a Reset operation on the semaphore sending a custom message. |
chSemResetWithMessageI() | Performs a Reset operation on the semaphore sending a custom message (I-Class variant). |
chSemResetI() | Performs a Reset operation on the semaphore (I-Class variant). |
chSemAddCounterI() | Adds a constant to the semaphore counter, threads are dequeued as required (I-Class variant). |
chSemSignalWait() | Atomically performs a Signal on a semaphore and a Wait on another semaphore. |
chSemGetCounterI() | Returns the current value of the semaphore counter (I-Class variant). |
chSemFastWaitI() | Faster version of Wait usable in those conditions where the counter is known to be greater than zero, it is a pure decrement (I-Class variant). |
chSemFastSignalI() | Faster version of Signal usable in those conditions where the counter is known to be non-negative, it is a pure increment (I-Class variant). |
2.12 Chapter 12 - RT Mutexes, Condition Variables and Monitors
2.12.1 Basic concepts
- Mutexes are the mechanism meant to implement mutual exclusion in the most general way. There is often confusion between Mutexes and Semaphores, both are apparently able to solve the same problem but there are important differences:
- Mutexes have an owner attribute, semaphores do not have owners. Because of this mutexes can only be unlocked by the same thread that locked them. This is not required for semaphores that can be unlocked by any thread or even ISRs.
- Mutexes can implement protocols to handle Priority Inversion, knowing the owner is required in order to be able to implement Priority Inheritance or Priority Ceiling algorithms. ChibiOS/RT mutexes implement the Priority Inheritance algorithm with no restrictions on the number of threads or the number of nested mutual exclusion zones.
- Mutexes can be implemented to be recursive mutexes, this means that the same thread can lock the same mutex repeatedly and then has to unlock it for the same number of times. In ChibiOS/RT mutexes can be made recursive by activating a configuration option.
- Condition variables are an additional construct working with mutexes in order to form Monitor constructs much similar, in behaviour, to the Java synchronized constructs.
A condition variable is basically a queue of threads, the function chCondWait() performs atomically the following steps;
- Releases the last acquired mutex.
- Puts the current thread in the condition variable queue.
When the queued thread is kicked out of the queue using chCondSignal() or chCondBroadcast() then it:
- Re-acquires the mutex previously released.
- Returns from chCondWait().
2.12.2 APIs
- Mutexes API
Function | Description |
---|---|
mutex_t | Type of a mutex object. |
MUTEX_DECL() | Mutexes static initializer. |
chMtxObjectInit() | Initializes a mutex object of type mutex_t. |
chMtxLock() | Locks the specified mutex. |
chMtxLockS() | Locks the specified mutex (S-Class variant). |
chMtxTryLock() | Tries to lock a mutex, exits without waiting. |
chMtxTryLockS() | Tries to lock a mutex, exits without waiting (S-Class variant). |
chMtxUnlock() | Unlocks the next owned mutex in reverse lock order. |
chMtxUnlockS() | Unlocks the next owned mutex in reverse lock order (S-Class variant). |
chMtxUnlockAll() | Unlocks all mutexes owned by invoking thread. |
- Condition Variables API
Function | Description |
---|---|
condition_variable_t | Type of a condition variable object. |
CONDVAR_DECL() | Condition variables static initializer. |
chCondObjectInit() | Initializes a condition variable object of type condition_variable_t. |
chCondSignal() | Signals a condition variable. |
chCondSignalI() | Signals a condition variable (I-Class variant). |
chCondBroadcast() | Broadcasts a condition variable. |
chCondBroadcastI() | Broadcasts a condition variable (I-Class variant). |
chCondWait() | Releases latest owned mutex and enters condition variable wait queue. |
chCondWaitS() | Releases latest owned mutex and enters condition variable wait queue (S-Class variant). |
chCondWaitTimeout() | Releases latest owned mutex and enters condition variable wait queue with timeout specification. |
chCondWaitTimeoutS() | Releases latest owned mutex and enters condition variable wait queue with timeout specification (S-Class variant). |
3. 参考资料
【1】ArduPilot开源飞控系统之简单介绍
【2】Ardupilot开源飞控之ChibiOS简介
【3】 ChibiOS官方文档