|
ChibiOS/RT
|
This package contains versions of the ChbiOS/RT RTOS for AVR Arduinos, Arduino Due, and Teensy 3.x.
The ports are based on ChibiOS 3.0.3.
Information about Teensy 3.x can be found here:
These systems are packaged as the Arduino libraries ChibiOS_ARM and ChibiOS_AVR. In addition a version of the SdFat library for ARM/AVR is included.
SdFat is a FAT16/FAT32 file system for SD cards. More information and newer versions are available here:
https://github.com/greiman/SdFat
The documentation for ChibiOS/RT is located here:
http://www.chibios.org/dokuwiki/doku.php?id=start
Also please explore the above tabs.
If this is your first exposure to a RTOS you will likely feel some pain.
You may want to start using ChibiOS in cooperative mode. See the chCoop.ino example below. In this mode preemptive context switches are disabled for threads of the same priority.
The normal Arduino environment is single-threaded so code does not need to be reentrant or threadsafe. With a preemptive RTOS, the same resources may be accessed concurrently by several threads.
Many arduino libraries and functions are not reentrant or threadsafe.
To protect resource integrity, code written for multithreaded programs must be reentrant and threadsafe.
Reentrance and thread safety are both related to the way that functions handle resources. Reentrance and thread safety are separate concepts: a function can be either reentrant, threadsafe, both, or neither.
A reentrant function does not hold static data over successive calls, nor does it return a pointer to static data. A reentrant function must not call non-reentrant functions.
A threadsafe function protects shared resources from concurrent access by locks. Only one thread can be executing at a time.
The dynamic memory functions malloc and free are not threadsafe. This means that libraries like String and SD.h are not thread safe since they use malloc/free.
SdFat does not use malloc but is not threadsafe. Notice that I put all access to the SD in the low priority loop thread to avoid problems.
You must not use Arduino delay() in other than the lowest priority task. delay() will block all lower priority threads.
Two of the most common design problems for embedded developers are the deadlock and the priority inversion problem. You should start with very simple designs to avoid these subtle problems.
I have installed simple exception error handlers for three ISR vectors. If an execution fault causes one of these exception, I blink the pin 13 LED. The codes are:
Hard fault - blink one short flash every two seconds
Bus fault - blink two short flashes every two seconds
Usage fault - blink three short flashes every two seconds
There are a number examples in each RTOS library.
The chBlink.ino example demonstrates thread definition, semaphores, and thread sleep.
Thread 1 waits on a semaphore and turns the LED off when signalled by thread 2.
Thread 2 turns the LED on, sleeps for a period, signals thread 1 to turn the LED off, and sleeps for another period.
The blink/print example in each library is chBlinkPrint.ino.
Each of the blink/print examples has three threads. A high priority thread blinks an LED, a medium priority thread prints a counter every second, and a low priority thread increments the counter.
The print thread also checks Serial for input. If the input is available, the print thread will display stack usage information for each thread and stop the blink thread.
An interesting experiment is to observe the nonatomic behavior of incrementing count in loop().
Comment out noInterrupts() and interrupts() like this:
You will then see occasional large counts when the print thread tries to zero count while the loop() thread is incrementing count.
You need an oscilloscope to run this example. This example is chContextTime.ino.
To run this example, connect the scope to pin 13. You will see two pulses. Measure difference in time between first pulse with no context switch and the second pulse started in ledControl and ended in ledOffTask.
The difference is the time for the semaphore and a context switch.
ChibiOS/RT uses cooperative scheduling when CH_TIME_QUANTUM is set to zero. This disables preemption for threads with equal priority and the round robin becomes cooperative. Note that higher priority threads can still preempt, the kernel is always preemptive.
The chCoop.ino example illustrates this feature.
Note that is is not necessary to protect count or maxDelay in this example since a context switch can not happen while these variables are accessed.
The chDataSharing.ino example illustrates thread safe data sharing between two threads.
Thread 1 reads a sensor into temp variables. Thread 1 calls chMtxLock() to prevent Thread 2 from accessing the shared data, and copies the temp variables to the shared area, and then unlocks access to the shared area.
Thread 2 runs every second. Thread 2 locks the shared data, copies the shared values to temp variables, and unlocks access to the shared area.
Thread 2 then prints the temp values and unused stack stats.
The fast data logger example is chFifoDataLogger.ino. This example require connection to an SD socket.
Two semaphores are used to implement a FIFO for data records. This uncouples the data acquisition task from the SD write task. SD card have unpredictable write latencies that can be over 100 milliseconds.
You need a quality SD card to avoid data overrun errors. Overruns could be avoided by allocating more memory to the buffer queue.
This example logs a counter as dummy data. You can replace this with data from an analog pin or your sensor.
Type any character to terminate the example. Memory usage information will be printed.
The chJitter.ino example delays for one tick and measures the time difference in micros between delay calls.
The min and max times are printed by a lower priority task.
The chIsrSemaphore.ino example demonstrates how a handler task can be triggered from an ISR by using a binary semaphore.
The chMailPool.ino example demonstrates use of a memory pool and mailboxes with two senders and one receiver.
The chMutex.ino example shows how to protect a shared resource. In this case the mutex is used to share Serial between three threads. The mutex prevents print calls from the three threads from being scrambled.
chRoundRobin.ino is a very simple demonstration of two tasks running in round robin mode.
chSemaphore.ino demonstrates use of a counting semaphore by three tasks. Execution is restrict execution of at most two tasks in one region of code.
1.8.10