Table of Contents
RT System Layer
The System Layer is the most fundamental part of the RT kernel, it lies just above the port layers and provides a series of important services:
- Initialization.
- Abnormal Termination.
- Interrupts Handling.
- Critical Sections.
- Power Management.
- Realtime Counter.
Initialization
This service handles the system initialization:
API
chSysInit() | Starts the RT kernel. This function must be called once from the main() function. |
Examples
Kernel Initialization
The RT kernel is always initialized as follow:
#include "ch.h" void main(void) { /* * System initializations. * - Kernel initialization, the main() function becomes a thread and the * RTOS is active. Interrupts are enabled on chSysInit() exit. */ chSysInit(); . . . }
Note that the main() function is not meant to return, the system would stop.
Abnormal Termination
This service handles the system panic stop, a reason can be provided for post mortem inspection or logging:
API
CH_CFG_SYSTEM_HALT_HOOK(reason) | Hook macro for inserting a custom action before the system halt. |
chSysHalt(const char *reason) | Stops the system, the behavior of the function can be overridden using a hook. |
Examples
Panic Stop
A panic is usually used in response of a unexpected non-recoverable condition.
#include "ch.h" void main(void) { . . . chSysHalt("unexpected condition #12"); }
Interrupts Handling
This service offers ISR abstraction and IRQ handling functions.
API
CH_IRQ_HANDLER() | Declaration of a normal interrupt handler. |
CH_IRQ_PROLOGUE() | ISR prologue code. |
CH_IRQ_EPILOGUE() | ISR epilogue code. |
CH_FAST_IRQ_HANDLER() | Declaration of a non-OS (fast) interrupt handler. |
chSysEnable() | Enables all interrupts. |
chSysSuspend() | Disables normal interrupts, fast interrupts are kept enabled. |
chSysDisable() | Disables all interrupts. |
Examples
Writing an OS ISR
ISRs can be written in an architecture/compiler independent form, myISR is the name of the interrupt vector function. Note that there is an ISR declaration macro and two macros that mark the beginning and the end of the ISR, all the RTOS-specific code is hidden within the macros.
CH_IRQ_HANDLER(myISR) { CH_IRQ_PROLOGUE(); /* ISR code.*/ ...; CH_IRQ_EPILOGUE(); }
Writing a Fast ISR
Interrupts that are not meant to interact with the Kernel can be written using this lighter form. No OS-related overhead is added to the ISR code path:
CH_FAST_IRQ_HANDLER(myISR) { /* Fast ISR code.*/ ...; }
Critical Sections
This service handles critical sections in various flavors:
- Non reentrant Thread-level critical sections.
- Non reentrant ISR-level critical sections.
- Reentrant “universal” critical sections.
API
chSysLock() | Enters a thread-level critical section. |
chSysUnlock() | Leaves a thread-level critical section. |
chSysLockFromISR() | Enters an ISR-level critical section. |
chSysUnlockFromISR() | Leaves an ISR-level critical section. |
chSysUnconditionalLock() | Enters a thread-level critical section regardless the previous state. |
chSysUnconditionalUnlock() | Leaves a thread-level critical section regardless the previous state. |
chSysGetStatusAndLockX() | Enters a critical section from any context returning the previous state. |
chSysRestoreStatusX() | Restores a critical section status saved by chSysGetStatusAndLockX(), a reschedule operation is performed if required and applicable. |
Examples
Critical Sections in Threads
THD_FUNCTION(myThread, arg) { /* Thread code.*/ ...; /* Entering a critical section.*/ chSysLock(); /* Protected code.*/ ...; /* Leaving the critical section.*/ chSysUnlock(); /* More thread code.*/ ...; }
Critical Sections in ISRs
CH_IRQ_HANDLER(myISR) { CH_IRQ_PROLOGUE(); /* ISR code.*/ ...; /* Entering a critical section.*/ chSysLockFromISR(); /* Protected code.*/ ...; /* Leaving the critical section.*/ chSysUnlockFromISR(); /* More ISR code.*/ ...; CH_IRQ_EPILOGUE(); }
Reentrant Critical Sections
/* * This function can be called from within or outside critical sections and * either in thread or ISR context. */ void myFunc(void) { /* Protected or unprotected code.*/ ...; /* Conditionally entering a critical section.*/ syssts_t sts = chSysGetStatusAndLockX(); /* Protected code.*/ ...; /* Conditionally leaving the critical section.*/ chSysRestoreStatusX(sts); /* Protected or unprotected code.*/ ...; }
Power Management
The kernel does not handle power management directly however there are features meant to allow the implementation of any kind of power management in response of important kernel actions. Another important power-related feature is the Tickless Mode that will be discussed in the Virtual Timers chapter.
API
CH_CFG_IDLE_ENTER_HOOK() | This hook is invoked when the system is going to switch into the idle thread. It can be used to enter a power saving mode. |
CH_CFG_IDLE_LEAVE_HOOK() | This hook is invoked when the system is going to switch out of idle thread. It can be used to leave a power saving mode. |
CH_CFG_IDLE_LOOP_HOOK() | Hook invoked from within the idle thread loop. |
Examples
Examples are not provided for the above hooks because any implementation would be necessarily architecture-dependent.
Realtime Counter
The realtime counter is an optional RT kernel feature. It is present only if the underlying architecture supports the required feature: a very fast counter driver increased by the system clock. The realtime counter is used for:
- Accurate time delays.
- Short loops with timeout.
API
PORT_SUPPORTS_RT | If defined, this macro indicates that the current kernel port supports the Realtime Counter feature. It can be used for conditional code or compile time errors. |
S2RTC() | Converts from seconds to number of RT clocks pulses. |
MS2RTC() | Converts from milliseconds to number of RT clocks pulses. |
US2RTC() | Converts from microseconds to number of RT clocks pulses. |
RTC2S() | Converts from number of RT clocks pulses to seconds. |
RTC2MS() | Converts from number of RT clocks pulses to milliseconds. |
RTC2US() | Converts from number of RT clocks pulses to microseconds. |
chSysIsCounterWithinX() | Determines if the specified counter value is within the specified interval. |
chSysPolledDelayX() | Inserts an accurate delay into execution of the current thread or ISR. |
Examples
Small Delay
This is a common need when dealing with HW devices, it is often required to do something after a small amount of time. Such delays cannot be reliably implemented as software loops. An interesting thing is that the function can be preempted and the ISRs/threads execution is accounted as part of the delays not as an added extra delay improving accuracy.
void start_conversion(void) { /* Activate peripheral.*/ ADC->CR1 |= ADC_CR1_ACTIVE; /* Wait at least 12uS before the ADC can be used.*/ chSysPolledDelayX(US2RTC(SYSCLK, 12)); /* Starts the conversion.*/ ADC->CR1 |= ADC_CR_START; }
Loop with Timeout
Another common need is to have an escape way for software loops:
void wait_conversion(void) { /* Wait the ADC to complete the operation, after 10mS a failure is assumed.*/ rtcnt_t start = chSysGetRealtimeCounterX(); rtcnt_t end = start + MS2RTC(10); do { if ((ADC->SR & ADC_SR_DONE) != 0) return; } while (chSysIsCounterWithinX(chSysGetRealtimeCounterX(), start, end)); /* This is unexpected, probably an ADC failure.*/ chSysHalt("ADC failure"); }