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.

/media/uploads/JimCarver/thread_priority.png

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.

/media/uploads/emilmont/threadstatus.png

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).

/media/uploads/emilmont/mutex.png

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.

/media/uploads/emilmont/semaphore.png

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:

/media/uploads/emilmont/messagequeue.png

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

Import library

Public Member Functions

Queue ()
Create and initialise a message Queue .
osStatus put (T *data, uint32_t millisec=0)
Put a message in a Queue .
osEvent get (uint32_t millisec=osWaitForever)
Get a message or Wait for a message from a Queue .

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).

/media/uploads/emilmont/mailqueue.png

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.

/media/uploads/emilmont/rtostimer.png

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.


All wikipages