]> begriffs open source - cmsis/blob - CMSIS/DoxyGen/RTOS2/src/cmsis_os2_Tutorial.txt
RTX5: Add Thread Entry wrapper to be compatible with GDB stack unwind (#1559)
[cmsis] / CMSIS / DoxyGen / RTOS2 / src / cmsis_os2_Tutorial.txt
1 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
2 /**
3 \page rtos2_tutorial Tutorial
4
5 This tutorial is an introduction to using a small footprint real-time operating system on an Arm Cortex-M microcontroller.
6 If you are used to writing procedural-based 'C' code on small 8-/16-bit microcontrollers, you may be doubtful about the need
7 for such an operating system. If you are not familiar with using an RTOS in real-time embedded systems, you should read this
8 chapter before dismissing the idea. The use of an RTOS represents a more sophisticated design approach, inherently fostering
9 structured code development which is enforced by the RTOS application programming interface (API). 
10
11 The RTOS structure allows you to take a more object-orientated design approach, while still programming in 'C'. The RTOS
12 also provides you with multithreaded support on a small microcontroller. These two features actually create quite a shift in
13 design philosophy, moving us away from thinking about procedural ‘C’ code and flow charts. Instead we consider the
14 fundamental program threads and the flow of data between them. The use of an RTOS also has several additional benefits which
15 may not be immediately obvious. Since an RTOS based project is composed of well-defined threads, it helps to improve project
16 management, code reuse, and software testing.
17
18 The tradeoff for this is that an RTOS has additional memory requirements and increased interrupt latency. Typically, the
19 Keil RTX5 RTOS will require 500 bytes of RAM and 5k bytes of code, but remember that some of the RTOS code would be
20 replicated in your program anyway. We now have a generation of small low-cost microcontrollers that have enough on-chip
21 memory and processing power to support the use of an RTOS. Developing using this approach is therefore much more accessible.
22
23 We will first look at setting up an introductory RTOS project for a Cortex-M based microcontroller. Next, we
24 will go through each of the RTOS primitives and how they influence the design of our application code. Finally, when we have
25 a clear understanding of the RTOS features, we will take a closer look at the RTOS configuration options. If you are used to
26 programming a microcontroller without using an RTOS i.e. bare metal, there are two key things to understand as you work
27 through this tutorial. In the first section, we will focus on creating and managing Threads. The key concept here is to
28 consider them running as parallel concurrent objects. In the second section, we will look at how to communicate between
29 threads. In this section the key concept is synchronization of the concurrent threads.
30
31
32 \section rtos2_tutorial_pre Prerequisites
33
34 It is assumed that you have Keil MDK installed on your PC. For download and installation instructions, please visit
35 the <a href="https://www2.keil.com/mdk5/install/" target="_blank">Getting Started</a> page. Once you have set up the tool,
36 open <a href="https://www2.keil.com/mdk5/packinstaller" target="_blank">Pack Installer</a>:
37 - Use the <b>Search</b> box on the <b>Devices</b> tab to look for the <b>STM32F103</b> device.
38 - On the <b>Packs</b> tab, download and install the latest <b>Keil:STM32F1xx_DFP</b> pack and the latest
39   <b>Hitex:CMSIS_RTOS2_Turorial</b> pack.
40
41 \note It is assumed that you are familiar with Arm Keil MDK and have basic 'C' programming knowledge.
42
43
44 \section rtos2_tutorial_first_steps First Steps with Keil RTX5
45
46 The RTOS itself consists of a scheduler which supports round-robin, pre-emptive and co-operative multitasking of program
47 threads, as well as time and memory management services. Inter-thread communication is supported by additional RTOS objects,
48 including signal thread and event flags, semaphores, mutex, message passing and a memory pool system. As we will see,
49 interrupt handling can also be accomplished by prioritized threads which are scheduled by the RTOS kernel.
50
51 \image html rtos_components.png
52
53
54 \section rtos2_tutorial_access Accessing the CMSIS-RTOS2 API
55
56 To access any of the CMSIS-RTOS2 features in our application code, it is necessary to include the following header file.
57 \code
58 #include <cmsis_os2.h>
59 \endcode
60 This header file is maintained by Arm as part of the CMSIS-RTOS2 standard. For Keil RTX5, this is the default API. Other
61 RTOS will have their own proprietary API but may provide a wrapper layer to implement the CMSIS-RTOS2 API so they can be
62 used where compatibility with the CMSIS standard is required.
63
64
65 \section rtos2_tutorial_threads Threads
66
67 The building blocks of a typical 'C' program are functions which we call to perform a specific procedure and which then
68 return to the calling function. In CMSIS-RTOS2, the basic unit of execution is a "Thread". A Thread is very similar to a 'C'
69 procedure but has some very fundamental differences.
70 \code
71 unsigned int procedure (void) {
72   ...
73         return(ch);                     
74 }
75  
76 void thread (void) {
77   while(1) {
78     ...
79         }
80 }       
81  
82 __NO_RETURN void Thread1(void*argument) {
83   while(1) {
84     ...
85   }
86 }
87 \endcode
88 While we always return from our 'C' function, once started an RTOS thread must contain a loop so that it never terminates
89 and thus runs forever. You can think of a thread as a mini self-contained program that runs within the RTOS. With the Arm
90 Compiler, it is possible to optimize a thread by using a \c __NO_RETURN macro. This attribute reduces the cost of calling a
91 function that never returns.
92
93 An RTOS program is made up of a number of threads, which are controlled by the RTOS scheduler. This scheduler uses the
94 SysTick timer to generate a periodic interrupt as a time base. The scheduler will allot a certain amount of execution time
95 to each thread. So \c thread1 will run for 5 ms then be de-scheduled to allow \c thread2 to run for a similar period;
96 \c thread2 will give way to \c thread3 and finally control passes back to \c thread1. By allocating these slices of runtime
97 to each thread in a round-robin fashion, we get the appearance of all three threads running in parallel to each other. 
98
99 Conceptually we can think of each thread as performing a specific functional unit of our program with all threads running
100 simultaneously. This leads us to a more object-orientated design, where each functional block can be coded and tested in
101 isolation and then integrated into a fully running program. This not only imposes a structure on the design of our final
102 application but also aids debugging, as a particular bug can be easily isolated to a specific thread. It also aids code
103 reuse in later projects. When a thread is created, it is also allocated its own thread ID. This is a variable which acts as
104 a handle for each thread and is used when we want to manage the activity of the thread.
105 \code
106 osThreadId_t id1, id2, id3;
107 \endcode
108 In order to make the thread-switching process happen, we have the code overhead of the RTOS and we have to dedicate a CPU
109 hardware timer to provide the RTOS time reference. In addition, each time we switch running threads, we have to save the
110 state of all the thread variables to a thread stack. Also, all the runtime information about a thread is stored in a thread
111 control block, which is managed by the RTOS kernel. Thus the “context switch time”, that is, the time to save the current
112 thread state and load up and start the next thread, is a crucial figure and will depend on both the RTOS kernel and the
113 design of the underlying hardware.
114
115 The Thread Control Block contains information about the status of a thread. Part of this information is its run state. In a
116 given system, only one thread can be running and all the others will be suspended but ready to run. The RTOS has various
117 methods of inter-thread communication (signals, semaphores, messages). Here, a thread may be suspended to wait to be
118 signaled by another thread or interrupt before it resumes its ready state, whereupon it can be placed into running state by
119 the RTOS scheduler.
120
121 | State   | Description |
122 |---------|-------------|
123 | Running | The currently running thread |
124 | Ready   | Threads ready to run |
125 | Wait    | Blocked threads waiting for an OS event |
126
127 At any given moment a single thread may be running. The remaining threads will be ready to run and will be scheduled by the
128 kernel. Threads may also be waiting pending an OS event. When this occurs they will return to the ready state and be
129 scheduled by the kernel.
130
131
132 \section rtos2_tutorial_start Starting the RTOS
133
134 To build a simple RTOS, program we declare each thread as a standard 'C' function and also declare a thread ID variable for
135 each function.
136 \code
137 void thread1 (void);    
138 void thread2 (void);
139  
140 osThreadId thrdID1, thrdID2;
141 \endcode
142 Once the processor leaves the reset vector, we will enter the \c main() function as normal. Once in \c main(), we must call
143 \ref osKernelInitialize() to setup the RTOS. It is not possible to call any RTOS function before the
144 \ref osKernelInitialize() function has successfully completed. Once \ref osKernelInitialize() has completed, we can create
145 further threads and other RTOS objects. This can be done by creating a launcher thread, in the example below this is called
146 \c app_main(). Inside the \c app_main() thread, we create all the RTOS threads and objects we need to start our application
147 running. As we will see later, it is also possible to dynamically create and destroy RTOS objects as the application is
148 running. Next, we can call \ref osKernelStart() to start the RTOS and the scheduler task switching. You can run any
149 initializing code you want before starting the RTOS to setup peripherals and initialize the hardware.
150 \code
151 void app_main(void *argument) {
152   T_led_ID1 = osThreadNew(led_Thread1, NULL, &ThreadAttr_LED1);
153   T_led_ID2 = osThreadNew(led_Thread2, NULL, &ThreadAttr_LED2);
154   osDelay(osWaitForever);
155   while (1)
156     ;
157 }
158  
159 void main(void) {
160   IODIR1 = 0x00FF0000;               // Do any C code you want
161   osKernelInitialize();              // Initialize the kernel
162   osThreadNew(app_main, NULL, NULL); // Create the app_main() launcher thread
163   osKernelStart();                   // Start the RTOS
164 }
165 \endcode
166 When threads are created they are also assigned a priority. If there are a number of threads ready to run and they all have
167 the same priority, they will be allotted run time in a round-robin fashion. However, if a thread with a higher priority
168 becomes ready to run, the RTOS scheduler will de-schedule the currently running thread and start the high priority thread
169 running. This is called pre-emptive priority-based scheduling. When assigning priorities, you have to be careful because the
170 high priority thread will continue to run until it enters a waiting state or until a thread of equal or higher priority is
171 ready to run.
172
173 \subsection rtos2_tutorial_ex1 Exercise 1 - A First CMSIS-RTOS2 Project
174
175 Open <a href="https://www2.keil.com/mdk5/packinstaller" target="_blank">Pack Installer</a>:
176 - Use the <b>Search</b> box on the <b>Boards</b> tab to look for the <b>CMSIS_RTOS_Tutorial (V2.1)</b> "board".
177 - On the <b>Examples</b> tab, copy <b>Ex 01 First Project</b> to your PC and start Keil MDK.
178 - In the project folder, you will find a file called "Instructions.pdf" that explains the setup and the steps you need to
179   take to successfully finish the exercise.
180
181
182 \section rtos2_tutorial_thread_create Creating Threads
183
184 Once the RTOS is running, there are a number of system calls that are used to manage and control the active threads. The
185 documentation lists \ref CMSIS_RTOS_ThreadMgmt "all thread management functions".
186
187 As we saw in the first example, the \c app_main() thread is used as a launcher thread to create the application threads.
188 This is done in two stages. First a thread structure is defined; this allows us to define the thread operating parameters.
189 \code
190 osThreadId thread1_id; // thread handle
191  
192 static const osThreadAttr_t threadAttr_thread1 = {
193         “Name_String ",            //Human readable Name for debugger
194     Attribute_bits Control_Block_Memory,
195     Control_Block_Size,
196     Stack_Memory,
197     Stack_Size,
198     Priority,
199     TrustZone_ID,
200     reserved};
201 \endcode
202 The thread structure requires us to define the name of the thread function, its thread priority, any special attribute bits,
203 its TrustZone_ID and its memory allocation. This is quite a lot of detail to go through but we will cover everything by the
204 end of this application note. Once the thread structure has been defined, the thread can be created using the
205 \ref osThreadNew() API call. Then the thread is created from within the application code, this is often the within the
206 \c app_main() thread but a thread can be created at any point within any thread.
207 \code
208 thread1_id = osThreadNew(name_Of_C_Function, argument,&threadAttr_thread1);
209 \endcode
210 This creates the thread and starts it running. It is also possible to pass a parameter to the thread when it starts.
211 \code
212 uint32_t startupParameter = 0x23;
213 thread1_id = osThreadNew(name_Of_C_Function, (uint32_t)startupParameter,&threadAttr_thread1);
214 \endcode
215
216
217 \subsection rtos2_tutorial_ex2 Exercise 2 - Creating and Managing Threads 
218
219 Open <a href="https://www2.keil.com/mdk5/packinstaller" target="_blank">Pack Installer</a>:
220 - Use the <b>Search</b> box on the <b>Boards</b> tab to look for the <b>CMSIS_RTOS_Tutorial (V2.1)</b> "board".
221 - On the <b>Examples</b> tab, copy <b>Ex 02 Threads</b> to your PC and start Keil MDK.
222 - In the project folder, you will find a file called "Instructions.pdf" that explains the setup and the steps you need to
223   take to successfully finish the exercise.
224
225
226 \section rtos2_tutorial_thread_mgmt Thread Management and Priority
227
228 When a thread is created it is assigned a priority level. The RTOS scheduler uses a thread’s priority to decide which thread
229 should be scheduled to run. If a number of threads are ready to run, the thread with the highest priority will be placed in
230 the run state. If a high priority thread becomes ready to run it will preempt a running thread of lower priority.
231 Importantly, a high priority thread running on the CPU will not stop running unless it blocks on an RTOS API call or is
232 preempted by a higher priority thread. A thread's priority is defined in the thread structure and the following priority
233 definitions are available. The default priority is \ref osPriorityNormal. The \ref osPriority_t value specifies the priority
234 for a thread.
235
236 Once the threads are running, there are a small number of RTOS system calls which are used to manage the running threads. It
237 is also then possible to elevate or lower a thread’s priority either from another function or from within its own code.
238 \code
239 osStatus   osThreadSetPriority(threadID, priority);
240 osPriority osThreadGetPriority(threadID);
241 \endcode
242 As well as creating threads, it is also possible for a thread to delete another active thread from the RTOS. Again, we use
243 the thread ID rather than the function name of the thread.
244 \code
245 osStatus = osThreadTerminate (threadID1);
246 \endcode                
247 If a thread wants to terminate itself then there is a dedicated exit function.
248 \code
249 osThreadExit (void)
250 \endcode
251 Finally, there is a special case of thread switching where the running thread passes control to the next ready thread of the
252 same priority. This is used to implement a third form of scheduling called co-operative thread switching.
253 \code
254 osStatus osThreadYield();               //switch to next ready to run thread at the same priority
255 \endcode
256
257
258 \section rtos2_tutorial_ex2_mem_mgmt Memory Management
259
260 When each thread is created, it is assigned its own stack for storing data during the context switch. This should not be
261 confused with the native Cortex-M processor stack; it is really a block of memory that is allocated to the thread. A
262 default stack size is defined in the RTOS configuration file (we will see this later) and this amount of memory will be
263 allocated to each thread unless we override it to allocate a custom size. The default stack size will be assigned to a
264 thread if the stack size value in the thread definition structure is set to zero. If necessary a thread can be given
265 additional memory resources by defining a bigger stack size in the thread structure. Keil RTX5 supports several memory
266 models to assign this thread memory. The default model is a global memory pool. In this model each RTOS object that is
267 created (threads, message queues, semaphores etc.) are allocated memory from a single block of memory.
268  
269 If an object is destroyed the memory it has been assigned is returned to the memory pool. This has the advantage of memory
270 reuse but also introduces the possible problem of memory fragmentation.
271
272 The size of the global memory pool is defined in the configuration file:
273 \code
274 #define OS_DYNAMIC_MEM_SIZE         4096
275 \endcode        
276 And the default stack size for each thread is defined in the threads section:
277 \code
278 #define OS_STACK_SIZE               256
279 \endcode 
280 It is also possible to define object specific memory pools for each different type of RTOS object. In this model you define
281 the maximum number of a specific object type and its memory requirements. The RTOS then calculates and reserves the required
282 memory usage.
283  
284 The object specific model is again defined in the RTOS configuration file by enabling the "object specific memory" option
285 provided in each section of the configuration file:
286 \code
287 #define OS_SEMAPHORE_OBJ_MEM        1
288 #define OS_SEMAPHORE_NUM            1
289 \endcode
290 In the case of simple object which requires a fixed memory allocation we just need to define the maximum number of a given
291 object type. In the case of more complex objects such as threads we will need to define the required memory usage:
292 \code
293 #define OS_THREAD_OBJ_MEM           1
294 #define OS_THREAD_NUM               1
295 #define OS_THREAD_DEF_STACK_NUM     0
296 #define OS_THREAD_USER_STACK_SIZE   1024
297 \endcode 
298 To use the object specific memory allocation model with threads we must provide details of the overall thread memory usage.
299 Finally it is possible to statically allocate the thread stack memory. This is important for safety related systems where
300 memory usage has to be rigorously defined.
301
302
303 \subsection rtos2_tutorial_ex3 Exercise 3 - Memory Model
304
305 Open <a href="https://www2.keil.com/mdk5/packinstaller" target="_blank">Pack Installer</a>:
306 - Use the <b>Search</b> box on the <b>Boards</b> tab to look for the <b>CMSIS_RTOS_Tutorial (V2.1)</b> "board".
307 - On the <b>Examples</b> tab, copy <b>Ex 03 Memory Model</b> to your PC and start Keil MDK.
308 - In the project folder, you will find a file called "Instructions.pdf" that explains the setup and the steps you need to
309   take to successfully finish the exercise.
310
311
312
313 \section rtos2_tutorial_multi_inst Multiple Instances
314
315 One of the interesting possibilities of an RTOS is that you can create multiple running instances of the same base thread
316 code. For example, you could write a thread to control a UART and then create two running instances of the same thread code.
317 Here, each instance of the UART code could manage a different UART. Then we can create two instances of the thread assigned
318 to different thread handles. A parameter is also passed to allow each instance to identify which UART it is responsible for.
319 \code
320 #define UART1 (void *) 1UL
321 #define UART2 (void *) 2UL
322  
323 ThreadID_1_0 = osThreadNew (thread1, UART1, &ThreadAttr_Task1);
324 ThreadID_1_1 = osThreadNew (thread1, UART0, &ThreadAttr_Task1);
325 \endcode
326
327
328 \subsection rtos2_tutorial_multi_inst_ex4 Exercise 4 - Multiple Instances
329
330 Open <a href="https://www2.keil.com/mdk5/packinstaller" target="_blank">Pack Installer</a>:
331 - Use the <b>Search</b> box on the <b>Boards</b> tab to look for the <b>CMSIS_RTOS_Tutorial (V2.1)</b> "board".
332 - On the <b>Examples</b> tab, copy <b>Ex 04 Multiple Instances</b> to your PC and start Keil MDK.
333 - In the project folder, you will find a file called "Instructions.pdf" that explains the setup and the steps you need to
334   take to successfully finish the exercise.
335
336
337 \section rtos2_tutorial_thread_join Joinable Threads
338
339 A new feature in CMSIS-RTOS2 is the ability to create threads in a 'joinable' state. This allows a thead to be created and
340 executed as a standard thread. In addition, a second thread can join it by calling \ref osThreadJoin(). This will cause the
341 second thread to deschedule and remain in a waiting state until the thread which has been joined is terminated. This allows
342 a temporary joinable thread to be created, which would acquire a block of memory from the global memory pool, this thread
343 could perform some processing and then terminate, releasing the memory back to the memory pool. A joinable thread can be
344 created by setting the joinable attribute bit in the thread attributes structure as shown below:
345 \code
346 static const osThreadAttr_t ThreadAttr_worker = {
347         .attr_bits = osThreadJoinable
348 };
349 \endcode
350 Once the thread has been created, it will execute following the same rules as 'normal' threads. Any other thread can then
351 join it by using the OS call:
352 \code
353 osThreadJoin(<joinable_thread_handle>);
354 \endcode
355 Once \ref osThreadJoin() has been called, the thread will deschedule and enter a waiting state until the joinable thread has
356 terminated.
357
358
359 \subsection rtos2_tutorial_ex4 Exercise 5 - Joinable Threads
360
361 Open <a href="https://www2.keil.com/mdk5/packinstaller" target="_blank">Pack Installer</a>:
362 - Use the <b>Search</b> box on the <b>Boards</b> tab to look for the <b>CMSIS_RTOS_Tutorial (V2.1)</b> "board".
363 - On the <b>Examples</b> tab, copy <b>Ex 05 Join</b> to your PC and start Keil MDK.
364 - In the project folder, you will find a file called "Instructions.pdf" that explains the setup and the steps you need to
365   take to successfully finish the exercise.
366
367
368 \section rtos2_tutorial_time_mgmt Time Management
369
370 As well as running your application code as threads, the RTOS also provides some timing services which can be accessed
371 through RTOS system calls. 
372
373
374 \subsection rtos2_tutorial_time_delay Time Delay
375
376 The most basic of these timing services is a simple timer delay function. This is an easy way of providing timing delays
377 within your application. Although the RTOS kernel size is quoted as 5 KB, features such as delay loops and simple scheduling
378 loops are often part of a non-RTOS application and would consume code bytes anyway, so the overhead of the RTOS can be less
379 than it immediately appears.
380 \code
381 void osDelay (uint32_t ticks)
382 \endcode
383 This call will place the calling thread into the WAIT_DELAY state for the specified number of milliseconds. The scheduler
384 will pass execution to the next thread in the READY state. 
385  
386 When the timer expires, the thread will leave the WAIT_DELAY  state and move to the READY state. The thread will resume
387 running when the scheduler moves it to the RUNNING state. If the thread then continues executing without any further
388 blocking OS calls, it will be descheduled at the end of its time slice and be placed in the ready state, assuming another
389 thread of the same priority is ready to run.
390
391
392 \subsection rtos2_tutorial_abs_time_delay Absolute Time Delay
393
394 In addition to the \ref osDelay() function which gives a relative time delay starting from the instant it is called, there
395 is also a delay function which halts a thread until a specific point in time:
396 \code
397 osStatus osDelayUntil (uint32_t ticks)   
398 \endcode
399 The \ref osDelayUntil() function will halt a thread until a specific value of kernel timer ticks is reached. There are a
400 number of kernel functions that allow you to read both the current SysTick count and the kernel ticks count.
401
402 | Kernel timer functions |
403 |------------------------|
404 | uint64_t \ref osKernelGetTickCount(void)     |
405 | uint32_t \ref osKernelGetTickFreq(void)      |
406 | uint32_t \ref osKernelGetSysTimerCount(void) |
407 | uint32_t \ref osKernelGetSysTimerFreq(void)  |
408
409
410 \subsection rtos2_tutorial_ex6 Exercise 6 - Time Management
411
412 Open <a href="https://www2.keil.com/mdk5/packinstaller" target="_blank">Pack Installer</a>:
413 - Use the <b>Search</b> box on the <b>Boards</b> tab to look for the <b>CMSIS_RTOS_Tutorial (V2.1)</b> "board".
414 - On the <b>Examples</b> tab, copy <b>Ex 06 Time Management</b> to your PC and start Keil MDK.
415 - In the project folder, you will find a file called "Instructions.pdf" that explains the setup and the steps you need to
416   take to successfully finish the exercise.
417
418
419 \subsection rtos2_tutorial_virtual_timers Virtual Timers
420
421 The CMSIS-RTOS API can be used to define any number of virtual timers which act as count down timers. When they expire, they
422 will run a user call-back function to perform a specific action. Each timer can be configured as a one shot or repeat timer.
423 A virtual timer is created by first defining a timer structure:
424 \code
425 static const struct osTimerAttr_t timerAttr_timer0 = {
426   const char* name;      ///< name of the timer
427   uint32_t    attr_bits; ///< attribute bits
428   void*       cb_mem;    ///< memory for control block
429   uint32_t    cb_size;   ///< size of provided memory for control block
430 }
431 \endcode
432 This defines a name for the timer. The timer must then be instantiated by an RTOS
433 thread providing a pointer to the callback function and its parameter.:
434 \code
435 osTimerId_t timer0_handle;
436 timer0_handle = osTimerNew(&callback, osTimerPeriodic,(void *)<parameter>, &timerAttr_timer0);
437 \endcode
438 This creates the timer and defines it as a periodic timer or a single shot timer (\ref osTimerOnce()). The next parameter
439 passes an argument to the call back function when the timer expires:
440 \code
441 osTimerStart (timer0_handle,0x100);
442 \endcode
443 The timer can then be started at any point in a thread the timer start function invokes the timer by its handle and defines
444 a count period in kernel ticks.
445
446
447 \subsection rtos2_tutorial_ex7 Exercise 7 - Virtual Timer
448
449 Open <a href="https://www2.keil.com/mdk5/packinstaller" target="_blank">Pack Installer</a>:
450 - Use the <b>Search</b> box on the <b>Boards</b> tab to look for the <b>CMSIS_RTOS_Tutorial (V2.1)</b> "board".
451 - On the <b>Examples</b> tab, copy <b>Ex 07 Virtual Timers</b> to your PC and start Keil MDK.
452 - In the project folder, you will find a file called "Instructions.pdf" that explains the setup and the steps you need to
453   take to successfully finish the exercise.
454
455
456 \subsection rtos2_tutorial_idle_thread Idle Thread
457
458 The final timer service provided by the RTOS isn't really a timer, but this is probably the best place to discuss it. If
459 during our RTOS program we have no thread running and no thread ready to run (e.g. they are all waiting on delay functions),
460 then the RTOS will start to run the Idle Thread. This thread is automatically created when the RTOS starts and runs at the
461 lowest priority. The Idle Thread function is located in the RTX_Config.c file:
462 \code 
463 __WEAK __NO_RETURN void osRtxIdleThread (void *argument) {
464   (void)argument;
465  
466   for (;;) {}
467 }
468 \endcode
469 You can add any code to this thread, but it has to obey the same rules as user threads. The simplest use of the idle demon
470 is to place the microcontroller into a low-power mode when it is not doing anything.
471 \code 
472 __WEAK __NO_RETURN void osRtxIdleThread (void *argument) {
473   (void)argument;
474  
475   for (;;) {
476     __WFE();
477   }
478 }
479 \endcode
480 What happens next depends on the power mode selected in the microcontroller. At a minimum, the CPU will halt until an
481 interrupt is generated by the SysTick timer and execution of the scheduler will resume. If there is a thread ready to run,
482 then execution of the application code will resume. Otherwise, the idle demon will be reentered and the system will go back
483 to sleep.
484
485
486 \subsection rtos2_tutorial_ex8 Exercise 8 - Idle Thread
487
488 Open <a href="https://www2.keil.com/mdk5/packinstaller" target="_blank">Pack Installer</a>:
489 - Use the <b>Search</b> box on the <b>Boards</b> tab to look for the <b>CMSIS_RTOS_Tutorial (V2.1)</b> "board".
490 - On the <b>Examples</b> tab, copy <b>Ex 08 Idle Thread</b> to your PC and start Keil MDK.
491 - In the project folder, you will find a file called "Instructions.pdf" that explains the setup and the steps you need to
492   take to successfully finish the exercise.
493
494
495 \section rtos2_tutorial_interthread_com Inter-thread Communication
496
497 So far, we have seen how application code can be defined as independent threads and how we can access the timing services
498 provided by the RTOS. In a real application, we need to be able to communicate between threads in order to make an
499 application useful. To this end, a typical RTOS supports several different communication objects which can be used to link
500 the threads together to form a meaningful program. The CMSIS-RTOS2 API supports inter-thread communication with thread and
501 event flags, semaphores, mutexes, mailboxes and message queues. In the first section, the key concept was concurrency. In
502 this section, the key concept is synchronizing the activity of multiple threads.
503
504
505 \subsection rtos2_tutorial_thread_flags Thread Flags
506
507 Keil RTX5 supports up to thirty two thread flags for each thread. These thread flags are stored in the thread control block.
508 It is possible to halt the execution of a thread until a particular thread flag or group of thread flags are set by another
509 thread in the system.
510
511 The \ref osThreadFlagsWait() system calls will suspend execution of the thread and place it into the wait_evnt state.
512 Execution of the thread will not start until at least one the flags set in the \ref osThreadFlagsWait() API call have been
513 set. It is also possible to define a periodic timeout after which the waiting thread will move back to the ready state, so
514 that it can resume execution when selected by the scheduler. A value of \ref osWaitForever (0xFFFF) defines an infinite
515 timeout period.
516 \code
517 osEvent osThreadFlagsWait (int32_t flags,int32_t options,uint32_t timeout);
518 \endcode
519 The thread flag options are as follows:
520 | Options             | Description |
521 |---------------------|-------------|
522 | \ref osFlagsWaitAny | Wait for any flag to be set(default) |
523 | \ref osFlagsWaitAll | Wait for all flags to be set |
524 | \ref osFlagsNoClear | Do not clear flags that have been specified to wait for |
525
526 If a pattern of flags is specified, the thread will resume execution when any one of the specified flags is set (Logic OR).
527 If the \ref osFlagsWaitAll option is used, then all the flags in the pattern must be set (Logic AND). Any thread can set a
528 flag on any other thread and a thread may clear its own flags:
529 \code
530 int32_t osThredFlagsSet (osThreadId_t  thread_id, int32_t flags);
531 int32_t osThreadFlagsClear (int32_t signals);
532 \endcode
533
534
535 \subsubsection rtos2_tutorial_ex9 Exercise 9 - Thread Flags
536
537 Open <a href="https://www2.keil.com/mdk5/packinstaller" target="_blank">Pack Installer</a>:
538 - Use the <b>Search</b> box on the <b>Boards</b> tab to look for the <b>CMSIS_RTOS_Tutorial (V2.1)</b> "board".
539 - On the <b>Examples</b> tab, copy <b>Ex 09 Thread Flags</b> to your PC and start Keil MDK.
540 - In the project folder, you will find a file called "Instructions.pdf" that explains the setup and the steps you need to
541   take to successfully finish the exercise.
542
543
544 \subsection rtos2_tutorial_event_flags Event Flags
545
546 Event flags operate in a similar fashion to thread flags but must be created and then act as a global RTOS object that can
547 be used by all the running threads.
548  
549 First, we need to create a set of event flags, this is a similar process to creating a thread. We define an event flag
550 attribute structure. The attribute structure defines an ASCII name string, attribute bits, and memory detention. If we are
551 using the static memory model.
552 \code
553 osEventFlagsAttr_t {
554   const char *name;   ///< name of the event flags
555   uint32_t attr_bits; ///< attribute bits (none)
556   void *cb_mem;       ///< memory for control block
557   uint32_t cb_size;   ///< size of provided memory for control block
558 };
559 \endcode
560 Next we need a handle to control access the event flags:
561 \code
562 osEventFlagsId_t EventFlag_LED;
563 \endcode
564 Then we can create the event flag object:
565 \code
566 EventFlag_LED = osEventFlagsNew(&EventFlagAttr_LED);
567 \endcode
568 Refer to \ref CMSIS_RTOS_EventFlags for more information.
569
570
571 \subsubsection rtos2_tutorial_ex10 Exercise 10 - Event Flags
572
573 Open <a href="https://www2.keil.com/mdk5/packinstaller" target="_blank">Pack Installer</a>:
574 - Use the <b>Search</b> box on the <b>Boards</b> tab to look for the <b>CMSIS_RTOS_Tutorial (V2.1)</b> "board".
575 - On the <b>Examples</b> tab, copy <b>Ex 10 Event Flags</b> to your PC and start Keil MDK.
576 - In the project folder, you will find a file called "Instructions.pdf" that explains the setup and the steps you need to
577   take to successfully finish the exercise.
578
579
580 \subsection rtos2_tutorial_semaphores Semaphores
581
582 Like thread flags, semaphores are a method of synchronizing activity between two or more threads. Put simply, a semaphore is
583 a container that holds a number of tokens. As a thread executes, it will reach an RTOS call to acquire a semaphore token. If
584 the semaphore contains one or more tokens, the thread will continue executing and the number of tokens in the semaphore will
585 be decremented by one. If there are currently no tokens in the semaphore, the thread will be placed in a waiting state until
586 a token becomes available. At any point in its execution, a thread may add a token to the semaphore causing its token count
587 to increment by one.
588
589 The diagram above illustrates the use of a semaphore to synchronize two threads. First, the semaphore must be created and
590 initialized with an initial token count. In this case the semaphore is initialized with a single token. Both threads will
591 run and reach a point in their code where they will attempt to acquire a token from the semaphore. The first thread to reach
592 this point will acquire the token from the semaphore and continue execution. The second thread will also attempt to acquire
593 a token, but as the semaphore is empty it will halt execution and be placed into a waiting state until a semaphore token is
594 available. 
595
596 Meanwhile, the executing thread can release a token back to the semaphore. When this happens, the waiting thread will
597 acquire the token and leave the waiting state for the ready state. Once in the ready state the scheduler will place the
598 thread into the run state so that thread execution can continue. While semaphores have a simple set of OS calls they can be
599 one of the more difficult OS objects to fully understand. In this section, we will first look at how to add semaphores to an
600 RTOS program and then go on to look at the most useful semaphore applications.
601
602 To use a semaphore in the CMSIS-RTOS you must first declare a semaphore attributes:
603 \code
604 osSemaphoreAttr_t {
605   const char *name;   ///< name of the semaphore
606   uint32_t attr_bits; ///< attribute bits (none)
607   void *cb_mem;       ///< memory for control block
608   uint32_t cb_size;   ///< size of provided memory for control block
609 };
610 \endcode
611 Next declare the semaphore handle:
612 \code
613 osSemaphoreId_t sem1;
614 \endcode
615 Then within a thread the semaphore container can be initialised with a number of tokens:
616 \code
617 sem1 = osSemaphoreNew(maxTokenCount,initalTokencount,&osSemaphoreAttr_t);
618 \endcode
619 It is important to understand that semaphore tokens may also be created and destroyed as threads run. So for example you can
620 initialise a semaphore with zero tokens and then use one thread to create tokens into the semaphore while another thread
621 removes them. This allows you to design threads as producer and consumer threads.
622
623 Once the semaphore is initialized, tokens may be acquired and sent to the semaphore in a similar fashion to event flags. The
624 \ref osSemaphoreAcquire() call is used to block a thread until a semaphore token is available. A timeout period may also be
625 specified with 0xFFFF being an infinite wait.
626 \code
627 osStatus osSemaphoreAcquire(osSemaphoreId_t semaphore_id, uint32_t ticks);
628 \endcode
629 Once the thread has finished using the semaphore resource, it can send a token to the semaphore container:
630 \code
631 osStatus osSemaphoreRelease(osSemaphoreId_t semaphore_id);
632 \endcode
633 All semaphore functions are listed in the \ref CMSIS_RTOS_SemaphoreMgmt "reference".
634
635
636 \subsubsection rtos2_tutorial_sem_usage Using Semaphores
637
638 Although semaphores have a simple set of OS calls, they have a wide range of synchronizing applications. This makes them
639 perhaps the most challenging RTOS object to understand. In this section we, will look at the most common uses of semaphores.
640 These are taken from free book
641 <a href="https://greenteapress.com/wp/semaphores/" target="_blank">"The Little Book Of Semaphores" by Allen B. Downey</a>.
642
643
644 \subsubsection rtos2_tutorial_sem_sig Signalling
645
646 Synchronizing the execution of two threads is the simplest use of a semaphore:
647 \code
648 osSemaphoreId_t sem1;
649 static const osSemaphoreAttr_t semAttr_SEM1 = {
650     .name = "SEM1",
651 };
652  
653 void thread1(void) {
654   sem1 = osSemaphoreNew(5, 0, &semAttr_SEM1);
655   while (1) {
656     FuncA();
657     osSemaphoreRelease(sem1)
658   }
659 }
660  
661 void task2(void) {
662
663   while (1) {
664     osSemaphoreAcquire(sem1, osWaitForever) FuncB();
665   }
666 }
667 \endcode
668 In this case the semaphore is used to ensure that the code in \c FuncA() is executed before the code in \c FuncB().
669
670
671 \subsubsection rtos2_tutorial_ex11 Exercise 11 - Semaphore Signalling
672
673 Open <a href="https://www2.keil.com/mdk5/packinstaller" target="_blank">Pack Installer</a>:
674 - Use the <b>Search</b> box on the <b>Boards</b> tab to look for the <b>CMSIS_RTOS_Tutorial (V2.1)</b> "board".
675 - On the <b>Examples</b> tab, copy <b>Ex 11 Semaphore Signalling</b> to your PC and start Keil MDK.
676 - In the project folder, you will find a file called "Instructions.pdf" that explains the setup and the steps you need to
677   take to successfully finish the exercise.
678
679
680 \subsubsection rtos2_tutorial_sem_multi Multiplex
681
682 A multiplex is used to limit the number of threads that can access a critical section of code. For example, this could be a
683 routine that accesses memory resources and can only support a limited number of calls.
684 \code
685 osSemaphoreId_t multiplex;
686 static const osSemaphoreAttr_t semAttr_Multiplex = {
687     .name = "SEM1",
688 };
689  
690 void thread1(void) {
691   multiplex = osSemaphoreCreate(5, 5, &semAttr_Multiplex);
692   while (1) {
693     osSemaphoreAcquire(multiplex, osWaitForever);
694     processBuffer();
695     osSemaphoreRelease(multiplex);
696   }
697 }
698 \endcode
699 In this example we initialise the multiplex semaphore with five tokens. Before a thread can call the \c processBuffer()
700 function, it must acquire a semaphore token. Once the function has completed, the token is sent back to the semaphore. If
701 more than five threads are attempting to call \c processBuffer(), the sixth must wait until a thread has finished with
702 \c processBuffer() and returns its token. Thus, the multiplex semaphore ensures that a maximum of five threads can call the
703 \c processBuffer() function "simultaneously".
704
705
706 \subsubsection rtos2_tutorial_ex12 Exercise 12 - Multiplex
707
708 Open <a href="https://www2.keil.com/mdk5/packinstaller" target="_blank">Pack Installer</a>:
709 - Use the <b>Search</b> box on the <b>Boards</b> tab to look for the <b>CMSIS_RTOS_Tutorial (V2.1)</b> "board".
710 - On the <b>Examples</b> tab, copy <b>Ex 12 Multiplex</b> to your PC and start Keil MDK.
711 - In the project folder, you will find a file called "Instructions.pdf" that explains the setup and the steps you need to
712   take to successfully finish the exercise.
713
714
715 \subsubsection rtos2_tutorial_sem_rend Rendezvous
716
717 A more generalised form of semaphore signalling is a rendezvous. A rendezvous ensures that two threads reach a certain point
718 of execution. Neither may continue until both have reached the rendezvous point.
719 \code
720 osSemaphoreId_t arrived1, arrived2;
721 static const osSemaphoreAttr_t semAttr_Arrived1 = {
722     .name = "Arr1",
723 };
724  
725 static const osSemaphoreAttr_t semAttr_Arrived2 = {
726     .name = "Arr2",
727 };
728  
729 void thread1(void) {
730   arrived1 = osSemaphoreNew(2, 0);
731   arrived1 = osSemaphoreNew(2, 0);
732   while (1) {
733     FuncA1();
734     osSemaphoreRelease(arrived1);
735     osSemaphoreAcquire(arrived2, osWaitForever);
736     FuncA2();
737   }
738 }
739  
740 void thread2(void) {
741   while (1) {
742     FuncB1();
743     os_sem_Release(arrived2);
744     os_sem_Acquire(arrived1, osWaitForever);
745     FuncB2();
746   }
747 }
748 \endcode
749 In the above case, the two semaphores will ensure that both threads will rendezvous and then proceed to execute \c FuncA2()
750 and \c FuncB2().
751
752 \subsubsection rtos2_tutorial_sem_rend_ex13 Exercise 13 - Rendezvous
753
754 Open <a href="https://www2.keil.com/mdk5/packinstaller" target="_blank">Pack Installer</a>:
755 - Use the <b>Search</b> box on the <b>Boards</b> tab to look for the <b>CMSIS_RTOS_Tutorial (V2.1)</b> "board".
756 - On the <b>Examples</b> tab, copy <b>Ex 13 Rendezvous</b> to your PC and start Keil MDK.
757 - In the project folder, you will find a file called "Instructions.pdf" that explains the setup and the steps you need to
758   take to successfully finish the exercise.
759
760
761 \subsubsection rtos2_tutorial_sem_barr_turn Barrier Turnstile
762
763 Although a rendezvous is very useful for synchronising the execution of code, it only works for two functions. A barrier is
764 a more generalised form of rendezvous which works to synchronise multiple threads.
765 \code
766 osSemaphoreId_t count, barrier;
767 static const osSemaphoreAttr_t semAttr_Counter = {
768     .name = "Counter",
769 };
770  
771 static const osSemaphoreAttr_t semAttr_Barier = {
772     .name = "Barrier",
773 };
774  
775 unsigned int count;
776  
777 void thread1(void) {
778   Turnstile_In = osSemaphoreNew(5, 0, &semAttr_SEM_In);
779   Turnstile_Out = osSemaphoreNew(5, 1, &semAttr_SEM_Out);
780   Mutex = osSemaphoreNew(1, 1, &semAttr_Mutex);
781   while (1) {
782     osSemaphoreAcquire(Mutex, osWaitForever); // Allow one task at a time to
783                                               // access the first turnstile
784     count = count + 1; // Increment count
785     if (count == 5) {
786       osSemaphoreAcquire(Turnstile_Out,
787                          osWaitForever); // Lock the second turnstile
788       osSemaphoreRelease(Turnstile_In);  // Unlock the first turnstile
789     }
790     osSemaphoreRelease(Mutex); // Allow other tasks to access the turnstile
791     osSemaphoreAcquire(Turnstile_In, osWaitForever); // Turnstile Gate
792     osSemaphoreRelease(Turnstile_In);
793     critical_Function();
794   }
795 }
796 \endcode
797 In this code, we use a global variable to count the number of threads which have arrived at the barrier. As each function
798 arrives at the barrier it will wait until it can acquire a token from the counter semaphore. Once acquired, the count
799 variable will be incremented by one. Once we have incremented the count variable, a token is sent to the counter semaphore
800 so that other waiting threads can proceed. Next, the barrier code reads the count variable. If this is equal to the number
801 of threads which are waiting to arrive at the barrier, we send a token to the barrier semaphore. 
802
803 In the example above we are synchronising five threads. The first four threads will increment the count variable and then
804 wait at the barrier semaphore. The fifth and last thread to arrive will increment the count variable and send a token to the
805 barrier semaphore. This will allow it to immediately acquire a barrier semaphore token and continue execution. After passing
806 through the barrier, it immediately sends another token to the barrier semaphore. This allows one of the other waiting
807 threads to resume execution. This thread places another token in the barrier semaphore which triggers another waiting thread
808 and so on. This final section of the barrier code is called a turnstile because it allows one thread at a time to pass the
809 barrier. In our model of concurrent execution this means that each thread waits at the barrier until the last arrives then
810 the all resume simultaneously. In the following exercise we create five instances of one thread containing barrier code.
811 However, the barrier could be used to synchronise five unique threads.
812
813
814 \subsubsection rtos2_tutorial_ex14 Exercise 14 - Semaphore Barrier
815
816 Open <a href="https://www2.keil.com/mdk5/packinstaller" target="_blank">Pack Installer</a>:
817 - Use the <b>Search</b> box on the <b>Boards</b> tab to look for the <b>CMSIS_RTOS_Tutorial (V2.1)</b> "board".
818 - On the <b>Examples</b> tab, copy <b>Ex 14 Barrier</b> to your PC and start Keil MDK.
819 - In the project folder, you will find a file called "Instructions.pdf" that explains the setup and the steps you need to
820   take to successfully finish the exercise.
821
822
823 \subsubsection rtos2_tutorial_sem_caveats Semaphore Caveats
824
825 Semaphores are an extremely useful feature of any RTOS. However semaphores can be misused. You must always remember that the
826 number of tokens in a semaphore is not fixed. During the runtime of a program semaphore tokens may be created and destroyed.
827 Sometimes this is useful, but if your code depends on having a fixed number of tokens available to a semaphore you must be
828 very careful to always return tokens back to it. You should also rule out the possibility of accidently creating additional
829 new tokens.
830
831
832 \subsection rtos2_tutorial_mutex Mutex
833
834 Mutex stands for “Mutual Exclusion”. In reality, a mutex is a specialized version of semaphore. Like a semaphore, a mutex is
835 a container for tokens. The difference is that a mutex can only contain one token which cannot be created or destroyed. The
836 principle use of a mutex is to control access to a chip resource such as a peripheral. For this reason a mutex token is
837 binary and bounded. Apart from this it really works in the same way as a semaphore. First of all we must declare the mutex
838 container and initialize the mutex:
839 \code
840 osMutexId_t uart_mutex;
841  
842 osMutexAttr_t {
843   const char *name;   ///< name of the mutex
844   uint32_t attr_bits; ///< attribute bits
845   void *cb_mem;       ///< memory for control block
846   uint32_t cb_size;   ///< size of provided memory for control block
847 };
848 \endcode
849 When a mutex is created its functionality can be modified by setting the following attribute bits:
850 | Bitmask                 | Description |
851 |-------------------------|-------------|
852 | \ref osMutexRecursive   | The same thread can consume a mutex multiple times without locking itself.        |
853 | \ref osMutexPrioInherit | While a thread owns the mutex it cannot be preempted by a higher priority thread. |
854 | \ref osMutexRobust      | Notify threads that acquire a mutex that the previous owner was terminated.       |
855
856 Once declared the mutex must be created in a thread.
857 \code
858 uart_mutex = osMutexNew(&MutexAttr);
859 \endcode
860 Then any thread needing to access the peripheral must first acquire the mutex token:
861 \code
862 osMutexAcquire(osMutexId_t mutex_id,uint32_t ticks);
863 \endcode
864 Finally, when we are finished with the peripheral the mutex must be released:
865 \code
866 osMutexRelease(osMutexId_t mutex_id);
867 \endcode
868 Mutex use is much more rigid than semaphore use, but is a much safer mechanism when controlling absolute access to
869 underlying chip registers.
870
871
872 \subsubsection rtos2_tutorial_ex15 Exercise 15 - Mutex
873
874 Open <a href="https://www2.keil.com/mdk5/packinstaller" target="_blank">Pack Installer</a>:
875 - Use the <b>Search</b> box on the <b>Boards</b> tab to look for the <b>CMSIS_RTOS_Tutorial (V2.1)</b> "board".
876 - On the <b>Examples</b> tab, copy <b>Ex 15 Mutex</b> to your PC and start Keil MDK.
877 - In the project folder, you will find a file called "Instructions.pdf" that explains the setup and the steps you need to
878   take to successfully finish the exercise.
879
880
881 \subsubsection rtos2_tutorial_mutex_caveats Mutex Caveats
882
883 Clearly, you must take care to return the mutex token when you are finished with the chip resource, or you will have
884 effectively prevented any other thread from accessing it. You must also be extremely careful about using the
885 \ref osThreadTerminate() call on functions which control a mutex token. Keil RTX5 is designed to be a small footprint RTOS
886 so that it can run on even the very small Cortex-M microcontrollers. Consequently, there is no thread deletion safety. This
887 means that if you delete a thread which is controlling a mutex token, you will destroy the mutex token and prevent any
888 further access to the guarded peripheral.
889
890
891 \subsection rtos2_tutorial_data_exchange Data Exchange
892
893 So far, all of the inter-thread communication methods have only been used to trigger execution of threads; they do not
894 upport the exchange of program data between threads. Clearly, in a real program we will need to move data between threads.
895 This could be done by reading and writing to globally declared variables. In anything but a very simple program, trying to
896 guarantee data integrity would be extremely difficult and prone to unforeseen errors. The exchange of data between threads
897 needs a more formal asynchronous method of communication. 
898
899 CMSIS-RTOS provides two methods of data transfer between threads. The first method is a message queue which creates a
900 buffered data 'pipe' between two threads. The message queue is designed to transfer integer values.
901
902 The second form of data transfer is a mail queue. This is very similar to a message queue except that it transfers blocks of
903 data rather than a single integer.
904
905 Message and mail queues both provide a method for transferring data between threads. This allows you to view your design as
906 a collection of objects (threads) interconnected by data flows. The data flow is implemented by message and mail queues.
907 This provides both a buffered transfer of data and a well defined communication interface between threads. Starting with a
908 system level design based on threads connected by mail and message queues allows you to code different subsystems of your
909 project, especially useful if you are working in a team. Also as each thread has well defined inputs and outputs it is easy
910 to isolate for testing and code reuse.
911
912
913 \subsubsection rtos2_tutorial_msg_queue Message Queue
914
915 To setup a message queue we first need to allocate the memory resources:
916 \code
917 osMessageQId_t Q_LED;
918  
919 osMessageQueueAttr_t {
920   const char *name;   ///< name of the message queue
921   uint32_t attr_bits; ///< attribute bits
922   void *cb_mem;       ///< memory for control block
923   uint32_t cb_size;   ///< size of provided memory for control block
924   void *mq_mem;       ///< memory for data storage
925   uint32_t mq_size;   ///< size of provided memory for data storage
926 };
927 \endcode
928 Once the message queue handle and attributes have been declared we can create the message queue in a thread:
929 \code
930 Q_LED = osMessageNew(DepthOfMesageQueue,WidthOfMessageQueue,&osMessageQueueAttr);
931 \endcode
932 Once the message queue has been created we can put data into the queue from one thread:
933 \code
934 osMessageQueuePut(Q_LED,&dataIn,messagePrioriy,osWaitForever);
935 \endcode
936 and then read if from the queue in another:
937 \code
938 result = osMessageQueueGet(Q_LED,&dataOut,messagePriority,osWaitForever);
939 \endcode
940
941
942 \subsubsection rtos2_tutorial_ex16 Exercise 16 - Message Queue
943
944 Open <a href="https://www2.keil.com/mdk5/packinstaller" target="_blank">Pack Installer</a>:
945 - Use the <b>Search</b> box on the <b>Boards</b> tab to look for the <b>CMSIS_RTOS_Tutorial (V2.1)</b> "board".
946 - On the <b>Examples</b> tab, copy <b>Ex 16 Message Queue</b> to your PC and start Keil MDK.
947 - In the project folder, you will find a file called "Instructions.pdf" that explains the setup and the steps you need to
948   take to successfully finish the exercise.
949
950
951 \subsubsection rtos2_tutorial_ext_msg_queue Extended Message Queue
952
953 In the last example we defined a word wide message queue. If you need to send a larger amount of data it is also possible to
954 define a message queue where each slot can hold more complex data. First, we can define a structure to hold our message
955 data:
956 \code
957 typedef struct {
958   uint32_t duration;
959   uint32_t ledNumber;
960   uint8_t priority;
961 } message_t;
962 \endcode
963 Then we can define a message queue which is formatted to receive this type of message:
964 \code
965 Q_LED = osMessageQueueNew(16,sizeof(message_t),&queueAttr_Q_LED );      
966 \endcode
967
968
969 \subsubsection rtos2_tutorial_ex17 Exercise 17 - Message Queue
970
971 Open <a href="https://www2.keil.com/mdk5/packinstaller" target="_blank">Pack Installer</a>:
972 - Use the <b>Search</b> box on the <b>Boards</b> tab to look for the <b>CMSIS_RTOS_Tutorial (V2.1)</b> "board".
973 - On the <b>Examples</b> tab, copy <b>Ex 17 Extended Message Queue</b> to your PC and start Keil MDK.
974 - In the project folder, you will find a file called "Instructions.pdf" that explains the setup and the steps you need to
975   take to successfully finish the exercise.
976
977
978 \subsubsection rtos2_tutorial_mem_pool Memory Pool
979
980 We can design a message queue to support the transfer of large amounts of data. However, this method has an overhead in that
981 we are "moving" the data in the queue. In this section, we will look at designing a more efficient "zero copy" mailbox where
982 the data remains static. CMSIS-RTOS2 supports the dynamic allocation of memory in the form of a fixed block memory pool.
983 First, we can declare the memory pool attributes:
984 \code
985 osMemoryPoolAttr_t {
986   const char *name;   ///< name of the memory pool
987   uint32_t attr_bits; ///< attribute bits
988   void *cb_mem;       ///< memory for control block
989   uint32_t cb_size;   ///< size of provided memory for control block
990   void *mp_mem;       ///< memory for data storage
991   uint32_t mp_size;   ///< size of provided memory for data storage
992 } osMemoryPoolAttr_t;
993 \endcode
994 And a handle for the memory pool:
995 \code
996 osMemoryPoolId_t mpool;
997 \endcode
998 For the memory pool itself, we need to declare a structure which contains the memory elements we require in each memory pool
999 lot:
1000 \code
1001 typedef struct {
1002   uint8_t LED0;
1003   uint8_t LED1;
1004   uint8_t LED2;
1005   uint8_t LED3;
1006 } memory_block_t;
1007 \endcode
1008 Then we can create a memory pool in our application code:
1009 \code
1010 mpool = osMemoryPoolNew(16, sizeof(message_t),&memorypoolAttr_mpool);
1011 \endcode
1012 Now we can allocate a memory pool slot within a thread:
1013 \code
1014 memory_block_t *led_data;
1015 *led_data = (memory_block_t *) osMemoryPoolAlloc(mPool,osWaitForever);
1016 \endcode
1017 and then populate it with data:
1018 \code
1019         led_data->LED0 = 0;
1020         led_data->LED1 = 1;
1021         led_data->LED2 = 2;
1022         led_data->LED3 = 3;
1023 \endcode
1024 It is then possible to place the pointer to the memory block in a message queue:
1025 \code
1026 osMessagePut(Q_LED,(uint32_t)led_data,osWaitForever);
1027 \endcode
1028 The data can now be accessed by another task:
1029 \code
1030 osEvent event;
1031 memory_block_t *received;
1032 event = osMessageGet(Q_LED, osWatiForever);
1033 *received = (memory_block *)event.value.p;
1034 led_on(received->LED0);
1035 \endcode
1036 Once the data in the memory block has been used, the block must be released back to the memory pool for reuse.
1037 \code
1038 osPoolFree(led_pool,received);
1039 \endcode
1040 To create a zero copy mail box system, we can combine a memory pool to store the data with a message queue which is used to
1041 transfer a pointer o the allocated memory pool slot. This way the message data stays static and we pass a pointer between
1042 threads.
1043
1044
1045 \subsubsection rtos2_tutorial_ex18 Exercise 18 - Zero Copy Mailbox
1046
1047 Open <a href="https://www2.keil.com/mdk5/packinstaller" target="_blank">Pack Installer</a>:
1048 - Use the <b>Search</b> box on the <b>Boards</b> tab to look for the <b>CMSIS_RTOS_Tutorial (V2.1)</b> "board".
1049 - On the <b>Examples</b> tab, copy <b>Ex 18 Zero Copy Mailbox</b> to your PC and start Keil MDK.
1050 - In the project folder, you will find a file called "Instructions.pdf" that explains the setup and the steps you need to
1051   take to successfully finish the exercise.
1052
1053
1054 \section rtos2_tutorial_config Configuration
1055
1056 So far we have looked at the CMSIS-RTOS2 API. This includes thread management functions, time management and inter-thread
1057 communication. Now that we have a clear idea of exactly what the RTOS kernel is capable of, we can take a more detailed look
1058 at the configuration file.
1059
1060 RTX_Config.h is the central configuration file for all of the Cortex-M based microcontrollers.  Like the other configuration
1061 files, it is a template file which presents all the necessary configurations as a set of menu options (when viewed in
1062 Configuration Wizard view).
1063
1064
1065 \subsection rtos2_tutorial_config_sys System Configuration
1066
1067 Before we discuss the settings in the system configuration section, it is worth mentioning what is missing. In earlier
1068 versions of CMSIS-RTOS, it was necessary to define the CPU frequency as part of the RTOS configuration. In CMSIS-RTOS2, the
1069 CPU frequency is now taken from the "SystemCoreClock" variable which is set as part of the CMSIS-Core system startup code.
1070 If you are working with a new microcontroller you will need to check that this value is being set correctly.
1071
1072 As we have seen earlier, we can set the amount of memory allocated to the "Global Dynamic Memory Pool". Next, we can define
1073 the tick frequency in Hertz. This defines the SysTick interrupt rate and is set to 1 ms by default. Generally, I would leave
1074 this frequency at its default setting. However, processor clock speeds are getting ever faster. If you are using a high
1075 performance device you may consider using a faster tick rate.
1076
1077 "Round Robin Thread" switching is also enabled by default in this section. Again, I would recommend leaving these settings
1078 in their default state unless you have a strong requirement to change them. The system configuration settings also allow us
1079 to control the range of messages sent to the event recorder as the RTOS runs.
1080
1081 Finally, if we are setting thread flags from an interrupt they are held in a queue until they are processed. Depending on
1082 your application you may need to increase the size of this queue.
1083
1084
1085 \subsection rtos2_tutorial_config_thread Thread Configuration
1086
1087 In the Thread Configuration section, we define the basic resources which will be required by the CMSIS-RTOS2 threads. For
1088 each thread we allocate a "default thread stack space" (by default, this is 200 bytes). As you create threads, this memory
1089 will be allocated from the Global Dynamic Mmemory Pool. However, if we enable Object specific memory allocation the RTOS
1090 will define a memory region which is dedicated to thread usage only. If you switch to object specific memory allocation, it
1091 is necessary to provide details about the number and size of threads memory so the RTOS can calculate the maximum memory
1092 requirement.
1093
1094 For object specific memory allocation, we must define the maximum number of user threads (don’t count the idle
1095 or timer threads) which will be running. We must also define the number of threads which have a default stack size and also
1096 the total amount of memory required by threads with custom tack sizes. Once we have defined the memory used by user threads,
1097 we can allocate memory to the idle thread. During development, CMSIS-RTOS can trap stack overflows. When this option is
1098 enabled, an overflow of a thread stack space will cause the RTOS kernel to call the \ref osRtxErrorNotify() function which
1099 is located in the RTX_Config.c file. This function gets an error code and then sits in an infinite loop. The stack checking
1100 option is intended for use during debugging and should be disabled on the final application to minimize the kernel overhead.
1101 However, it is possible to modify the \ref osRtxErrorNotify() function if enhanced error protection is required in the final
1102 release.
1103 \code
1104 // OS Error Callback function
1105 __WEAK uint32_t osRtxErrorNotify (uint32_t code, void *object_id) {
1106   (void)object_id;
1107
1108   switch (code) {
1109     case osRtxErrorStackUnderflow:
1110       // Stack overflow detected for thread (thread_id=object_id)
1111       break;
1112     case osRtxErrorISRQueueOverflow:
1113       // ISR Queue overflow detected when inserting object (object_id)
1114       break;
1115     case osRtxErrorTimerQueueOverflow:
1116       // User Timer Callback Queue overflow detected for timer (timer_id=object_id)
1117       break;
1118     case osRtxErrorClibSpace:
1119       // Standard C/C++ library libspace not available: increase OS_THREAD_LIBSPACE_NUM
1120       break;
1121     case osRtxErrorClibMutex:
1122       // Standard C/C++ library mutex initialization failed
1123       break;
1124     default:
1125       // Reserved
1126       break;
1127   }
1128   for (;;) {}
1129 //return 0U;
1130 }
1131 \endcode
1132 It is also possible to monitor the maximum stack memory usage during run time. If you check the "Stack Usage Watermark"
1133 option, a pattern (0xCC) is written into each stack space. During runtime, this watermark is used to calculate the maximum
1134 memory usage. In Arm Keil MDK, this figure is reported in the threads section of the View - Watch Window - RTX RTOS window.
1135  
1136 This section also allows us to select whether the threads are running in privileged or unprivileged mode. The last option
1137 allows us to define the processor operating mode for the user threads. If you want an easy life, leave this set to
1138 "privileged mode" and you will have full access to all the processor features. However, if you are writing a safety critical
1139 or secure application then "unprivileged mode" can be used to prevent thread access to critical processor registers limiting
1140 run time errors or attempts at intrusion.
1141
1142
1143 \subsection rtos2_tutorial_config_sys_timer System Timer Configuration
1144
1145 The default timer for use with CMSIS-RTOS is the Cortex-M SysTick timer which is present on nearly all Cortex-M processors.
1146 The input to the SysTick timer will generally be the CPU clock. It is possible to use a different timer by overloading the
1147 kernel timer functions as outlined explained in the \ref CMSIS_RTOS_TickAPI documentation.
1148
1149
1150 \section rtos2_tutorial_conclusion Conclusion
1151
1152 In this tutorial, we have worked our way through the CMSIS-RTOS2 API and introduced some of the key concepts associated with
1153 using an RTOS. The only real way to learn how to develop with an RTOS is to actually use one in a real project. 
1154 */