RTOS
This content relates to a deprecated version of Mbed
Mbed 2 is now deprecated. For the latest version please see the Mbed OS documentation.
For the latest RTOS API, please see RTOS.
Import librarymbed-rtos
Official mbed Real Time Operating System based on the RTX implementation of the CMSIS-RTOS API open standard.
Thread¶
The Thread
class allows defining, creating, and controlling thread functions in the system. The function main
is a special thread function that is started at system initialization and has the initial priority osPriorityNormal
.
Import program
00001 #include "mbed.h" 00002 #include "rtos.h" 00003 00004 DigitalOut led1(LED1); 00005 DigitalOut led2(LED2); 00006 Thread thread; 00007 00008 void led2_thread() { 00009 while (true) { 00010 led2 = !led2; 00011 Thread::wait(1000); 00012 } 00013 } 00014 00015 int main() { 00016 thread.start(led2_thread); 00017 00018 while (true) { 00019 led1 = !led1; 00020 Thread::wait(500); 00021 } 00022 }
main
The main
function is already the first thread scheduled by the rtos.
Import library
Public Types |
|
enum |
State
{
Inactive , Ready , Running , WaitingDelay , WaitingInterval , WaitingOr , WaitingAnd , WaitingSemaphore , WaitingMailbox , WaitingMutex , Deleted } |
State of the Thread . More... |
|
Public Member Functions |
|
Thread (osPriority priority=osPriorityNormal, uint32_t stack_size=DEFAULT_STACK_SIZE, unsigned char *stack_pointer=NULL) | |
Allocate a new thread without starting execution.
|
|
MBED_DEPRECATED_SINCE ("mbed-os-5.1"," Thread -spawning constructors hide errors. ""Replaced by thread.start(task).") Thread(mbed | |
Create a new thread, and start it executing the specified function.
|
|
template<typename T > | |
MBED_DEPRECATED_SINCE ("mbed-os-5.1"," Thread -spawning constructors hide errors. ""Replaced by thread.start(callback(task, argument)).") Thread(T *argument | |
Create a new thread, and start it executing the specified function.
|
|
template<typename T , typename M > | |
MBED_DEPRECATED_SINCE ("mbed-os-5.1","The start function does not support cv-qualifiers. ""Replaced by thread.start(callback(obj, method)).") osStatus start(T *obj | |
Starts a thread executing the specified function.
|
|
osStatus | join () |
Wait for thread to terminate.
|
|
osStatus | terminate () |
Terminate execution of a thread and remove it from Active Threads.
|
|
osStatus | set_priority (osPriority priority) |
Set priority of an active thread.
|
|
osPriority | get_priority () |
Get priority of an active thread.
|
|
int32_t | signal_set (int32_t signals) |
Set the specified Signal Flags of an active thread.
|
|
int32_t | signal_clr (int32_t signals) |
Clears the specified Signal Flags of an active thread.
|
|
State | get_state () |
State of this
Thread
.
|
|
uint32_t | stack_size () |
Get the total stack memory size for this
Thread
.
|
|
uint32_t | free_stack () |
Get the currently unused stack memory for this
Thread
.
|
|
uint32_t | used_stack () |
Get the currently used stack memory for this
Thread
.
|
|
uint32_t | max_stack () |
Get the maximum stack memory usage to date for this
Thread
.
|
|
Static Public Member Functions |
|
static osEvent | signal_wait (int32_t signals, uint32_t millisec=osWaitForever) |
Wait for one or more Signal Flags to become signaled for the current RUNNING thread.
|
|
static osStatus | wait (uint32_t millisec) |
Wait for a specified time period in millisec:
|
|
static osStatus | yield () |
Pass control to next thread that is in state READY.
|
|
static osThreadId | gettid () |
Get the thread id of the current running thread.
|
|
static void | attach_idle_hook (void(*fptr)(void)) |
Attach a function to be called by the RTOS idle task.
|
|
static void | attach_terminate_hook (void(*fptr)(osThreadId id)) |
Attach a function to be called when a task is killed.
|
A Thread
can be in the following states:
- RUNNING: The thread that is currently running is in the RUNNING state. Only one thread at a time can be in this state.
- READY: Threads which are ready to run are in the READY state. Once the RUNNING thread has terminated or is WAITING the next READY thread with the highest priority becomes the RUNNING thread.
- WAITING: Threads that are waiting for an event to occur are in the WAITING state.
- INACTIVE: Threads that are not created or terminated are in the INACTIVE state. These threads typically consume no system resources.
Mutex¶
A Mutex
is used to synchronize the execution of threads: for example to protect the access to a shared resource.
ISR
The Mutex
methods cannot be called from interrupt service routines (ISR).
Import program
00001 #include "mbed.h" 00002 #include "rtos.h" 00003 00004 Mutex stdio_mutex; 00005 00006 void notify(const char* name, int state) { 00007 stdio_mutex.lock(); 00008 printf("%s: %d\n\r", name, state); 00009 stdio_mutex.unlock(); 00010 } 00011 00012 void test_thread(void const *args) { 00013 while (true) { 00014 notify((const char*)args, 0); Thread::wait(1000); 00015 notify((const char*)args, 1); Thread::wait(1000); 00016 } 00017 } 00018 00019 int main() { 00020 Thread t2; 00021 Thread t3; 00022 00023 t2.start(callback(test_thread, (void *)"Th 2")); 00024 t3.start(callback(test_thread, (void *)"Th 3")); 00025 00026 test_thread((void *)"Th 1"); 00027 }
C standard library mutexes
The ARM C standard library has already mutexes in place to protect the access to stdio, therefore on the M3 mbed the above example is not necessary. On the contrary, ARM microlib (used on the M0 mbed) does not provide default stdio mutexes making the above example a necessity.
stdio (printf, putc, getc, etc), malloc & new in ISR
Because of the mutexes in the ARM C standard library you cannot use stdio (printf
, putc
, getc
, etc), malloc
and new
in ISR!
Import library
Public Member Functions |
|
Mutex () | |
Create and Initialize a
Mutex
object.
|
|
osStatus | lock (uint32_t millisec=osWaitForever) |
Wait until a
Mutex
becomes available.
|
|
bool | trylock () |
Try to lock the mutex, and return immediately.
|
|
osStatus | unlock () |
Unlock the mutex that has previously been locked by the same thread.
|
Semaphore¶
A Semaphore
is particularly useful to manage thread access to a pool of shared resources of a certain type.
Import program
00001 #include "mbed.h" 00002 #include "rtos.h" 00003 00004 Semaphore two_slots(2); 00005 00006 void test_thread(void const *name) { 00007 while (true) { 00008 two_slots.wait(); 00009 printf("%s\n\r", (const char*)name); 00010 Thread::wait(1000); 00011 two_slots.release(); 00012 } 00013 } 00014 00015 int main (void) { 00016 Thread t2; 00017 Thread t3; 00018 00019 t2.start(callback(test_thread, (void *)"Th 2")); 00020 t3.start(callback(test_thread, (void *)"Th 3")); 00021 00022 test_thread((void *)"Th 1"); 00023 }
Import library
Public Member Functions |
|
Semaphore (int32_t count=0) | |
Create and Initialize a
Semaphore
object used for managing resources.
|
|
int32_t | wait (uint32_t millisec=osWaitForever) |
Wait until a
Semaphore
resource becomes available.
|
|
osStatus | release (void) |
Release a
Semaphore
resource that was obtain with Semaphore::wait.
|
Signals¶
Each Thread
can be notified and wait for signals:
Import program
00001 #include "mbed.h" 00002 #include "rtos.h" 00003 00004 DigitalOut led(LED1); 00005 00006 void led_thread() { 00007 while (true) { 00008 // Signal flags that are reported as event are automatically cleared. 00009 Thread::signal_wait(0x1); 00010 led = !led; 00011 } 00012 } 00013 00014 int main (void) { 00015 Thread thread; 00016 00017 thread.start(callback(led_thread)); 00018 00019 while (true) { 00020 Thread::wait(1000); 00021 thread.signal_set(0x1); 00022 } 00023 }
Queue¶
A Queue
allows you to queue pointers to data from producers threads to consumers threads:
Queue<message_t, 16> queue; message_t *message; queue.put(message); osEvent evt = queue.get(); if (evt.status == osEventMessage) { message_t *message = (message_t*)evt.value.p;
Import programrtos_queue
Basic example showing the Queue and MemoryPool API
MemoryPool¶
The MemoryPool class is used to define and manage fixed-size memory pools:
MemoryPool<message_t, 16> mpool; message_t *message = mpool.alloc(); mpool.free(message);
Import program
00001 #include "mbed.h" 00002 #include "rtos.h" 00003 00004 typedef struct { 00005 float voltage; /* AD result of measured voltage */ 00006 float current; /* AD result of measured current */ 00007 uint32_t counter; /* A counter value */ 00008 } message_t; 00009 00010 MemoryPool<message_t, 16> mpool; 00011 Queue<message_t, 16> queue; 00012 00013 /* Send Thread */ 00014 void send_thread (void) { 00015 uint32_t i = 0; 00016 while (true) { 00017 i++; // fake data update 00018 message_t *message = mpool.alloc(); 00019 message->voltage = (i * 0.1) * 33; 00020 message->current = (i * 0.1) * 11; 00021 message->counter = i; 00022 queue.put(message); 00023 Thread::wait(1000); 00024 } 00025 } 00026 00027 int main (void) { 00028 Thread thread; 00029 thread.start(callback(send_thread)); 00030 00031 while (true) { 00032 osEvent evt = queue.get(); 00033 if (evt.status == osEventMessage) { 00034 message_t *message = (message_t*)evt.value.p; 00035 printf("\nVoltage: %.2f V\n\r" , message->voltage); 00036 printf("Current: %.2f A\n\r" , message->current); 00037 printf("Number of cycles: %u\n\r", message->counter); 00038 00039 mpool.free(message); 00040 } 00041 } 00042 }
Import library
Public Member Functions |
|
MemoryPool () | |
Create and Initialize a memory pool.
|
|
T * | alloc (void) |
Allocate a memory block of type T from a memory pool.
|
|
T * | calloc (void) |
Allocate a memory block of type T from a memory pool and set memory block to zero.
|
|
osStatus | free (T *block) |
Return an allocated memory block back to a specific memory pool.
|
Mail¶
A Mail
works like a queue with the added benefit of providing a memory pool for allocating messages (not only pointers).
Import program
00001 #include "mbed.h" 00002 #include "rtos.h" 00003 00004 /* Mail */ 00005 typedef struct { 00006 float voltage; /* AD result of measured voltage */ 00007 float current; /* AD result of measured current */ 00008 uint32_t counter; /* A counter value */ 00009 } mail_t; 00010 00011 Mail<mail_t, 16> mail_box; 00012 00013 void send_thread (void) { 00014 uint32_t i = 0; 00015 while (true) { 00016 i++; // fake data update 00017 mail_t *mail = mail_box.alloc(); 00018 mail->voltage = (i * 0.1) * 33; 00019 mail->current = (i * 0.1) * 11; 00020 mail->counter = i; 00021 mail_box.put(mail); 00022 Thread::wait(1000); 00023 } 00024 } 00025 00026 int main (void) { 00027 Thread thread; 00028 thread.start(callback(send_thread)); 00029 00030 while (true) { 00031 osEvent evt = mail_box.get(); 00032 if (evt.status == osEventMail) { 00033 mail_t *mail = (mail_t*)evt.value.p; 00034 printf("\nVoltage: %.2f V\n\r" , mail->voltage); 00035 printf("Current: %.2f A\n\r" , mail->current); 00036 printf("Number of cycles: %u\n\r", mail->counter); 00037 00038 mail_box.free(mail); 00039 } 00040 } 00041 }
Import library
Public Member Functions |
|
Mail () | |
Create and Initialise
Mail
queue.
|
|
T * | alloc (uint32_t millisec=0) |
Allocate a memory block of type T.
|
|
T * | calloc (uint32_t millisec=0) |
Allocate a memory block of type T and set memory block to zero.
|
|
osStatus | put (T *mptr) |
Put a mail in the queue.
|
|
osEvent | get (uint32_t millisec=osWaitForever) |
Get a mail from a queue.
|
|
osStatus | free (T *mptr) |
Free a memory block from a mail.
|
RTOS Timer¶
The RtosTimer
class allows creating and and controlling of timer functions in the system. A timer function is called when a time period expires whereby both one-shot and periodic timers are possible. A timer can be started, restarted, or stopped. Timers are handled in the thread osTimerThread
. Callback functions run under control of this thread and may use CMSIS-RTOS API calls.
Import program
00001 #include "mbed.h" 00002 #include "rtos.h" 00003 00004 DigitalOut LEDs[4] = { 00005 DigitalOut(LED1), DigitalOut(LED2), DigitalOut(LED3), DigitalOut(LED4) 00006 }; 00007 00008 void blink(void const *n) { 00009 LEDs[(int)n] = !LEDs[(int)n]; 00010 } 00011 00012 int main(void) { 00013 RtosTimer led_1_timer(blink, osTimerPeriodic, (void *)0); 00014 RtosTimer led_2_timer(blink, osTimerPeriodic, (void *)1); 00015 RtosTimer led_3_timer(blink, osTimerPeriodic, (void *)2); 00016 RtosTimer led_4_timer(blink, osTimerPeriodic, (void *)3); 00017 00018 led_1_timer.start(2000); 00019 led_2_timer.start(1000); 00020 led_3_timer.start(500); 00021 led_4_timer.start(250); 00022 00023 Thread::wait(osWaitForever); 00024 }
Import library
Public Member Functions |
|
MBED_DEPRECATED_SINCE ("mbed-os-5.1","Replaced with RtosTimer (Callback<void()>, os_timer_type)") RtosTimer(void(*func)(void const *argument) | |
Create timer.
|
|
osStatus | start (uint32_t millisec) |
Start the timer.
|
Interrupt Service Routines¶
The same RTOS API can be used in ISR. The only two warnings are:
Mutex
can not be used.- Wait in ISR is not allowed: all the timeouts in method parameters have to be set to 0 (no wait).
Import program
00001 #include "mbed.h" 00002 #include "rtos.h" 00003 00004 Queue<uint32_t, 5> queue; 00005 00006 DigitalOut myled(LED1); 00007 00008 void queue_isr() { 00009 queue.put((uint32_t*)2); 00010 myled = !myled; 00011 } 00012 00013 void queue_thread(void const *args) { 00014 while (true) { 00015 queue.put((uint32_t*)1); 00016 Thread::wait(1000); 00017 } 00018 } 00019 00020 int main (void) { 00021 Thread thread(queue_thread); 00022 00023 Ticker ticker; 00024 ticker.attach(queue_isr, 1.0); 00025 00026 while (true) { 00027 osEvent evt = queue.get(); 00028 if (evt.status != osEventMessage) { 00029 printf("queue->get() returned %02x status\n\r", evt.status); 00030 } else { 00031 printf("queue->get() returned %d\n\r", evt.value.v); 00032 } 00033 } 00034 }
Default Timeouts¶
The mbed rtos API has made the choice of defaulting to 0
timeout (no wait) for the producer methods, and osWaitForever
(infinitive wait) for the consumer methods.
A typical scenario for a producer could be a peripheral triggering an interrupt to notify an event: in the corresponding interrupt service routine you cannot wait (this would deadlock the entire system). On the other side, the consumer could be a background thread waiting for events: in this case the desired default behaviour is not using CPU cycles until this event is produced, hence the osWaitForever.
No wait in ISR
When calling an rtos object method in an ISR all the timeout parameters have to be set to 0 (no wait): waiting in ISR is not allowed.
Status and Error Codes¶
The Status and Error Codes section lists all the return values that the CMSIS-RTOS functions will return:
osOK
: function completed; no event occurred.osEventSignal
: function completed; signal event occurred.osEventMessage
: function completed; message event occurred.osEventMail
: function completed; mail event occurred.osEventTimeout
: function completed; timeout occurred.osErrorParameter
: parameter error: a mandatory parameter was missing or specified an incorrect object.osErrorResource
: resource not available: a specified resource was not available.osErrorTimeoutResource
: resource not available within given time: a specified resource was not available within the timeout period.osErrorISR
: not allowed in ISR context: the function cannot be called from interrupt service routines.osErrorISRRecursive
: function called multiple times from ISR with same object.osErrorPriority
: system cannot determine priority or thread has illegal priority.osErrorNoMemory
: system is out of memory: it was impossible to allocate or reserve memory for the operation.osErrorValue
: value of a parameter is out of range.osErrorOS
: unspecified RTOS error: run-time error but no other error message fits.
osEvent¶
The osEvent
data structure is returned by get
methods of Queue
and Mail
objects.
This data structure contains both an error code and a pointer to the actual data:
[Repository '/users/mbed_official/code/rtx/docs/tip/structosEvent.html' not found]
Implementation¶
The mbed RTOS is based on the CMSIS RTOS.