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");
}