CMSIS-RTOS Tutorial 
Introduction 
This tutorial is an excerpt from “The Designers Guide to the Cortex-M Processor 
Family”  by  Trevor  Martin  and  is  reproduced  with  permission  of  Elsevier.  For 
more details please see the Further Reading section at the end of this tutorial. 
In this tutorial we are going to look at using a small footprint RTOS running on a 
Cortex-M based microcontroller. Specifically we are going to use an RTOS that 
meets 
the  ‘Cortex  Microcontroller  Interface  Standard’  (CMSIS)  RTOS 
Specification.  This  specification  defines  a  standard  RTOS  API  for  use  with 
Cortex-M  based  microcontrollers.   The  CMSIS-RTOS  API  provides  us  with  all 
the features we will need to develop with an RTOS, we only need to learn it once 
and  then  can  use  it  across  a  very  wide  range  of  devices.  CMSIS-RTOS  also 
provides  a  standard  interface  for  more  complex  frameworks  (Java  Virtual 
Machine,  UML).  It  is  also  a  standard  interface  for  anyone  wanting  to  develop 
reusable software components. If you are new to using an RTOS it takes a bit of 
practice to get used to working with an RTOS but once you have made the leap 
the  advantages  are  such  that  you  will  not  want  to  return  to  writing  bare  metal 
code.   
Getting Started- Installing the tools 
To run the examples in this tutorial, it is first necessary to install the MDK-ARM 
toolchain.  First  download  the  MDK-Core  Version  5  using  the  embedded  URL 
below and run the installation file.  
http://www.keil.com/mdk5/install 
 
This installs the core toolchain which includes the IDE, compiler/linker and the 
basic  debugger.  It  does  not  include  support  for  specific  Cortex-M  based 
microcontrollers. To support a given microcontroller family we need  to install a 
‘Device Family Pack’. This is a collection of support files such as startup code, 
flash  programming  algorithms  and  debugger  support  that  allow  you  to  develop 
with a specific microcontroller family. 
 
 
The  MDK-ARM 
toolchain 
consists of a Core Installation 
(IDE,  Compiler  and  Debugger) 
plus additional software packs 
added through a pack installer 
 
 
   
   
2   
 
   
   
CMSIS-RTOS Tutorial 
In  the  exercises  we  are  going  to  use  an  STM32F103RB  so  we  need  to  install 
support for this device using the ‘Pack Installer’ within the  µVision IDE. When 
the  MDK-Core  finishes  installing  the  pack  installer  will  start  automatically, 
alternatively  you  can  start  the  µVision  IDE  and  access  Pack  Installer  from  the 
toolbar by pressing the icon shown below 
Pack Installer Icon 
 
Once the pack installer is open it will connect to cloud based pack database and 
display the available device packs. 
this  utility 
Installer. 
The  Pack 
Use 
to 
install device support 
and 
party 
software components 
third 
Select  the  Keil::STM32F1xx_DFP  and  press  the  install  button.  This  will  take  a 
few minutes to download and install the STM32F1xx support files.  
 
 
 
Install support for the 
STM32F1xx Family 
If  the  pack  installer  has  any  problems  accessing  the  remote  pack  you  can 
download it manually using the URL below 
http://www.keil.com/dd2/Pack/ 
 
CMSIS-RTOS Tutorial 
Again select the STM32F1xx pack and save it to your hard disk. The file may be 
saved as a .zip file depending on the browser you are using. If it is saved as a .zip  
change  the  .zip  extension  to  .pack,  you  can  then  install  it  locally  by  double 
clicking on the STM32F1xx.pack file. 
Installing the examples 
The examples for this tutorial are provided as a CMSIS pack. You can install the 
pack into the MDK-ARM by simply double clicking on the 
Hitex.CMSIS_RTOS_Tutorial.1.0.3. pack file. 
Once 
installing click next 
the  pack  has  started 
Here you must accept the license 
and  again  click  next  to  continue 
the installation 
 
 
Once  the  examples  have  been  installed  into  MDK-ARM  they  are  part  of  the 
toolchain  and  can  be accessed  through  the  pack  installer. The tutorial  examples 
can be found in the boards section under ‘CMSIS_RTOS_Tutorial’. 
 
 
 
   
   
   
   
4   
CMSIS-RTOS Tutorial 
What Hardware do I need? 
Simple  answer:  none!  The  Keil  toolchain  contains  simulators  for  each  of  the 
Cortex-M processors. It also contains full simulation models (CPU + Peripherals) 
for  some  of  the  earlier  Cortex-M  microcontrollers.  This  means  we  can  run  the 
examples in the debugger using the simulation models and explore every aspect 
of  using  the  RTOS.  In  fact  this  method  of  working  is  a  better  way  of  learning 
how to use the RTOS than going straight to a real microcontroller.  
Overview 
In this tutorial we will first look at setting up an introductory RTOS project for a 
Cortex-M  based  microcontroller.  Next,  we  will  go  through  each  of  the  RTOS 
primitives  and  how  they  influence  the  design  of  our  application  code.  Finally, 
when we have a clear understanding of the RTOS features, we will take a closer 
look  at  the  RTOS  configuration  options.  If  you  are  used  to  programming  a 
microcontroller without using an RTOS i.e. bare metal, there are two key things 
to understand as you work through this tutorial. In the first section we will focus 
on  creating  and  managing  Threads.  The  key  concept  here  is  to  consider  them 
running as parallel concurrent objects. In the second section we will look at how 
threads.  In 
to  communicate  between 
is 
synchronization of the concurrent threads.  
the  key  concept 
this  section 
 
CMSIS-RTOS Tutorial 
First steps with CMSIS-RTOS 
The RTOS itself consists of a scheduler which supports round-robin, pre-emptive 
and  co-operative  multitasking  of  program  threads,  as  well  as  time  and  memory 
management  services.  Inter-thread  communication  is  supported  by  additional 
RTOS  objects,  including  signal  triggering,  semaphores,  mutex  and  a  mailbox 
system.  As  we  will  see,  interrupt  handling  can  also  be  accomplished  by 
prioritized threads which are scheduled by the RTOS kernel. 
The  RTOS  kernel  contains  a 
scheduler 
that  runs  program 
code  as  tasks.  Communication 
between  tasks  is  accomplished 
by RTOS objects such as events, 
semaphores,  mutexes 
and 
mailboxes.  Additional  RTOS 
and 
services 
memory  management 
and 
interrupt support. 
include 
time 
 
Accessing the CMSIS-RTOS API 
To access any of the CMSIS-RTOS features in our application code it is 
necessary to include the following header file 
#include  
This  header  file  is  maintained  by  ARM  as  part  of  the  CMSIS-RTOS  standard. 
For the CMSIS-RTOS Keil RTX this is the default API. Other RTOS will have 
their  own  proprietary  API  but  may  provide  a  wrapper  layer  to  implement  the 
CMSIS-RTOS  API  so  they  can  be  used  where  compatibility  with  the  CMSIS 
standard is required.   
Threads 
The  building  blocks  of  a  typical  ‘C’  program  are  functions  which  we  call  to 
perform  a  specific  procedure  and  which  then  return  to  the  calling  function.  In 
CMSIS-RTOS the basic unit of execution is a “Thread”. A Thread is very similar 
to a ‘C’ procedure but has some very fundamental differences. 
 
 
   
   
   
   
6   
CMSIS-RTOS Tutorial 
 
 
 
 
 
 
 
 
 
return(ch);         
 
 
 
 
 
 
 
 
 
 
 
 
 
 
unsigned int procedure (void)  
 
 
{ 
 
 
 
  ……   
 
 
  
 
 
 
} 
 
 
While we always return from our ‘C’ function, once started an RTOS thread must 
contain a loop so that it never terminates and thus runs forever. You can think of 
a thread as a mini self-contained program that runs within the RTOS.  
void thread (void) 
 
 
 
  
 
 
 
while(1) 
 
 
{ 
 …… 
{ 
 
 
 
} 
} 
 
 
An RTOS program is made up of a number of threads, which are controlled by 
the RTOS scheduler. This scheduler uses the SysTick timer to generate a periodic 
interrupt  as  a  time  base.  The  scheduler  will  allot  a  certain  amount  of  execution 
time  to  each  thread.  So thread1  will run for  5ms  then  be  de-scheduled to  allow 
thread2 to run for a similar period; thread 2 will give way to thread3 and finally 
control  passes  back  to  thread1.  By  allocating  these  slices  of  runtime  to  each 
thread  in  a  round-robin  fashion,  we  get  the  appearance  of  all  three  threads 
running in parallel to each other.  
Conceptually we can think of each thread as performing a specific functional unit 
of our program with all threads running simultaneously.  This leads us to a more 
object-orientated design, where each functional block can be coded and tested in 
isolation and then integrated into a fully running program. This not only imposes 
a  structure  on  the  design  of  our  final  application  but  also  aids  debugging,  as  a 
particular bug can be easily isolated to a specific thread.  It also aids code reuse 
in later projects. When a thread is created, it is also allocated its own thread ID. 
This  is  a  variable  which  acts  as  a  handle  for  each  thread  and  is  used  when  we 
want to manage the activity of the thread. 
osThreadId id1,id2,id3; 
In  order  to  make  the  thread-switching  process  happen,  we  have  the  code 
overhead of the RTOS and we have to dedicate a CPU hardware timer to provide 
the RTOS time reference. In addition, each time we switch running threads, we 
have to save the state of all  the thread variables to a  thread stack.  Also, all the 
runtime  information  about a  thread is stored  in  a thread  control  block,  which  is 
managed by the RTOS kernel. Thus the “context switch time”, that is, the time to 
save  the  current  thread  state  and  load  up  and  start  the  next  thread,  is  a  crucial 
figure and will depend on both the RTOS kernel and the design of the underlying 
hardware.  
 
Each thread has its own stack for saving 
its  data  during  a  context  switch.  The 
thread control block is used by the kernel 
to manage the active thread. 
ThreadThread Control BlockThread StackPriority & StateContext
CMSIS-RTOS Tutorial 
The Thread Control Block contains information about the status of a thread. Part 
of  this  information  is  its  run  state.  In  a  given  system  only  one  thread  can  be 
running  and  all  the  others  will  be  suspended  but  ready  to  run.    The  RTOS  has 
various methods of inter-thread communication (signals, semaphores, messages).  
Here,  a  thread  may  be  suspended  to  wait  to  be  signaled  by  another  thread  or 
interrupt  before  it  resumes  its  ready  state,  whereupon  it  can  be  placed  into 
running state by the RTOS scheduler. 
Running  The Currently Running Thread 
Ready 
Threads ready to Run 
Wait  
Blocked Threads waiting for an OS Event 
 
 
by 
and  will 
At  any  given  moment  a 
single  thread  may  be 
running.  The remaining 
threads will be ready to 
run 
be 
scheduled 
the 
kernel.  Threads  may 
also 
waiting 
pending  an  OS  event. 
When  this  occurs  they 
will  return  to  the  ready 
state and be scheduled 
by the kernel. 
be 
Starting the RTOS 
To  build  a  simple  RTOS  program  we  declare  each  thread  as  a  standard  ‘C’ 
function and also declare a thread ID variable for each function. 
void thread1 (void); 
void thread2 (void); 
 
osThreadId thrdID1, thrdID2; 
 
By  default the  CMSIS-RTOS  scheduler  will  be running  when  main()  is  entered 
and the main() function becomes the first active thread. Once in main(), we can 
stop  the  scheduler  task  switching  by  calling  osKernelInitialize  ().  While  the 
RTOS is halted we can create further threads and other RTOS objects. Once the 
system  is  in  a  defined  state  we  can  restart  the  RTOS  scheduler  with 
osKernelStart(). 
You can run any initializing code you want before starting the RTOS. 
void main (void) 
{ 
 
 
 
 
} 
osKernelInitialize ();   
IODIR1 = 0x00FF0000;          
Init_Thread(); 
 
osKernelStart();  
 
 
// Do any C code you want 
//Create a Thread 
//Start the RTOS 
 
 
   
   
   
   
8   
CMSIS-RTOS Tutorial 
 
When threads are created they are also assigned a priority. If there are a number 
of threads ready to run and they all have the same priority, they will be allotted 
run  time  in  a  round-robin  fashion.  However,  if  a  thread  with  a  higher  priority 
becomes ready to run, the RTOS scheduler will de-schedule the currently running 
thread  and  start  the  high  priority  thread  running.  This  is  called  pre-emptive 
priority-based  scheduling.  When  assigning  priorities  you  have  to  be  careful 
because the high priority thread will continue to run until it enters a waiting state 
or until a thread of equal or higher priority is ready to run. 
 
 
 
 
 
Threads  of  equal  priority  will  be 
scheduled  in  a  round-robin  fashion. 
High priority tasks will pre-empt low 
priority  tasks  and  enter  the  running 
state ‘on demand’. 
Exercise a first CMSIS-RTOS project 
This  project  will  take  you  through  the  steps  necessary  to  create  and  debug  a 
CMSIS-RTOS based project. 
Start µVision and select Project  New µVision Project 
 
In  the  new  project  dialog  enter  a  suitable  project  name  and  directory  and 
click Save 
Next the device database will open. Navigate through to the  
STMicroelectronics::STM32F103:STM32F103RB