class: title, smokescreen, shelf, bottom, no-footer background-image: url(images/chibioslogo.jpg) # 181U Spring 2020 ### ChibiOS Real-Time Operating System --- layout: true .footer[ - Geoffrey Brown, 2020 - 181U ] <style> h1 { border-bottom: 8px solid rgb(32,67,143); border-radius: 2px; width: 90%; } .smokescreen h1 { border-bottom: none; } .small.remark-slide-content.compact {font-size:1.2rem} .smaller.remark-slide-content.compact {font-size:1.1rem} .small-code.remark-slide-content.compact code {font-size:1.0rem} .very-small-code.remark-slide-content.compact code {font-size:0.9rem} .line-numbers{ /* Set "line-numbers-counter" to 0 */ counter-reset: line-numbers-counter; } .line-numbers .remark-code-line::before { /* Increment "line-numbers-counter" by 1 */ counter-increment: line-numbers-counter; content: counter(line-numbers-counter); text-align: right; width: 20px; border-right: 1px solid #aaa; display: inline-block; margin-right: 10px; padding: 0 5px; } </style> --- class: compact # Agenda * What is a Real-Time Operating System * ChibiOS Overview * ChibiOS Structure * Threads and Synchronization Primitives * Device Drivers * ChibiOS Configuration --- class: compact # What is a Real-Time Operating System (RTOS) * Real-time operating systems are optimized to handle *event* quickly * Real-time operating systems have thread/process schedulers that enable high-priority services to meet defined timing constraints * Most RTOSs support threads rather than processes --- class: compact # ChibiOS ![](images/2020-01-12-16-57-29.png# w-33pct fr) * ChibiOS is a lightweight RTOS consisting of three major components - a *kernel* providing threads, thread synchronization, and inter-thread communication - a *hardware abstraction layer* providing a consistent model of key hardware devices - a *port layer* providing device specific hardware drivers --- class: compact # Threads (Tasks in ChibiOS) * Threads are independent execution units with their own stacks and contexts (register states) ![](images/space.png# w-20pct) ![](images/2020-01-12-17-08-50.png# w-60pct) * **INIT** -- The task has not yet been created * **READY** -- The task is eligible for execution * **RUNNING** -- The task is currently running (only one!) * **WAITING** -- The task is waiting for an event --- class: compact # ChibiOS ![](images/2020-01-12-16-57-29.png# w-33pct fr) * The Startup Code - Initializes the core (processor) - Initializes the stack(s) - Initializes the C Runtime (typically, BSS and Data sections) - Calls the `main()` function * ChibiOS/RT - **Portable Kernel** -- architecture and device independent part of RT - **Port Layer** -- architecure/compiler specific part of RT * ChibiOS/HALL - **API Layer** -- architecture independent part - **Port Layer** -- architecture dependent layer - **Board Layer** -- board specific layer (e.g. pin assignments) --- class: compact # ChibiOS/RT Kernel Architecture * Base Kernel Services - **System** low level locks, initialization - **Timers** virtual timers and time APIs - **Scheduler** task scheduler and high level synchronization - **Threads** ![](images/space.png# w-20pct) ![](images/2020-01-12-17-14-13.png# w-60pct) --- class: compact # ChibiOS/RT Kernel Architecture * Synchronization - **Semaphores** counter and binary - **Mutexes** - **Condvars** condition variables - **Events** event sources and flags - **Messages** lightweight synchronous messages - **Mailboxes** Asynchronous message queues ![](images/space.png# w-20pct) ![](images/2020-01-12-17-16-40.png# w-60pct) --- class: compact # Other Kernel Services * Streams and I/O Channels - **Data Streams** abstract stream interface - **I/O Channels** inherit from abstract stream interface - **I/O Queues** generic, byte wide, I/O queues * Debug Support - **Assertions** integrity checks - **Parameter checks** -- test parameters - **Stack checks** -- test stack integrity - **Trace Buffer** -- trace system events --- class: compact # HAL Architecture The HAL is a collection of abstract device drivers, it relies on the Platform component for the low level implementation on specific hardware. The purpose of the HAL is to offer a cross platform API to access common peripheral types. ![](images/2020-01-12-17-25-01.png# w-33pct fr) **Normal Device Drivers** ![](images/2020-01-12-17-22-30.png# w-40pct) Examples include SPI, UART, I2C **Complex Device Drivers** ![](images/2020-01-12-17-24-12.png# w-40pct) Example includes SD card support, serial over USB, etc. --- class: very-small-code,compact,hljs-tomorrow-night-eighties,line-numbers # Thread Declaration ```C /* MyThread Working Area.*/ static THD_WORKING_AREA(waMyThread, 128); /* MyThread function.*/ static THD_FUNCTION(MyThread, arg) { /* Thread body code.*/ ...; } void main(void) { /* initialization */ ... /* The thread is spawned.*/ thread_t *tp = chThdCreateStatic(waMyThread, sizeof(waMyThread), NORMALPRIO, MyThread , NULL); ``` --- class: very-small-code,compact,hljs-tomorrow-night-eighties,line-numbers # Thread Delay ``` static THD_WORKING_AREA(waBlinker, 128); static THD_FUNCTION(Blinker, arg) { while (true) { LED_on(); chThdSleepMilliseconds(500); LED_off(); chThdSleepMilliseconds(500); } } ``` --- class: very-small-code,compact,hljs-tomorrow-night-eighties,line-numbers # Mutexes (basic synchronization mechanism) ```C static mutex_t mtx1; static THD_WORKING_AREA(waThread1, 128); static THD_FUNCTION(Thread1, arg) { while (true) { ...; // noormal thread activity chMtxLock(&mtx1); // request access to protected resource ...; // access shared resource chMtxUnlock(&mtx1); // release shared resource ...; } } void main(void) { chSysInit(); chMtxObjectInit(&mtx1); // initialize mutex chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL); ``` --- class: compact # Events Events provide a powerful way for threads to synchronize * Thread can wait for multiple events * Multiple threads can wait on a given event * Events are asynchronously broadcast * Interrupt handlers can signal events Simple case * `chEvtSignal()` -- signal a set of events to a thread * `chEvtWaitAny()` -- wait for any of a set of events * `chEvtWaitAnyTimeout()` -- wait for any of a set of events with a timeout --- class: very-small-code,compact,hljs-tomorrow-night-eighties,line-numbers,col-2 # Events -- Direct signalling ```C #define EVT_UART_RX EVENT_MASK(0) #define EVT_UART_TX EVENT_MASK(1) #define EVT_UART_ERR EVENT_MASK(2) thread_t *uart_thread; CH_IRQ_HANDLER(UART_RX_IRQ) { eventmask_t events = 0; ... if ((UART->SR & UART_SR_ERRORS) != 0) events |= EVT_UART_ERR; if ((UART->SR & UART_SR_DATA_AVAILABLE) != 0) events |= EVT_UART_RX; ... if (events) { chSysLockFromISR(); chEvtSignalI(uart_thread, events); chSysUnlockFromISR(); } } ``` ```C static THD_FUNCTION(UARTThread, arg) { while (true) { eventmask_t evt = chEvtWaitAny(ALL_EVENTS); if (evt & EVT_UART_ERR) { error_handler(); } if (evt & EVT_UART_RX) { rx_handler(); ... ``` --- class: compact # Streams ![](images/2020-01-12-18-34-49.png# w-20pct fr) The ancestor of all streams interfaces is a *Sequential Stream* * `chSequentialStreamWrite()` Write to a stream * `chSequentialStreamRead()` Read from a stream * `chSequentialStreamPut()` Write a byte to a stream * `chSequentialStreamGet()` Read a byte from a stream Some examples of streams * Memory Streams -- stream implemented in memory * UART interface -- buffered read/write to/from uart --- class: compact # Threads (again) How threads in ChibiOS/RT change their state: ![](images/space.png# w-20pct) ![](images/2020-01-12-18-41-08.png# w-60pct) The edges are marked by kernel system calls. --- class: compact # Thread Priority Levels * **IDLEPRIO**, this is the lowest priority level and is reserved for the idle thread, no other threads should share this priority level. This is the lowest numerical value of the priorities space. * **LOWPRIO**, the lowest priority level that can be assigned to an user thread. * **NORMALPRIO**, this is the central priority level for user threads. It is advisable to assign priorities to threads as values relative to NORMALPRIO, as example NORMALPRIO-1 or NORMALPRIO+4, this ensures the portability of code should the numerical range change in future implementations. * **HIGHPRIO**, the highest priority level that can be assigned to an user thread. --- class: compact # Example Driver -- Serial * **sdPut** write a character * **sdPutI** write a character from an interrupt handler * **sdPutTimeout** write a character (with timeout) * **sdGet** read a character (plus I and Timeout versions) * **sdRead** read a buffer of characters (plus I and Timeout versions) * **sdWrite** write a buffer of characters (plus I and Timeout versions) The serial driver implements a sequential stream on top of the UART --- class: compact # ChibiOS Configuration ChibiOS makes extensive use of C macros to enable exactly the features needed for an application. In addition, a given hardware board may require specific pins to be configured and names to be assigned to those pins. A configuration consists of * `mcuconf.h` : low level processor configuration (clocks, etc.) * `chconf.h` : kernel configuration * `hal.h` : hal configuration * `board.[ch]` : board configuration and initialization. --- class: very-small-code,compact,hljs-tomorrow-night-eighties,line-numbers # mcuconf.h (processor configuration) ```C #ifndef MCUCONF_H #define MCUCONF_H #define STM32L4xx_MCUCONF #define STM32L476_MCUCONF #define STM32L486_MCUCONF /* * HAL driver system settings. */ #define STM32_NO_INIT FALSE #define STM32_VOS STM32_VOS_RANGE1 #define STM32_PVD_ENABLE FALSE #define STM32_PLS STM32_PLS_LEV0 #define STM32_HSI16_ENABLED FALSE #define STM32_LSI_ENABLED TRUE #define STM32_HSE_ENABLED FALSE ... ``` --- class: very-small-code,compact,hljs-tomorrow-night-eighties,line-numbers # chconf.h (kernel configuration) ```C /** * @brief System time counter resolution. * @note Allowed values are 16 or 32 bits. */ #if !defined(CH_CFG_ST_RESOLUTION) #define CH_CFG_ST_RESOLUTION 32 #endif /** * @brief System tick frequency. * @details Frequency of the system timer that drives the system ticks. This * setting also defines the system tick time unit. */ #if !defined(CH_CFG_ST_FREQUENCY) #define CH_CFG_ST_FREQUENCY 10000 #endif ... ``` --- class: very-small-code,compact,hljs-tomorrow-night-eighties,line-numbers # halconf.h (hal configuration) ``` /*===========================================================================*/ /* SERIAL driver related settings. */ /*===========================================================================*/ /** * @brief Default bit rate. * @details Configuration parameter, this is the baud rate selected for the * default configuration. */ #if !defined(SERIAL_DEFAULT_BITRATE) || defined(__DOXYGEN__) #define SERIAL_DEFAULT_BITRATE 115200 #endif /** * @brief Serial buffers size. * @details Configuration parameter, you can change the depth of the queue * buffers depending on the requirements of your application. * @note The default is 16 bytes for both the transmission and receive * buffers. */ #if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__) #define SERIAL_BUFFERS_SIZE 16 #endif ``` --- class: very-small-code,compact,hljs-tomorrow-night-eighties,line-numbers # board.h (board configuration) ```C ... #define BOARD_ST_NUCLEO64_L476RG #define BOARD_NAME "STMicroelectronics STM32 Nucleo64-L476RG" /* * Board oscillators-related settings. */ #if !defined(STM32_LSECLK) #define STM32_LSECLK 32768U #endif #define STM32_LSEDRV (3U << 3U) #if !defined(STM32_HSECLK) #define STM32_HSECLK 8000000U #endif /* * IO pins assignments. */ #define GPIOA_ARD_A0 0U #define GPIOA_ACD12_IN5 0U #define GPIOA_ARD_A1 1U #define GPIOA_ACD12_IN6 1U #define GPIOA_ARD_D1 2U ... ``` --- class: compact # Summary * Real-time Operating systems * ChibiOS - structure - kernel - hal - synchronization - configuration * Much of these slides is drawn from http://chibios.org/dokuwiki