embOS Real-Time Operating System CPU-independent User & Reference Guide Document: UM01001 Software version 4.06b Revision: 0 Date: March 24, 2015 A product of SEGGER Microcontroller GmbH & Co. KG www.segger.com 2 CHAPTER Disclaimer Specifications written in this document are believed to be accurate, but are not guaranteed to be entirely free of error. The information in this manual is subject to change for functional or performance improvements without notice. Please make sure your manual is the latest edition. While the information herein is assumed to be accurate, SEGGER Microcontroller GmbH & Co. KG (SEGGER) assumes no responsibility for any errors or omissions. SEGGER makes and you receive no warranties or conditions, express, implied, statutory or in any communication with you. SEGGER specifically disclaims any implied warranty of merchantability or fitness for a particular purpose. Copyright notice You may not extract portions of this manual or modify the PDF file in any way without the prior written permission of SEGGER. The software described in this document is furnished under a license and may only be used or copied in accordance with the terms of such a license. (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG, Hilden / Germany Trademarks Names mentioned in this manual may be trademarks of their respective companies. Brand and product names are trademarks or registered trademarks of their respective holders. Contact address SEGGER Microcontroller GmbH & Co. KG In den Weiden 11 D-40721 Hilden Germany Tel.+49 2103-2878-0 Fax.+49 2103-2878-28 E-mail: support@segger.com Internet: http://www.segger.com UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 3 Manual versions This manual describes the current software version. If any error occurs, inform us and we will try to assist you as soon as possible. Contact us for further information on topics or routines not yet specified. Print date: March 24, 2015 Software Revision Date By Description 4.06b 0 150324 MC Minor spelling and wording corrections. 4.06a 0 150318 MC Update to latest software version. Minor spelling and wording corrections. 4.06 0 150312 TS Update to latest software version. 4.04a 0 141201 TS Update to latest software version. 4.04 0 141112 TS Chapter "Tasks" * Task priority description updated. Chapter "Debugging" * New error number 4.02a 0 140918 TS Update to latest software version. Minor corrections. TS New functions in chapter Time Measurement added: OS_Config_SysTimer() OS_GetTime_us() OS_GetTime_us64() TS New function added in chapter SystemTick: OS_StopTicklessMode() New function added in chapter Profiling: OS_STAT_Start() OS_STAT_Stop() OS_STAT_GetTaskExecTime() Tickless suppport added. 4.02 0 140818 4.00a 0 140723 4.00 0 140606 TS 3.90a 0 140410 AW Software-Update, OS_TerminateTask() modified / corrected. 3.90 1 140312 SC 140303 New functions to globally enable / diasble Interrupts: OS_INTERRUPT_MaskGlobal() OS_INTERRUPT_UnmaskGlobal() AW OS_INTERRUPT_PreserveGlobal() OS_INTERRUPT_RestoreGlobal() OS_INTERRUPT_PreserveAndMaskGlobal() 3.90 0 Added cross-references to the API-lists. 3.88h 0 131220 New functions added, chapter "Sytem tick": OS_GetNumIdleTicks(); AW OS_AdjustTime(); Chapter "System variable" Description of internal variable OS_Global.TimeDex corrected 3.88g 1 131104 TS Corrections. 3.88g 0 131030 TS Update to latest software version. Minor corrections. 3.88f 0 130922 TS Update to latest software version. 3.88e 0 130906 TS Update to latest software version. 3.88d 0 130904 AW Update to latest software version. 3.88c 0 130808 TS Update to latest software version. 3.88b 0 130528 TS Update to latest software version. Software update. Event handling modified, the reset behaviour of events can be controlled. New functions added, chapter "Events": AW OS_EVENT_CreateEx(); OS_EVENT_SetResetMode(); OS_EVENT_GetResetMode(); Mailbox message size limits enlarged. 3.88a 0 130503 3.88 0 130219 TS Minor corrections. 3.86n 0 121210 AW Update to latest software version. /TS 3.86l 0 121122 Software update AW OS_AddTickHook() function corrected. Several functions modified to allow most of MISRA rule checks 3.86k 0 121004 TS UM01001 User & Reference Guide for embOS Chapter "Queue" * OS_Q_GetMessageSize() and OS_Q_PeekPtr() added. (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 4 CHAPTER Software Revision Date By 3.86i 0 120926 TS Description Update to latest software version. 3.86h 0 120906 Software update, AW OS_EVENT handling with timeout corrected. 3.86g 0 120806 Software update, OS_RetriggerTimer() corrected. AW Task events explained more in detail. Additional software examples in the manual. 120723 Task events modified, default set to 32bit on 32bit CPUs. Chapter 4: New API function OS_AddOnTerminateHook() AW OS_ERR_TIMESLICE removed. A time slice value of zero is legal when creating tasks. 3.86f 0 3.86e 0 120529 Update to latest software version with corrected functions: OS_GetSysStackBase() OS_GetSysStackSize() OS_GetSysStackSpace() OS_GetSysStackUsed() OS_GetIntStackBase() AW OS_GetIntStackSize() OS_GetIntStackSpace() OS_GetIntStackUsed() could not be used in release builds of embOS. Manual corrections: Several index entries corrected. OS_EnterRegion() described more in detail. 3.86d 0 120510 TS 3.86c 0 120508 TS Update to latest software version. TS Chapter "Mailbox" * OS_PeekMail() added. Chapter "Support" added. Chapter "Debugging": * Application defined error codes added. 3.86b 0 120502 Update to latest software version. Timeout handling for waitable objects modified. A timeout will be returned from the waiting function, when the obeject was not avaialbale during the timeout time. Previous implementation of timeout functions might have returned a signaled state when the object was signaled after the timeout when the calling task was blocked for a longer period by higher priorized tasks. Modified functions: OS_UseTimed(), Chapter 6.2.3 OS_WaitCSemaTimed(), Chapter 7.2.6 OS_GetMailTimed(), Chapter 8.5.8 OS_WaitMailTimed(), Chapter 8.5.10 OS_Q_GetPtrTimed(), Chapter 9.3.7 OS_EVENT_WaitTimed(), Chapter 11.2.4 OS_MEMF_AllocTimed(), Chapter 13.2.4 New Chapter 4.3. "Extending the task context" added. 3.86 0 120323 AW New functions added and described in the manual: Chapter 4.4.14: OS_GetTaskName() Chapter 4.4.14: OS_GetTimeSliceRem() Handling of queues described mor in detail: Chapter 9.3.5: OS_Q_GetPtr() Chapter 9.3.6: OS_Q_GetPtrCond() Chapter 9.3.7: OS_Q_GetPtrTimed() Chapter 9.3.8: OS_Q_Purge() Chapter 10, Task Events: Type for task events OS_TASK_EVENT introduced. This type is used for all events and event masks. it defaults to unsigned char. Chapter 2.4.3 "Priority inversion / inheritance" updated Chapter 17.3.1 function names OS_Timing_Start() and OS_Timing_End() corrected in the API table. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 5 Software Revision Date By Description 3.84c 1 120130 Since version 3.82w of embOS, all pointer parameter pointing to objects which were not modified by the function were declared as const, but the manual was not updated accordingly. The prototype descriptions of the following API functions are corrected now: OS_GetTimerValue() OS_GetTimerStatus() OS_GetTimerPeriod() OS_GetSemaValue() OS_GetResourceOwner() OS_Q_IsInUse() OS_Q_GetMessageCnt() OS_IsTask() OS_GetEventsOccurred() AW OS_GetCSemaValue() /TS OS_TICK_RemoveHook() OS_MEMF_IsInPool() OS_MEMF_GetMaxUsed() OS_MEMF_GetNumBlocks() OS_MEMF_GetBlockSize() OS_GetSuspendCnt() OS_GetPriority() OS_EVENT_Get() OS_Timing_Getus() Chapter "Preface" * Segger Logo replaced. Chapter "Mailbox" * OS_CREARTEMB() changed to OS_CreateMB(). Chapter "Queues" * Typos corrected. 3.84c 0 120104 TS Chapter "Events" * Return value of OS_EVENT_WaitTimed() explained in more detail 3.84b 0 111221 TS Chapter "Queues" * OS_Q_PutBlocked() added. 3.84a 0 111207 TS General updates and corrections. 3.84 0 110927 TS Chapter "Stacks" * OS_GetSysStackBase() added. * OS_GetSysStackSize() added. * OS_GetSysStackUsed() added. * OS_GetSysStackSpace() added. * OS_GetIntStackBase() added. * OS_GetIntStackSize() added. * OS_GetIntStackUsed() added. * OS_GetIntStackSpace() added. 3.82x 0 110829 TS Chapter "Debugging" * New error code "OS_ERR_REGIONCNT" added. 3.82w 0 110812 TS New embOS generic sources. Chapter 24 "Debugging" updated. 3.82v 0 110715 AW OS_Terminate() renamed to OS_TerminateTask(). 3.82u 0 110630 TS New embOS generic sources. Chapter 13: Fixed size memory pools modified. 3.82t 0 110503 TS New embOS generic sources. Trial time limitation increased. 110318 Chapter 5.2, "Timer" API functions table corrected. All functions can be called from main(), task, ISR or Timer. AW Chapter 6: OS_UseTimed() added. Chapter 9: OS_Q_IsInUse() added. 3.82s 0 3.82p 0 110112 Chapter "Mailboxes" * OS_PutMail() * OS_PutMailCond() * OS_PutMailFront() AW * OS_PutMailFrontCond() parameter declaration changed. Chapter 4.3 API functions table corrected. OS_Suspend() cannot be called from ISR or Timer. 3.82o 0 110104 AW UM01001 User & Reference Guide for embOS Chapter "Mailboxes" * OS_WaitMailTimed() added. (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 6 CHAPTER Software Revision Date By Description 3.82n 0 101206 Chapter "Taskroutines" * OS_ResumeAllSuspendedTasks() added. * OS_SetInitialSuspendCnt() added. * OS_SuspendAllTasks() added. AW Chapter "Time Measurement" * Description of OS_GetTime32() corrected. Chapter "List of error codes" * New error codes added. 3.82k 0 100927 TS Chapter "Taskroutines" * OS_Delayus() added * OS_Q_Delete() added 3.82i 0 100917 TS General updates and corrections. 3.82h 0 100621 Chapter Event objects: Samples added. AW Chapter: Configuration of target system: Detailed description of OS_idle() added 3.82f 1 100505 TS Chapter Profiling added Chapter SystemTick: OS_TickHandleNoHook() added. 3.82f 0 100419 AW Chapter Tasks: New function OS_IsRunning()added. Chapter Tasks: Description of OS_Start() added. 3.82e 0 100309 TS Chapter "Working with embOS - Recommendations" added Chapter Basics * Priority inversion image added Chapter Interrupt * subchapter "Using OS functions from high priority interrupts" added Added text at chapter 22 "Performance and resource usage" 3.82 0 090922 TS API function overview now contains information about allowed context of function usage (main, task, ISR or timer) TOC format corrected 3.80 0 090612 AW Scheduler optimized for higher task switching speed. Chapter structure updated. Chapter "Interrupts": * OS_LeaveNestableInterruptNoSwitch() removed. * OS_LeaveInterruptNoSwitch() removed. Chapter "System tick": * OS_TICK_Config() added. 3.62.c 0 080903 SK 3.60 2 080722 SK Contact address updated. 3.60 1 080617 SK General updates. Chapter "Mailboxes": - OS_GetMailCond() / OS_GetMailCond1() corrected. 3.60 0 080117 OO General updates. Chapter "System tick" added. 3.52 1 071026 AW Chapter "Task routines": Added OS_SetTaskName(). 3.52 0 070824 Chapter "Task routines": Added OS_ExtendTaskContext(). OO Chapter "Interrupts": Updated, added OS_CallISR() and OS_CallNestableISR(). 3.50c 0 070814 AW Chapter "List of libraries" updated, XR library type added. 3.40C 3 070716 OO Chapter "Performance and resource usage" updated, 3.40C 3.40A 2 1 070625 070608 UM01001 User & Reference Guide for embOS SK Chapter "Debugging", error codes updated: - OS_ERR_ISR_INDEX added. - OS_ERR_ISR_VECTOR added. - OS_ERR_RESOURCE_OWNER added. - OS_ERR_CSEMA_OVERFLOW added. Chapter "Task routines": - OS_Yield() added. Chapter "Counting semaphores" updated. - OS_SignalCSema(), additional information adjusted. Chapter "Performance and resource usage" updated: - Minor changes in wording. SK Chapter "Counting semaphores" updated. - OS_SetCSemaValue() added. - OS_CreateCSema(): Data type of parameter InitValue changed from unsigned char to unsigned int. - OS_SignalCSemaMax(): Data type of parameter MaxValue changed from unsigned char to unsigned int. - OS_SignalCSema(): Additional information updated. (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 7 Software Revision Date By Description 3.40 0 070516 SK Chapter "Performance and resource usage" added. Chapter "Configuration of your target system (RTOSInit.c)" renamed to "Configuration of your target system". Chapter "STOP\WAIT\IDLE modes" moved into chapter "Configuration of your target system". Chapter "time-related routines" renamed to "Time measurement". 3.32o 9 070422 SK Chapter 4: OS_CREATETIMER_EX(), additional information corrected. 3.32m 8 070402 Chapter 4: Extended timer added. AW Chapter 8: API overview corrected, OS_Q_GetMessageCount() 3.32j 7 070216 AW Chapter 6: OS_CSemaRequest() function added. 3.32e 6 061220 SK 3.32e 5 061107 AW Chapter 7: OS_GetMessageCnt() return value corrected to unsigned int. 3.32d 4 061106 AW About: Company description added. Some minor formatting changes. Chapter 8: OS_Q_GetPtrTimed() function added. Chapter 3: OS_CreateTaskEx() function, description of parameter pContext corrected. Chapter 3: OS_CreateTaskEx() function, type of parameter TimeSlice corrected. AW Chapter 3: OS_CreateTask() function, type of parameter TimeSlice corrected. Chapter 9: OS_GetEventsOccured() renamed to OS_GetEventsOccurred(). Chapter 10: OS_EVENT_WaitTimed() added. 3.32a 3 061012 3.32a 2 060804 AW Chapter 3: OS_CREATETASK_EX() function added. Chapter 3: OS_CreateTaskEx() function added. 3.32 1 060717 OO Event objects introduced. Chapter 10 inserted which describes event objects. Previous chapter "Events" renamed to "Task events" 3.30 1 060519 OO New software version. 3.28 5 060223 OO All chapters: Added API tables. Some minor changes. 3.28 4 051109 AW Chapter 7: OS_SignalCSemaMax() function added. Chapter 14: Explanation of interrupt latencies and high / low priorities added. 3.28 3 050926 AW Chapter 6: OS_DeleteRSema() function added. 3.28 2 050707 AW Chapter 4: OS_GetSuspendCnt() function added. 3.28 1 050425 AW Version number changed to 3.28 to fit to current ombOS version. Chapter 18.1.2: Type of return value of OS GetTime32() corrected 3.26 050209 3.24 041115 Chapter 4: OS_Terminate() modified due to new features of AW version 3.26. Chapter 24: Source code version: additional compile time switches and build process of libraries explained more in detail. AW Chapter 6: Some prototype declarations showed in OS_SEMA instead of OS_RSEMA. Corrected. 3.22 1 040816 AW Chapter 8: New Mailbox functions added OS_PutMailFront() OS_PutMailFront1() OS_PutMailFrontCond() OS_PutMailFrontCond1() 3.20 5 040621 RS Software timers: Maximum timeout values and AW OS_TIMER_MAX_TIME described. Chapter 14: Description of rules for interrupt handlers revised. OS_LeaveNestableInterruptNoSwitch() added which was not described before. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 8 CHAPTER Software Revision Date 3.20 4 040329 AW OS_CreateCSema() prototype declaration corrected. Return type is void. OS_Q_GetMessageCnt() prototype declaration corrected. OS_Q_Clear() function description added. OS_MEMF_FreeBlock() prototype declaration corrected. 3.20 2 031128 AW OS_CREATEMB() Range for parameter MaxnofMsg corrected. Upper limit is 65535, but was declared 65536 in previous manuals. 3. 1 040831 AW Code samples modified: Task stacks defined as array of int, because most CPUs require alignment of stack on integer aligned addresses. 3.20 1 031016 AW Chapter 4: Type of task priority parameter corrected to unsigned char. Chapter 4: OS_DelayUntil(): Sample program modified. Chapter 4: OS_Suspend() added. Chapter 4: OS_Resume() added. Chapter 5: OS_GetTimerValue(): Range of return value corrected. Chapter 6: Sample program for usage of resource semaphores modified. Chapter 6: OS_GetResourceOwner(): Type of return value corrected. Chapter 8: OS_CREATEMB(): Types and valid range of parameter corrected. Chapter 8: OS_WaitMail() added Chapter 10: OS_WaitEventTimed(): Range of timeout value specified. 3.12 1 021015 AW Chapter 8: OS_GetMailTimed() added Chapter 11 (Heap type memory management) inserted Chapter 12 (Fixed block size memory pools) inserted 3.10 3 020926 020924 020910 KG KG KG UM01001 User & Reference Guide for embOS By Description Index and glossary revised. Section 16.3 (Example) added to Chapter 16 (Time-related routines). Revised for language/grammar. Version control table added. Screenshots added: superloop, cooperative/preemptive multitasking, nested interrupts, low-res and hi-res measurement. Section 1.3 (Typographic conventions) changed to table. Section 3.2 added (Single-task system). Section 3.8 merged with section 3.9 (How the OS gains control). Chapter 4 (Configuration for your target system) moved to after Chapter 15 (System variables). Chapter 16 (Time-related routines) added. (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 9 About this document Assumptions This document assumes that you already have a solid knowledge of the following: * * * * The software tools used for building your application (assembler, linker, C compiler) The C programming language The target processor DOS command line If you feel that your knowledge of C is not sufficient, we recommend The C Programming Language by Kernighan and Richie (ISBN 0-13-1103628), which describes the standard in C-programming and, in newer editions, also covers the ANSI C standard. How to use this manual This manual explains all the functions and macros that the product offers. It assumes you have a working knowledge of the C language. Knowledge of assembly programming is not required. Typographic conventions for syntax This manual uses the following typographic conventions: Style Used for Body Body text. Keyword Text that you enter at the command-prompt or that appears on the display (that is system functions, file- or pathnames). Parameter Parameters in API functions. Sample Sample code in program examples. Sample comment Comments in programm examples. Reference Reference to chapters, sections, tables and figures or other documents. GUIElement Buttons, dialog boxes, menu names, menu commands. Emphasis Very important sections. Table 1.1: Typographic conventions UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 10 SEGGER Microcontroller GmbH & Co. KG develops and distributes software development tools and ANSI C software components (middleware) for embedded systems in several industries such as telecom, medical technology, consumer electronics, automotive industry and industrial automation. SEGGER's intention is to cut software development time for embedded applications by offering compact flexible and easy to use middleware, allowing developers to concentrate on their application. Our most popular products are emWin, a universal graphic software package for embedded applications, and embOS, a small yet efficient real-time kernel. emWin, written entirely in ANSI C, can easily be used on any CPU and most any display. It is complemented by the available PC tools: Bitmap Converter, Font Converter, Simulator and Viewer. embOS supports most 8/16/32-bit CPUs. Its small memory footprint makes it suitable for single-chip applications. Apart from its main focus on software tools, SEGGER develops and produces programming tools for flash micro controllers, as well as J-Link, a JTAG emulator to assist in development, debugging and production, which has rapidly become the industry standard for debug access to ARM cores. Corporate Office: http://www.segger.com EMBEDDED SOFTWARE (Middleware) emWin Graphics software and GUI emWin is designed to provide an efficient, processor- and display controller-independent graphical user interface (GUI) for any application that operates with a graphical display. embOS Real Time Operating System embOS is an RTOS designed to offer the benefits of a complete multitasking system for hard real time applications with minimal resources. embOS/IP TCP/IP stack embOS/IP a high-performance TCP/IP stack that has been optimized for speed, versatility and a small memory footprint. United States Office: http://www.segger-us.com SEGGER TOOLS Flasher Flash programmer Flash Programming tool primarily for micro controllers. J-Link JTAG emulator for ARM cores USB driven JTAG interface for ARM cores. J-Trace JTAG emulator with trace USB driven JTAG interface for ARM cores with Trace memory. supporting the ARM ETM (Embedded Trace Macrocell). J-Link / J-Trace Related Software Add-on software to be used with SEGGER's industry standard JTAG emulator, this includes flash programming software and flash breakpoints. emFile File system emFile is an embedded file system with FAT12, FAT16 and FAT32 support. Various Device drivers, e.g. for NAND and NOR flashes, SD/MMC and CompactFlash cards, are available. USB-Stack USB device/host stack A USB stack designed to work on any embedded system with a USB controller. Bulk communication and most standard device classes are supported. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 11 Table of Contents 1 Introduction to embOS ...................................................................................................19 1.1 1.2 What is embOS ....................................................................................... 20 Features................................................................................................. 21 2 Basic concepts...............................................................................................................23 2.1 2.1.1 2.1.2 2.2 2.2.1 2.2.2 2.2.3 2.3 2.3.1 2.3.2 2.3.3 2.3.4 2.3.5 2.4 2.4.1 2.4.2 2.4.3 2.5 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 2.6 2.6.1 2.7 2.8 2.9 2.9.1 2.9.2 2.9.3 Tasks ..................................................................................................... 24 Threads.................................................................................................. 24 Processes ............................................................................................... 24 Single-task systems (superloop) ................................................................ 25 Advantages & disadvantages ..................................................................... 25 Using embOS in super-loop applications...................................................... 26 Migrating from superloop to multi-tasking ................................................... 26 Multitasking systems................................................................................ 27 Task switches.......................................................................................... 27 Cooperative task switch............................................................................ 27 Preemptive task switch............................................................................. 27 Preemptive multitasking ........................................................................... 28 Cooperative multitasking .......................................................................... 29 Scheduling.............................................................................................. 30 Round-robin scheduling algorithm .............................................................. 30 Priority-controlled scheduling algorithm ...................................................... 30 Priority inversion / priority inheritance ........................................................ 31 Communication between tasks .................................................................. 33 Periodic polling ........................................................................................ 33 Event-driven communication mechanisms ................................................... 33 Mailboxes and queues .............................................................................. 33 Semaphores ........................................................................................... 33 Events ................................................................................................... 33 How task switching works ......................................................................... 34 Switching stacks...................................................................................... 35 Change of task status............................................................................... 36 How the OS gains control ......................................................................... 37 Different builds of embOS ......................................................................... 38 Profiling ................................................................................................. 38 List of libraries ........................................................................................ 38 embOS functions context .......................................................................... 39 3 Working with embOS .....................................................................................................41 3.1 3.1.1 General advice ........................................................................................ 42 Timers or task......................................................................................... 42 4 Tasks .............................................................................................................................43 4.1 4.1.1 4.1.2 4.2 4.2.1 4.2.2 4.3 4.3.1 Introduction............................................................................................ 44 Example of a task routine as an endless loop............................................... 44 Example of a task routine that terminates itself ........................................... 44 Cooperative vs. preemptive task switches ................................................... 45 Disabling preemptive task switches for tasks of equal priority ........................ 45 Completely disabling preemptions for a task................................................ 45 Extending the task context ....................................................................... 46 Passing one parameter to a task during task creation ................................... 46 UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 12 4.3.2 4.3.3 4.4 4.4.1 4.4.2 4.4.3 4.4.4 4.4.5 4.4.6 4.4.7 4.4.8 4.4.9 4.4.10 4.4.11 4.4.12 4.4.13 4.4.14 4.4.15 4.4.16 4.4.17 4.4.18 4.4.19 4.4.20 4.4.21 4.4.22 4.4.23 4.4.24 4.4.25 4.4.26 4.4.27 4.4.28 4.4.29 Extending the task context individually at runtime ....................................... 46 Extending the task context by using own task structures .............................. 46 API functions .......................................................................................... 48 OS_AddOnTerminateHook()...................................................................... 50 OS_CREATETASK().................................................................................. 51 OS_CreateTask() .................................................................................... 53 OS_CREATETASK_EX() ............................................................................ 55 OS_CreateTaskEx() ................................................................................. 57 OS_Delay() ............................................................................................ 58 OS_DelayUntil() ...................................................................................... 59 OS_Delayus() ......................................................................................... 60 OS_ExtendTaskContext() ......................................................................... 61 OS_GetpCurrentTask()............................................................................. 64 OS_GetPriority() ..................................................................................... 65 OS_GetSuspendCnt()............................................................................... 66 OS_GetTaskID() ..................................................................................... 67 OS_GetTaskName()................................................................................. 68 OS_GetTimeSliceRem()............................................................................ 69 OS_IsRunning() ...................................................................................... 70 OS_IsTask() ........................................................................................... 71 OS_Resume() ......................................................................................... 72 OS_ResumeAllSuspendedTasks()............................................................... 73 OS_SetInitialSuspendCnt() ....................................................................... 74 OS_SetPriority() ..................................................................................... 75 OS_SetTaskName() ................................................................................. 76 OS_SetTimeSlice() .................................................................................. 77 OS_Start() ............................................................................................. 78 OS_Suspend() ........................................................................................ 79 OS_SuspendAllTasks() ............................................................................. 80 OS_TerminateTask()................................................................................ 81 OS_WakeTask() ...................................................................................... 82 OS_Yield() ............................................................................................. 83 5 Software timers ..............................................................................................................85 5.1 5.2 5.2.1 5.2.2 5.2.3 5.2.4 5.2.5 5.2.6 5.2.7 5.2.8 5.2.9 5.2.10 5.2.11 5.2.12 5.2.13 5.2.14 5.2.15 5.2.16 5.2.17 5.2.18 5.2.19 5.2.20 5.2.21 5.2.22 Introduction ........................................................................................... 86 API functions .......................................................................................... 87 OS_CREATETIMER() ................................................................................ 88 OS_CreateTimer() ................................................................................... 89 OS_StartTimer() ..................................................................................... 90 OS_StopTimer()...................................................................................... 91 OS_RetriggerTimer() ............................................................................... 92 OS_SetTimerPeriod() ............................................................................... 93 OS_DeleteTimer() ................................................................................... 94 OS_GetTimerPeriod()............................................................................... 95 OS_GetTimerValue()................................................................................ 96 OS_GetTimerStatus() .............................................................................. 97 OS_GetpCurrentTimer() ........................................................................... 98 OS_CREATETIMER_EX() ........................................................................... 99 OS_CreateTimerEx()...............................................................................100 OS_StartTimerEx() .................................................................................101 OS_StopTimerEx() .................................................................................102 OS_RetriggerTimerEx() ...........................................................................103 OS_SetTimerPeriodEx() ..........................................................................104 OS_DeleteTimerEx() ...............................................................................105 OS_GetTimerPeriodEx() ..........................................................................106 OS_GetTimerValueEx() ...........................................................................107 OS_GetTimerStatusEx() ..........................................................................108 OS_GetpCurrentTimerEx().......................................................................109 6 Resource semaphores.................................................................................................111 UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 13 6.1 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.2.6 6.2.7 6.2.8 Introduction.......................................................................................... 112 API functions ........................................................................................ 114 OS_CREATERSEMA() .............................................................................. 115 OS_Use() ............................................................................................. 116 OS_UseTimed() ..................................................................................... 118 OS_Unuse() .......................................................................................... 119 OS_Request() ....................................................................................... 120 OS_GetSemaValue() .............................................................................. 121 OS_GetResourceOwner() ........................................................................ 122 OS_DeleteRSema()................................................................................ 123 7 Counting Semaphores .................................................................................................125 7.1 7.2 7.2.1 7.2.2 7.2.3 7.2.4 7.2.5 7.2.6 7.2.7 7.2.8 7.2.9 7.2.10 Introduction.......................................................................................... 126 API functions ........................................................................................ 127 OS_CREATECSEMA().............................................................................. 128 OS_CreateCSema()................................................................................ 129 OS_SignalCSema() ................................................................................ 130 OS_SignalCSemaMax()........................................................................... 131 OS_WaitCSema() .................................................................................. 132 OS_WaitCSemaTimed() .......................................................................... 133 OS_CSemaRequest() ............................................................................. 134 OS_GetCSemaValue() ............................................................................ 135 OS_SetCSemaValue() ............................................................................ 136 OS_DeleteCSema()................................................................................ 137 8 Mailboxes.....................................................................................................................139 8.1 8.2 8.3 8.3.1 8.3.2 8.3.3 8.4 8.5 8.5.1 8.5.2 8.5.3 8.5.4 8.5.5 8.5.6 8.5.7 8.5.8 8.5.9 8.5.10 8.5.11 8.5.12 8.5.13 8.5.14 Introduction.......................................................................................... 140 Basics .................................................................................................. 141 Typical applications................................................................................ 142 A keyboard buffer .................................................................................. 142 A buffer for serial I/O ............................................................................. 142 A buffer for commands sent to a task ....................................................... 142 Single-byte mailbox functions.................................................................. 143 API functions ........................................................................................ 144 OS_CreateMB() ..................................................................................... 145 OS_PutMail() / OS_PutMail1() ................................................................. 146 OS_PutMailCond() / OS_PutMailCond1() ................................................... 147 OS_PutMailFront() / OS_PutMailFront1()................................................... 148 OS_PutMailFrontCond() / OS_PutMailFrontCond1()..................................... 149 OS_GetMail() / OS_GetMail1()................................................................. 150 OS_GetMailCond() / OS_GetMailCond1() .................................................. 151 OS_GetMailTimed()................................................................................ 152 OS_WaitMail()....................................................................................... 153 OS_WaitMailTimed() .............................................................................. 154 OS_PeekMail() ...................................................................................... 155 OS_ClearMB() ....................................................................................... 156 OS_GetMessageCnt() ............................................................................. 157 OS_DeleteMB() ..................................................................................... 158 9 Queues ........................................................................................................................159 9.1 9.2 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.3.6 9.3.7 Introduction.......................................................................................... 160 Basics .................................................................................................. 161 API functions ........................................................................................ 162 OS_Q_Create() ..................................................................................... 163 OS_Q_Put() .......................................................................................... 164 OS_Q_PutBlocked() ............................................................................... 165 OS_Q_PutTimed().................................................................................. 166 OS_Q_GetPtr()...................................................................................... 167 OS_Q_GetPtrCond()............................................................................... 168 OS_Q_GetPtrTimed() ............................................................................. 169 UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 14 9.3.8 9.3.9 9.3.10 9.3.11 9.3.12 9.3.13 9.3.14 OS_Q_Purge() .......................................................................................170 OS_Q_Clear() ........................................................................................171 OS_Q_GetMessageCnt()..........................................................................172 OS_Q_Delete() ......................................................................................173 OS_Q_IsInUse() ....................................................................................174 OS_Q_GetMessageSize().........................................................................175 OS_Q_PeekPtr().....................................................................................176 10 Task events................................................................................................................177 10.1 10.2 10.2.1 10.2.2 10.2.3 10.2.4 10.2.5 10.2.6 10.2.7 Introduction ..........................................................................................178 API functions .........................................................................................179 OS_WaitEvent() .....................................................................................180 OS_WaitSingleEvent() ............................................................................181 OS_WaitEventTimed() ............................................................................182 OS_WaitSingleEventTimed() ....................................................................183 OS_SignalEvent()...................................................................................184 OS_GetEventsOccurred() ........................................................................186 OS_ClearEvents()...................................................................................187 11 Event objects .............................................................................................................189 11.1 11.2 11.2.1 11.2.2 11.2.3 11.2.4 11.2.5 11.2.6 11.2.7 11.2.8 11.2.9 11.2.10 11.2.11 11.3 11.3.1 11.3.2 Introduction ..........................................................................................190 API functions .........................................................................................191 OS_EVENT_Create() ...............................................................................192 OS_EVENT_CreateEx()............................................................................193 OS_EVENT_Wait() ..................................................................................194 OS_EVENT_WaitTimed() .........................................................................195 OS_EVENT_Set()....................................................................................197 OS_EVENT_Reset() ................................................................................198 OS_EVENT_Pulse() .................................................................................199 OS_EVENT_Get() ...................................................................................200 OS_EVENT_Delete() ...............................................................................201 OS_EVENT_SetResetMode() ....................................................................202 OS_EVENT_GetResetMode() ....................................................................203 Examples of using event objects...............................................................204 Activate a task from interrupt by an event object .......................................204 Activating multiple tasks using a single event object ...................................205 12 Heap type memory management...............................................................................207 12.1 12.2 12.2.1 12.2.2 12.2.3 Introduction ..........................................................................................208 API functions .........................................................................................209 OS_malloc() ..........................................................................................210 OS_free()..............................................................................................211 OS_realloc() ..........................................................................................212 13 Fixed block size memory pools..................................................................................213 13.1 13.2 13.2.1 13.2.2 13.2.3 13.2.4 13.2.5 13.2.6 13.2.7 13.2.8 13.2.9 13.2.10 13.2.11 13.2.12 Introduction ..........................................................................................214 API functions .........................................................................................215 OS_MEMF_Create() ................................................................................216 OS_MEMF_Delete() ................................................................................217 OS_MEMF_Alloc()...................................................................................218 OS_MEMF_AllocTimed() ..........................................................................219 OS_MEMF_Request() ..............................................................................220 OS_MEMF_Release()...............................................................................221 OS_MEMF_FreeBlock() ............................................................................222 OS_MEMF_GetNumBlocks() .....................................................................223 OS_MEMF_GetBlockSize() .......................................................................224 OS_MEMF_GetNumFreeBlocks() ...............................................................225 OS_MEMF_GetMaxUsed() ........................................................................226 OS_MEMF_IsInPool() ..............................................................................227 UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 15 14 Stacks ........................................................................................................................229 14.1 14.1.1 14.1.2 14.1.3 14.1.4 14.1.5 14.2 14.2.1 14.2.2 14.2.3 14.2.4 14.2.5 14.2.6 14.2.7 14.2.8 14.2.9 14.2.10 14.2.11 14.2.12 Introduction.......................................................................................... 230 System stack ........................................................................................ 230 Task stack ............................................................................................ 230 Interrupt stack ...................................................................................... 230 Stack size calculation ............................................................................. 231 Stack-check .......................................................................................... 231 API functions ........................................................................................ 232 OS_GetStackBase() ............................................................................... 233 OS_GetStackSize() ................................................................................ 234 OS_GetStackSpace().............................................................................. 235 OS_GetStackUsed() ............................................................................... 236 OS_GetSysStackBase() .......................................................................... 237 OS_GetSysStackSize() ........................................................................... 238 OS_GetSysStackSpace()......................................................................... 239 OS_GetSysStackUsed() .......................................................................... 240 OS_GetIntStackBase() ........................................................................... 241 OS_GetIntStackSize() ............................................................................ 242 OS_GetIntStackSpace().......................................................................... 243 OS_GetIntStackUsed() ........................................................................... 244 15 Interrupts....................................................................................................................245 15.1 15.2 15.2.1 15.2.2 15.3 15.4 15.4.1 15.5 15.5.1 15.5.2 15.6 15.6.1 15.6.2 15.6.3 15.6.4 15.7 15.7.1 15.7.2 15.8 15.9 15.9.1 15.9.2 15.9.3 15.10 15.10.1 15.10.2 15.10.3 15.10.4 15.10.5 15.11 What are interrupts? .............................................................................. 246 Interrupt latency ................................................................................... 247 Causes of interrupt latencies ................................................................... 247 Additional causes for interrupt latencies.................................................... 247 Zero interrupt latency ............................................................................ 249 High / low priority interrupts ................................................................... 250 Using OS functions from high priority interrupts......................................... 250 Rules for interrupt handlers..................................................................... 252 General rules ........................................................................................ 252 Additional rules for preemptive multitasking .............................................. 252 API functions ........................................................................................ 253 OS_CallISR() ........................................................................................ 254 OS_CallNestableISR() ............................................................................ 255 OS_EnterInterrupt() .............................................................................. 256 OS_LeaveInterrupt() .............................................................................. 257 Enabling / disabling interrupts from C....................................................... 258 OS_IncDI() / OS_DecRI() ....................................................................... 259 OS_DI() / OS_EI() / OS_RestoreI().......................................................... 260 Definitions of interrupt control macros (in RTOS.h)..................................... 261 Nesting interrupt routines ....................................................................... 262 OS_EnterNestableInterrupt()................................................................... 263 OS_LeaveNestableInterrupt() .................................................................. 264 OS_InInterrupt() ................................................................................... 265 Global interrupt enable / disable .............................................................. 266 OS_INTERRUPT_MaskGlobal() ................................................................. 267 OS_INTERRUPT_UnmaskGlobal() ............................................................. 267 OS_INTERRUPT_PreserveGlobal() ............................................................ 268 OS_INTERRUPT_PreserveAndMaskGlobal() ................................................ 269 OS_INTERRUPT_RestoreGlobal().............................................................. 269 Non-maskable interrupts (NMIs) .............................................................. 270 16 Critical Regions..........................................................................................................271 16.1 16.2 16.2.1 16.2.2 Introduction.......................................................................................... 272 API functions ........................................................................................ 273 OS_EnterRegion().................................................................................. 274 OS_LeaveRegion() ................................................................................. 275 17 Time measurement ....................................................................................................277 UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 16 17.1 17.2 17.2.1 17.2.1.1 17.2.1.2 17.3 17.3.1 17.3.1.1 17.3.1.2 17.3.1.3 17.3.1.4 17.4 17.5 17.5.1 17.5.2 17.5.3 17.5.4 17.5.4.1 17.5.4.2 17.5.4.3 Introduction ..........................................................................................278 Low-resolution measurement ...................................................................279 API functions .........................................................................................280 OS_GetTime() .......................................................................................281 OS_GetTime32() ....................................................................................282 High-resolution measurement ..................................................................283 API functions .........................................................................................284 OS_Timing_Start() .................................................................................285 OS_Timing_End()...................................................................................286 OS_Timing_Getus() ................................................................................287 OS_Timing_GetCycles() ..........................................................................288 Example ...............................................................................................289 Micro second precise system time.............................................................291 API functions .........................................................................................291 OS_GetTime_us() ..................................................................................292 OS_GetTime_us64() ...............................................................................293 OS_Config_SysTimer()............................................................................294 pfGetTimerCycles() ................................................................................294 pfGetTimerIntPending() ..........................................................................294 Example ...............................................................................................295 18 System variables........................................................................................................297 18.1 18.2 18.2.1 18.2.2 18.2.3 18.3 Introduction ..........................................................................................298 Time variables .......................................................................................299 OS_Global.............................................................................................299 OS_Global.Time .....................................................................................299 OS_Global.TimeDex................................................................................299 OS internal variables and data-structures ..................................................300 19 System tick.................................................................................................................301 19.1 19.2 19.2.1 19.2.1.1 19.2.1.2 19.2.1.3 19.2.1.4 19.3 19.3.1 19.3.1.1 19.3.1.2 19.4 19.4.1 19.4.2 19.4.3 19.4.3.1 19.4.3.2 19.4.3.3 19.4.3.4 19.4.4 Introduction ..........................................................................................302 Tick handler ..........................................................................................303 API functions .........................................................................................303 OS_TICK_Handle() .................................................................................304 OS_TICK_HandleEx()..............................................................................305 OS_TICK_HandleNoHook() ......................................................................306 OS_TICK_Config() ..................................................................................307 Hooking into the system tick....................................................................308 API functions .........................................................................................308 OS_TICK_AddHook() ..............................................................................309 OS_TICK_RemoveHook() ........................................................................310 Tickless support .....................................................................................311 OS_Idle()..............................................................................................311 Callback Function ...................................................................................312 API functions .........................................................................................313 OS_GetNumIdleTicks() ...........................................................................314 OS_AdjustTime() ...................................................................................315 OS_StartTicklessMode() ..........................................................................316 OS_StopTicklessMode()...........................................................................317 Frequently Asked Questions.....................................................................318 20 Configuration of target system (BSP) ........................................................................319 20.1 20.2 20.2.1 20.3 20.4 20.4.1 20.4.2 20.4.3 Introduction ..........................................................................................320 Hardware-specific routines ......................................................................321 OS_Idle()..............................................................................................321 Configuration defines ..............................................................................323 How to change settings ...........................................................................324 Setting the system frequency OS_FSYS.....................................................324 Using a different timer to generate the tick-interrupts for embOS .................324 Using a different UART or baudrate for embOSView ....................................324 UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 17 20.4.4 20.5 Changing the tick frequency.................................................................... 324 STOP / HALT / IDLE modes ..................................................................... 326 21 Profiling ......................................................................................................................327 21.0.1 21.0.1.1 21.0.1.2 21.0.1.3 21.0.1.4 21.0.1.5 21.0.1.6 21.0.1.7 21.0.1.8 21.0.1.9 API functions ........................................................................................ 328 OS_STAT_Sample() ............................................................................... 329 OS_STAT_GetLoad() .............................................................................. 330 Sample application for OS_STAT_Sample() and OS_STAT_GetLoad()............ 331 OS_AddLoadMeasurement() .................................................................... 332 OS_GetLoadMeasurement() .................................................................... 333 OS_CPU_Load ....................................................................................... 334 OS_STAT_Enable() ................................................................................ 335 OS_STAT_Disable() ............................................................................... 336 OS_STAT_GetTaskExecTime() ................................................................. 337 22 embOSView: Profiling and analyzing.........................................................................339 22.1 22.2 22.3 22.4 22.5 22.5.1 22.5.2 22.6 22.7 22.8 22.8.1 22.8.2 22.8.3 22.8.4 22.8.5 22.8.6 22.8.7 22.8.8 22.9 22.10 22.10.1 22.10.2 22.10.3 22.10.4 22.10.5 22.11 22.12 Overview .............................................................................................. 340 Task list window .................................................................................... 341 System variables window........................................................................ 342 Sharing the SIO for terminal I/O.............................................................. 343 API functions ........................................................................................ 344 OS_SendString() ................................................................................... 345 OS_SetRxCallback()............................................................................... 346 Using the API trace ................................................................................ 347 Trace filter setup functions...................................................................... 349 API functions ........................................................................................ 350 OS_TraceEnable().................................................................................. 351 OS_TraceDisable()................................................................................. 352 OS_TraceEnableAll() .............................................................................. 353 OS_TraceDisableAll() ............................................................................. 354 OS_TraceEnableId()............................................................................... 355 OS_TraceDisableId() .............................................................................. 356 OS_TraceEnableFilterId()........................................................................ 357 OS_TraceDisableFilterId() ....................................................................... 358 Trace record functions............................................................................ 359 API functions ........................................................................................ 360 OS_TraceVoid()..................................................................................... 361 OS_TracePtr() ....................................................................................... 362 OS_TraceData() .................................................................................... 363 OS_TraceDataPtr() ................................................................................ 364 OS_TraceU32Ptr() ................................................................................. 365 Application-controlled trace example ........................................................ 366 User-defined functions ........................................................................... 367 23 Performance and resource usage..............................................................................369 23.1 23.2 23.3 23.4 23.4.1 23.4.1.1 23.4.1.2 23.4.1.3 23.4.1.4 Introduction.......................................................................................... 370 Memory requirements ............................................................................ 371 Performance ......................................................................................... 372 Benchmarking ....................................................................................... 372 Measurement with port pins and oscilloscope............................................. 373 Oscilloscope analysis .............................................................................. 374 Example measurements AT91SAM7S, ARM code in RAM.............................. 375 Example measurements AT91SAM7S, Thumb code in FLASH ....................... 376 Measurement with high-resolution timer ................................................... 377 24 Debugging..................................................................................................................379 24.1 24.1.1 24.2 Runtime errors ...................................................................................... 380 OS_DEBUG_LEVEL ................................................................................. 380 List of error codes.................................................................................. 381 UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 18 24.3 Application defined error codes ................................................................385 25 Supported development tools ....................................................................................387 25.1 Overview ..............................................................................................388 26 Limitations..................................................................................................................389 27 Source code of kernel and library ..............................................................................391 27.1 27.2 27.3 27.3.1 Introduction ..........................................................................................392 Building embOS libraries .........................................................................393 Major compile time switches ....................................................................394 OS_RR_SUPPORTED ...............................................................................394 28 FAQ (frequently asked questions) .............................................................................395 29 Support ......................................................................................................................397 29.1 Contacting support .................................................................................398 30 Glossary.....................................................................................................................399 UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 19 Chapter 1 Introduction to embOS UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 20 1.1 CHAPTER 1 Introduction to embOS What is embOS embOS is a priority-controlled multitasking system, designed to be used as an embedded operating system for the development of real-time applications for a variety of microcontrollers. embOS is a high-performance tool that has been optimized for minimal memory consumption in both RAM and ROM, as well as high speed and versatility. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 21 1.2 Features Throughout the development process of embOS, the limited resources of microcontrollers have always been kept in mind. The internal structure of the real-time operating system (RTOS) has been optimized in a variety of applications with different customers, to fit the needs of industry. Fully source-compatible implementations of embOS are available for a variety of microcontrollers, making it well worth the time and effort to learn how to structure real-time programs with real-time operating systems. embOS is highly modular. This means that only those functions that are required are linked into an application, keeping the ROM size very small. The minimum memory consumption is little more than 1 Kbyte of ROM and about 30 bytes of RAM (plus memory for stacks). A couple of files are supplied in source code to make sure that you do not loose any flexibility by using embOS and that you can customize the system to fully fit your needs. The tasks you create can easily and safely communicate with each other using a number of communication mechanisms such as semaphores, mailboxes, and events. Some features of embOS include: * * * * * * * * * * * * * * * * * * * * * * * * * * Preemptive scheduling: Guarantees that of all tasks in READY state the one with the highest priority executes, except for situations where priority inheritance applies. Round-robin scheduling for tasks with identical priorities. Preemptions can be disabled for entire tasks or for sections of a program. Up to 4.294.967.296 priorities. Every task can have an individual priority, which means that the response of tasks can be precisely defined according to the requirements of the application. Unlimited number of tasks (limited only by the amount of available memory). Unlimited number of semaphores (limited only by the amount of available memory). Two types of semaphores: resource and counting. Unlimited number of mailboxes (limited only by the amount of available memory). Size and number of messages can be freely defined when initializing mailboxes. Unlimited number of software timers (limited only by the amount of available memory). Up to 32-bit events for every task. Time resolution can be freely selected (default is 1ms). Easily accessible time variable. Power management. Calculation time in which embOS is idle can automatically be spent in low-power mode. power-consumption is minimized. Full interrupt support: Interrupts can call any function except those that require waiting for data, as well as create, delete or change the priority of a task. Interrupts can wake up or suspend tasks and directly communicate with tasks using all available communication methods (mailboxes, semaphores, events). Disabling interrupts for very short periods allows minimal interrupt latency. Nested interrupts are permitted. embOS has its own interrupt stack (usage optional). Application samples for an easy start. Debug build performs runtime checks that catch common programming errors early on. Profiling and stack-check may be implemented by choosing specified libraries. Monitoring during runtime is available using embOSView via UART, Debug Communications Channel (DCC) and memory read/write, or else via Ethernet. Very fast and efficient, yet small code. Minimal RAM usage. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 22 CHAPTER 1 * * * Introduction to embOS Core written in assembly language. API can be called from assembly, C or C++ code. Initialization of microcontroller hardware as sources (BSP). UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 23 Chapter 2 Basic concepts This chapter explains some basic concepts behind embOS. It should be relativly easy to read and is recommended before moving to other chapters. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 24 CHAPTER 2 2.1 Basic concepts Tasks In this context, a task is a program running on the CPU core of a microcontroller. Without a multitasking kernel (an RTOS), only one task can be executed by the CPU at a time. This is called a single-task system. A real-time operating system allows the execution of multiple tasks on a single CPU. All tasks execute as if they completely "own" the entire CPU. The tasks are scheduled for execution, meaning that the RTOS can activate and deactivate each task according to its priority, with the highest priority task being executed in general. 2.1.1 Threads Threads are tasks which share the same memory layout. Two threads can access the same memory locations. If virtual memory is used, the same virtual to physical translation and access rights are used. The embOS tasks are threads; they all have the same memory access rights and translation (in systems with virtual memory). 2.1.2 Processes Processs are tasks with their own memory layout. Two processes cannot normally access the same memory locations. Different processes typically have different access rights and (in case of MMUs) different translation tables. Processes are not supported by the present version of embOS. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 25 2.2 Single-task systems (superloop) The classic way of designing embedded systems does not use the services of an RTOS, which is also called "superloop design". Typically, no real time kernel is used, so interrupt service routines (ISRs) are used for the real-time parts of the application and for critical operations (at interrupt level). This type of system is typically used in small, simple systems or if real-time behavior is not critical. Typically, because no real-time kernel and only one stack is used, both program (ROM) and RAM size for simple applications are smaller when compared to using an RTOS. Of course, there are no inter-task synchronization problems with a superloop application. However, superloops can become difficult to maintain if the program becomes too large or uses complex interactions. As sequential processes cannot interrupt themselves, reaction times depend on the execution time of the entire sequence, resulting in a poor real-time behavior. 2.2.1 Advantages & disadvantages Advantages * * Simple structure (for small applications) Low stack usage (only one stack required) Disadvantages * * * * * * No "delay" capability Higher power consumption due to the lack of a sleep mode in most architectures Difficult to maintain as program grows Timing of all software components depends on all other software componts: Small change in one place can have major side effects in other places Defeats modular programming Real time behavior only with interrupts UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 26 CHAPTER 2 2.2.2 Basic concepts Using embOS in super-loop applications In a true superloop application, no tasks are used, so the biggest advantage of using an RTOS cannot be used unless the application is converted to use multitasking. However, even with just a single task, using embOS has the following advantages: * * * 2.2.3 Software timers are available Power saving: Idle mode can be used Future extensions can be put in a separate task Migrating from superloop to multi-tasking A common situation is that an application exists for some time and has been designed as single task, super loop application. At a certain point, the disadvantages of this approach lead to a decision to use an RTOS. The typical question is then: How do I do this? The easiest way is to take the start application that comes with the embOS and put your existing "superloop code" into one task. At this point you should also make sure that the stack size of this task is sufficient. Later, additional functionality which is added to the software can be put in one or more additional tasks; the functionality of the super loop can also be distributed over multiple tasks. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 27 2.3 Multitasking systems In a multitasking system, there are different ways of distributing the CPU time amongst different tasks. This process is called scheduling. Priority Low prio task High prio task ISR OS_Start() OS_EVENT_Wait() Interrupt Interrupt (Rx) Time OS_EVENT_Set() OS_EVENT_Wait() OS_Delay() Interrupt (Tick) OS_Delay() Idle task 2.3.1 Application level tasks Interrupt service Task switches There are two types of task switches, also called context switches: Cooperative and preemptive task switches. 2.3.2 Cooperative task switch A cooperative task switch is performed by the task itself. It requires the cooperation of the task, hence the name. What happens is that the task blocks itself by calling a blocking RTOS function such as OS_Delay() or OS_WaitEvent(). 2.3.3 Preemptive task switch A preemptive task switch is a task switch caused by an interrupt. Typically some other high priority task becomes ready for execution and, as a result, the current task is suspended. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 28 CHAPTER 2 2.3.4 Basic concepts Preemptive multitasking Real-time operating systems like embOS operate with preemptive multitasking. The highest-priority task in the READY state always executes as long as the task is not suspended by a call of any operating system function. A high-priority task waiting for an event is signalled READY as soon as the event occurs. The event can be set by an interrupt handler, which then activates the task immediately. Other tasks with lower priority are suspended (preempted) as long as the high-priority task is executing. A real-time operating system, such as embOS, normally comes with a regular timer interrupt to interrupt tasks at regular intervals and to perform task switches if timed task switches are necessary. Low priority task Executing task is interrupted ISR Time ISR puts high priority task in READY state; task switch occurs High priority task Higher priority task Is executed Interrupted task is completed UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 29 2.3.5 Cooperative multitasking Cooperative multitasking requires all tasks to cooperate by using blocking functions. A task switch can only take place if the running task blocks itself by calling a blocking function such as OS_Delay() or OS_Wait...(). If tasks do not cooperate, the system "hangs", which means that other tasks have no chance of being executed by the CPU while the first task is being carried out. This is illustrated in the diagram below. Even if an ISR makes a higher-priority task ready to run, the interrupted task will be resumed and complete before the task switch is made. Low priority task Executing task is interrupted ISR ISR puts high priority task in READY state Time Interrupted task is completed High priority task Higher priority task Is executed A pure cooperative multi-tasking system has the disadvantage of longer reaction times when high priority tasks become ready for execution. This makes their usage in embedded real-time systems uncommon. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 30 CHAPTER 2 2.4 Basic concepts Scheduling There are different algorithms that determine which task to execute, called schedulers. All schedulers have one thing in common: they distinguish between tasks that are ready to be executed (in the READY state) and other tasks that are suspended for some reason (delay, waiting for mailbox, waiting for semaphore, waiting for event, and so on). The scheduler selects one of the tasks in the READY state and activates it (executes the body of this task). The task which is currently executing is referred to as the running task. The main difference between schedulers is the way they distribute computation time between tasks in the READY state. 2.4.1 Round-robin scheduling algorithm With round-robin scheduling, the scheduler has a list of tasks and, when deactivating the running task, activates the next task that is in the READY state. Round-robin can be used with either preemptive or cooperative multitasking. It works well if you do not need to guarantee response time. Round-robin scheduling can be illustrated as follows: All tasks share the same priority; the possession of the CPU changes periodically after a predefined execution time. This time is called a time slice, and may be defined individually for every task. 2.4.2 Priority-controlled scheduling algorithm In real-world applications, different tasks require different response times. For example, in an application that controls a motor, a keyboard, and a display, the motor usually requires faster reaction time than the keyboard and display. While the display is being updated, the motor needs to be controlled. This makes preemptive multitasking essential. Round-robin might work, but because it cannot guarantee a specific reaction time, an improved algorithm should be used. In priority-controlled scheduling, every task is assigned a priority. Depending on these priorities, one task gets chosen for execution according to one simple rule: Note: The scheduler activates the task that has the highest priority of all tasks in the READY state. This means that every time a task with a priority higher than the running task becomes ready, it immediately becomes the running task, thus the previous task gets preempted. However, the scheduler can be switched off in sections of a program where task switches are prohibited, known as critical regions. embOS uses a priority-controlled scheduling algorithm with round-robin between tasks of identical priority. One hint at this point: round-robin scheduling is a nice feature because you do not need to decide whether one task is more important than another. Tasks with identical priority cannot block each other for longer than their time slices. But round-robin scheduling also costs time if two or more tasks of identical priority are ready and no task of higher priority is ready, because execution constantly switch between the identical-priority tasks. It is more efficient to assign a different priority to each task, which will avoid unnecessary task switches. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 31 2.4.3 Priority inversion / priority inheritance The rule the scheduler obeys is: Activate the task that has the highest priority of all tasks in the READY state. But what happens if the highest-priority task is blocked because it is waiting for a resource owned by a lower-priority task? According to the above rule, it would wait until the low-priority task is resumed and releases the resource. Up to this point, everything works as expected. Problems arise when a task with medium priority becomes ready during the execution of the higher prioritized task. When the higher priority task is suspended waiting for the resource, the task with the medium priority will run until it finishes its work, because it has a higher priority than the low-priority task. In this scenario, a task with medium priority runs in place of the task with high priority. This is known as priority inversion. With Priority Inversion Low priority task Medium priority task High priority task OS_Use() Interrupt activates high prio task OS_Use() OS_Delay() Time OS_Unuse() OS_Unuse() The low priority task claims the semaphore with OS_Use(). An interrupt activates the high priority task, which also calls OS_Use(). Meanwhile a task with medium priority becomes ready and runs when the high priority task is suspended. The task with medium priority eventually calls OS_Delay() and is therefore suspended. The task with lower priority now continues and calls OS_Unuse() to release the resource semaphore. After the low priority task releases the semaphore, the high priority task is activated and claims the semaphore. To avoid this situation, embOS temporarily raises the low-priority task to high priority until it releases the resource. This unblocks the task that originally had the highest priority and can now be resumed. This is known as priority inheritance. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 32 CHAPTER 2 Basic concepts With Priority Inheritance Low priority task Medium priority task High priority task OS_Use() Interrupt activates high prio task Priority inheritance Time OS_Use() OS_Unuse() OS_Unuse() With priority inheritance, the low priority task inherits the priority of the waiting high priority task as long as it holds the resource semaphore. The lower priority task is activated instead of the medium priority task when the high priority task tries to claim the semaphore. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 33 2.5 Communication between tasks In a multitasking (multithreaded) program, multiple tasks and ISRs work completely separately. Because they all work in the same application, it will sometimes be necessary for them to exchange information with each other. 2.5.1 Periodic polling The easiest way to communicate between different pieces of code is by using global variables. In certain situations, it can make sense for tasks to communicate via global variables, but most of the time this method has disadvantages. For example, if you want to synchronize a task to start when the value of a global variable changes, you must continually poll this variable, wasting precious computation time and energy, and the reaction time depends on how often you poll. 2.5.2 Event-driven communication mechanisms When multiple tasks work with each other, they often have to: * * * exchange data, synchronize with another task, or make sure that a resource is used by no more than one task at a time. For these purposes embOS offers mailboxes, queues, semaphores and events. 2.5.3 Mailboxes and queues A mailbox is a data buffer managed by the RTOS and is used for sending a message to a task. It works without conflicts even if multiple tasks and interrupts try to access the same mailbox simultaneously. embOS activates any task that is waiting for a message in a mailbox the moment it receives new data and, if necessary, switches to this task. A queue works in a similar manner, but handles larger messages than mailboxes, and each message may have an individual size. For more information, refer to the chapters Mailboxes on page 139 and Queues on page 159. 2.5.4 Semaphores Two types of semaphores are used for synchronizing tasks and to manage resources of any kind. The most common are resource semaphores, although counting semaphores are also used. For details and samples, refer to the chapters Resource semaphores on page 111 and Counting Semaphores on page 125. 2.5.5 Events A task can wait for a particular event without consuming any calculation time. The idea is as simple as it is convincing, there is no sense in polling if we can simply activate a task the moment the event it is waiting for occurs. This saves processor cycles and energy and ensures that the task can respond to the event without delay. Typical applications for events are those where a task waits for some data, a pressed key, a received command or character, or the pulse of an external real-time clock. For further details, refer to the chapters Task events on page 177 and Event objects on page 189. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 34 CHAPTER 2 2.6 Basic concepts How task switching works A real-time multitasking system lets multiple tasks run like multiple single-task programs, quasi-simultaneously, on a single CPU. A task consists of three parts in the multitasking world: * * * The program code, which typically resides in ROM A stack, residing in a RAM area that can be accessed by the stack pointer A task control block, residing in RAM. The task's stack has the same function as in a single-task system: storage of return addresses of function calls, parameters and local variables, and temporary storage of intermediate results and register values. Each task can have a different stack size. More information can be found in chapter Stacks on page 229. The task control block (TCB) is a data structure assigned to a task when it is created. The TCB contains status information for the task, including the stack pointer, task priority, current task status (ready, waiting, reason for suspension) and other management data. Knowledge of the stack pointer allows access to the other registers, which are typically stored (pushed onto) the stack when the task is created and each time it is suspended. This information allows an interrupted task to continue execution exactly where it left off. TCBs are only accessed by the RTOS. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 35 2.6.1 Switching stacks The following diagram demonstrates the process of switching from one stack to another. Task 0 Task n Stack Task Control block Stack Task Control block variables temp. storage ret. addresses CPU registers SP variables temp. storage ret. addresses CPU registers SP Free Stack area Free Stack area Scheduler CPU The scheduler deactivates the task to be suspended (Task 0) by saving the processor registers on its stack. It then activates the higher-priority task (Task n) by loading the stack pointer (SP) and the processor registers from the values stored on Task n's stack. Deactivating a task The scheduler deactivates the task to be suspended (Task 0) as follows: 1. 2. Save (push) the processor registers on the task's stack. Save the stack pointer in the Task Control Block. Activating a task The scheduler activates the higher-priority task (Task n) by performing the sequence in reverse order: 1. 2. Load (pop) the stack pointer (SP) from the Task Control Block. Load the processor registers from the values stored on Task n's stack. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 36 2.7 CHAPTER 2 Basic concepts Change of task status A task may be in one of several states at any given time. When a task is created, it is placed into the READY state. A task in the READY state is activated as soon as there is no other task in the READY state with higher priority. Only one task may be running at a time. If a task with higher priority becomes READY, this higher priority task is activated and the preempted task remains in the READY state. The running task may be delayed for or until a specified time; in this case it is placed into the WAITING state and the next-highest-priority task in the READY state is activated. The running task might need to wait for an event (or semaphore, mailbox or queue). If the event has not yet occurred, the task is placed into the waiting state and the next-highest-priority task in the READY state is activated. A non-existent task is one that is not yet available to embOS; it either has been terminated or was not created at all. The following illustration shows all possible task states and transitions between them. Not existing OS_CreateTask() OS_CreateTaskEx() OS_Terminate() Ready API class such as OS_Delay() OS_Wait_...() Scheduler Running API class such as OS_Signal...() or delay expiration Waiting UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 37 2.8 How the OS gains control When the CPU is reset, the special-function registers are set to their default values. After reset, program execution begins. The PC register is set to the start address defined by the start vector or start address (depending on the CPU). This start address is usually in a startup module shipped with the C compiler, and is sometimes part of the standard library. The startup code performs the following: * * * Loads the stack pointer(s) with the default values, which is for most CPUs the end of the defined stack segment(s) Initializes all data segments to their respective values Calls the main() function. The main() function is the part of your program which takes control immediately after the C startup. Normally, embOS works with the standard C startup module without any modification. If there are any changes required, they are documented in the CPU & Compiler Specifics manual of the embOS documentation. With embOS, the main() function is still part of your application program. Essentially, main() creates one or more tasks and then starts multitasking by calling OS_Start(). From this point, the scheduler controls which task is executed. Startup code main() OS_IncDI() OS_InitKern() OS_InitHW() Additional initialization code; creating at least one task. OS_Start() The main() function will not be interrupted by any of the created tasks because those tasks execute only following the call to OS_Start(). It is therefore usually recommended to create all or most of your tasks here, as well as your control structures such as mailboxes and semaphores. Good practice is to write software in the form of modules which are (up to a point) reusable. These modules usually have an initialization routine, which creates any required task(s) and control structures. A typical main() function looks similar to the following example: Example /************************************************************************** * * main * *************************************************************************** */ void main(void) { OS_IncDI(); OS_InitKern(); /* Initialize OS (should be first !) OS_InitHW(); /* Initialize Hardware for OS (in RtosInit.c) /* Call Init routines of all program modules which in turn will create /* the tasks they need ... (Order of creation may be important) MODULE1_Init(); MODULE2_Init(); MODULE3_Init(); MODULE4_Init(); MODULE5_Init(); OS_Start(); /* Start multitasking */ } */ */ */ */ With the call to OS_Start(), the scheduler starts the highest-priority task created in main(). Note that OS_Start() is called only once during the startup process and does not return. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 38 CHAPTER 2 2.9 Basic concepts Different builds of embOS embOS comes in different builds or versions of the libraries. The reason for different builds is that requirements vary during development. While developing software, the performance (and resource usage) is not as important as in the final version which usually goes as release build into the product. But during development, even small programming errors should be caught by use of assertions. These assertions are compiled into the debug build of the embOS libraries and make the code a little bigger (about 50%) and also slightly slower than the release or stack-check build used for the final product. This concept gives you the best of both worlds: a compact and very efficient build for your final product (release or stack-check build of the libraries), and a safer (though bigger and slower) build for development which will catch most common application programming errors. Of course, you may also use the release build of embOS during development, but it will not catch these errors. 2.9.1 Profiling embOS supports profiling in profiling builds. Profiling makes precise information available about the execution time of individual tasks. You may always use the profiling libraries, but they require larger task control blocks, additional ROM (approximately 200 bytes) and additional runtime overhead. This overhead is usually acceptable, but for best performance you may want to use non-profiling builds of embOS if you do not use this feature. 2.9.2 List of libraries In your application program, you need to let the compiler know which build of embOS you are using. This is done by defining a single identifier prior to including RTOS.h. Description Smallest fastest build. Stack check OS_LIBMODE_S X Stack check plus profiling OS_LIBMODE_SP X Debug OS_LIBMODE_D X X OS_LIBMODE_DP X X X OS_LIBMODE_DT X X X Debug plus profiling Debug including trace, profiling Task names OS_LIBMODE_R Round Robin Release Trace OS_LIBMODE_XR Profiling Extreme Release Stack check Define Debug code Name X X X X X X X X X X X X X X Small, fast build, normally used for release build of application. Same as release, plus stack checking. Same as stack check, plus profiling. Maximum runtime checking. Maximum runtime checking, plus profiling. Maximum runtime checking, plus tracing API calls and profiling. Table 2.1: List of libraries UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 39 2.9.3 embOS functions context Not all embOS functions can be called from every place in your application. We need to distinguish between Main (before the call of OS_Start() ), Task, ISR and Software timer. Please consult the embOS API tables to be sure that an embOS function is allowed to be called from your execution context, e.g. from an ISR. The embOS debug build helps you to check that you do not violate these rules. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 40 UM01001 User & Reference Guide for embOS CHAPTER 2 Basic concepts (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 41 Chapter 3 Working with embOS This chapter gives some recommendations on how to use embOS in your applications. These are simply recommendations that we feel are helpful when designing and structuring an application. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 42 CHAPTER 3 3.1 Working with embOS General advice - Avoid Round Robin if possible - Avoid dynamically creating and terminating tasks - Avoid nesting interrupts if possible 3.1.1 Timers or task For periodic jobs you can use either a task or a software timer. An embOS software timer has the advantage that it does not need its own task stack since it runs on the system stack. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 43 Chapter 4 Tasks This chapter explains some basic concepts related to tasks and embOS task API functions. It should be relatively easy to read and is recommended before moving to other chapters. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 44 CHAPTER 4 4.1 Tasks Introduction A task that should run under embOS needs a task control block (TCB), a stack, and a task body written in C. The following rules apply to task routines: * * * 4.1.1 The task routine can either not take parameters (void parameter list), in which case OS_CreateTask() is used to create it, or take a single void pointer as parameter, in which case OS_CreateTaskEx() is used to create it. The task routine must not return. The task routine must be implemented as an endless loop or it must terminate itself (see examples below). Example of a task routine as an endless loop /* Example of a task routine as an endless loop */ void Task1(void) { while(1) { DoSomething(); /* Do something */ OS_Delay(1); /* Give other tasks a chance */ } } 4.1.2 Example of a task routine that terminates itself /* Example of a task routine that terminates void Task2(void) { char DoSomeMore; do { DoSomeMore = DoSomethingElse(); /* Do something OS_Delay(1); /* Give other tasks a chance } while (DoSomeMore); OS_TerminateTask(0); /* Terminate yourself } */ */ */ */ There are different ways to create a task; embOS offers a simple macro that makes this easy and which is sufficient in most cases. However, if you are dynamically creating and deleting tasks, a function is available allowing "fine-tuning" of all parameters. For most applications, at least initially, using the macro as in the sample start project works fine. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 45 4.2 Cooperative vs. preemptive task switches In general, preemptive task switches are an important feature of an RTOS. Preemptive task switches are required to guarantee responsiveness of high-priority, timecritical tasks. However, it may be desireable to disable preemptive task switches for certain tasks in some circumstances. The default behavior of embOS is to always allow preemptive task switches. 4.2.1 Disabling preemptive task switches for tasks of equal priority In some situations, preemptive task switches between tasks running at identical priorities are not desireable. To inhibit time slicing of equal-priority tasks, the time slice of the tasks running at identical priorities must be set to zero as in the example below: #include "RTOS.h" #define PRIO_COOP 10 #define TIME_SLICE_NULL 0 OS_STACKPTR int StackHP[128], StackLP[128]; /* Task stacks */ OS_TASK TCBHP, TCBLP; /* Task-control-blocks */ /********************************************************************/ static void TaskEx(void * pData) { while (1) { OS_Delay ((OS_TIME) pData); } } /********************************************************************* * * main * *********************************************************************/ int main(void) { OS_IncDI(); /* Initially disable interrupts */ OS_InitKern(); /* initialize OS */ OS_InitHW(); /* initialize Hardware for OS */ /* You need to create at least one task before calling OS_Start() */ OS_CreateTaskEx(&TCBHP, "HP Task", PRIO_COOP, TaskEx, StackHP, sizeof(StackHP), TIME_SLICE_NULL, (void*) 50); OS_CreateTaskEx(&TCBLP, "LP Task", PRIO_COOP, TaskEx, StackLP, sizeof(StackLP), TIME_SLICE_NULL, (void*) 200); OS_Start(); /* Start multitasking */ return 0; } 4.2.2 Completely disabling preemptions for a task This is simple: The first line of code should be OS_EnterRegion() as shown in the following sample: void MyTask(void *pContext) { OS_EnterRegion(); /* Disable preemptive context switches */ while (1) { // Do something. In the code, make sure that you call a blocking // funtion periodically to give other tasks a chance to run. } } Note: This will entirely disable preemptive context switches from that particular task and will therefore affect the timing of higher-priority-tasks. Do not use this carelessly. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 46 CHAPTER 4 4.3 Tasks Extending the task context For some applications it might be useful or required to have individual data in tasks that are unique to the task. Local variables, declared in the task, are unique to the task and remain valid, even when the task is suspended and resumed again. When the same task function is used for multiple tasks, local variables in the task may be used, but cannot be initialized individually for every task. embOS offers different options to extend the task context. 4.3.1 Passing one parameter to a task during task creation Very often it is sufficient to have just one individual parameter passed to a task. Using the OS_CREATETASK_EX() or OS_CreateTaskEx() function to create a task allows passing a void-pointer to the task. The pointer may point to individual data, or may represent any data type that can be held within a pointer. 4.3.2 Extending the task context individually at runtime Sometimes it may be required to have an extended task context for individual tasks to store global data or special CPU registers such as floating-point registers in the task context. The standard libraries for file I/O, locale support and others may require task-local storage for specific data like errno and other variables. embOS enables extension of the task context for individual tasks during runtime by a call of OS_ExtendTaskContext(). The sample application file ExtendTaskContext.c delivered in the application samples folder of embOS demonstrates how the individual task context extension can be used. 4.3.3 Extending the task context by using own task structures When complex data is needed for an individual task context, the OS_CREATETASK_EX() or OS_CreateTaskEx() functions may be used, passing a pointer to individual data structures to the task. Alternatively you may define your own task structure which can be used. Note, that the first item in the task structure must be an embOS task control structure OS_TASK. This can be followed by any amount and type of additional data of different types. The following code shows the example application Start_Extended_OS_TASK.c which is delivered in the sample application folder of embOS. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 47 /********************************************************************* * SEGGER MICROCONTROLLER GmbH & Co KG * * Solutions for real time microcontroller applications * ********************************************************************** ---------------------------------------------------------------------File : Start_Extended_OS_TASK.c Purpose : Skeleton program for OS to demonstrate extended tasks -------- END-OF-HEADER --------------------------------------------*/ #include "RTOS.h" #include /****** Define an own task structure with extended task context *****/ typedef struct { OS_TASK Task; // OS_TASK must be the first element OS_TIME Timeout; // Any other data may follow char* pString; } MY_APP_TASK; /****** Variables ***************************************************/ OS_STACKPTR int StackHP[128], StackLP[128]; /* Task stacks */ MY_APP_TASK TCBHP, TCBLP; /* Task-control-blocks */ /********************************************************************* * * Task function */ static void MyTask(void) { char* pString; OS_TIME Delay; MY_APP_TASK* pThis; pThis = (MY_APP_TASK*) OS_GetTaskID(); while (1) { Delay = pThis->Timeout; pString = pThis->pString; printf(pString); OS_Delay (Delay); } } /*********************************************************************** * * main * ***********************************************************************/ int main(void) { OS_IncDI(); /* Initially disable interrupts */ OS_InitKern(); /* Initialize OS */ OS_InitHW(); /* Initialize Hardware for OS */ /* * Create the extended tasks just as normal tasks. * Note that the first paramater must be of type OS_TASK */ OS_CREATETASK(&TCBHP.Task, "HP Task", MyTask, 100, StackHP); OS_CREATETASK(&TCBLP.Task, "LP Task", MyTask, 50, StackLP); /* * Give task contexts individual data */ TCBHP.Timeout = 200; TCBHP.pString = "HP task running\n"; TCBLP.Timeout = 500; TCBLP.pString = "LP task running\n"; OS_Start(); /* Start multitasking */ return 0; } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 48 4.4 CHAPTER 4 Tasks API functions OS_AddOnTerminateHook() OS_CREATETASK() OS_CreateTask() OS_CREATETASK_EX() OS_CreateTaskEx() OS_Delay() OS_DelayUntil() OS_Delayus() OS_ExtendTaskContext() OS_GetpCurrentTask() OS_GetPriority() OS_GetSuspendCnt() OS_GetTaskID() OS_GetTaskName() OS_GetTimeSliceRem() OS_IsRunning() OS_IsTask() OS_Resume() OS_ResumeAllSuspendedTasks() OS_SetInitialSuspendCnt() OS_SetPriority() OS_SetTaskName() OS_SetTimeSlice() OS_Start() OS_Suspend() OS_SuspendAllTasks() Description Adds a hook (callback) function to the list of functions which are called when a task is terminated. Creates a task. Creates a task. Creates a task with parameter. Creates a task with parameter. Suspends the calling task for a specified period of time. Suspends the calling task until a specified time. Waits for the given time in microseconds Make global variables or processor registers task-specific. Returns a pointer to the task control block structure of the currently running task. Returns the priority of a specified task Returns the suspension count. Returns the ID of the currently running task. Returns the name of a task. Returns the remaining time slice time of a task. Exxamine whether OS_Start() was called. Determines whether a task control block actually belongs to a valid task. Decrements the suspend count of specified task and resumes the task, if the suspend count reaches zero. Decrements the suspend count of specified task and resumes the task, if the suspend count reaches zero. Sets an initial suspension count for newly created tasks. Assigns a specified priority to a specified task. Allows modification of a task name at runtime. Assigns a specified time slice value to a specified task. Start the embOS kernel. Suspends the specified task and increments a counter. Suspends all tasks except the running task. Timer ISR Task main Routine X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X Table 4.1: Task routine API list UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 49 OS_TerminateTask() OS_WakeTask() OS_Yield() Description Ends (terminates) a task. Ends delay of a task immediately. Calls the scheduler to force a task switch. Timer ISR Task main Routine X X X X X X Table 4.1: Task routine API list UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 50 CHAPTER 4 4.4.1 Tasks OS_AddOnTerminateHook() Description Adds a handler function to a list of functions that are called when a task is terminated. Prototype void OS_AddOnTerminateHook (OS_ON_TERMINATE_HOOK * pHook, OS_ON_TERMINATE_FUNC * pfUser); Parameter pHook pfUser Description Pointer to a variable of type OS_ON_TERMINATE_HOOK which will be inserted into the linked list of functions to be called during OS_TerminateTask(). Pointer to the function of type OS_TERMINATE_FUNC which shall be called when a task is terminated. Table 4.2: OS_AddOnTerminateHook() parameter list Additional Information For some applications, it may be useful to allocate memory or objects specific to tasks. For other applications, it may be useful to have task-specific information on the stack. When a task is terminated, the task-specific objects may become invalid. A callback function may be hooked into OS_TerminateTask() by calling OS_AddOnTerminateHook() to allow the application to invalidate all task-specific objects before the task is terminated. The callback function of type OS_ON_TERMINATE_FUNC receives the ID of the terminated task as its parameter. OS_ON_TERMINATE_FUNC is defined as: typedef void OS_ON_TERMINATE_FUNC(OS_CONST_PTR OS_TASK * pTask); Important The variable of type OS_ON_TERMINATE_HOOK must reside in memory as a global or static variable. It may be located on a task stack, as local variable, but it must not be located on any stack of any task that might be terminated. Example OS_ON_TERMINATE_HOOK _OnTerminateHook; /* Stack-space */ ... void OnTerminateHookFunc(OS_CONST_PTR OS_TASK * pTask) { // This function is called when OS_TerminateTask() is called. if (pTask == &MyTask) { free(MytaskBuffer); } } ... main(void) { OS_AddOnTerminateHook(&_OnTerminateHook, OnTerminateHookFunc); ... } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 51 4.4.2 OS_CREATETASK() Description Creates a task. Prototype void OS_CREATETASK ( OS_TASK * char * void * OS_PRIO void * Parameter pTask pName pRoutine Priority pStack pTask, pName, pRoutine, Priority, pStack); Description Pointer to a task control block structure. Pointer to the name of the task. Can be NULL (or 0) if not used. Pointer to a function that should run as the task body. Priority of the task. Must be within the following range: 1 <= Priority <= 2 8-1 = 0xFF for 8/16-bit CPUs 1 <= Priority <= 232-1 = 0xFFFFFFFF for 32-bit CPUs Higher values indicate higher priorities. The type OS_PRIO is defined as 32-bit value for 32-bit CPUs and 8-bit value for 8- or 16-bit CPUs by default. Pointer to an area of memory in RAM that will serve as stack area for the task. The size of this block of memory determines the size of the stack area. Table 4.3: OS_CREATETASK() parameter list Additional Information OS_CREATETASK() is a macro which calls an OS library function. It creates a task and makes it ready for execution by placing it into the READY state. The newly created task will be activated by the scheduler as soon as there is no other task with higher priority in the READY state. If there is another task with the same priority, the new task will be placed immediately before it. This macro is normally used for creating a task instead of the function call OS_CreateTask() because it has fewer parameters and is therefore easier to use. OS_CREATETASK() can be called either from main() during initialization or from any other task. The recommended strategy is to create all tasks during initialization in main() to keep the structure of your tasks easy to understand. The absolute value of Priority is of no importance, only the value in comparison to the priorities of other tasks matters. OS_CREATETASK() determines the size of the stack automatically, using sizeof(). This is possible only if the memory area has been defined at compile time. Important The stack that you define must reside in an area that the CPU can address as stack. Most CPUs cannot use the entire memory area as stack and require the stack to be aligned to a multiple of the processor word size. The task stack cannot be shared between multiple tasks and must be assigned to one task only. The memory used as task stack cannot be used for other purposes unless the task is terminated. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 52 CHAPTER 4 Tasks Example OS_STACKPTR int UserStack[150]; /* Stack-space */ OS_TASK UserTCB; /* Task-control-blocks */ void UserTask(void) { while (1) { Delay (100); } } void InitTask(void) { OS_CREATETASK(&UserTCB, "UserTask", UserTask, 100, UserStack); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 53 4.4.3 OS_CreateTask() Description Creates a task. Prototype void OS_CreateTask ( OS_TASK * char * OS_PRIO voidRoutine * void * unsigned unsigned char Parameter pTask pName Priority pRoutine pStack StackSize TimeSlice pTask, pName, Priority, pRoutine, pStack, StackSize, TimeSlice ); Description Pointer to a task control block structure. Pointer to the name of the task. Can be NULL (or 0) if not used. Priority of the task. Must be within the following range: 1 <= Priority <= 2 8-1 = 0xFF for 8/16-bit CPUs 1 <= Priority <= 232-1 = 0xFFFFFFFF for 32-bit CPUs Higher values indicate higher priorities. The type OS_PRIO is defined as a 32-bit value for 32-bit CPUs and as an 8-bit value for 8- or 16-bit CPUs by default. Pointer to a function that should run as the task body. Pointer to an area of memory in RAM that will serve as stack area for the task. The size of this block of memory determines the size of the stack area. Size of the stack in bytes. Time slice value for round-robin scheduling. Has an effect only if other tasks are running at the same priority. TimeSlice denotes the time in embOS timer ticks that the task will run before it suspends, thus enabling another task with the same priority. The time slice value must be in the following range: 0 <= TimeSlice <= 255. Table 4.4: OS_CreateTask() parameter list Additional Information This function works the same way as OS_CREATETASK(), except that all parameters of the task can be specified. The task can be dynamically created because the stack size is not calculated automatically as it is with the macro. A time slice value of zero is allowed and disables round-robin task switches (see sample in chapter Disabling preemptive task switches for tasks of equal priority on page 45). Important The stack that you define must reside in an area that the CPU can address as stack. Most CPUs cannot use the entire memory area as stack and require the stack to be aligned to a multiple of the processor word size. The task stack cannot be shared between multiple tasks and must be assigned to one task only. The memory used as task stack cannot be used for other purposes unless the task is terminated. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 54 CHAPTER 4 Tasks Example /* Demo-program to illustrate the use of OS_CreateTask */ OS_STACKPTR int StackMain[100], StackClock[50]; OS_TASK TaskMain,TaskClock; OS_SEMA SemaLCD; void Clock(void) { while(1) { /* Code to update the clock */ } } void Main(void) { while (1) { /* Your code */ } } void InitTask(void) { OS_CreateTask(&TaskMain, NULL, 50, Main, StackMain, sizeof(StackMain), 2); OS_CreateTask(&TaskClock, NULL, 100, Clock,StackClock,sizeof(StackClock),2); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 55 4.4.4 OS_CREATETASK_EX() Description Creates a task and passes a parameter to the task. Prototype void OS_CREATETASK_EX ( OS_TASK * char * void * OS_PRIO void * void * Parameter pTask pName pRoutine Priority pStack pContext pTask, pName, pRoutine, Priority, pStack, pContext ); Description Pointer to a task control block structure. Pointer to the name of the task. Can be NULL (or 0) if not used. Pointer to a function that should run as the task body. Priority of the task. Must be within the following range: 1 <= Priority <= 2 8-1 = 0xFF for 8/16-bit CPUs 1 <= Priority <= 232-1 = 0xFFFFFFFF for 32-bit CPUs Higher values indicate higher priorities. The type OS_PRIO is defined as a 32-bit value for 32-bit CPUs and an 8-bit value for 8- or 16-bit CPUs per default. Pointer to an area of memory in RAM that will serve as stack area for the task. The size of this block of memory determines the size of the stack area. Parameter passed to the created task function. Table 4.5: OS_CREATETASK_EX() parameter list Additional Information OS_CREATETASK_EX() is a macro calling an embOS library function. It works like OS_CREATETASK() but allows passing a parameter to the task. Using a void pointer as an additional parameter gives the flexibility to pass any kind of data to the task function. Example The following example is delivered in the Samples folder of embOS. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 56 CHAPTER 4 Tasks /*-----------------------------------------------------------------File : Main_TaskEx.c Purpose : Sample program for embOS using OC_CREATETASK_EX --------- END-OF-HEADER --------------------------------------------*/ #include "RTOS.h" OS_STACKPTR int StackHP[128], StackLP[128]; /* Task stacks */ OS_TASK TCBHP, TCBLP; /* Task-control-blocks */ /********************************************************************/ static void TaskEx(void* pVoid) { while (1) { OS_Delay ((OS_TIME) pVoid); } } /********************************************************************* * * main * *********************************************************************/ int main(void) { OS_IncDI(); /* Initially disable interrupts */ OS_InitKern(); /* initialize OS */ OS_InitHW(); /* initialize Hardware for OS */ /* You need to create at least one task before calling OS_Start() */ OS_CREATETASK_EX(&TCBHP, "HP Task", TaskEx, 100, StackHP, (void*) 50); OS_CREATETASK_EX(&TCBLP, "LP Task", TaskEx, 50, StackLP, (void*) 200); OS_SendString("Start project will start multitasking !\n"); OS_Start(); /* Start multitasking */ return 0; } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 57 4.4.5 OS_CreateTaskEx() Description Creates a task and passes a parameter to the task. Prototype void OS_CreateTaskEx ( OS_TASK * char * OS_PRIO voidRoutine * void * unsigned unsigned char void * Parameter pTask pName Priority pRoutine pStack StackSize TimeSlice pContext pTask, pName, Priority, pRoutine, pStack, StackSize, TimeSlice, pContext ); Description Pointer to a task control block structure. Pointer to the name of the task. Can be NULL (or 0) if not used. Priority of the task. Must be within the following range: 1 <= Priority <= 2 8-1 = 0xFF for 8/16-bit CPUs 1 <= Priority <= 232-1 = 0xFFFFFFFF for 32-bit CPUs Higher values indicate higher priorities. The type OS_PRIO is defined as a 32-bit value for 32-bit CPUs and an 8-bit value for 8- or 16-bit CPUs per default. Pointer to a function that should run as the task body. Pointer to an area of memory in RAM that will serve as stack area for the task. The size of this block of memory determines the size of the stack area. Size of the stack in bytes. Time slice value for round-robin scheduling. Has an effect only if other tasks are running at the same priority. TimeSlice denotes the time in embOS timer ticks that the task will run until it suspends; thus enabling another task with the same priority. The time slice value must be in the following range: 0 <= TimeSlice <= 255. Parameter passed to the created task. Table 4.6: OS_Create_TaskEx() parameter list Additional Information This function works the same way as OS_CreateTask() except that a parameter is passed to the task function. An example of parameter passing to tasks is shown under OS_CREATETASK_EX(). A time slice value of zero is allowed and disables round-robin task switches (see sample in chapter Disabling preemptive task switches for tasks of equal priority on page 45). Important The stack that you define must reside in an area that the CPU can address as stack. Most CPUs cannot use the entire memory area as stack and require the stack to be aligned to a multiple of the processor word size. The task stack cannot be shared between multiple tasks and must be assigned to one task only. The memory used as task stack cannot be used for other purposes unless the task is terminated. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 58 CHAPTER 4 4.4.6 Tasks OS_Delay() Description Suspends the calling task for a specified period of time. Prototype void OS_Delay (OS_TIME ms); Parameter ms Description Time interval to delay. Must be within the following range: 2 15 = 0x8000 <= ms <= 2 15-1 = 0x7FFF for 8/16-bit CPUs 2 31 = 0x80000000 <= ms <= 231-1 = 0x7FFFFFFF for 32-bit CPUs Please note that these are signed values. Table 4.7: OS_Delay() parameter list Additional Information The calling task is placed into the WAITING state for the period of time specified. The task will stay in the delayed state until the specified time has expired. OS_Delay() returns immediately if the parameter ms is less than or equal to zero. The parameter ms specifies the precise interval during which the task is suspended given in basic time intervals (usually 1/1000 seconds). The actual delay (in basic time intervals) will be in the following range: ms - 1 <= delay <= ms, depending on when the interrupt for the scheduler occurs. After the expiration of the delay, the task is made ready and activated according to the rules of the scheduler. A delay can be ended prematurely by another task or by an interrupt handler calling OS_WakeTask(). Example void Hello(void) { printf("Hello"); printf("The next output will occur in 5 seconds"); OS_Delay (5000); printf("Delay is over"); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 59 4.4.7 OS_DelayUntil() Description Suspends the calling task until a specified time. Prototype void OS_DelayUntil (OS_TIME t); Parameter t Description Time to delay until. Must be within the following range: 0 <= t <= 2 16 -1 = 0xFFFF = 65535 for 8/16-bit CPUs 0 <= t <= 2 32-1 = 0xFFFFFFFF for 32-bit CPUs and must meet the following additional condition 1 <= ( t - OS_Time) <= 2 15-1 = 0x7FFF = 32767 for 8/16-bit CPUs 1 <= ( t- OS_Time) <= 231-1 = 0x7FFFFFFF for 32-bit CPUs Table 4.8: OS_DelayUntil() parameter list Additional Information The calling task will be put into the WAITING state until the time specified. The OS_DelayUntil() function delays until the value of the time-variable OS_Time reaches a certain value. It is very useful to avoid accumulating delays. An embOS SysTick timer overflow is no problem as long as parameter t is within the specified range. Example int sec,min; void TaskShowTime(void) { OS_TIME t0; t0 = OS_GetTime(); while (1) { ShowTime(); t0 += 1000; OS_DelayUntil (t0); if (sec < 59) { sec++; } else { sec = 0; min++; } } } /* Routine to display time */ In the example above, using OS_Delay() could lead to accumulating delays and would cause the simple "clock" to be slow. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 60 CHAPTER 4 4.4.8 Tasks OS_Delayus() Description Waits for the given time in microseconds. Prototype void OS_Delayus (OS_U16 us); Parameter us Description Number of microseconds to delay. Must be within the following range: 1 <= us <= 2 15-1 = 0x7FFF = 32767 Table 4.9: OS_Delay() parameter list Additional Information This function can be used for short delays. OS_Delayus() must only be called with interrupts enabled and after OS_InitKern() and OS_InitHW() have been called. This only works when the embOS system timer is running. The embOS debug build of OS_Delayus() checks that interrupts are enabled, and if not then OS_Error() is called. OS_Delayus() does not block task switches and does not block interrupts. Therefore, the delay may not be accurate because the function may be interrupted for an undefined time. The delay duration therefore is a minimum delay. Example void Hello(void) { printf("Hello"); printf("The next output will occur in 500 microseconds"); OS_Delayus (500); printf("Delay is over"); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 61 4.4.9 OS_ExtendTaskContext() Description The function may be used for a variety of purposes. Typical applications are: * * * * global variables such as "errno" in the C library, making the C-lib functions thread-safe. additional, optional CPU / registers such as MAC / EMAC registers (multiply and accumulate unit) if they are not saved in the task context per default. Coprocessor registers such as registers of a VFP (floating-point coprocessor). Data registers of an additional hardware unit such as a CRC calculation unit This allows the user to extend the task context as required. A major advantage is that the task extension is task-specific. This means that the additional information (such as floating-point registers) needs to be saved only by tasks that actually use these registers. The advantage is that the task switching time of other tasks is not affected. The same is true for the required stack space: Additional stack space is required only for the tasks which actually save the additional registers. Prototype void OS_ExtendTaskContext(const OS_EXTEND_TASK_CONTEXT * pExtendContext); Parameter pExtendContext Description Pointer to the OS_EXTEND_TASK_CONTEXT structure which contains the addresses of the specific save and restore functions that save and restore the extended task context during task switches. Table 4.10: OS_ExtendTaskContext() parameter list Additional Information The OS_EXTEND_TASK_CONTEXT structure is defined as follows: typedef struct OS_EXTEND_TASK_CONTEXT { void (*pfSave) ( void * pStack); void (*pfRestore)(const void * pStack); } OS_EXTEND_TASK_CONTEXT; The save and restore functions must be declared according the function type used in the structure. The sample below shows how the task stack must be addressed to save and restore the extended task context. OS_ExtendTaskContext() is not available in the XR libraries. Important The task context can be extended only once per task. The function must not be called multple times for one task. Note that some ports of embOS use the mechanism of extending the task context for individual tasks for CPU or compiler-specific purposes such as storing floating-point registers or deliver a thread-local storage. In this case, the user cannot extend the task context using OS_ExtendTaskContext(). Extended tasks created by OS_CREATETASK_EX() or OS_CreateTaskEx() can still be used. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 62 CHAPTER 4 Tasks Example The following example is delivered in the Samples folder of embOS. /*-------------------------------------------------------------------File : ExtendTaskContext.c Purpose : Sample program for embOS demonstrating how to dynamically extend the task context. This example adds a global variable to the task context of certain tasks. -------- END-OF-HEADER ----------------------------------------------*/ #include "RTOS.h" OS_STACKPTR int StackHP[128], StackLP[128]; OS_TASK TCBHP, TCBLP; int GlobalVar; /* Task stacks */ /* Task-control-blocks */ /********************************************************************* * * _Restore * _Save * * Function description * This function pair saves and restores an extended task context. * In this case, the extended task context consists of just a single * member, which is a global variable. */ typedef struct { int GlobalVar; } CONTEXT_EXTENSION; static void _Save(void * pStack) { CONTEXT_EXTENSION * p; p = ((CONTEXT_EXTENSION*)pStack) - (1 - OS_STACK_AT_BOTTOM); // // Save all members of the structure // p->GlobalVar = GlobalVar; } static void _Restore(const void * pStack) { CONTEXT_EXTENSION * p; p = ((CONTEXT_EXTENSION*)pStack) - (1 - OS_STACK_AT_BOTTOM); // // Restore all members of the structure // GlobalVar = p->GlobalVar; } // Create pointer // Create pointer /********************************************************************* * * Global variable which holds the function pointers * to save and restore the task context. */ const OS_EXTEND_TASK_CONTEXT _SaveRestore = { _Save, _Restore }; /********************************************************************/ /********************************************************************* * * HPTask * * Function description * During the execution of this function, the thread-specific * global variable has always the same value of 1. */ static void HPTask(void) { OS_ExtendTaskContext(&_SaveRestore); GlobalVar = 1; while (1) { OS_Delay(10); } } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 63 /********************************************************************* * * LPTask * * Function description * During the execution of this function, the thread-specific * global variable has always the same value of 2. */ static void LPTask(void) { OS_ExtendTaskContext(&_SaveRestore); GlobalVar = 2; while (1) { OS_Delay(50); } } /********************************************************************* * * main */ int main(void) { OS_IncDI(); /* Initially disable interrupts */ OS_InitKern(); /* initialize OS */ OS_InitHW(); /* initialize Hardware for OS */ /* You need to create at least one task here ! */ OS_CREATETASK(&TCBHP, "HP Task", HPTask, 100, StackHP); OS_CREATETASK(&TCBLP, "LP Task", LPTask, 50, StackLP); OS_Start(); /* Start multitasking */ return 0; } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 64 CHAPTER 4 Tasks 4.4.10 OS_GetpCurrentTask() Description Returns a pointer to the task control block structure of the running task. Prototype OS_TASK* OS_GetpCurrentTask (void); Return value A pointer to the task control block structure. Additional Information This function may be used for determining which task is executing. This may be helpful if the reaction of any function depends on the currently running task. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 65 4.4.11 OS_GetPriority() Description Returns the priority of a specified task. Prototype OS_PRIO OS_GetPriority (const OS_TASK* pTask); Parameter pTask Description Pointer to a task control block structure. Table 4.11: OS_GetPriority() parameter list Return value Priority of the specified task (range 1 to 255). Additional Information If pTask is NULL, the function returns the priority of the currently running task. If pTask does not specify a valid task, the debug build of embOS calls OS_Error(). The release build of embOS cannot check the validity of pTask and may therefore return invalid values if pTask does not specify a valid task. Important This function must not be called from within an interrupt handler. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 66 CHAPTER 4 Tasks 4.4.12 OS_GetSuspendCnt() Description The function returns the suspension count and thus suspension state of the specified task. This function may be used to examine whether a task is suspended by previous calls of OS_Suspend(). Prototype unsigned char OS_GetSuspendCnt (const OS_TASK* pTask); Parameter pTask Description Pointer to a task control block structure. Table 4.12: OS_GetSuspendCnt() parameter list Return value Suspension count of the specified task. 0: Task is not suspended. >0: Task is suspended by at least one call of OS_Suspend(). Additional Information If pTask does not specify a valid task, the debug build of embOS calls OS_Error(). The release build of embOS cannot check the validity of pTask and may therefore return invalid values if pTask does not specify a valid task. When tasks are created and terminated dynamically, OS_IsTask() may be called prior to calling OS_GetSuspendCnt() to determine whether a task is valid. The returned value can be used to resume a suspended task by calling OS_Resume() as often as indicated by the returned value. Example /* Demo-function to illustrate the use of OS_GetSuspendCnt() */ void ResumeTask(OS_TASK* pTask) { unsigned char SuspendCnt; SuspendCnt = OS_GetSuspendCnt(pTask); while (SuspendCnt > 0) { OS_Resume(pTask); /* May cause a task switch */ SuspendCnt--; } } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 67 4.4.13 OS_GetTaskID() Description Returns a pointer to the task control block structure of the currently running task. This pointer is unique for the task and is used as a task Id. Prototype OS_TASK * OS_GetTaskID ( void ); Return value A pointer to the task control block. A value of 0 (NULL) indicates that no task is executing. Additional Information This function may be used for determining which task is executing. This may be helpful if the reaction of any function depends on the currently running task. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 68 CHAPTER 4 Tasks 4.4.14 OS_GetTaskName() Description Returns a pointer to the name of a task. Prototype const char* OS_GetTaskName(const OS_TASK* pTask); Parameter pTask Description Pointer to a task control block structure. Table 4.13: OS_GetTaskName() parameter list Return value A pointer to the name of the task. A value of 0 (NULL) indicates that the task has no name. Additional Information If pTask is NULL, the function returns the name of the running task. If not called from a task with a NULL pointer as parameter, the return value is "OS_Idle()". If pTask does not specify a valid task, the debug build of embOS calls OS_Error(). The release build of embOS cannot check the validity of pTask and may therefore return invalid values if pTask does not specify a valid task. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 69 4.4.15 OS_GetTimeSliceRem() Description Returns the remaining time slice value of a task. Prototype unsigned char OS_GetTimeSliceRem(const OS_TASK* pTask); Parameter pTask Description Pointer to a task control block structure. Table 4.14: OS_GetTimeSliceRem() parameter list Return value The remaining time slice value of the task. Additional Information If pTask is NULL, the function returns the remaining time slice of the running task. If not called from a task with a NULL pointer as parameter, or if pTask does not specify a valid task, the debug build of embOS calls OS_Error(). The release build of embOS cannot check the validity of pTask and may therefore return invalid values if pTask does not specify a valid task. The function is unavailable when using an embOS build without round-robin support. The embOS eXtreme release libraries do not support round robin. Furthermore, when embOS is recompiled with OS_RR_SUPPORTED set to 0, the function will not be available. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 70 CHAPTER 4 Tasks 4.4.16 OS_IsRunning() Description Determines whether the embOS scheduler was started by a call of OS_Start(). Prototype unsigned char OS_IsRunning (void); Return value Character value: 0: Scheduler is not started. !=0: Scheduler is running, OS_Start() has been called. Additional Information This function may be helpful for some functions which might be called from main() or from running tasks. As long as the scheduler is not started and a function is called from main(), blocking task switches are not allowed. A function which may be called from a task or main() may use OS_IsRunning() to determine whether a blocking task switch is allowed. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 71 4.4.17 OS_IsTask() Description Determines whether a task control block belongs to a valid task. Prototype char OS_IsTask (const OS_TASK* pTask); Parameter pTask Description Pointer to a task control block structure. Table 4.15: OS_IsTask() parameter list Return value Character value: 0: TCB is not used by any task 1: TCB is used by a task Additional Information This function checks if the specified task is present in the internal task list. When a task is terminated it is removed from the internal task list. In applications that create and terminate tasks dynamically, this function may be useful to determine whether the task control block and stack for one task may be reused for another task. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 72 CHAPTER 4 Tasks 4.4.18 OS_Resume() Description Decrements the suspend count of the specified task and resumes it if the suspend count reaches zero. Prototype void OS_Resume (OS_TASK* pTask); Parameter pTask Description Pointer to a task control block structure. Table 4.16: OS_Resume() parameter list Additional Information The specified task's suspend count is decremented. When the resulting value is zero, the execution of the specified task is resumed. If the task is not blocked by other task blocking mechanisms, the task is placed in the READY state and continues operation according to the rules of the scheduler. In debug builds of embOS, OS_Resume() checks the suspend count of the specified task. If the suspend count is zero when OS_Resume() is called, OS_Error() is called with error OS_ERR_RESUME_BEFORE_SUSPEND. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 73 4.4.19 OS_ResumeAllSuspendedTasks() Description Decrements the suspend count of all tasks that have a nonzero suspend count and resumes these tasks when their respective suspend count reaches zero. Prototype void OS_ResumeAllSuspendedTasks (void); Additional Information This function may be helpful to synchronize or start multiple tasks at the same time. The function resumes all tasks, no specific task must be addressed. The function may be used together with the functions OS_SuspendAllTasks() and OS_SetInitialSuspendCnt(). The function may cause a task switch when a task with higher priority than the calling task is resumed. The task switch will be executed after all suspended tasks are resumed. As this is a non-blocking function, the function may be called from all contexts, main, ISR or timer. The function may be called even if no task is suspended. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 74 CHAPTER 4 Tasks 4.4.20 OS_SetInitialSuspendCnt() Description Sets the initial suspend count for newly created tasks to one. May be used to create tasks which are initially suspended. Prototype void OS_SetInitialSuspendCnt (unsigned char SuspendCnt); Parameter SuspendCnt Description != 0: Tasks will be created in suspended state. = 0: Tasks will be created normally without suspension. Table 4.17: OS_SetInitialSuspendCnt() parameter list Additional Information Can be called at any time from main(), any task, ISR or software timer. After calling this function with nonzero SuspendCnt, all newly created tasks will be automatically suspended with a suspend count of one. This function may be used to inhibit further task switches, which may be useful during system initailization. Important When this function is called from main() to initialize all tasks in suspended state, at least one task must be resumed before the system is started by a call of OS_Start(). The initial suspend count should be reset to allow normal creation of tasks before the system is started. Example /* Sample to demonstrate the use of OS_SetInitialSuspendCnt */ void InitTask(void) { // // High priority task started first after OS_Start(). // OS_SuspendAllTasks(); // Ensure no other existing task can run. OS_SetInitialSuspendCnt(1); // Ensure no newly created task will run. // // Perform application initialization. // ... // New tasks may be created but cannot start. ... // Even when InitTask() blocks itself by a delay, no other task will run. OS_SetInitialSuspendCnt(0); // Reset the initial suspend count for tasks. // // Resume all tasks that were blocked before or were created in suspended state. // OS_ResumeAllSuspendedTasks(); while (1) { ... // Do the normal work. } } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 75 4.4.21 OS_SetPriority() Description Assigns a priority to a specified task. Prototype void OS_SetPriority (OS_TASK* pTask, OS_PRIO Priority); Parameter pTask Priority Description Pointer to a task control block structure. Priority of the task. Must be within the following range: 1 <= Priority <= 2 8-1 = 0xFF for 8/16-bit CPUs 1 <= Priority <= 232-1 = 0xFFFFFFFF for 32-bit CPUs Higher values indicate higher priorities. The type OS_PRIO is defined as 32-bit value for 32-bit CPUs and 8-bit value for 8- or 16-bit CPUs per default. Table 4.18: OS_SetPriority() parameter list Additional Information Can be called at any time from any task or software timer. Calling this function might lead to an immediate task switch. Important This function must not be called from within an interrupt handler. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 76 CHAPTER 4 Tasks 4.4.22 OS_SetTaskName() Description Allows modification of a task name at runtime. Prototype void OS_SetTaskName (OS_TASK* pTask, const char* s); Parameter pTask s Description Pointer to a task control block structure. Pointer to a zero terminated string which is used as task name. Table 4.19: OS_SetTaskName() parameter list Additional Information Can be called at any time from any task or software timer. When pTask is NULL, the name of the currently running task is modified. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 77 4.4.23 OS_SetTimeSlice() Description Assigns a time slice period to a specified task. Prototype unsigned char OS_SetTimeSlice (OS_TASK* pTask, unsigned char TimeSlice); Parameter pTask TimeSlice Description Pointer to a task control block structure. New time slice period for the task. Must be within the following range: 0 <= TimeSlice <= 255. Table 4.20: OS_SetTimeSlice() parameter list Return value Previous time slice period of the task. Additional Information Can be called at any time from any task or software timer. Setting the time slice period only affects tasks running in round-robin mode. This means another task with the same priority must exist. The new time slice period is interpreted as a reload value. It is used after the next activation of the task. It does not affect the remaining time slice of a running task. A time slice value of zero is allowed, but disables round-robin task switches (see Disabling preemptive task switches for tasks of equal priority on page 45). UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 78 CHAPTER 4 Tasks 4.4.24 OS_Start() Description Starts the embOS scheduler. Prototype void OS_Start (void); Additional Information This function starts the embOS scheduler and should be the last function called from main(). * * * * * OS_Start() marks embOS as running. The running state can be examined by a call of the function OS_IsRunning(). OS_Start() will activate and start the task with the highest priority. OS_Start() automatically enables interrupts. OS_Start() does not return. OS_Start() must not be called from a task, from an interrupt or an embOS timer, and must be called from main() only once. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 79 4.4.25 OS_Suspend() Description Suspends the specified task. Prototype void OS_Suspend (OS_TASK* pTask); Parameter pTask Description Pointer to a task control block structure. Table 4.21: OS_Suspend() parameter list Additional Information If pTask is NULL, the current task suspends. If the function succeeds, execution of the specified task is suspended and the task's suspend count is incremented. The specified task will be suspended immediately. It can only be restarted by a call of OS_Resume(). Every task has a suspend count with a maximum value of OS_MAX_SUSPEND_CNT. If the suspend count is greater than zero, the task is suspended. In debug builds of embOS, upon calling OS_Suspend() more often than the maximum value without calling OS_Resume() the task's internal suspend count is not incremented and OS_Error() is called with error OS_ERR_SUSPEND_TOO_OFTEN. Cannot be called from an interrupt handler or timer as this function may cause an immediate task switch. The debug build of embOS will call the OS_Error() function when OS_Suspend() is called from an interrupt handler. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 80 CHAPTER 4 Tasks 4.4.26 OS_SuspendAllTasks() Description Suspends all tasks except the running task. Prototype void OS_SuspendAllTasks (void); Additional Information This function may be used to inhibit task switches. It may be useful during application initialization or supervising. The calling task will not be suspended. After calling OS_SuspendAllTasks(), the calling task may block or suspend itself. No other task will be activated unless one or more tasks are resumed again. The tasks may be resumed individually by a call of OS_Resume() or all at once by a call of OS_ResumeAllSuspendedTasks(). Example /* Sample to demonstrate the use of OS_SuspendAllTasks */ void InitTask(void) { // // High priority task started first after OS_Start(). // OS_SuspendAllTasks(); // Ensure no other existing task can run. OS_SetInitialSuspendCnt(1); // Ensure no newly created task will run. // // Perform application initialization. // ... // New tasks may be created but cannot start. ... // Even when InitTask() blocks itself by a delay, no other task will run. OS_SetInitialSuspendCnt(0); // Reset the initial suspend count for tasks. // // Resume all tasks that were blocked before or were created in suspended state. // OS_ResumeAllSuspendedTasks(); while (1) { ... // Do the normal work. } } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 81 4.4.27 OS_TerminateTask() Description Ends (terminates) a task. Prototype void OS_TerminateTask (OS_TASK* pTask); Parameter pTask Description Pointer to a task control block structure. Table 4.22: OS_Terminate() parameter list Additional Information If pTask is NULL, the current task terminates. The specified task will terminate immediately. The memory used for stack and task control block can be reassigned. Since version 3.26 of embOS, all resources which are held by a task are released upon its termination. Any task may be terminated regardless of its state. This functionality is default for any 16-bit or 32-bit CPU and may be changed by recompiling embOS sources. On 8-bit CPUs, terminating tasks that hold any resources such as semaphores, which may block other tasks, is prohibited. Since embOS version 3.82u, OS_TerminateTask() replaces the deprecated function OS_Terminate(), which may still be used. Important This function must not be called from within an interrupt handler. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 82 CHAPTER 4 Tasks 4.4.28 OS_WakeTask() Description Ends delay of a specified task immediately. Prototype void OS_WakeTask (OS_TASK* pTask); Parameter pTask Description Pointer to a task control block structure. Table 4.23: OS_WakeTask() parameter list Additional Information Places the specified task, which is already suspended for a certain amount of time by a call of OS_Delay() or OS_DelayUntil(), back into the READY state. The specified task will be activated immediately if it has a higher priority than the task that had the highest priority before. If the specified task is not in the WAITING state (because it has already been activated, or the delay has already expired, or for some other reason), calling this function has no effect. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 83 4.4.29 OS_Yield() Description Calls the scheduler to force a task switch. Prototype void OS_Yield (void); Additional Information If the task is running round-robin, it will be suspended if there is another task with equal priority ready for execution. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 84 UM01001 User & Reference Guide for embOS CHAPTER 4 Tasks (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 85 Chapter 5 Software timers UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 86 5.1 CHAPTER 5 Software timers Introduction A software timer is an object that calls a user-specified routine after a specified delay. An unlimited number of software timers can be defined with the macro OS_CREATETIMER(). Timers can be stopped, started and retriggered much like hardware timers. When defining a timer, you specify a routine to be called after the expiration of the delay. Timer routines are similar to interrupt routines: they have a priority higher than the priority of any task. For that reason they should be kept short just like interrupt routines. Software timers are called by embOS with interrupts enabled, so they can be interrupted by any hardware interrupt. Generally, timers run in single-shot mode, which means they expire exctly once and call their callback routine exactly once. By calling OS_RetriggerTimer() from within the callback routine, the timer is restarted with its initial delay time and therefore functions as a periodic timer. The state of timers can be checked by the functions OS_GetTimerStatus(), OS_GetTimerValue() and OS_GetTimerPeriod(). Maximum timeout / period The timeout value is stored as an integer, thus a 16-bit value on 8/16-bit CPUs, a 32bit value on 32-bit CPUs. The comparisons are done as signed comparisons because expired time-outs are permitted. This means that only 15 bits can be used on 8/16 bit CPUs, 31-bits on 32-bit CPUs. Another factor to take into account is the maximum time spent in critical regions. Timers may expire during critical regions, but because the timer routine cannot be called from a critical region (timers are "put on hold"), the maximum time that the system continuously spends in a critical region needs to be deducted. In most systems, this is no more than a single tick. However, to be safe, we have assumed that your system spends no more than a maximum of 255 consecutive ticks in a critical region and defined a macro which defines the maximum timeout value. This macro, OS_TIMER_MAX_TIME, defaults to 0x7F00 on 8/16-bit systems and to 0x7FFFFF00 on 32-bit Systems as defined in RTOS.h. If your system spends more than 255 consecutive ticks in a critical section, effectively disabling the scheduler during this time (which is not recommended), you must make sure your application uses shorter timeouts. Extended software timers Sometimes it may be useful to pass a parameter to the timer callback function. This allows the callback function to be shared between different software timers. Since version 3.32m of embOS, the extended timer structure and related extended timer functions were implemented to allow parameter passing to the callback function. Except for the different callback function with parameter passing, extended timers behave exactly the same as regular embOS software timers and may be used in parallel with these. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 87 5.2 API functions OS_CREATETIMER() OS_CreateTimer() OS_StartTimer() OS_StopTimer() OS_RetriggerTimer() OS_SetTimerPeriod() OS_DeleteTimer() OS_GetTimerPeriod() OS_GetTimerValue() OS_GetTimerStatus() OS_GetpCurrentTimer() OS_CREATETIMER_EX() OS_CreateTimerEx() OS_StartTimerEx() OS_StopTimerEx() OS_RetriggerTimerEx() OS_SetTimerPeriodEx() OS_DeleteTimerEx() OS_GetTimerPeriodEx() OS_GetTimerValueEx() OS_GetTimerStatusEx() OS_GetpCurrentTimerEx() Description Macro that creates and starts a softwaretimer. Creates a software timer without starting it. Starts a software timer. Stops a software timer. Restarts a software timer with its initial time value. Sets a new timer reload value for a software timer. Stops and deletes a software timer. Returns the current reload value of a software timer. Returns the remaining timer value of a software timer. Returns the current timer status of a software timer. Returns a pointer to the data structure of the timer that just expired. Macro that creates and starts an extended software-timer. Creates an extended software timer without starting it. Starts an extended timer. Stops an extended timer. Restarts an extended timer with its initial time value. Sets a new timer reload value for an extended timer. Stops and deletes an extended timer. Returns the current reload value of an extended timer. Returns the remaining timer value of an extended timer. Returns the current timer status of an extended timer. Returns a pointer to the data structure of the extended timer that just expired. Timer ISR Task main Routine X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X Table 5.1: Software timers API UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 88 CHAPTER 5 5.2.1 Software timers OS_CREATETIMER() Description Macro that creates and starts a software timer. Prototype void OS_CREATETIMER (OS_TIMER* pTimer, OS_TIMERROUTINE* Callback, OS_TIME Timeout); Parameter pTimer Callback Timeout Description Pointer to the OS_TIMER data structure which contains the data of the timer. Pointer to the callback routine to be called by the RTOS after expiration of the delay. The callback function must be a void function which does not take any parameter and does not return any value. Initial timeout in basic embOS time units (nominal ms): The data type OS_TIME is defined as an integer, therefore valid values are 1 <= Timeout <= 2 15-1 = 0x7FFF = 32767 for 8/16-bit CPUs 1 <= Timeout <= 2 31-1 = 0x7FFFFFFF for 32-bit CPUs Table 5.2: OS_CREATETIMER() parameter list Additional Information embOS keeps track of the timers by using a linked list. Once the timeout is expired, the callback routine will be called immediately (unless the current task is in a critical region or has interrupts disabled). This deprecated macro uses the functions OS_CreateTimer() and OS_StartTimer(). It is supplied for backward compatibility; in newer applications these routines should instead be called directly. OS_TIMERROUTINE is defined in RTOS.h as follows: typedef void OS_TIMERROUTINE(void); Source of the macro (in RTOS.h): #define OS_CREATETIMER(pTimer, c, d) \ OS_CreateTimer(pTimer, c, d); \ OS_StartTimer(pTimer); Example OS_TIMER TIMER100; void Timer100(void) { LED = LED ? 0 : 1; OS_RetriggerTimer(&TIMER100); } /* Toggle LED */ /* Make timer periodic */ void InitTask(void) { /* Create and start Timer100 */ OS_CREATETIMER(&TIMER100, Timer100, 100); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 89 5.2.2 OS_CreateTimer() Description Creates a software timer (but does not start it). Prototype void OS_CreateTimer (OS_TIMER* pTimer, OS_TIMERROUTINE* Callback, OS_TIME Timeout); Parameter pTimer Callback Timeout Description Pointer to the OS_TIMER data structure which contains the data of the timer. Pointer to the callback routine to be called by the RTOS after expiration of the delay. Initial timeout in basic embOS time units (nominal ms): The data type OS_TIME is defined as an integer, therefore valid values are 1 <= Timeout <= 215-1 = 0x7FFF = 32767 for 8/16-bit CPUs 1 <= Timeout <= 231-1 = 0x7FFFFFFF for 32-bit CPUs Table 5.3: OS_CreateTimer() parameter list Additional Information embOS keeps track of the timers by using a linked list. Once the timeout is expired, the callback routine will be called immediately (unless the current task is in a critical region or has interrupts disabled). The timer is not automatically started. This must be done explicitly by a call of OS_StartTimer() or OS_RetriggerTimer(). OS_TIMERROUTINE is defined in RTOS.h as follows: typedef void OS_TIMERROUTINE(void); Example OS_TIMER TIMER100; void Timer100(void) { LED = LED ? 0 : 1; OS_RetriggerTimer(&TIMER100); } /* Toggle LED */ /* Make timer periodic */ void InitTask(void) { /* Create Timer100, start it elsewhere */ OS_CreateTimer(&TIMER100, Timer100, 100); OS_StartTimer(&TIMER100); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 90 CHAPTER 5 5.2.3 Software timers OS_StartTimer() Description Starts a software timer. Prototype void OS_StartTimer (OS_TIMER* pTimer); Parameter pTimer Description Pointer to the OS_TIMER data structure which contains the data of the timer. Table 5.4: OS_StartTimer() parameter list Additional Information OS_StartTimer() is used for the following reasons: * * Start a timer which was created by OS_CreateTimer(). The timer will start with its initial timer value. Restart a timer which was stopped by calling OS_StopTimer(). In this case, the timer will continue with the remaining time value which was preserved by stopping the timer. Important This function has no effect on running timers. It also has no effect on timers that are not running, but have expired: use OS_RetriggerTimer() to restart those timers. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 91 5.2.4 OS_StopTimer() Description Stops a software timer. Prototype void OS_StopTimer (OS_TIMER* pTimer); Parameter pTimer Description Pointer to the OS_TIMER data structure which contains the data of the timer. Table 5.5: OS_StopTimer() parameter list Additional Information The actual value of the timer (the time until expiration) is maintained until OS_StartTimer() lets the timer continue. The function has no effect on timers that are not running, but have expired. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 92 CHAPTER 5 5.2.5 Software timers OS_RetriggerTimer() Description Restarts a software timer with its initial time value. Prototype void OS_RetriggerTimer (OS_TIMER* pTimer); Parameter pTimer Description Pointer to the OS_TIMER data structure which contains the data of the timer. Table 5.6: OS_RetriggerTimer() parameter list Additional Information OS_RetriggerTimer() restarts the timer using the initial time value programmed at creation of the timer or with the function OS_SetTimerPeriod(). OS_RetriggerTimer() can be called regardless the state of the timer. A running timer will continue using the full initial time. A timer that was stopped before or had expired will be restarted. Example OS_TIMER TIMERCursor; BOOL CursorOn; void TimerCursor(void) { if (CursorOn) ToggleCursor(); /* Invert character at cursor-position */ OS_RetriggerTimer(&TIMERCursor); /* Make timer periodic */ } void InitTask(void) { /* Create and start TimerCursor */ OS_CREATETIMER(&TIMERCursor, TimerCursor, 500); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 93 5.2.6 OS_SetTimerPeriod() Description Sets a new timer reload value for a software timer. Prototype void OS_SetTimerPeriod (OS_TIMER* pTimer, OS_TIME Period); Parameter pTimer Period Description Pointer to the OS_TIMER data structure which contains the data of the timer. Timer period in basic embOS time units (nominal ms): The data type OS_TIME is defined as an integer, therefore valid values are 1 <= Timeout <= 215-1 = 0x7FFF = 32767 for 8/16-bit CPUs 1 <= Timeout <= 231-1 = 0x7FFFFFFF for 32-bit CPUs Table 5.7: OS_SetTimerPeriod() parameter list Additional Information OS_SetTimerPeriod() sets the initial time value of the specified timer. Period is the reload value of the timer to be used as initial value when the timer is retriggered by OS_RetriggerTimer(). Example OS_TIMER TIMERPulse; void TimerPulse(void) { TogglePulseOutput(); /* Toggle output */ OS_RetriggerTimer(&TIMERPulse); /* Make timer periodic */ } void InitTask(void) { /* Create and start Pulse Timer with first pulse = 500ms */ OS_CREATETIMER(&TIMERPulse, TimerPulse, 500); /* Set timer period to 200 ms for further pulses */ OS_SetTimerPeriod(&TIMERPulse, 200); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 94 CHAPTER 5 5.2.7 Software timers OS_DeleteTimer() Description Stops and deletes a software timer. Prototype void OS_DeleteTimer (OS_TIMER* pTimer); Parameter pTimer Description Pointer to the OS_TIMER data structure which contains the data of the timer. Table 5.8: OS_DeleteTimer() parameter list Additional Information The timer is stopped and therefore removed from the linked list of running timers. In debug builds of embOS, the timer is also marked as invalid. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 95 5.2.8 OS_GetTimerPeriod() Description Returns the current reload value of a software timer. Prototype OS_TIME OS_GetTimerPeriod (const OS_TIMER* pTimer); Parameter pTimer Description Pointer to the OS_TIMER data structure which contains the data of the timer. Table 5.9: OS_GetTimerPeriod() parameter list Return value Type OS_TIME, which is defined as an integer between 1 and 2 15-1 = 0x7FFF = 32767 for 8/16-bit CPUs and as an integer between 1 and <= 231-1 = 0x7FFFFFFF for 32-bit CPUs, which is the permitted range of timer values. Additional Information The period returned is the reload value of the timer which was set as initial value when the timer was created or which was modified by a call of OS_SetTimerPeriod(). This reload value will be used as time period when the timer is retriggered by OS_RetriggerTimer(). UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 96 CHAPTER 5 5.2.9 Software timers OS_GetTimerValue() Description Returns the remaining timer value of a software timer. Prototype OS_TIME OS_GetTimerValue (const OS_TIMER* pTimer); Parameter pTimer Description Pointer to the OS_TIMER data structure which contains the data of the timer. Table 5.10: OS_GetTimerValue() parameter list Return value Type OS_TIME, which is defined as an integer between 1 and 2 15-1 = 0x7FFF = 32767 for 8/16-bit CPUs and as an integer between 1 and <= 2 31 -1 = 0x7FFFFFFF for 32-bit CPUs, which is the permitted range of timer values. The returned timer value is the remaining timer time in embOS tick units until expiration of the timer. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 97 5.2.10 OS_GetTimerStatus() Description Returns the current timer status of a software timer. Prototype unsigned char OS_GetTimerStatus (const OS_TIMER* pTimer); Parameter pTimer Description Pointer to the OS_TIMER data structure which contains the data of the timer. Table 5.11: OS_GetTimerStatus parameter list Return value Denotes whether the specified timer is running or not: 0: timer has stopped ! = 0: timer is running. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 98 CHAPTER 5 Software timers 5.2.11 OS_GetpCurrentTimer() Description Returns a pointer to the data structure of the timer that just expired. Prototype OS_TIMER* OS_GetpCurrentTimer (void); Return value A pointer to the control structure of a timer. Additional Information The return value of OS_GetpCurrentTimer() is valid during execution of a timer callback function; otherwise it is undefined. If only one callback function should be used for multiple timers, this function can be used for examining the timer that expired. The example below shows one usage of OS_GetpCurrentTimer(). Since version 3.32m of embOS, the extended timer structure and functions may be used to generate and use a software timer with an individual parameter for the callback function. Please be aware that OS_TIMER must be the first member of the structure. Example #include "RTOS.H" /********************************************************** * * Types */ typedef struct { /* Timer object with its own user data */ OS_TIMER Timer; /* OS_TIMER must be the first element */ void* pUser; } TIMER_EX; /********************************************************** * * Variables */ TIMER_EX Timer_User; int a; /********************************************************** * * Local Functions */ static void _CreateTimer(TIMER_EX* timer, OS_TIMERROUTINE* Callback, OS_UINT Timeout, void* pUser) { timer->pUser = pUser; OS_CreateTimer(&timer->Timer, Callback, Timeout); } /* Timer callback function for multiple timers */ static void _cb(void) { TIMER_EX* p = (TIMER_EX*)OS_GetpCurrentTimer(); void* pUser = p->pUser; /* Examine user data */ OS_RetriggerTimer(&p->Timer); /* Retrigger timer */ } /********************************************************** * * main */ int main(void) { OS_InitKern(); /* Initialize OS */ OS_InitHW(); /* Initialize Hardware for OS */ _CreateTimer(&Timer_User, _cb, 100, &a); OS_Start(); /* Start multitasking */ return 0; } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 99 5.2.12 OS_CREATETIMER_EX() Description Macro that creates and starts an extended software timer. Prototype void OS_CREATETIMER_EX (OS_TIMER_EX* OS_TIMER_EX_ROUTINE* OS_TIME void* Parameter pTimerEx Callback Timeout pData pTimerEx, Callback, Timeout pData) Description Pointer to the OS_TIMER_EX data structure which contains the data of the extended software timer. Pointer to the callback routine to be called by the RTOS after expiration of the delay. The callback function must be of type OS_TIMER_EX_ROUTINE which takes a void pointer as parameter and does not return any value. Initial timeout in basic embOS time units (nominal ms): The data type OS_TIME is defined as an integer, therefore valid values are 1 <= Timeout <= 215-1 = 0x7FFF = 32767 for 8/16-bit CPUs 1 <= Timeout <= 231-1 = 0x7FFFFFFF for 32-bit CPUs A void pointer which is used as parameter for the extended timer callback function. Table 5.12: OS_CREATETIMER_EX() parameter list Additional Information embOS keeps track of the timers by using a linked list. Once the timeout is expired, the callback routine will be called immediately (unless the current task is in a critical region or has interrupts disabled). This macro uses the functions OS_CreateTimerEx() and OS_StartTimerEx(). OS_TIMER_EX_ROUTINE is defined in RTOS.h as follows: typedef void OS_TIMER_EX_ROUTINE(void* pVoid); Source of the macro (in RTOS.h): #define OS_CREATETIMER_EX(pTimerEx, cb, Timeout, pData) OS_CreateTimerEx(pTimerEx, cb, Timeout, pData); OS_StartTimerEx(pTimerEx) \ \ Example OS_TIMER_EX TIMER100; OS_TASK TCB_HP; void Timer100(void* pTask) { LED = LED ? 0 : 1; /* Toggle LED */ if (pTask != NULL) { OS_SignalEvent(0x01, (OS_TASK*)pVoid); } OS_RetriggerTimerEx(&TIMER100); /* Make timer periodic */ } void InitTask(void) { /* Create and start Timer100 */ OS_CREATETIMER_EX(&TIMER100, Timer100, 100, (void*) &TCB_HP); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 100 CHAPTER 5 Software timers 5.2.13 OS_CreateTimerEx() Description Creates an extended software timer (but does not start it). Prototype void OS_CreateTimerEx (OS_TIMER_EX* OS_TIMER_EX_ROUTINE* OS_TIME void* Parameter pTimerEx Callback Timeout pData pTimerEx, Callback, Timeout, pData) Description Pointer to the OS_TIMER_EX data structure which contains the data of the extended software timer. Pointer to the callback routine of type OS_TIMER_EX_ROUTINE to be called by the RTOS after expiration of the timer. Initial timeout in basic embOS time units (nominal ms): The data type OS_TIME is defined as an integer, therefore valid values are 1 <= Timeout <= 2 15-1 = 0x7FFF = 32767 for 8/16-bit CPUs 1 <= Timeout <= 2 31-1 = 0x7FFFFFFF for 32-bit CPUs A void pointer which is used as parameter for the extended timer callback function. Table 5.13: OS_CreateTimerEx() parameter list Additional Information embOS keeps track of timers by using a linked list. Once the timeout has expired, the callback routine will be called immediately (unless the current task is in a critical region or has interrupts disabled). The extended software timer is not automatically started. This must be done explicitly by a call of OS_StartTimerEx() or OS_RetriggerTimerEx(). OS_TIMER_EX_ROUTINE is defined in RTOS.h as follows: typedef void OS_TIMER_EX_ROUTINE(void* pVoid); Example OS_TIMER_EX TIMER100; OS_TASK TCB_HP; void Timer100(void* pTask) { LED = LED ? 0 : 1; /* Toggle LED */ if (pTask != NULL) { OS_SignalEvent(0x01, (OS_TASK*) pVoid); } OS_RetriggerTimerEx(&TIMER100); /* Make timer periodic */ } void InitTask(void) { /* Create Timer100, start it elsewhere later on*/ OS_CreateTimerEx(&TIMER100, Timer100, 100, (void*) & TCB_HP); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 101 5.2.14 OS_StartTimerEx() Description Starts an extended software timer. Prototype void OS_StartTimerEx (OS_TIMER_EX* pTimerEx); Parameter pTimerEx Description Pointer to the OS_TIMER_EX data structure which contains the data of the extended software timer. Table 5.14: OS_StartTimereEx() parameter list Additional Information OS_StartTimerEx() is used for the following reasons: * * Start an extended software timer which was created by OS_CreateTimerEx(). The timer will start with its initial timer value. Restart a timer which was stopped by calling OS_StopTimerEx(). In this case, the timer will continue with the remaining time value which was preserved by stopping the timer. Important This function has no effect on running timers. It also has no effect on timers that are not running, but have expired. Use OS_RetriggerTimerEx() to restart those timers. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 102 CHAPTER 5 Software timers 5.2.15 OS_StopTimerEx() Description Stops an extended software timer. Prototype void OS_StopTimerEx (OS_TIMER_EX* pTimerEx); Parameter pTimerEx Description Pointer to the OS_TIMER_EX data structure which contains the data of the extended software timer. Table 5.15: OS_StopTimerEx() parameter list Additional Information The actual time value of the extended software timer (the time until expiration) is maintained until OS_StartTimerEx() lets the timer continue. The function has no effect on timers that are not running, but have expired. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 103 5.2.16 OS_RetriggerTimerEx() Description Restarts an extended software timer with its initial time value. Prototype void OS_RetriggerTimerEx (OS_TIMER_EX* pTimerEx); Parameter pTimerEx Description Pointer to the OS_TIMER_EX data structure which contains the data of the extended software timer. Table 5.16: OS_RetriggerTimerEx() parameter list Additional Information OS_RetriggerTimerEx() restarts the extended software timer using the initial time value which was programmed at creation of the timer or which was set using the function OS_SetTimerPeriodEx(). OS_RetriggerTimerEx() can be called regardless of the state of the timer. A running timer will continue using the full initial time. A timer that was stopped before or had expired will be restarted. Example OS_TIMER_EX TIMERCursor; OS_TASK TCB_HP; BOOL CursorOn; void TimerCursor(void* pTask) { if (CursorOn != 0) ToggleCursor(); /* Invert character at cursor-position */ OS_SignalEvent(0x01, (OS_TASK*) pTask); OS_RetriggerTimerEx(&TIMERCursor); /* Make timer periodic */ } void InitTask(void) { /* Create and start TimerCursor */ OS_CREATETIMER_EX(&TIMERCursor, TimerCursor, 500, (void*)&TCB_HP); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 104 CHAPTER 5 Software timers 5.2.17 OS_SetTimerPeriodEx() Description Sets a new timer reload value for an extended software timer. Prototype void OS_SetTimerPeriodEx (OS_TIMER_EX* pTimerEx, OS_TIME Period); Parameter pTimerEx Period Description Pointer to the OS_TIMER_EX data structure which contains the data of the extended software timer. Timer period in basic embOS time units (nominal ms): The data type OS_TIME is defined as an integer, therefore valid values are 1 <= Timeout <= 2 15-1 = 0x7FFF = 32767 for 8/16-bit CPUs 1 <= Timeout <= 2 31-1 = 0x7FFFFFFF for 32-bit CPUs Table 5.17: OS_SetTimerPeriodEx() parameter list Additional Information OS_SetTimerPeriodEx() sets the initial time value of the specified extended software timer. Period is the reload value of the timer to be used as initial value when the timer is retriggered the next time by OS_RetriggerTimerEx(). A call of OS_SetTimerPeriodEx() does not affect the remaining time period of an extended software timer. Example OS_TIMER_EX TIMERPulse; OS_TASK TCB_HP; void TimerPulse(void* pTask) { OS_SignalEvent(0x01, (OS_TASK*) pTask); OS_RetriggerTimerEx(&TIMERPulse); /* Make timer periodic */ } void InitTask(void) { /* Create and start Pulse Timer with first pulse == 500ms */ OS_CREATETIMER_EX(&TIMERPulse, TimerPulse, 500, (void*)&TCB_HP); /* Set timer period to 200 ms for further pulses */ OS_SetTimerPeriodEx(&TIMERPulse, 200); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 105 5.2.18 OS_DeleteTimerEx() Description Stops and deletes an extended software timer. Prototype void OS_DeleteTimerEx(OS_TIMER_EX* pTimerEx); Parameter pTimerEx Description Pointer to the OS_TIMER_EX data structure which contains the data of the timer. Table 5.18: OS_DeleteTimerEx() parameter list Additional Information The extended software timer is stopped and removed from the linked list of running timers. In debug builds of embOS, the timer is also marked as invalid. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 106 CHAPTER 5 Software timers 5.2.19 OS_GetTimerPeriodEx() Description Returns the current reload value of an extended software timer. Prototype OS_TIME OS_GetTimerPeriodEx (OS_TIMER_EX* pTimerEx); Parameter pTimerEx Description Pointer to the OS_TIMER_EX data structure which contains the data of the extended timer. Table 5.19: OS_GetTimerPeriodEx() parameter list Return value Type OS_TIME, which is defined as an integer between 1 and 2 15-1 = 0x7FFF = 32767 for 8/16-bit CPUs and as an integer between 1 and <= 2 31 -1 = 0x7FFFFFFF for 32-bit CPUs, which is the permitted range of timer values. Additional Information The period returned is the reload value of the timer which was set as initial value when the timer was created or which was modified by a call of OS_SetTimerPeriodEx(). This reload value will be used as time period when the timer is retriggered by OS_RetriggerTimerEx(). UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 107 5.2.20 OS_GetTimerValueEx() Description Returns the remaining timer value of an extended software timer. Prototype OS_TIME OS_GetTimerValueEx(OS_TIMER_EX* pTimerEx); Parameter pTimerEx Description Pointer to the OS_TIMER_EX data structure which contains the data of the timer. Table 5.20: OS_GetTimerValueEx() parameter list Return value Type OS_TIME, which is defined as an integer between 1 and 2 15-1 = 0x7FFF = 32767 for 8/16-bit CPUs and as an integer between 1 and <= 231-1 = 0x7FFFFFFF for 32-bit CPUs, which is the permitted range of timer values. The returned time value is the remaining timer value in embOS tick units until expiration of the extended software timer. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 108 CHAPTER 5 Software timers 5.2.21 OS_GetTimerStatusEx() Description Returns the current timer status of an extended software timer. Prototype unsigned char OS_GetTimerStatusEx (OS_TIMER_EX* pTimerEx); Parameter pTimerEx Description Pointer to the OS_TIMER_EX data structure which contains the data of the extended timer. Table 5.21: OS_GetTimerStatusEx parameter list Return value Denotes whether the specified timer is running or not: 0: timer has stopped ! = 0: timer is running. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 109 5.2.22 OS_GetpCurrentTimerEx() Description Returns a pointer to the data structure of the extended timer that just expired. Prototype OS_TIMER_EX* OS_GetpCurrentTimerEx (void); Return value A pointer to the control structure of an extended software timer. Additional Information The return value of OS_GetpCurrentTimerEx() is valid during execution of a timer callback function; otherwise it is undefined. If one callback function should be used for multiple extended timers, this function can be used for examining the timer that expired. Example #include "RTOS.H" OS_TIMER_EX MyTimerEx; /******************************************************** * * Local Functions */ void cbTimerEx(void* pData) { /* Timer callback function for multiple timers */ OS_TIMER_EX* pTimerEx; pTimerEx = OS_GetpCurrentTimerEx(); OS_SignalEvent(0x01, (OS_TASK*) pData); OS_RetriggerTimer(pTimerEx); /* Retrigger timer */ } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 110 UM01001 User & Reference Guide for embOS CHAPTER 5 Software timers (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 111 Chapter 6 Resource semaphores UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 112 CHAPTER 6 6.1 Resource semaphores Introduction Resource semaphores are used for managing resources by avoiding conflicts caused by simultaneous use of a resource. The resource managed can be of any kind: a part of the program that is not reentrant, a piece of hardware like the display, a flash prom that can only be written to by a single task at a time, a motor in a CNC control that can only be controlled by one task at a time, and a lot more. The basic procedure is as follows: Any task that uses a resource first claims it calling the OS_Use() or OS_Request() routines of embOS. If the resource is available, the program execution of the task continues, but the resource is blocked for other tasks. If a second task now tries to use the same resource while it is in use by the first task, this second task is suspended until the first task releases the resource. However, if the first task that uses the resource calls OS_Use() again for that resource, it is not suspended because the resource is blocked only for other tasks. The following diagram illustrates the process of using a resource: OS_Use() Access resource OS_Unuse() A resource semaphore contains a counter that keeps track of how many times the resource has been claimed by calling OS_Request() or OS_Use() by a particular task. It is released when that counter reaches zero, which means the OS_Unuse() routine must be called exactly the same number of times as OS_Use() or OS_Request(). If it is not, the resource remains blocked for other tasks. On the other hand, a task cannot release a resource that it does not own by calling OS_Unuse(). In debug builds of embOS, a call of OS_Unuse() for a semaphore that is not owned by this task will result in a call to the error handler OS_Error(). Example of using resource semaphores Here, two tasks access an LC display completely independently from each other. The LCD is a resource that needs to be protected with a resource semaphore. One task may not interrupt another task which is writing to the LCD, because otherwise the following might occur: * * * Task A positions the cursor Task B interrupts Task A and repositions the cursor Task A writes to the wrong place in the LCD's memory. To avoid this type of situation, every time the LCD must be accessed by a task, it is first claimed by a call to OS_Use() (and is automatically waited for if the resource is blocked). After the LCD has been written to, it is released by a call to OS_Unuse(). UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 113 /* * Demo program to illustrate the use of resource semaphores */ OS_STACKPTR int StackMain[100], StackClock[50]; OS_TASK TaskMain,TaskClock; OS_RSEMA SemaLCD; void TaskClock(void) { char t = -1; char s[] = "00:00"; while(1) { while (TimeSec == t) { Delay(10); } t = TimeSec; s[4] = TimeSec % 10 + '0'; s[3] = TimeSec / 10 + '0'; s[1] = TimeMin % 10 + '0'; s[0] = TimeMin / 10 + '0'; OS_Use(&SemaLCD); LCD_Write(10, 0, s); OS_Unuse(&SemaLCD); } } /* Make sure noone else uses LCD */ /* Release LCD */ void TaskMain(void) { signed char pos ; LCD_Write(0, 0, "Software tools by Segger!"); OS_Delay(2000); while (1) { for ( pos=14 ; pos >=0 ; pos-- ) { OS_Use(&SemaLCD); /* Make sure noone else uses LCD */ LCD_Write(pos, 1, "train"); /* Draw train */ OS_Unuse(&SemaLCD); /* Release LCD */ OS_Delay(500); } OS_Use(&SemaLCD); /* Make sure noone else uses LCD */ LCD_Write(0, 1, " "); OS_Unuse(&SemaLCD); /* Release LCD */ } } void InitTask(void) { OS_CREATERSEMA(&SemaLCD); /* Creates resource semaphore OS_CREATETASK(&TaskMain, 0, Main, 50, StackMain); OS_CREATETASK(&TaskClock, 0, Clock, 100, StackClock); } */ In most applications the routines that access a resource should automatically call OS_Use() and OS_Unuse() so that when using the resource you do not need to worry about it and can use it just as you would in a single-task system. The following is an example of how to implement a resource into the routines that actually access the display: /* * Simple example when accessing single line dot matrix LCD */ OS_RSEMA RDisp; /* Define resource semaphore */ void UseDisp() { OS_Use(&RDisp); } /* Simple routine to be called before using display */ void UnuseDisp() { OS_Unuse(&RDisp); } /* Simple routine to be called after using display */ void DispCharAt(char c, char x, char y) { UseDisp(); LCDGoto(x, y); LCDWrite1(ASCII2LCD(c)); UnuseDisp(); } void DISPInit(void) { OS_CREATERSEMA(&RDisp); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 114 6.2 CHAPTER 6 Resource semaphores API functions OS_CREATERSEMA() OS_Use() OS_UseTimed() OS_Unuse() OS_Request() OS_GetSemaValue() OS_GetResourceOwner() OS_DeleteRSema() Description Macro that creates a resource semaphore. Claims a resource and blocks it for other tasks. Tries to claim a resource within a given time. Releases a semaphore currently in use by a task. Requests a specified semaphore, blocks it for other tasks if it is available. Continues execution in any case. Returns the value of the usage counter of a specified resource semaphore. Returns a pointer to the task that is currently using (blocking) a resource. Deletes a specified resource semaphore. Timer ISR Task main Routine X X X X X X X X X X X X X X X X Table 6.1: Resource semaphore API functions UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 115 6.2.1 OS_CREATERSEMA() Description Macro that creates a resource semaphore. Prototype void OS_CREATERSEMA (OS_RSEMA* pRSema); Parameter pRSema Description Pointer to the data structure for a resource semaphore. Table 6.2: OS_CREATESEMA() parameter list Additional Information After creation, the resource is not blocked; the value of the counter is zero. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 116 CHAPTER 6 6.2.2 Resource semaphores OS_Use() Description Claims a resource and blocks it for other tasks. Prototype int OS_Use (OS_RSEMA* pRSema); Parameter pRSema Description Pointer to the data structure for a resource semaphore. Table 6.3: OS_Use() parameter list Return value The counter value of the semaphore. A value greater than one denotes the resource was already locked by the calling task. Additional Information The following situations are possible: * * * Case A: The resource is not in use. If the resource is not used by a task, which means the counter of the semaphore is zero, the resource will be blocked for other tasks by incrementing the counter and writing a unique code for the task that uses it into the semaphore. Case B: The resource is used by this task. The counter of the semaphore is incremented. The program continues without a break. Case C: The resource is being used by another task. The execution of this task is suspended until the resource semaphore is released. In the meantime if the task blocked by the resource semaphore has a higher priority than the task blocking the semaphore, the blocking task is assigned the priority of the task requesting the resource semaphore. This is called priority inheritance. Priority inheritance can only temporarily increase the priority of a task, never reduce it. An unlimited number of tasks can wait for a resource semaphore. According to the rules of the scheduler, of all the tasks waiting for the resource the task with the highest priority will acquire the resource and continue program execution. Important This function must not be called from within an interrupt handler. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 117 The following diagram illustrates how OS_Use() works: OS_Use(...) Resource in use? Yes, by other task Wait for resource to be released Yes, by this task No Mark current task as owner Increase Usage counter Usage counter = 1 return return UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 118 CHAPTER 6 6.2.3 Resource semaphores OS_UseTimed() Description Tries to claim a resource and blocks it for other tasks if it is available within a specified time. Prototype int OS_UseTimed(OS_RSEMA* pRSema, OS_TIME TimeOut) Parameter pRSema TimeOut Description Pointer to the data structure of a resource semaphore. Maximum time until the resource semaphore should be available. Timer period in basic embOS time units (nominal ms): The data type OS_TIME is defined as an integer, therefore valid values are 1 <= Timeout <= 2 15-1 = 0x7FFF = 32767 for 8/16-bit CPUs 1 <= Timeout <= 2 31-1 = 0x7FFFFFFF for 32-bit CPUs. Table 6.4: OS_UseTimed() parameter list Return value 0: Failed, semaphore not available before timeout. >0: Success, resource semaphore was available. The counter value of the semaphore. A value greater than one denotes the resource was already locked by the calling task. Additional Information The following situations are possible: * * * Case A: The resource is not in use. If the resource is not used by a task, which means the counter of the semaphore is zero, the resource will be blocked for other tasks by incrementing the counter and writing a unique code for the task that uses it into the semaphore. Case B: The resource is used by this task. The counter of the semaphore is incremented. The program continues without a break. Case C: The resource is being used by another task. The execution of this task is suspended until the resource semaphore is released or the timeout time expired. In the meantime if the task blocked by the resource semaphore has a higher priority than the task blocking the semaphore, the blocking task is assigned the priority of the task requesting the resource semaphore. This is called priority inheritance. Priority inheritance can only temporarily increase the priority of a task, never reduce it. If the resource semaphore becomes available during the timeout, the calling task claims the resource and the function returns a value greater than zero, otherwise, if the resource does not become available, the function returns zero. When the calling task is blocked by higher priority tasks for a period longer than the timeout value, it may happen that the resource semaphore becomes available before the calling task is resumed. Anyhow, the function will not claim the resource because it was not availbale within the requested time. An unlimited number of tasks can wait for a resource semaphore. According to the rules of the scheduler, of all the tasks waiting for the resource the task with the highest priority will acquire the resource and continue program execution. Important This function must not be called from within an interrupt handler. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 119 6.2.4 OS_Unuse() Description Releases a semaphore currently in use by a task. Prototype void OS_Unuse (OS_RSEMA* pRSema) Parameter pRSema Description Pointer to the data structure for a resource semaphore. Table 6.5: OS_Unuse() parameter list Additional Information OS_Unuse() may be used on a resource semaphore only after that semaphore has been used by calling OS_Use() or OS_Request(). OS_Unuse() decrements the usage counter of the semaphore which must never become negative. If this counter becomes negative, a debug build will call the embOS error handler OS_Error() with error code OS_ERR_UNUSE_BEFORE_USE. In a debug build OS_Error() will also be called if OS_Unuse() is called from a task which does not own the resource. The error code is OS_ERR_RESOURCE_OWNER in this case. Important This function must not be called from within an interrupt handler. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 120 CHAPTER 6 6.2.5 Resource semaphores OS_Request() Description Requests a specified semaphore and blocks it for other tasks if it is available. Continues execution in any case. Prototype char OS_Request (OS_RSEMA* pRSema); Parameter pRSema Description Pointer to the data structure for a resource semaphore. Table 6.6: OS-Request() parameter list Return value 1: Resource was available, now in use by the calling task. 0: Resource was not available. Additional Information The following diagram illustrates how OS_Request() works: OS_Request (RSEMA*ps) Resource in use by other task ? Yes return 0 No In use by this task ? No Mark current task as owner Yes Inc Usage counter Usage counter = 1 return 1 return 1 Example if (OS_Request(&RSEMA_LCD) ) { DispTime(); /* Access the resource LCD */ OS_Unuse(&RSEMA_LCD); /* Resource LCD is no longer needed */ } else { ... // Do something else } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 121 6.2.6 OS_GetSemaValue() Description Returns the value of the usage counter of a specified resource semaphore. Prototype int OS_GetSemaValue (const OS_SEMA* pSema); Parameter pRSema Description Pointer to the data structure for a resource semaphore. Table 6.7: OS_GetSemaValue() parameter list Return value The counter of the semaphore. A value of zero means the resource is available. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 122 CHAPTER 6 6.2.7 Resource semaphores OS_GetResourceOwner() Description Returns a pointer to the task that is currently using (blocking) a resource. Prototype OS_TASK* OS_GetResourceOwner (const OS_RSEMA* pSema); Parameter pRSema Description Pointer to the data structure for a resource semaphore. Table 6.8: OS_GetResourceOwner() parameter list Return value Pointer to the task that holds the resource. A value of NULL means the resource is available. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 123 6.2.8 OS_DeleteRSema() Description Deletes a specified resource semaphore. The memory of that semaphore may be reused for other purposes or may be used for creating another resources semaphore using the same memory. Prototype void OS_DeleteRSema (OS_RSEMA* pRSema); Parameter pRSema Description Pointer to a data structure of type OS_RSEMA. Table 6.9: OS_DeleteRSema parameter list Additional Information Before deleting a resource semaphore, make sure that no task is claiming the resource semaphore. A debug build of embOS will call OS_Error() with the error code OS_DEL_RSEMA_DELETE if a resource semaphore is deleted when it is already in use. In systems with dynamic creation of resource semaphores, you must delete a resource semaphore before recreating it. Failure to so may cause semaphore handling to work incorrectly. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 124 UM01001 User & Reference Guide for embOS CHAPTER 6 Resource semaphores (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 125 Chapter 7 Counting Semaphores UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 126 7.1 CHAPTER 7 Counting Semaphores Introduction Counting semaphores are counters that are managed by embOS. They are not as widely used as resource semaphores, events or mailboxes, but they can be very useful sometimes. They are used in situations where a task needs to wait for something that can be signaled one or more times. The semaphores can be accessed from any point, any task, or any interrupt by any means. Example of using counting semaphores OS_STACKPTR int Stack0[96], Stack1[64]; /* Task stacks */ OS_TASK TCB0, TCB1; /* Data-area for tasks (task-control-blocks) */ OS_CSEMA SEMALCD; void Task0(void) { while(1) { Disp("Task0 will wait for task 1 to signal"); OS_WaitCSema(&SEMALCD); Disp("Task1 has signaled !!"); OS_Delay(100); } } void Task1(void) { while(1) { OS_Delay(5000); OS_SignalCSema(&SEMALCD); } } void InitTask(void) { OS_CREATECSEMA(&SEMALCD); OS_CREATETASK(&TCB0, NULL, Task0, 100, Stack0); OS_CREATETASK(&TCB1, NULL, Task1, 50, Stack1); } UM01001 User & Reference Guide for embOS /* Create Semaphore */ /* Create Task0 */ /* Create Task1 */ (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 127 7.2 API functions OS_CREATECSEMA() OS_CreateCSema() OS_SignalCSema() OS_SignalCSemaMax() OS_WaitCSema() OS_CSemaRequest() OS_WaitCSemaTimed() OS_GetCSemaValue() OS_SetCSemaValue() OS_DeleteCSema() Description Macro that creates a counting semaphore with an initial count value of zero. Creates a counting semaphore with a specified initial count value. Increments the counter of a semaphore. Increments the counter of a semaphore up to a specified maximum value. Decrements the counter of a semaphore. Decrements the counter of a semaphore, if available. Decrements a semaphore counter if the semaphore is available within a specified time. Returns the counter value of a specified semaphore. Sets the counter value of a specified semaphore. Deletes a specified semaphore. Timer ISR Task main Routine X X X X X X X X X X X X X X X X X X X X X X X X Table 7.1: Counting semaphores API functions UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 128 CHAPTER 7 7.2.1 Counting Semaphores OS_CREATECSEMA() Description Macro that creates a counting semaphore with an initial count value of zero. Prototype void OS_CREATECSEMA (OS_CSEMA* pCSema); Parameter pCSema Description Pointer to a data structure of type OS_CSEMA. Table 7.2: OS_CREATECSEMA() parameter list Additional Information To create a counting semaphore a data structure of the type OS_CSEMA must be defined in memory and initialized using OS_CREATECSEMA(). The value of a semaphore created by using this macro is zero. If for any reason you need create a semaphore with an initial counting value greater than zero, use the function OS_CreateCSema(). UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 129 7.2.2 OS_CreateCSema() Description Creates a counting semaphore with a specified initial count value. Prototype void OS_CreateCSema (OS_CSEMA* pCSema, OS_UINT InitValue); Parameter pCSema InitValue Description Pointer to a data structure of type OS_CSEMA. Initial count value of the semaphore: 0 <= InitValue <= 216-1 = 0xFFFF for 8/16-bit CPUs 0 <= InitValue <= 232-1 = 0xFFFFFFFF for 32-bit CPUs Table 7.3: OS_CreateCSema() parameter list Additional Information To create a counting semaphore a data structure of the type OS_CSEMA must be defined in memory and initialized using OS_CreateCSema(). UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 130 CHAPTER 7 7.2.3 Counting Semaphores OS_SignalCSema() Description Increments the counter of a semaphore. Prototype void OS_SignalCSema (OS_CSEMA* pCSema); Parameter pCSema Description Pointer to a data structure of type OS_CSEMA. Table 7.4: OS_SignalCSema() parameter list Additional Information OS_SignalCSema() signals an event to a semaphore by incrementing its counter. If one or more tasks are waiting for an event to be signaled to this semaphore, the task with the highest priority becomes the running task. The counter can have a maximum value of 0xFFFF for 8/16-bit CPUs or 0xFFFFFFFF for 32-bit CPUs. It is the responsibility of the application to make sure that this limit is not exceeded. A debug build of embOS detects a counter overflow and calls OS_Error() with error code OS_ERR_CSEMA_OVERFLOW if an overflow occurs. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 131 7.2.4 OS_SignalCSemaMax() Description Increments the counter of a semaphore up to a specified maximum value. Prototype void OS_SignalCSemaMax (OS_CSEMA* pCSema, OS_UINT MaxValue); Parameter pCSema MaxValue Description Pointer to a data structure of type OS_CSEMA. Limit of semaphore count value. 1 <= MaxValue <= 216-1 = 0xFFFF for 8/16-bit CPUs 1 <= MaxValue <= 232-1 = 0xFFFFFFFF for 32-bit CPUs Table 7.5: OS_SignalCSemaMax() parameter list Additional Information As long as current value of the semaphore counter is below the specified maximum value, OS_SignalCSemaMax() signals an event to a semaphore by incrementing its counter. If one or more tasks are waiting for an event to be signaled to this semaphore, the tasks are placed into the READY state and the task with the highest priority becomes the running task. Calling OS_SignalCSemaMax() with a MaxValue of 1 makes a counting semaphore behave like a binary semaphore. Consider using a binary resource instead. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 132 CHAPTER 7 7.2.5 Counting Semaphores OS_WaitCSema() Description Decrements the counter of a semaphore. Prototype void OS_WaitCSema (OS_CSEMA* pCSema); Parameter pCSema Description Pointer to a data structure of type OS_CSEMA. Table 7.6: OS_WaitCSema() parameter list Additional Information If the counter of the semaphore is not zero, the counter is decremented and program execution continues. If the counter is zero, WaitCSema() waits until the counter is incremented by another task, a timer or an interrupt handler by a call to OS_SignalCSema(). The counter is then decremented and program execution continues. An unlimited number of tasks can wait for a semaphore. According to the rules of the scheduler, of all the tasks waiting for the semaphore, the task with the highest priority will continue program execution. Important This function must not be called from within an interrupt handler. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 133 7.2.6 OS_WaitCSemaTimed() Description Decrements a semaphore counter if the semaphore is available within a specified time. Prototype int OS_WaitCSemaTimed (OS_CSEMA* pCSema, OS_TIME TimeOut); Parameter pCSema TimeOut Description Pointer to a data structure of type OS_CSEMA. Maximum time until semaphore should be available Timer period in basic embOS time units (nominal ms): The data type OS_TIME is defined as an integer, therefore valid values are 1 <= Timeout <= 215-1 = 0x7FFF = 32767 for 8/16-bit CPUs 1 <= Timeout <= 231-1 = 0x7FFFFFFF for 32-bit CPUs. Table 7.7: OS_WaitCSemaTimed parameter list Return value 0: Failed, semaphore not available before timeout. 1: OK, semaphore was available and counter decremented. Additional Information If the counter of the semaphore is not zero, the counter is decremented and program execution continues. If the counter is zero, WaitCSemaTimed() waits until the semaphore is signaled by another task, a timer, or an interrupt handler by a call to OS_SignalCSema(). The counter is then decremented and program execution continues. If the semaphore was not signaled within the specified time the program execution continues, but returns a value of zero. An unlimited number of tasks can wait for a semaphore. According to the rules of the scheduler, of all the tasks waiting for the semaphore, the task with the highest priority will continue program execution. When the calling task is blocked by higher priority tasks for a longer period than the timeout value, it may happen, that the semaphore becomes signaled after the timeout time before the calling task continues. In this case, the function returns with timeout, because the semaphore was not availbale within the requested time. In this case, the state of the semaphore is not modified by OS_WaitCSemaTimed(). Important This function must not be called from within an interrupt handler. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 134 CHAPTER 7 7.2.7 Counting Semaphores OS_CSemaRequest() Description Decrements the counter of a semaphore, if it is signaled. Prototype char OS_CSemaRequest (OS_CSEMA* pCSema); Parameter pCSema Description Pointer to a data structure of type OS_CSEMA. Table 7.8: OS_CSemaRequest() parameter list Return value 0: Failed, semaphore was not signaled. 1: OK, semaphore was available and counter was decremented once. Additional Information If the counter of the semaphore is not zero, the counter is decremented and program execution continues. If the counter is zero, OS_CSemaRequest() does not wait and does not modify the semaphore counter. The function returns with error state. Because this function never blocks a calling task, this function may be called from an interrupt handler. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 135 7.2.8 OS_GetCSemaValue() Description Returns the counter value of a specified semaphore. Prototype int OS_GetCSemaValue (const OS_SEMA* pCSema); Parameter pCSema Description Pointer to a data structure of type OS_CSEMA. Table 7.9: OS_GetCSemaValue() parameter list Return value The counter value of the semaphore. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 136 CHAPTER 7 7.2.9 Counting Semaphores OS_SetCSemaValue() Description Sets the counter value of a specified semaphore. Prototype OS_U8 OS_SetCSemaValue (OS_SEMA* pCSema, OS_UINT Value); Parameter pCSema Value Description Pointer to a data structure of type OS_CSEMA. Count value of the semaphore: 0 <= InitValue <= 216-1 = 0xFFFF for 8/16-bit CPUs 0 <= InitValue <= 232-1 = 0xFFFFFFFF for 32-bit CPUs Table 7.10: OS_SetCSemaValue() parameter list Return value 0: In any case. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 137 7.2.10 OS_DeleteCSema() Description Deletes a specified semaphore. Prototype void OS_DeleteCSema (OS_CSEMA* pCSema); Parameter pCSema Description Pointer to a data structure of type OS_CSEMA. Table 7.11: OS_DeleteCSema() parameter list Additional Information Before deleting a semaphore, make sure that no task is waiting for it and that no task will signal that semaphore at a later point. A debug build of embOS will reflect an error if a deleted semaphore is signaled. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 138 UM01001 User & Reference Guide for embOS CHAPTER 7 Counting Semaphores (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 139 Chapter 8 Mailboxes UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 140 8.1 CHAPTER 8 Mailboxes Introduction In the preceding chapters task synchronization by the use of semaphores was described. Unfortunately, semaphores cannot transfer data from one task to another. If we need to transfer data between tasks for example via a buffer, we could use a resource semaphore every time we accessed the buffer. But doing so would make the program less efficient. Another major disadvantage would be that we could not access the buffer from an interrupt handler, because the interrupt handler is not allowed to wait for the resource semaphore. One solution would be the usage of global variables. In this case we would need to disable interrupts each time and in each place that we accessed these variables. This is possible, but it is a path full of pitfalls. It is also not easy for a task to wait for a character to be placed in a buffer without polling the global variable that contains the number of characters in the buffer. Again, there is solution -- the task could be notified by an event signaled to the task each time a character is placed in the buffer. This is why there is an easier way to do this with a real-time OS: The use of mailboxes. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 141 8.2 Basics A mailbox is a buffer that is managed by the real-time operating system. The buffer behaves like a normal buffer; you can deposit something (called a message) and retrieve it later. Mailboxes usually work as FIFO: first in, first out. So a message that is deposited first will usually be retrieved first. "Message" might sound abstract, but very simply it means "item of data". It will become clearer in the typical applications explained in the following section. A mailbox can be used by more than one producer but should be used by one consumer only. This means that more than one task or interrupt handler is allowed to deposit new data into the mailbox, but it does not make sense to retrieve messages by multiple tasks. Limitations: The number of mailboxes and buffers is limited only by the amount of available memory. The message size, number of messages and buffer size per mailbox are limited by software design. Message size: 1 <= x <= 32767 bytes. Number of messages: 1 <= x <= 32767 on 8 or 16bit CPUs. Number of messages: 1 <= x <= 2 31-1 on 32bit CPUs. Maximum buffer size for one mailbox: 65536 bytes (64KB) on 16bit CPUs Maximum buffer size for one mailbox: 232 bytes on 32bit CPUs These limitations have been placed on mailboxes to guarantee efficient coding and also to ensure efficient management. These limitations are normally not a problem. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 142 CHAPTER 8 8.3 Mailboxes Typical applications 8.3.1 A keyboard buffer In most programs, you use either a task, a software timer or an interrupt handler to check the keyboard. When a key has been pressed, that key is deposited into a mailbox that is used as a keyboard buffer. The message is then retrieved by the task that handles keyboard input. The message in this case is typically a single byte that holds the key code; the message size is therefore one byte. The advantage of a keyboard buffer is that management is very efficient; you do not need to worry about it, because it is reliable, proven code and you have a type-ahead buffer at no extra cost. In addition, a task can easily wait for a key to be pressed without having to poll the buffer. It simply calls the OS_GetMail() routine for that particular mailbox. The number of keys that can be deposited in the type-ahead buffer depends only on the size of the mailbox buffer, which you define when creating the mailbox. 8.3.2 A buffer for serial I/O In most cases, serial I/O is done with the help of interrupt handlers. The communication to these interrupt handlers is very easy with mailboxes. Both your task programs and your interrupt handlers deposit or retrieve data into/from the same mailbox. As with a keyboard buffer, the message size is one character. For interrupt-driven sending, the task deposits the character(s) in the mailbox using OS_PutMail() or OS_PutMailCond(); the interrupt handler that is activated when a new character can be sent retrieves the character(s) with OS_GetMailCond(). For interrupt-driven receiving, the interrupt handler that is activated when a new character is received deposits it in the mailbox using OS_PutMailCond(); the task receives it using OS_GetMail() or OS_GetMailCond(). 8.3.3 A buffer for commands sent to a task Assume you have one task controlling a motor, as you might have in applications that control a machine. A simple way to give commands to this task would be to define a structure for commands. The message size would then be the size of this structure. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 143 8.4 Single-byte mailbox functions In many (if not the most) situations, mailboxes are used simply to hold and transfer single-byte messages. This is the case, for example, with a mailbox that takes the character received or sent via serial interface, or normally with a mailbox used as a keyboard buffer. In some of these cases, time is very critical, especially if a lot of data is transferred in short periods of time. To minimize the overhead caused by the mailbox management of embOS, variations on some mailbox functions are available for single-byte mailboxes. The general functions OS_PutMail(), OS_PutMailCond(), OS_GetMail(), and OS_GetMailCond() can transfer messages of sizes between 1 and 32767 bytes each. Their single-byte equivalents OS_PutMail1(), OS_PutMailCond1(), OS_GetMail1(), and OS_GetMailCond1() work the same way with the exception that they execute much faster because management is simpler. It is recommended to use the singlebyte versions if you transfer a lot of single-byte data via mailboxes. The routines OS_PutMail1(), OS_PutMailCond1(), OS_GetMail1(), and OS_GetMailCond1() work exactly the same way as their universal equivalents and are therefore not described separately. The only difference is that they can only be used for single-byte mailboxes. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 144 8.5 CHAPTER 8 Mailboxes API functions OS_CreateMB() OS_PutMail() / OS_PutMail1() OS_PutMailCond() / OS_PutMailCond1() OS_PutMailFront() / OS_PutMailFront1() OS_PutMailFrontCond() / OS_PutMailFrontCond1() OS_GetMail() / OS_GetMail1() OS_GetMailCond() / OS_GetMailCond1() OS_GetMailTimed() OS_WaitMail() OS_WaitMailTimed() OS_PeekMail() OS_ClearMB() OS_GetMessageCnt() OS_DeleteMB() Explanation Creates a new mailbox. Stores a new message of a predefined size in a mailbox. Stores a new message of a predefined size in a mailbox, if the mailbox is able to accept one more message. Stores a new message of a predefined size into a mailbox in front of all other messages. This new message will be retrieved first. Stores a new message of a predefined size into a mailbox in front of all other messages, if the mailbox is able to accept one more message. Retrieves a message of a predefined size from a mailbox. Retrieves a message of a predefined size from a mailbox, if a message is available. Retrieves a new message of a predefined size from a mailbox, if a message is available within a given time. Waits until a mail is available, but does not retrieve the message from the mailbox. Suspends the calling task until a mail is available or until the timeout expires, but does not retrieve the message from the mailbox. Reads a mail from a mailbox without removing it Clears all messages in a specified mailbox. Returns number of messages currently in a specified mailbox. Deletes a specified mailbox. Timer ISR Task main Routine X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X Table 8.1: Mailboxes API functions UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 145 8.5.1 OS_CreateMB() Description Creates a new mailbox. Prototype void OS_CreateMB (OS_MAILBOX* unsigned short unsigned int void* Parameter pMB sizeofMsg maxnoMsg pMsg pMB, sizeofMsg, maxnofMsg, pMsg); Description Pointer to a data structure of type OS_MAILBOX reserved for managing the mailbox. Size of a message in bytes. (1 <= sizeofMsg <= 32767) Maximum number of messages. (1 <= MaxnofMsg <= 32767) Pointer to a memory area used as buffer. The buffer must be big enough to hold the given number of messages of the specified size: sizeofMsg * maxnoMsg bytes. Table 8.2: OS_CreateMB() parameter list Example Mailbox used as keyboard buffer: OS_MAILBOX MBKey; char MBKeyBuffer[6]; void InitKeyMan(void) { /* Create mailbox, functioning as type ahead buffer */ OS_CreateMB(&MBKey, 1, sizeof(MBKeyBuffer), &MBKeyBuffer); } Mailbox used for transferring complex commands from one task to another: /* * Example of mailbox used for transferring commands to a task * that controls a motor */ typedef struct { char Cmd; int Speed[2]; int Position[2]; } MOTORCMD ; OS_MAILBOX MBMotor; #define NUM_MOTORCMDS 4 char BufferMotor[sizeof(MOTORCMD) * NUM_MOTORCMDS]; void MOTOR_Init(void) { /* Create mailbox that holds commands messages */ OS_CreateMB(&MBMotor, sizeof(MOTORCMD), NUM_MOTORCMDS, &BufferMotor); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 146 CHAPTER 8 8.5.2 Mailboxes OS_PutMail() / OS_PutMail1() Description Stores a new message of a predefined size in a mailbox. Prototype void OS_PutMail (OS_MAILBOX* const void* void OS_PutMail1 (OS_MAILBOX* const char* pMB, pMail); pMB, pMail); Parameter pMB pMail Description Pointer to the mailbox. Pointer to the message to store. Table 8.3: OS_PutMail() / OS_PutMail1() parameter list Additional Information If the mailbox is full, the calling task is suspended. Because this routine might require a suspension, it must not be called from an interrupt routine. Use OS_PutMailCond()/OS_PutMailCond1() instead if you need to store data in a mailbox from within an ISR. When using a debug build of embOS, calling from an interrupt routine will call the error handler OS_Error() with error code OS_ERR_IN_ISR. Important This function must not be called from within an interrupt handler. Example Single-byte mailbox as keyboard buffer: OS_MAILBOX MBKey; char MBKeyBuffer[6]; void KEYMAN_StoreKey(char k) { OS_PutMail1(&MBKey, &k); /* Store key, wait if no space in buffer */ } void KEYMAN_Init(void) { /* Create mailbox functioning as type ahead buffer */ OS_CreateMB(&MBKey, 1, sizeof(MBKeyBuffer), &MBKeyBuffer); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 147 8.5.3 OS_PutMailCond() / OS_PutMailCond1() Description Stores a new message of a predefined size in a mailbox, if the mailbox is able to accept one more message. Prototype char OS_PutMailCond (OS_MAILBOX* const void* char OS_PutMailCond1 (OS_MAILBOX* const char* Parameter pMB pMail pMB, pMail); pMB, pMail); Description Pointer to the mailbox. Pointer to the message to store. Table 8.4: OS_PutMailCond() / OS_PutMailCond1() overview Return value 0: Success; message stored. 1: Message could not be stored (mailbox is full). Additional Information If the mailbox is full, the message is not stored. This function never suspends the calling task. It may therefore be called from an interrupt routine. Example OS_MAILBOX MBKey; char MBKeyBuffer[6]; char KEYMAN_StoreCond(char k) { return OS_PutMailCond1(&MBKey, &k); /* Store key if space in buffer */ } This example can be used with the sample program shown earlier to handle a mailbox as keyboard buffer. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 148 CHAPTER 8 8.5.4 Mailboxes OS_PutMailFront() / OS_PutMailFront1() Description Stores a new message of a predefined size at the beginning of a mailbox in front of all other messages. This new message will be retrieved first. Prototype void OS_PutMailFront (OS_MAILBOX* const void* void OS_PutMailFront1 (OS_MAILBOX* const char* Parameter pMB pMail pMB, pMail); pMB, pMail); Description Pointer to the mailbox. Pointer to the message to store. Table 8.5: OS_PutMailFront() / OS_PutMailFront1() parameter list Additional Information If the mailbox is full, the calling task is suspended. Because this routine might require a suspension, it must not be called from an interrupt routine. Use OS_PutMailFrontCond()/OS_PutMailFrontCond1() instead if you need to store data in a mailbox from within an ISR. This function is useful to store "emergency" messages into a mailbox which must be handled quickly. It may also be used in general instead of OS_PutMail() to change the FIFO structure of a mailbox into a LIFO structure. Important This function must not be called from within an interrupt handler. Example Single-byte mailbox as keyboard buffer which will follow the LIFO pattern: OS_MAILBOX MBCmd; char MBCmdBuffer[6]; void KEYMAN_StoreCommand(char k) { OS_PutMailFront1(&MBCmd, &k); /* Store command, wait if no space in buffer*/ } void KEYMAN_Init(void) { /* Create mailbox for command buffer */ OS_CreateMB(&MBCmd, 1, sizeof(MBCmdBuffer), &MBCmdBuffer); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 149 8.5.5 OS_PutMailFrontCond() / OS_PutMailFrontCond1() Description Stores a new message of a predefined size into a mailbox in front of all other messages, if the mailbox is able to accept one more message. The new message will be retrieved first. Prototype char OS_PutMailFrontCond (OS_MAILBOX* const void* char OS_PutMailFrontCond1 (OS_MAILBOX* const char* Parameter pMB pMail pMB, pMail); pMB, pMail); Description Pointer to the mailbox. Pointer to the message to store. Table 8.6: OS_PutMailFrontCond() / OS_PutMailFrontCond1() parameter list Return value 0: Success; message stored. 1: Message could not be stored (mailbox is full). Additional Information If the mailbox is full, the message is not stored. This function never suspends the calling task. It may therefore be called from an interrupt routine. This function is useful to store "emergency" messages into a mailbox which must be handled quickly. It may also be used in general instead of OS_PutMailCond() to change the FIFO structure of a mailbox into a LIFO structure. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 150 CHAPTER 8 8.5.6 Mailboxes OS_GetMail() / OS_GetMail1() Description Retrieves a new message of a predefined size from a mailbox. Prototype void OS_GetMail (OS_MAILBOX* void* void OS_GetMail1 (OS_MAILBOX* char* Parameter pMB pDest pMB, pDest); pMB, pDest); Description Pointer to the mailbox. Pointer to the memory area that the message should be stored at. Make sure that it points to a valid memory area and that there is sufficient space for an entire message. The message size (in bytes) was defined when the mailbox was created. Table 8.7: OS_GetMail() / OS_GetMail1() parameter list Additional Information If the mailbox is empty, the task is suspended until the mailbox receives a new message. Because this routine might require a suspension, it must not be called from an interrupt routine. Use OS_GetMailCond/OS_GetMailCond1 instead if you need to retrieve data from a mailbox from within an ISR. Important This function must not be called from within an interrupt handler. Example OS_MAILBOX MBKey; char WaitKey(void) { char c; OS_GetMail1(&MBKey, &c); return c; } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 151 8.5.7 OS_GetMailCond() / OS_GetMailCond1() Description Retrieves a new message of a predefined size from a mailbox, if a message is available. Prototype char OS_GetMailCond (OS_MAILBOX* void* char OS_GetMailCond1 (OS_MAILBOX* char* Parameter pMB pDest pMB, pDest); pMB, pDest); Description Pointer to the mailbox. Pointer to the memory area that the message should be stored at. Make sure that it points to a valid memory area and that there is sufficient space for an entire message. The message size (in bytes) was defined when the mailbox was created. Table 8.8: OS_GetMailCond() / OS_GetMailCond1() parameter list Return value 0: Success; message retrieved. 1: Message could not be retrieved (mailbox is empty); destination remains unchanged. Additional Information If the mailbox is empty, no message is retrieved and pDest remains unchanged, but the program execution continues. This function never suspends the calling task. It may therefore also be called from an interrupt routine. Example OS_MAILBOX MBKey; /* * If a key has been pressed, it is taken out of the mailbox and returned to caller. * Otherwise 0 is returned. */ char GetKey(void) { char c = 0; OS_GetMailCond1(&MBKey, &c); return c; } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 152 CHAPTER 8 8.5.8 Mailboxes OS_GetMailTimed() Description Retrieves a new message of a predefined size from a mailbox, if a message is available within a given time. Prototype char OS_GetMailTimed (OS_MAILBOX* pMB, void* pDest, OS_TIME Timeout); Parameter pMB pDest Timeout Description Pointer to the mailbox. Pointer to the memory area that the message should be stored at. Make sure that it points to a valid memory area and that there is sufficient space for an entire message. The message size (in bytes) has been defined upon creation of the mailbox. Maximum time in timer ticks until the requested mail must be available. The data type OS_TIME is defined as an integer, therefore valid values are 1 <= Timeout <= 2 15-1 = 0x7FFF = 32767 for 8/16-bit CPUs 1 <= Timeout <= 2 31-1 = 0x7FFFFFFF for 32-bit CPUs Table 8.9: OS_GetMailTimed() parameter list Return value 0: Success; message retrieved. 1: Message could not be retrieved (mailbox is empty); destination remains unchanged. Additional Information If the mailbox is empty, no message is retrieved, pDest remains unchanged and the task is suspended for the given timeout. The task continues execution according to the rules of the scheduler as soon as a mail is available within the given timeout, or after the timeout value has expired. When the calling task is blocked by higher priority tasks for a period longer than the timeout value, it may happen that mail becomes available before the calling task is resumed. Anyhow, the function returns with timeout because the mail was not availbale within the requested time. In this case, no mail is retrieved from the mailbox. Important This function must not be called from within an interrupt handler. Example OS_MAILBOX MBKey; /* * If a key has been pressed, it is taken out of the mailbox and returned to caller. * Otherwise, 0 is returned. */ char GetKey(void) { char c = 0; OS_GetMailTimed(&MBKey, &c, 10); /* Wait for 10 timer ticks */ return c; } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 153 8.5.9 OS_WaitMail() Description Waits until a mail is available, but does not retrieve the message from the mailbox. Prototype void OS_WaitMail (OS_MAILBOX* pMB); Parameter pMB Description Pointer to the mailbox. Table 8.10: OS_WaitMail() parameter list Additional Information If the mailbox is empty, the task is suspended until a mail is available, otherwise the task continues. The task continues execution according to the rules of the scheduler as soon as a mail is available, but the mail is not retrieved from the mailbox. Important This function must not be called from within an interrupt handler. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 154 CHAPTER 8 Mailboxes 8.5.10 OS_WaitMailTimed() Description Waits until a mail is available or the timeout has expired, but does not retrieve the message from the mailbox. Prototype char OS_WaitMailTimed (OS_MAILBOX* pMB, OS_TIME Timeout); Parameter pMB Timeout Description Pointer to the mailbox. Maximum time in timer ticks until the requested mail must be available. The data type OS_TIME is defined as an integer, therefore valid values are 1 <= Timeout <= 2 15-1 = 0x7FFF = 32767 for 8/16-bit CPUs 1 <= Timeout <= 2 31-1 = 0x7FFFFFFF for 32-bit CPUs Table 8.11: OS_WaitMail() parameter list Return value 0: Success; message available. 1: Timeout; no message available within the given timeout time. Additional Information If the mailbox is empty, the task is suspended for the given timeout. The task continues execution according to the rules of the scheduler as soon as a mail is available within the given timeout, or after the timeout value has expired. When the calling task is blocked by higher priority tasks for a period longer than the timeout value, it may happen that mail becomes available before the calling task is resumed. In this case the function returns with timeout, because the mail was not available within the requested time. Important This function must not be called from within an interrupt handler. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 155 8.5.11 OS_PeekMail() Description Peeks a mail from a mailbox without removing the mail. Prototype char OS_PeekMail (OS_MAILBOX* pMB, void* pDest); Parameter pMB pDest Description Pointer to the mailbox. Pointer to a buffer that should receive the mail Table 8.12: OS_PeekMail() parameter list Return value 0: Success; message available. 1: Message could not be retrieved (mailbox is empty). Additional Information This function is non-blocking and never suspends the calling task. It may therefore be called from an interrupt routine. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 156 CHAPTER 8 Mailboxes 8.5.12 OS_ClearMB() Description Clears all messages in a specified mailbox. Prototype void OS_ClearMB (OS_MAILBOX* pMB); Parameter pMB Description Pointer to the mailbox. Table 8.13: OS_ClearMB() parameter list Additional Information OS_ClearMB() may cause a task switch. Example OS_MAILBOX MBKey; /* * Clear keyboard type ahead buffer */ void ClearKeyBuffer(void) { OS_ClearMB(&MBKey); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 157 8.5.13 OS_GetMessageCnt() Description Returns the number of messages currently available in a specified mailbox. Prototype unsigned int OS_GetMessageCnt (OS_MAILBOX* pMB); Parameter pMB Description Pointer to the mailbox. Table 8.14: OS_GetMessageCnt() parameter list Return value The number of messages in the mailbox. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 158 CHAPTER 8 Mailboxes 8.5.14 OS_DeleteMB() Description Deletes a specified mailbox. Prototype void OS_DeleteMB (OS_MAILBOX* pMB); Parameter pMB Description Pointer to the mailbox. Table 8.15: OS_DeleteMB() parameter list Additional Information To keep the system fully dynamic, it is essential that mailboxes can be created dynamically. This also means there must be a way to delete a mailbox when it is no longer needed. The memory that has been used by the mailbox for the control structure and the buffer can then be reused or reallocated. It is the programmer's responsibility to: * * make sure that the program no longer uses the mailbox to be deleted make sure that the mailbox to be deleted actually exists (i.e. has been created first). In a debug build OS_Error() will also be called, if OS_DeleteMB() is called while tasks are waiting for new data from the mailbox. The error code in this case is OS_ERR_MAILBOX_DELETE. Example OS_MAILBOX MBSerIn; void Cleanup(void) { OS_DeleteMB(&MBSerIn); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 159 Chapter 9 Queues UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 160 9.1 CHAPTER 9 Queues Introduction In the preceding chapter, intertask communication using mailboxes was described. Mailboxes can handle small messages with fixed data size only. Queues enable intertask communication with larger messages or with messages of differing lengths. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 161 9.2 Basics A queue consists of a data buffer and a control structure that is managed by the realtime operating system. The queue behaves like a normal buffer; you can deposit something (called a message) in the queue and retrieve it later. Queues work as FIFO: first in, first out. So a message that is deposited first will be retrieved first. There are three major differences between queues and mailboxes: 1. 2. 3. 4. Queues accept messages of differing lengths. When depositing a message into a queue, the message size is passed as a parameter. Retrieving a message from the queue does not copy the message, but returns a pointer to the message and its size. This enhances performance because the data is copied only when the message is written into the queue. The retrieving function must delete every message after processing it. A new message can only be retrieved from the queue when the previous message was deleted from the queue. Both the number and size of queues is limited only by the amount of available memory. Any data structure can be written into a queue, the message size is not fixed. Similar to mailboxes, queues can be used by more than one producer but should be used by one consumer only. This means that more than one task or interrupt handler is allowed to deposit new data into the queue, but it does not make sense to retrieve messages by multiple tasks. The queue data buffer contains the messages and some additional management information. Each message has a message header containing the message size. The define OS_Q_SIZEOF_HEADER defines the size of the message header. Additionally, the queue buffer will be aligned for those CPUs which need data alignment. Therefore the queue data buffer size must be bigger than the sum of all messages. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 162 9.3 CHAPTER 9 Queues API functions OS_Q_Create() OS_Q_Put() OS_Q_PutBlocked() OS_Q_PutTimed() OS_Q_GetPtr() OS_Q_GetPtrCond() OS_Q_GetPtrTimed() OS_Q_Purge() OS_Q_Clear() OS_Q_GetMessageCnt() OS_Q_Delete() OS_Q_IsInUse() OS_Q_GetMessageSize() OS_Q_PeekPtr() Description Creates and initializes a message queue. Stores a new message of given size in a queue. Stores a new message of given size in a queue. Blocks the calling task when queue is full. Stores a new message of given size in a queue within a given timeout time. Suspends the calling task when the queue is full. Retrieves a message from a queue. Retrieves a message from a queue, if one message is available or returns without suspension. Retrieves a message from a queue within a specified time, if one message is available. Deletes the last retrieved message in a queue. Deletes all message in a queue. Returns the number of messages currently in a queue. Deletes a specified queue. Delivers information about the usage state of the queue. Returns the size of the first message in the queue. Retrieves a message from a queue without removing it. Timer ISR Task main Routine X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X Table 9.1: Queues API UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 163 9.3.1 OS_Q_Create() Description Creates and initializes a message queue. Prototype void OS_Q_Create (OS_Q* pQ, void* pData, OS_UINT Size); Parameter pQ pData Size Description Pointer to a data structure of type OS_Q reserved for the management of the message queue. Pointer to a memory area used as data buffer for the queue. Size in bytes of the data buffer. Table 9.2: OS_Q_Create() parameter list Example #define MESSAGE_CNT 100 #define MESSAGE_SIZE 100 #define MEMORY_QSIZE MESSAGE_CNT * (MESSAGE_SIZE + OS_Q_SIZEOF_HEADER) static OS_Q _MemoryQ; static char _acMemQBuffer[MEMORY_QSIZE]; void MEMORY_Init(void) { OS_Q_Create(&_MemoryQ, &_acMemQBuffer, sizeof(_acMemQBuffer)); } Additional Information The define OS_Q_SIZEOF_HEADER can be used to calculate the additional management information bytes needed for each message in the queue data buffer. But it does not account for the additional space needed for data alignment. Thus the number of messages that can actually be stored in the queue buffer depends on the message sizes. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 164 CHAPTER 9 9.3.2 Queues OS_Q_Put() Description Deposits a new message of given size in a queue. Prototype int OS_Q_Put (OS_Q* pQ, const void* pSrc, OS_UINT Size); Parameter pQ pSrc Size Description Pointer to a data structure of type OS_Q reserved for the management of the message queue. Pointer to the message to store. Size of the message to store. Table 9.3: OS_Q_Put() parameter list Return value 0: Success, message stored. 1: Message could not be stored (queue is full). Additional Information This routine never suspends the calling task and may therefore be called from an interrupt routine. When the message is deposited into the queue, the entire message is copied into the queue buffer, not only the pointer to the data. Therefore the message content is protected and remains valid until it is retrieved and accessed by a task reading the message. Example int MEMORY_Write(const char* pData, OS_UINT Len) { return OS_Q_Put(&_MemoryQ, pData, Len); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 165 9.3.3 OS_Q_PutBlocked() Description Deposits a new message of given size in a queue. Prototype void OS_Q_PutBlocked (OS_Q* pQ, const void* pSrc, OS_UINT Size); Parameter pQ pSrc Size Description Pointer to a data structure of type OS_Q reserved for the management of the message queue. Pointer to the message to store. Size of the message to store. Table 9.4: OS_Q_Put() parameter list Additional Information If the queue is full, the calling task is suspended. Because this routine might require a suspension, it must not be called from an interrupt routine. Use OS_Q_Put() instead if you need to deposit messages in a queue from within an ISR. Important This function must not be called from within an interrupt handler. When using a debug build of embOS, calling from an interrupt handler will call the error handler OS_Error() with error code OS_ERR_IN_ISR . Example void StoreMessage(const char* pData, OS_UINT Len) OS_Q_PutBlocked(&_MemoryQ, pData, Len); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 166 CHAPTER 9 9.3.4 Queues OS_Q_PutTimed() Description Deposits a new message of given size in a queue if space is available within a given time. Prototype int OS_Q_PutTimed (OS_Q* const void* OS_UINT OS_TIME Parameter pQ pSrc Size Timeout pQ, pSrc, Size, Timeout); Description Pointer to a data structure of type OS_Q reserved for the management of the message queue. Pointer to the message to store. Size of the message to store. Maximum time in timer ticks until the requested message must be stored into the queue. The data type OS_TIME is defined as an integer, therefore valid values are 1 <= Timeout <= 2 15-1 = 0x7FFF = 32767 for 8/16-bit CPUs 1 <= Timeout <= 2 31-1 = 0x7FFFFFFF for 32-bit CPUs Table 9.5: OS_Q_Put() parameter list Return value 0: Success, message stored. 1: Message could not be stored within the specified time (insufficient space). Additional Information If the queue holds insufficient space, the calling task is suspended until space for the message is available, or the specified timeout time has expired. If the message could be deposited into the queue within the sepcified time, the function returns zero. As the calling function may be suspended, the function must not be called from an interrupt routine or timer. A debug build of embOS will call the embOS error function OS_Error() if this function is called from an interrupt handler or timer. Example int MEMORY_WriteTimed(const char* pData, OS_UINT Len, OS_TIME Timeout) { return OS_Q_PutTimed(&_MemoryQ, pData, Len, Timeout); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 167 9.3.5 OS_Q_GetPtr() Description Retrieves a message from a queue. Prototype int OS_Q_GetPtr (OS_Q* pQ, void** ppData); Parameter pQ ppData Description Pointer to the queue. Address of pointer to the message to be retrieved from queue. Table 9.6: OS_Q_GetPtr() parameter list Return value The size of the retrieved message. Sets the pointer ppData to the message that should be retrieved. Additional Information If the queue is empty, the calling task is suspended until the queue receives a new message. Because this routine might require a suspension, it must not be called from an interrupt routine or timer. Use OS_GetPtrCond() instead. The retrieved message is not removed from the queue, this must be done by a call of OS_Q_Purge() after the message was processed. Only one message can be processed at a time. As long as the message is not removed from the queue, the queue is marked "in use". A following call of OS_Q_GetPtr() or OS_Q_GetPtrCond() is not allowed before OS_Q_Purge() is called as long as the queue is in use. Consecutive calls of OS_Q_GetPtr() without calling OS_Q_Purge() will call the embOS error handler OS_Error() in debug builds of embOS. Example static void MemoryTask(void) { int Len; char* pData; while (1) { Len = OS_Q_GetPtr(&_MemoryQ, &pData); Memory_WritePacket(*(U32*)pData, Len); OS_Q_Purge(&_MemoryQ); } /* Get message */ /* Process message */ /* Delete message */ } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 168 CHAPTER 9 9.3.6 Queues OS_Q_GetPtrCond() Description Retrieves a message from a queue if a message is available. Prototype int OS_Q_GetPtrCond (OS_Q* pQ, void** ppData); Parameter pQ ppData Description Pointer to the queue. Address of pointer to the message to be retrieved from queue. Table 9.7: OS_Q_GetPtrCond() parameter list Return value 0: No message available in queue. >0: Size of the message that was retrieved from the queue. Sets the pointer ppData to the message that should be retrieved. Additional Information If the queue is empty, the function returns zero and the value of ppData is undefined. This function never suspends the calling task. It may therefore be called from an interrupt routine or timer. If a message could be retrieved it is not removed from the queue, this must be done by a call of OS_Q_Purge() after the message was processed. As long as the message is not removed from the queue, the queue is marked "in use". A following call of OS_Q_GetPtrCond() or OS_Q_GetPtr() is not allowed before OS_Q_Purge() is called as long as the queue is in use. Consecutive calls of OS_Q_GetPtrCond() without calling OS_Q_Purge() will call the embOS error handler OS_Error() in debug builds of embOS. Example static void MemoryTask(void) { int Len; char* pData; while (1) { Len = OS_Q_GetPtrCond(&_MemoryQ, &pData); if (Len > 0) { Memory_WritePacket(*(U32*)pData, Len); OS_Q_Purge(&_MemoryQ); } else { DoSomethingElse(); } } } UM01001 User & Reference Guide for embOS /* Check message */ /* Process message */ /* Delete message */ (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 169 9.3.7 OS_Q_GetPtrTimed() Description Retrieves a message from a queue within a specified time if a message is available. Prototype int OS_Q_GetPtrTimed (OS_Q* pQ, void** ppData, OS_TIME Timeout); Parameter pQ ppData Timeout Description Pointer to the queue. Address of pointer to the message to be retrieved from queue. Maximum time in timer ticks until the requested message must be available. The data type OS_TIME is defined as an integer, therefore valid values are 1 <= Timeout <= 215-1 = 0x7FFF = 32767 for 8/16-bit CPUs 1 <= Timeout <= 231-1 = 0x7FFFFFFF for 32-bit CPUs Table 9.8: OS_Q_GetPtrTimed() parameter list Return value 0: No message available in queue. >0: Size of the message that was retrieved from the queue. Sets the pointer ppData to the message that should be retrieved. Additional Information If the queue is empty no message is retrieved, the task is suspended for the given timeout and the value of ppData is undefined. The task continues execution according to the rules of the scheduler as soon as a message is available within the given timeout, or after the timeout value has expired. When the calling task is blocked by higher priority tasks for a period longer than the timeout value, it may happen that a message becomes available before the calling task is resumed. Anyhow, the function returns with timeout because the message was not availbale within the requested time. In this case the state of the queue is not modified by OS_Q_GetPtrTimed() and a pointer to the message is not delivered. As long as a message was retrieved and the message is not removed from the queue, the queue is marked "in use". A following call of OS_Q_GetPtrTimed() is not allowed before OS_Q_Purge() is called as long as the queue is in use. Consecutive calls of OS_Q_GetPtrTimed() without calling OS_Q_Purge() after retrieving a message call the embOS error handler OS_Error() in debug builds of embOS. Example static void MemoryTask(void) { int Len; char* pData; while (1) { Len = OS_Q_GetPtrTimed(&_MemoryQ, &pData, 10); if (Len > 0) { Memory_WritePacket(*(U32*)pData, Len); OS_Q_Purge(&_MemoryQ); } else { DoSomethingElse(); } } } UM01001 User & Reference Guide for embOS /* Check message */ /* Process message */ /* Delete message */ /* Timeout */ (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 170 CHAPTER 9 9.3.8 Queues OS_Q_Purge() Description Deletes the last retrieved message in a queue. Prototype void OS_Q_Purge (OS_Q* pQ); Parameter pQ Description Pointer to the queue. Table 9.9: OS_Q_Purge() parameter list Additional Information This routine should be called by the task that retrieved the last message from the queue, after the message is processed. Once a message was retrieved by a call of OS_Q_GetPtr(), OS_Q_GetPtrCond() or OS_Q_GetPtrTimed(), the message must be removed from the queue by a call of OS_Q_Purge() before a following message can be retrieved from the queue. Consecutive calls of OS_Q_GetPtr(), OS_Q_GetPtrCond() or OS_Q_GetPtrTimed() will call the embOS error handler OS_Error() in embOS debug builds. Consecutive calls of OS_Q_Purge() or calling OS_Q_Purge() without having retrieved a message from the queue will also call the embOS error handler OS_Error() in embOS debug builds. Example static void MemoryTask(void) { int Len; char* pData; while (1) { Len = OS_Q_GetPtr(&_MemoryQ, &pData); Memory_WritePacket(*(U32*)pData, Len); OS_Q_Purge(&_MemoryQ); } /* Get message */ /* Process message */ /* Delete message */ } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 171 9.3.9 OS_Q_Clear() Description Deletes all message in a queue. Prototype void OS_Q_Clear (OS_Q* pQ); Parameter pQ Description Pointer to the queue. Table 9.10: OS_Q_Clear() parameter list Additional Information When the queue is in use, a debug build of embOS will call OS_Error() with error code OS_ERR_QUEUE_INUSE. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 172 CHAPTER 9 Queues 9.3.10 OS_Q_GetMessageCnt() Description Returns the number of messages that are currently stored in a queue. Prototype int OS_Q_GetMessageCnt (const OS_Q* pQ); Parameter pQ Description Pointer to the queue. Table 9.11: OS_Q_GetMessageCnt() parameter list Return value The number of messages in the queue. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 173 9.3.11 OS_Q_Delete() Description Deletes a specific queue. Prototype void OS_Q_Delete (OS_Q* pQ); Parameter Description Pointer to the queue. pQ Table 9.12: OS_Q_Delete() parameter list Additional Information To keep the system fully dynamic, it is essential that queues can be created dynamically. This also means there must be a way to delete a queue when it is no longer needed. The memory that has been used by the queue for the control structure and the buffer can then be reused or reallocated. It is the programmer's responsibility to: * * make sure that the program no longer uses the queue to be deleted make sure that the queue to be deleted actually exists (i.e. has been created first). When the queue is in use, a debug build of embOS will call OS_Error() with error code OS_ERR_QUEUE_INUSE. When tasks are waiting, a debug build of embOS will call OS_Error() with error code OS_ERR_QUEUE_DELETE is called. Example OS_Q QSerIn; void Cleanup(void) { OS_Q_Delete(&QSerIn); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 174 CHAPTER 9 Queues 9.3.12 OS_Q_IsInUse() Description Delivers information whether the queue is actually in use. Prototype OS_BOOL OS_Q_IsInUse(const OS_Q* pQ) Parameter pQ Description Pointer to the queue. Table 9.13: OS_Q_IsInUse() parameter list Return value 0: Queue is not in use !=0: Queue is in use and may not be deleted or cleared. Additional Information A queue must not be cleared or deleted when it is in use. In use means a task or function actually accesses the queue and holds a pointer to a message in the queue. OS_Q_IsInUse() can be used to examine the state of the queue before it can be cleared or deleted, as these functions must not be performed as long as the queue is used. Example void DeleteQ(OS_Q* pQ) { OS_IncDI(); // Avoid state change of the queue by task or interrupt // // Wait until queue is not used // while (OS_Q_IsInUse(pQ) != 0) { OS_Delay(1); } OS_Q_Delete(pQ); OS_DecRI(); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 175 9.3.13 OS_Q_GetMessageSize() Description Returns the size of the first message. Prototype int OS_Q_GetMessageSize (OS_Q* pQ) Parameter pQ Description Pointer to the queue. Table 9.14: OS_Q_GetMessageSize() parameter list Return value The size of the first message or zero when no message is available. Additional Information If the queue is empty OS_Q_GetMessageSize returns zero. If a message is available OS_Q_GetMessageSize returns the size of that message. The message is not retrieved from the queue. Example static void MemoryTask(void) { int Len; Len = OS_Q_GetMessageSize(&_MemoryQ); /* Get message length */ if (Len > 0) { printf("Message with size %d retrieved\n", Len); } } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 176 CHAPTER 9 Queues 9.3.14 OS_Q_PeekPtr() Description Retrieves a message from a queue. Prototype int OS_Q_PeekPtr (OS_Q* pQ, void** ppData); Parameter pQ ppData Description Pointer to the queue. Address of pointer to the message to be retrieved from queue. Table 9.15: OS_Q_PeekPtr() parameter list Return value The size of the retrieved message or zero when no new message is available. Sets the pointer ppData to the message that should be retrieved. Additional Information If the queue is empty zero is returned. The retrieved message is not removed from the queue. Use OS_Q_Purge() to retrieve and remove a message from the queue. OS_GetPtr()/ Example static void MemoryTask(void) { int Len; char* pData; while (1) { OS_IncDI(); // Avoid state changes of the queue by task or interrupt Len = OS_Q_PeekPtr(&_MemoryQ, &pData); /* Get message */ if (Len > 0) { Memory_WritePacket(*(U32*)pData, Len); /* Process message */ } OS_RESTORE_I(); } Warning Ensure the queues state is not altered as long as a message is processed. That is the reason for calling OS_IncDI() in the sample. Ensure no cooperative task switch is performed, as this may also alter the queue state and buffer. OS_EnterRegion() does not inhibit cooperative task switches! UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 177 Chapter 10 Task events UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 178 CHAPTER 10 Task events 10.1 Introduction Task events are another way of communication between tasks. In contrast to semaphores and mailboxes, task events are messages to a single, specified recipient. In other words, a task event is sent to a specified task. The purpose of a task event is to enable a task to wait for a particular event (or for one of several events) to occur. This task can be kept inactive until the event is signaled by another task, a S/W timer or an interrupt handler. The event can consist of anything that the software has been made aware of in any way. For example, the change of an input signal, the expiration of a timer, a key press, the reception of a character, or a complete command. Every task has an individual bit-mask, which per default is 32bit wide on 32bit CPUs, and 8bits wide on 16- and 8-bit CPUs. This means that 32 or 8 different events can be signaled to and distinguished by every task. By calling OS_WaitEvent(), a task waits for one of the events specified as a bitmask. As soon as one of the events occurs, this task must be signaled by calling OS_SignalEvent(). The waiting task will then be put in the READY state immediately. It will be activated according to the rules of the scheduler as soon as it becomes the task with the highest priority of all the tasks in the READY state. By changing the definition of OS_TASK_EVENT which is defined as unsigned long on 32bit CPUs and unsigned char on 16- or 8-bit CPUs per default, the task events can be expanded to 16 or 32 bits thus allowing more different events, or reduced to smaller data types on 32bit CPUs. Changing the definition of OS_TASK_EVENT can only be done when using the embOS sources in a project, or when the libraries are rebuilt from sources with the modified definition UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 179 10.2 API functions OS_WaitEvent() OS_WaitSingleEvent() OS_WaitEventTimed() OS_WaitSingleEventTimed() OS_SignalEvent() OS_GetEventsOccurred() OS_ClearEvents() Description Timer ISR Task main Routine Waits for one of the events specified in the bitmask and clears the event memory X after an event occurs. Waits for one of the events specified as bitmask and clears only that event after X it occurs. Waits for the specified events for a given time, and clears the event memory after X an event occurs. Waits for the specified events for a given time; after an event occurs, only that X event is cleared. Signals event(s) to a specified task. X X X X Returns a list of events that have X X occurred for a specified task. Returns the actual state of events and X X X X then clears the events of a specified task. Table 10.1: Events API functions UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 180 CHAPTER 10 Task events 10.2.1 OS_WaitEvent() Description Waits for one of the events specified in the bitmask and clears the event memory after an event occurs. Prototype OS_TASK_EVENT OS_WaitEvent (OS_TASK_EVENT EventMask); Parameter EventMask Description The events that the task will be waiting for. The type OS_TASK_EVENT is defined as unsigned long for 32bit CPUs and unsigned char for 8- or 16-bit CPUs per default. Table 10.2: OS_WaitEvent() parameter list Return value All events that have actually occurred. Additional Information If none of the specified events are signaled, the task is suspended. The first of the specified events will wake the task. These events are signaled by another task, a S/W timer or an interrupt handler. Any bit in the event mask may enable the corresponding event. When a task shall wait on multiple events, all of the specified events shall be requested by a single call of OS_WaitEvent() and all events must be be handled when the function returns. Note that all events of the task are cleared when the function returns, even those events that were not given as parameter in the eventmask. Consecutive calls of OS_WaitEvent() with different event masks will not work, as all events are cleared when the function returns. Events may got lost. OS_WaitSingleEvent() may be used for this case. OS_TASK_EVENT is defined as unsigned long for 32bit CPUs and unsigned char for 8- or 16-bit CPUs per default. It may be modified to any other type when embOS sources are used in a project, or when the libraries are rebuilt with a modified definition. Example void Task(void) { OS_TASK_EVENT MyEvents; while(1) { MyEvents = OS_WaitEvent(3); /* Handle ALL events */ /* Wait for event 1 or 2 to be signaled */ if (MyEvents & (1 << 0)) { _HandleEvent1(); } if (MyEvents & (1 << 1)) { _HandleEvent2(); } } } For a further example, see OS_SignalEvent(). UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 181 10.2.2 OS_WaitSingleEvent() Description Waits for one or more of the events specified by the Eventmask and clears only those events that were specified in the eventmask. Prototype OS_TASK_EVENT OS_WaitSingleEvent (OS_TASK_EVENT EventMask); Parameter EventMask Description The events that the task will be waiting for. Table 10.3: OS_WaitSingleEvent() parameter list Return value All requested events that have actually occurred. Additional Information If none of the specified events are signaled, the task is suspended. The first of the requested events will wake the task. These events are signaled by another task, a S/ W timer, or an interrupt handler. Any bit in the event mask may enable the corresponding event. When the function returns, it delivers all of the requested events. The requested events are cleared in the event state of the task. All other events remain unchanged and will not be returned. OS_WaitSingleEvent() may be used in consecutive calls with individual requests. Only requested events will be handled, no other events can get lost. When the function waits on multiple events, the returned value must be evaluated because the function returns when at least one of the requested events was signaled. When the function requests a single event, the returned value does not need to be evaluated. OS_TASK_EVENT is defined as unsigned long for 32bit CPUs and unsigned char for 8- or 16-bit CPUs per default. It may be modified to any other type when embOS sources ar used in a project, or when the libraries are rebuilt with a modified definition. Example void Task(void) { OS_TASK_EVENT MyEvents; while(1) { MyEvents = OS_WaitSingleEvent(3); /* Handle ALL events */ if (MyEvents & (1 << 0)) _HandleEvent1(); } if (MyEvents & (1 << 1)) _HandleEvent2(); } OS_WaitSingleEvent((1 << _HandleEvent3(); OS_WaitSingleEvent((1 << _HandleEvent4(); /* Wait for event 1 or 2 to be signaled */ { { 2)); /* Wait for event 3 to be signaled */ 3)); /* Wait for event 4 to be signaled */ } } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 182 CHAPTER 10 Task events 10.2.3 OS_WaitEventTimed() Description Waits for the specified events for a given time, and clears the event memory after one of the requsted events occurs, or after the timeout expired. Prototype OS_TASK_EVENT OS_WaitEventTimed (OS_TASK_EVENT EventMask, OS_TIME TimeOut); Parameter EventMask Timeout Description The events that the task will be waiting for. Maximum time in timer ticks until the events must be signaled. The data type OS_TIME is defined as an integer, therefore valid values are 1 <= Timeout <= 2 15-1 = 0x7FFF = 32767 for 8/16-bit CPUs 1 <= Timeout <= 2 31-1 = 0x7FFFFFFF for 32-bit CPUs Table 10.4: OS_WaitEventTimed() parameter list Return value The events that have actually occurred within the specified time. 0 if no events were signaled in time. Additional Information If none of the specified events are available, the task is suspended for the given time. The first of the requested events will wake the task if the event is signaled by another task, a S/W timer, or an interrupt handler within the specified TimeOut time. If none of the requested events is signaled, the task is activated after the specified timeout and all actual events are returned and then cleared. Note that the function returns all events that were signaled within the given timeout time, even those which were not requested. The calling function must evaluate the returned value. Consecutive calls of OS_WaitEventTimed() with different event masks will not work, as all events are cleared when the function returns. Events may got lost. OS_WaitSingleEventTimed() may be used for this case. OS_TASK_EVENT is defined as unsigned long for 32bit CPUs and unsigned char for 8- or 16-bit CPUs per default. It may be modified to any other type when embOS sources ar used in a project, or when the libraries are rebuilt with a modified definition. Example void Task(void) { OS_TASK_EVENT MyEvents; while(1) { MyEvents = OS_WaitEvent_Timed(3, 10); /* Wait for events 1+2 for 10 ms */ if ((MyEvents & 0x3) == 0) { _HandleTimeout(); } else { if (MyEvents & (1 << 0)) { _HandleEvent1(); } if (MyEvents & (1 << 1)) { _HandleEvent2(); } } } } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 183 10.2.4 OS_WaitSingleEventTimed() Description Waits for the specified events for a given time; after an event occurs, only the requested events are cleared. Prototype OS_TASK_EVENT OS_WaitSingleEventTimed (OS_TASK_EVENT EventMask, OS_TIME TimeOut); Parameter EventMask Timeout Description The events that the task will be waiting for. Maximum time in timer ticks until the events must be signaled. The data type OS_TIME is defined as an integer, therefore valid values are 1 <= Timeout <= 215-1 = 0x7FFF = 32767 for 8/16-bit CPUs 1 <= Timeout <= 231-1 = 0x7FFFFFFF for 32-bit CPUs Table 10.5: OS_WaitSingleEventTimed() parameter list Return value The masked events that have actually occurred within the specified time. 0 if no masked events were signaled in time. Additional Information If none of the specified events are available, the task is suspended for the given time. The first of the specified events will wake the task if the event is signaled by another task, a S/W timer or an interrupt handler within the specified TimeOut time. If no event is signaled, the task is activated after the specified timeout and the function returns zero. Any bit in the event mask may enable the corresponding event. All unmasked events remain unchanged. OS_TASK_EVENT is defined as unsigned long for 32bit CPUs and unsigned char for 8- or 16-bit CPUs per default. It may be modified to any other type when embOS sources ar used in a project, or when the libraries are rebuilt with a modified definition. Example void Task(void) { OS_TASK_EVENT MyEvents; while(1) { MyEvents = OS_WaitSingleEventTimed(3, 10); /* Wait for event 1 or 2 to be signaled within 10ms */ /* Handle requested events */ if (MyEvents == 0) { _HandleTimeout; } else { if (MyEvents & (1 << 0)) { _HandleEvent1(); } if (MyEvents & (1 << 1)) { _HandleEvent2(); } } if (OS_WaitSingleEvent((1 << 2), 10) == 0) { _HandleTimeout(); } else { _HandleEvent3(); } } } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 184 CHAPTER 10 Task events 10.2.5 OS_SignalEvent() Description Signals event(s) to a specified task. Prototype void OS_SignalEvent (OS_TASK_EVENT Event, OS_TASK* pTask); Parameter Event pTask Description The event(s) to signal: 1 means event 1 2 means event 2 4 means event 3 ... 128 means event 8. Multiple events can be signaled as the sum of the single events (for example, 6 will signal events 2 & 3). Task that the events are sent to. Table 10.6: OS_SignalEvent() parameter list Additional Information If the specified task is waiting for one of these events, it will be put in the READY state and activated according to the rules of the scheduler. OS_TASK_EVENT is defined as unsigned long for 32bit CPUs and unsigned char for 8- or 16-bit CPUs per default. It may be modified to any other type when embOS sources ar used in a project, or when the libraries are rebuilt with a modified definition. Example The task that handles the serial input and the keyboard waits for a character to be received either via the keyboard (EVENT_KEYPRESSED) or serial interface (EVENT_SERIN): /* * Just a small demo for events */ #define EVENT_KEYPRESSED (1) #define EVENT_SERIN (2) OS_STACKPTR int Stack0[96]; OS_TASK TCB0; // Task stacks // Data area for tasks (task control blocks) void Task0(void) { OS_TASK_EVENT MyEvent; while(1) MyEvent = OS_WaitEvent(EVENT_KEYPRESSED | EVENT_SERIN) if (MyEvent & EVENT_KEYPRESSED) { /* handle key press */ } if (MyEvent & EVENT_SERIN) { /* Handle serial reception */ } } } void TimerKey(void) { /* More code to find out if key has been pressed */ OS_SignalEvent(EVENT_SERIN, &TCB0); /* Notify Task that key was pressed */ } void InitTask(void) { OS_CREATETASK(&TCB0, 0, Task0, 100, Stack0); } UM01001 User & Reference Guide for embOS /* Create Task0 */ (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 185 If the task was only waiting for a key to be pressed, OS_GetMail() could simply be called. The task would then be deactivated until a key is pressed. If the task has to handle multiple mailboxes, as in this case, events are a good option. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 186 CHAPTER 10 Task events 10.2.6 OS_GetEventsOccurred() Description Returns a list of events that have occurred for a specified task. Prototype OS_TASK_EVENT OS_GetEventsOccurred (const OS_TASK* pTask); Parameter pTask Description The task who's event mask is to be returned, NULL means current task. Table 10.7: OS_GetEventsOccurred() parameter list Return value The event mask of the events that have actually occurred. Additional Information By calling this function, the actual events remain signaled. The event memory is not cleared. This is one way for a task to find out which events have been signaled. The task is not suspended if no events are signaled. OS_TASK_EVENT is defined as unsigned long for 32bit CPUs and unsigned char for 8- or 16-bit CPUs per default. It may be modified to any other type when embOS sources ar used in a project, or when the libraries are rebuilt with a modified definition. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 187 10.2.7 OS_ClearEvents() Description Returns the actual state of events and then clears the events of a specified task. Prototype OS_TASK_EVENT OS_ClearEvents (OS_TASK* pTask); Parameter pTask Description The task who's event mask is to be returned, NULL means current task. Table 10.8: OS_ClearEvents() parameter list Return value The events that were actually signaled before clearing. OS_TASK_EVENT is defined as unsigned long for 32bit CPUs and unsigned char for 8- or 16-bit CPUs per default. It may be modified to any other type when embOS sources ar used in a project, or when the libraries are rebuilt with a modified definition. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 188 UM01001 User & Reference Guide for embOS CHAPTER 10 Task events (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 189 Chapter 11 Event objects UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 190 CHAPTER 11 Event objects 11.1 Introduction Event objects are another type of communication and synchronization objects. In contrast to task-events, event objects are standalone objects which are not owned by any task. The purpose of an event object is to enable one or multiple tasks to wait for a particular event to occur. The tasks can be kept suspended until the event is set by another task, a S/W timer, or an interrupt handler. The event can be anything that the software is made aware of in any way. Examples include the change of an input signal, the expiration of a timer, a key press, the reception of a character, or a complete command. Compared to a task event, the signaling function does not need to know which task is waiting for the event to occur. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 191 11.2 API functions Description Creates an event object. Must be called before the event object can be used. Creates an event object and allows selection OS_EVENT_CreateEx() of the reset behavior of the event. OS_EVENT_Wait() Waits for an event. Waits for an event with timeout and optionOS_EVENT_WaitTimed() ally resets the event according the reset mode. OS_EVENT_Set() Sets the events, or resumes waiting tasks. OS_EVENT_Reset() Resets the event to none-signaled state. Sets the event, resumes waiting tasks, if any, OS_EVENT_Pulse() and then resets the event. OS_EVENT_Get() Returns the state of an event object. OS_EVENT_Delete() Deletes the specified event object. Sets the reset behaviour of events to autoOS_EVENT_SetResetMode() matic, manual or semiauto. Retrieves the current the reset behaviour OS_EVENT_GetResetMode() mode of an event object. OS_EVENT_Create() Timer ISR Task main Routine X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X Table 11.1: Event object API functions UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 192 CHAPTER 11 Event objects 11.2.1 OS_EVENT_Create() Description Creates an event object and resets the event. Prototype void OS_EVENT_Create (OS_EVENT* pEvent) Parameter pEvent Description Pointer to an event object data structure. Table 11.2: OS_EVENT_Create() parameter list Additional Information Before the event object can be used, it must be created by a call of OS_EVENT_Create(). On creation, the event is set in non-signaled state, and the list of waiting tasks is deleted. Therefore, OS_EVENT_Create() must not be called for an event object which was already created before. A debug build of embOS cannot check whether the specified event object was already created. The event is created with the default reset behavior which is semiauto. Since version 3.88a of embOS, the reset behavior of the event can be modified by a call of the function OS_EVENT_SetResetMode(). Example OS_EVENT _HW_Event; OS_EVENT_Create(&HW_Event); UM01001 User & Reference Guide for embOS /* Create and initialize event object */ (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 193 11.2.2 OS_EVENT_CreateEx() Description Creates an event object with specified rest behavior and resets the event. Prototype void OS_EVENT_Create (OS_EVENT* pEvent, OS_EVENT_RESET_MODE ResetMode) Parameter pEvent ResetMode Description Pointer to an event object data structure. Specifies the reset behavior of the event object. One of the predefined reset modes can be used: OS_EVENT_RESET_MODE_SEMIAUTO OS_EVENT_RESET_MODE_AUTO OS_EVENT_RESET_MODE_MANUAL which are dscribed under Additional information Table 11.3: OS_EVENT_CreateEx() parameter list Additional Information Before the event object can be used, it must be created by a call of OS_EVENT_Create() or OS_EVENT_CreateEx(). On creation, the event is set in nonsignaled state, and the list of waiting tasks is deleted. Therefore, OS_EVENT_CreateEx() must not be called for an event object which was already created before. A debug build of embOS cannot check whether the specified event object was already created. Since version 3.88a of embOS, the reset behavior of the event can be controlled by different reset modes which may be passed as parameter to the new function OS_EVENT_CreateEx() or may be modified by a call of OS_EVENT_SetResetMode(). * * * OS_EVENT_RESET_MODE_SEMIAUTO: This reset mode is the default mode used with all previous versions of embOS. The reset behavior unfortunately is not consistent and depends on the function called to set or wait for an event. This reset mode is defined for compatibility with older embOS versions (prior version 3.88a). Calling OS_EVENT_Create() sets the reset mode to OS_EVENT_RESET_MODE_SEMIAUTO to be compatible with older embOS versions. OS_EVENT_RESET_MODE_AUTO: This mode sets the reset behavior of an event object to automatic clear. When an event is set, all waiting tasks are resumed and the event is cleared automatically, except waiting tasks called OS_EVENT_WaitTimed() and the timeout of the task expired before the event was set. OS_EVENT_RESET_MODE_MANUAL: This mode sets the event to manual reset mode. When an event is set, all waiting tasks are resumed and the event object remains signaled. The event must be reset by one task which was waiting for the event. Example OS_EVENT _HW_Event; /* Create and initialize an event object with automatic reset */ OS_EVENT_CreateEx(&HW_Event, OS_EVENT_RESET_MODE_AUTO); UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 194 CHAPTER 11 Event objects 11.2.3 OS_EVENT_Wait() Description Waits for an event and suspends the calling task as long as the event is not signaled. Prototype void OS_EVENT_Wait (OS_EVENT* pEvent) Parameter pEvent Description Pointer to the event object that the task will be waiting for. Table 11.4: OS_EVENT_Wait() parameter list Additional Information pEvent must address an existing event object, which must be created before the call of OS_EVENT_Wait(). A debug build of embOS will check whether pEvent addresses a valid event object and will call OS_Error() with error code OS_ERR_EVENT_INVALID in case of an error. The state of the event object after calling OS_EVENT_Wait() depends on the reset mode of the event object wich was set by creating the event object by a call of OS_EVENT_CreateEx() or OS_EVENT_SetResetMode(). * * * With reset mode OS_EVENT_RESET_MODE_SEMIAUTO: This is the default mode when the event object was created with OS_EVENT_Create(). This was the only mode available in embOS versions prior version 3.88a. If the specified event object is already set, the calling task resets the event and continues operation. If the specified event object is not set, the calling task is suspended until the event object becomes signaled. The event is not reset when the task resumes. With reset mode OS_EVENT_RESET_MODE_AUTO: If the specified event object is already set, the calling task resets the event and continues operation. If the specified event object is not set, the calling task is suspended until the event object becomes signaled and then the event object is reset when the waiting task resumes. With reset mode OS_EVENT_RESET_MODE_MANUAL: If the specified event object is already set, the calling task continues operation. The event object remains signaled. If the specified event object is not set, the calling task is suspended until the event object becomes signaled. Then the waiting task is resumed and the event object remains signaled. The event object must be reset by the calling task. Important This function must not be called from within an interrupt handler or software timer. A debug build of embOS will call OS_Error() when OS_EVENT_Wait() is called from an ISR or timer. Example OS_EVENT_Wait(&_HW_Event); OS_EVENT_Reset(&_HW_Event); UM01001 User & Reference Guide for embOS // Wait for event object // Reset the event (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 195 11.2.4 OS_EVENT_WaitTimed() Description Waits for an event and suspends the calling task for a specified time as long as the event is not signaled. Prototype char OS_EVENT_WaitTimed (OS_EVENT* pEvent, OS_TIME Timeout) Parameter pEvent Timeout Description Pointer to the event object that the task will be waiting for. Maximum time in timer ticks until the event must be signaled. The data type OS_TIME is defined as an integer, therefore valid values are 1 <= Timeout <= 215-1 = 0x7FFF = 32767 for 8/16-bit CPUs 1 <= Timeout <= 231-1 = 0x7FFFFFFF for 32-bit CPUs Table 11.5: OS_EVENT_WaitTimed() parameter list Return value 0 success, the event was signaled within the specified time. 1 if the event was not signaled within the specified timeout time. Additional Information pEvent must address an existing event object, which must be created before the call of OS_EVENT_WaitTimed(). A debug build of embOS will check whether pEvent addresses a valid event object and will call OS_Error() with error code OS_ERR_EVENT_INVALID in case of an error. If the specified event object is not set, the calling task is suspended until the event object becomes signaled or the timeout time has expired. When the timeout expired and the event was not signaled during the specified timeout time, OS_EVENT_WaitTimed() returns 1. If the specified event object is already set, or becomes signaled within the specified timeout time, the state of the event depends on the reset mode of the event. * * * With reset mode OS_EVENT_RESET_MODE_SEMIAUTO: This is the default mode when the event object was created with OS_EVENT_Create(). This was the only mode available in embOS versions prior version 3.88a. If the specified event object is already set, the calling task resets the event and continues operation. If the event object becomes signaled within the specified timeout time, the event is reset and the function returns without timeout result. With reset mode OS_EVENT_RESET_MODE_AUTO: If the specified event object is already set, the calling task resets the event and continues operation. If the event object becomes signaled within the specified timeout time, the event is reset and the function returns without timeout result. With reset mode OS_EVENT_RESET_MODE_MANUAL: If the specified event object is already set, the calling task continues operation. The event object remains signaled. If the specified event object is not set, the calling task is suspended until the event object becomes signaled. When the event object is signaled within the specified timeout time, the waiting task is resumed and the event object remains signaled. The event object must be reset by the calling task. The function returns without timeout result. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 196 CHAPTER 11 Event objects When the calling task is blocked by higher priority tasks for a longer period than the timeout value, it may happen, that the event becomes signaled after the timeout time before the calling task continues. In this case, the function returns with timeout, because the event was not available within the requested time. In this case, the state of the event is not modified by OS_EVENT_WaitTimed() regardless the reset mode. Important This function must not be called from within an interrupt handler or software timer. A debug build of embOS will call OS_Error() when OS_EVENT_Wait() is called from an ISR or timer. Example if (OS_EVENT_WaitTimed(&_HW_Event, 10) == 0) { /* event was signaled within timeout time, handle event */ ... } else { /* event was not signaled within timeout time, handle timeout */ ... } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 197 11.2.5 OS_EVENT_Set() Description Sets an event object to signaled state, or resumes tasks which are waiting at the event object. Prototype void OS_EVENT_Set (OS_EVENT* pEvent) Parameter pEvent Description Pointer to the event object which should be set to signaled state. Table 11.6: OS_EVENT_Set() parameter list Additional Information pEvent must address an existing event object, which must be created before by a call of OS_EVENT_Create(). A debug build of embOS will check whether pEvent addresses a valid event object and will call OS_Error() with error code OS_ERR_EVENT_INVALID in case of an error. If no tasks are waiting at the event object, the event object is set to signaled state. If at least one task is already waiting at the event object, all waiting tasks are resumed. The state of the event object after calling OS_EVENT_Set() then depends on the reset mode of the event object. * * * With reset mode OS_EVENT_RESET_MODE_SEMIAUTO: This is the default mode when the event object was created with OS_EVENT_Create(). This was the only mode available in embOS versions prior version 3.88a. If tasks were waiting, the event is reset when the waiting tasks are resumed. With reset mode OS_EVENT_RESET_MODE_AUTO: The event object is automatically reset when waiting tasks are resumed and continue operation. With reset mode OS_EVENT_RESET_MODE_MANUAL: The event object remains signaled when waiting tasks are resumed and continue operation. The event object must be reset by the calling task. Example Examples on how to use the OS_EVENT_Set() function are shown in the section "Examples". UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 198 CHAPTER 11 Event objects 11.2.6 OS_EVENT_Reset() Description Resets the specified event object to non-signaled state. Prototype void OS_EVENT_Reset (OS_EVENT* pEvent) Parameter pEvent Description Pointer to the event object which should be reset to non-signaled state. Table 11.7: OS_EVENT_Reset() parameter list Additional Information pEvent must address an existing event object, which has been created before by a call of OS_EVENT_Create(). A debug build of embOS will check whether pEvent addresses a valid event object and will call OS_Error() with the error code OS_ERR_EVENT_INVALID in case of an error. Example OS_EVENT_Reset(&_HW_Event); /* Reset event object to non-signaled state */ UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 199 11.2.7 OS_EVENT_Pulse() Description Signals an event object and resumes waiting tasks, then resets the event object to non-signaled state. Prototype void OS_EVENT_Pulse (OS_EVENT* pEvent); Parameter pEvent Description Pointer to the event object which should be pulsed. Table 11.8: OS_EVENT_Pulse() parameter list Additional Information If any tasks are waiting at the event object, the tasks are resumed. The event object remains in non-signaled state, regardless the reset mode. A debug build of embOS will check whether pEvent addresses a valid event object and will call OS_Error() with the error code OS_ERR_EVENT_INVALID in case of an error. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 200 CHAPTER 11 Event objects 11.2.8 OS_EVENT_Get() Description Returns the state of an event object. Prototype unsigned char OS_EVENT_Get (const OS_EVENT* pEvent); Parameter pEvent Description Pointer to an event object who's state should be examined. Table 11.9: OS_EVENT_Get() parameter list Return value 0: Event object is not set to signaled state 1: Event object is set to signaled state. Additional Information By calling this function, the actual state of the event object remains unchanged. pEvent must address an existing event object, which has been created before by a call of OS_EVENT_Create(). A debug build of embOS will check whether pEvent addresses a valid event object and will call OS_Error() with error code OS_ERR_EVENT_INVALID in case of an error. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 201 11.2.9 OS_EVENT_Delete() Description Deletes an event object. Prototype void OS_EVENT_Delete (OS_EVENT* pEvent); Parameter pEvent Description Pointer to an event object which should be deleted. Table 11.10: OS_EVENT_Delete() parameter list Additional Information To keep the system fully dynamic, it is essential that event objects can be created dynamically. This also means there must be a way to delete an event object when it is no longer needed. The memory that has been used by the event object's control structure can then be reused or reallocated. It is your responsibility to make sure that: * * * the program no longer uses the event object to be deleted the event object to be deleted actually exists (has been created first) no tasks are waiting at the event object when it is deleted. pEvent must address an existing event object, which has been created before by a call of OS_EVENT_Create()or OS_EVENT_CreateEx(). A debug build of embOS will check whether pEvent addresses a valid event object and will call OS_Error() with error code OS_ERR_EVENT_INVALID in case of an error. If any task is waiting at the event object which is deleted, a debug build of embOS calls OS_Error() with error code OS_ERR_EVENT_DELETE. To avoid any problems, an event object should not be deleted in a normal application. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 202 CHAPTER 11 Event objects 11.2.10 OS_EVENT_SetResetMode() Description Used to set the reset behavior mode of an event object. Prototype void OS_EVENT_SetResetMode (OS_EVENT* pEvent, OS_EVENT_RESET_MODE ResetMode) Parameter pEvent ResetMode Description Pointer to an event object which should be deleted. Specifies the reset behavior of the event object. One of the predefined reset modes can be used: OS_EVENT_RESET_MODE_SEMIAUTO OS_EVENT_RESET_MODE_AUTO OS_EVENT_RESET_MODE_MANUAL which are dscribed under Additional information Table 11.11: OS_EVENT_Delete() parameter list Additional Information pEvent must address an existing event object, which has been created before by a call of OS_EVENT_Create()or OS_EVENT_CreateEx(). A debug build of embOS will check whether pEvent addresses a valid event object and will call OS_Error() with error code OS_ERR_EVENT_INVALID in case of an error. Implementation of event objects in embOS versions before 3.88a unfortunately was not consistent with respect to the state of the event after calling OS_EVENT_Set() or OS_EVENT_Wait() wait functions. The state of the event was different when tasks were waiting or not. Since embOS version 3.88a, the state of the event (reset behavior) can be controlled after creation by the new function OS_EVENT_SetResetMode(), or during creation by the new OS_EVENT_CreateEx() function. The following reset modes are defined an can be used as parameter: * * * OS_EVENT_RESET_MODE_SEMIAUTO: This reset mode is the default mode used with all previous versions of embOS. The reset behavior unfortunately is not consistent and depends on the function called to set or wait for an event. This reset mode is defined for compatibility with older embOS versions (prior version 3.88a). Calling OS_EVENT_Create() sets the reset mode to OS_EVENT_RESET_MODE_SEMIAUTO to be compatible with older embOS versions. OS_EVENT_RESET_MODE_AUTO: This mode sets the reset behavior of an event object to automatic clear. When an event is set, all waiting tasks are resumed and the event is cleared automatically, except waiting tasks called OS_EVENT_WaitTimed() and the timeout of the task expiered before the event was set. OS_EVENT_RESET_MODE_MANUAL: This mode sets the event to manual reset mode. When an event is set, all waiting tasks are resumed and the event object remains signaled. The event must be reset by one task which was waiting for the event. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 203 11.2.11 OS_EVENT_GetResetMode() Description Retrieves the current reset mode of an event object. Prototype OS_EVENT_RESET_MODE OS_EVENT_GetResetMode (OS_EVENT* pEvent); Parameter pEvent Description Pointer to an event object which should be deleted. Table 11.12: OS_EVENT_Delete() parameter list Additional Information pEvent must address an existing event object, which has been created before by a call of OS_EVENT_Create()or OS_EVENT_CreateEx(). A debug build of embOS will check whether pEvent addresses a valid event object and will call OS_Error() with error code OS_ERR_EVENT_INVALID in case of an error. Since version 3.88a of embOS, the reset mode of an event object can be controlled by the new OS_EVENT_CreateEx() function or set after creation using the new function OS_EVENT_SetResetMode(). If needed, the current setting of the reset mode can be retrieved with OS_EVENT_GetResetMode(). Example OS_EVENT_Wait(&_HW_Event); // Wait for event object if (OS_EVENT_GetResetMode(&_HW_Event) == OS_EVENT_RESET_MODE_MANUAL) { OS_EVENT_Reset(&_HW_Event); // Reset the event } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 204 CHAPTER 11 Event objects 11.3 Examples of using event objects This chapter shows some examples on how to use event objects in an application. 11.3.1 Activate a task from interrupt by an event object The following code example shows usage of an event object which is signaled from an ISR handler to activate a task. The waiting task should reset the event after waiting for it. static OS_EVENT _HW_Event; /************************************************************ * * _ISRhandler */ static void _ISRhandler(void) { // // Perform some simple & fast processing in ISR // // ... // // Wake up task to do the rest of the work // OS_EVENT_Set(&_Event); } /************************************************************ * * _Task */ static void _Task(void) { while (1) { OS_EVENT_Wait(&_Event); OS_EVENT_Reset(&_Event); // // Do the rest of the work (which has not been done in the ISR) // } } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 205 11.3.2 Activating multiple tasks using a single event object The following sample program shows how to synchronize multiple tasks with one event object. The sample program is delivered with embOS in the "Application" or "Samples" folder. /******************************************************************** * SEGGER MICROCONTROLLER SYSTEME GmbH * Solutions for real time microcontroller applications ********************************************************************* File : Main_EVENT.c Purpose : Sample program for embOS using EVENT object --------- END-OF-HEADER --------------------------------------------*/ #include "RTOS.h" OS_STACKPTR int StackHP[128], StackLP[128]; OS_TASK TCBHP, TCBLP; /* Task stacks */ /* Task-control-blocks */ /********************************************************************/ /****** Interface to HW module **************************************/ void HW_Wait(void); void HW_Free(void); void HW_Init(void); /********************************************************************/ /****** HW module ***************************************************/ OS_STACKPTR int _StackHW[128]; OS_TASK _TCBHW; /* Task stack /* Task-control-block */ */ /****** local data **************************************************/ static OS_EVENT _HW_Event; /****** local functions *********************************************/ static void _HWTask(void) { /* Initialize HW functionality */ OS_Delay(100); /* Init done, send broadcast to waiting tasks */ HW_Free(); while (1) { OS_Delay (40); } } /****** global functions ********************************************/ void HW_Wait(void) { OS_EVENT_Wait(&_HW_Event); } void HW_Free(void) { OS_EVENT_Set(&_HW_Event); } void HW_Init(void) { OS_CREATETASK(&_TCBHW, "HWTask", _HWTask, 25, _StackHW); OS_EVENT_Create(&_HW_Event); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 206 CHAPTER 11 Event objects /********************************************************************/ /****** Main application ********************************************/ static void HPTask(void) { HW_Wait(); while (1) { OS_Delay (50); } } static void LPTask(void) { HW_Wait(); while (1) { OS_Delay (200); } } /* Wait until HW module is set up */ /* Wait until HW module is set up */ /********************************************************************* * * main * **********************************************************************/ int main(void) { OS_IncDI(); /* Initially disable interrupts OS_InitKern(); /* Initialize OS OS_InitHW(); /* Initialize Hardware for OS HW_Init(); /* Initialize HW module /* You need to create at least one task before calling OS_Start() OS_CREATETASK(&TCBHP, "HP Task", HPTask, 100, StackHP); OS_CREATETASK(&TCBLP, "LP Task", LPTask, 50, StackLP); OS_SendString("Start project will start multitasking !\n"); OS_Start(); /* Start multitasking return 0; } UM01001 User & Reference Guide for embOS */ */ */ */ */ */ (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 207 Chapter 12 Heap type memory management UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 208 CHAPTER 12 Heap type memory management 12.1 Introduction ANSI C offers some basic dynamic memory management functions. These are malloc, free, and realloc. Unfortunately, these routines are not thread-safe, unless a special thread-safe implementation exists in the compiler specific runtime libraries; they can only be used from one task or by multiple tasks if they are called sequentially. Therefore, embOS offer task-safe variants of these routines. These variants have the same names as their ANSI counterparts, but are prefixed OS_; they are called OS_malloc(), OS_free(), OS_realloc(). The thread-safe variants that embOS offers use the standard ANSI routines, but they guarantee that the calls are serialized using a resource semaphore. If heap memory management is not supported by the standard C-libraries for a specific CPU, embOS heap memory management is not implemented. Heap type memory management is part of the embOS libraries. It does not use any resources if it is not referenced by the application (that is, if the application does not use any memory management API function). Note that another aspect of these routines may still be a problem: the memory used for the functions (known as heap) may fragment. This can lead to a situation where the total amount of memory is sufficient, but there is not enough memory available in a single block to satisfy an allocation request. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 209 12.2 API functions OS_malloc() OS_free() OS_realloc() Description Allocates a block of memory on the heap. Frees a block of memory previously allocated. Changes allocation size. Timer ISR Task main API routine X X X X X X Table 12.1: Heap type memory manager API functions UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 210 CHAPTER 12 Heap type memory management 12.2.1 OS_malloc() Description OS_malloc() is a thread safe malloc function. Prototype void* OS_malloc(unsigned int Size); Parameter Size Description Size of memory block to be allocated in bytes. Table 12.2: OS_malloc() parameter list Return value Upon successful completion with size not equal 0, OS_malloc() returns a pointer to the allocated space. Otherwise, it returns a null pointer. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 211 12.2.2 OS_free() Description OS_free() is a thread safe free function. Prototype void OS_free(void* pMemBlock); Parameter pMemBlock Description Pointer to a memory block previously allocated with malloc. Table 12.3: OS_free() parameter list UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 212 CHAPTER 12 Heap type memory management 12.2.3 OS_realloc() Description OS_realloc() is a thread safe ralloc function. Prototype void* OS_realloc(void* pMemBlock, unsigned int NewSize); Parameter pMemBlock NewSize Description Pointer to a memory block previously allocated with malloc. New size for the memory block in bytes. Table 12.4: OS_realloc() paramter list Return value OS_realloc() returns a pointer to the reallocated memory block. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 213 Chapter 13 Fixed block size memory pools UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 214 CHAPTER 13 Fixed block size memory pools 13.1 Introduction Fixed block size memory pools contain a specific number of fixed-size blocks of memory. The location in memory of the pool, the size of each block, and the number of blocks are set at runtime by the application via a call to the OS_MEMF_CREATE() function. The advantage of fixed memory pools is that a block of memory can be allocated from within any task in a very short, determined period of time. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 215 13.2 API functions All API functions for fixed block size memory pools are prefixed OS_MEMF_. Description Create / Delete Creates fixed block memory pool. Deletes fixed block memory pool. Allocation Allocates memory block from a given OS_MEMF_Alloc() memory pool. Wait indefinitely if no block is available. Allocates memory block from a given OS_MEMF_AllocTimed() memory pool. Wait no longer than given time limit if no block is available. Allocates block from a given memory pool, OS_MEMF_Request() if available. Non-blocking. Release Releases memory block from a given OS_MEMF_Release() memory pool. OS_MEMF_FreeBlock() Releases memory block from any pool. Info Returns the number of available blocks in OS_MEMF_GetNumFreeBlocks() a pool. OS_MEMF_IsInPool() Returns !=0 if block is in memory pool. Returns the maximum number of blocks in OS_MEMF_GetMaxUsed() a pool which have been used at a time. OS_MEMF_GetNumBlocks() Returns the number of blocks in a pool. Returns the size of one block of a given OS_MEMF_GetBlockSize() pool. OS_MEMF_Create() OS_MEMF_Delete() Timer ISR Task main API routine X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X Table 13.1: Memory pools API functions UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 216 CHAPTER 13 Fixed block size memory pools 13.2.1 OS_MEMF_Create() Description Creates and initializes a fixed block size memory pool. Prototype void OS_MEMF_Create (OS_MEMF* pMEMF, void* pPool, OS_UINT NumBlocks, OS_UINT BlockSize); Parameter pMEMF pPool NumBlocks BlockSize Description Pointer to the control data structure of memory pool. Pointer to memory to be used for the memory pool. Required size is: NumBlocks * (BlockSize + OS_MEMF_SIZEOF_BLOCKCONTROL). Number of blocks in the pool. Size in bytes of one block. Table 13.2: OS_MEMF_Create() parameter list Additional Information OS_MEMF_SIZEOF_BLOCKCONTROL gives the number of bytes used for control and debug purposes. It is guaranteed to be 0 in release or stack-check builds. Before using any memory pool, it must be created. A debug build of libraries keeps track of created and deleted memory pools. The release and stack-check builds do not. The maximum number of blocks and the maximum block size is for 16Bit CPUs 32768 and for 32Bit CPUs 2147483648. Example #define NUM_BLOCKS (16) #define BLOCK_SIZE (16) #define POOL_SIZE (NUM_BLOCKS * (BLOCK_SIZE + OS_MEMF_SIZEOF_BLOCKCONTROL)) OS_U8 aPool[POOL_SIZE]; OS_MEMF MyMEMF; void Init(void) { /* Create 16 Blocks with size of 16 Bytes */ OS_MEMF_Create(&MyMEMF, aPool, NUM_BLOCKS, BLOCK_SIZE); } Note OS_MEMF_SIZEOF_BLOCKCONTROL is always zero because additional debug code is not implemented. It is only designed for future use. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 217 13.2.2 OS_MEMF_Delete() Description Deletes a fixed block size memory pool. After deletion, the memory pool and memory blocks inside this pool can no longer be used. Prototype void OS_MEMF_Delete (OS_MEMF* pMEMF); Parameter pMEMF Description Pointer to the control data structure of memory pool. Table 13.3: OS_MEMF_Delete() parameter list Additional Information This routine is provided for completeness. It is not used in the majority of applications because there is no need to dynamically create/delete memory pools. For most applications it is preferred to have a static memory pool design; memory pools are created at startup (before calling OS_Start()) and will never be deleted. A debug build of libraries mark the memory pool as deleted. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 218 CHAPTER 13 Fixed block size memory pools 13.2.3 OS_MEMF_Alloc() Description Requests allocation of a memory block. Waits until a block of memory is available. Prototype void* OS_MEMF_Alloc (OS_MEMF* pMEMF, int Purpose); Parameter pMEMF Purpose Description Pointer to the control data structure of memory pool. This is a parameter which is used for debugging purpose only. Its value has no effect on program execution, but may be remembered in debug builds to allow runtime analysis of memory allocation problems. Table 13.4: OS_MEMF_Alloc() parameter list Return value Pointer to the allocated block. Additional Information If there is no free memory block in the pool, the calling task is suspended until a memory block becomes available. The retrieved pointer must be delivered to OS_MEMF_Release() as a parameter to free the memory block. The pointer must not be modified. Note The parameter Purpose is never used because additional debug code is not implemented. It is only designed for future use. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 219 13.2.4 OS_MEMF_AllocTimed() Description Requests allocation of a memory block. Waits until a block of memory is available or the timeout has expired. Prototype void* OS_MEMF_AllocTimed (OS_MEMF* pMEMF, OS_TIME Timeout, int Purpose); Parameter pMEMF Timeout Purpose Description Pointer to the control data structure of memory pool. Time limit before timeout, given in ticks. 0 or negative values are permitted. Timeout in basic embOS time units (nominal ms): The data type OS_TIME is defined as an integer, therefore valid values are 1 <= Timeout <= 215-1 = 0x7FFF = 32767 for 8/16-bit CPUs 1 <= Timeout <= 231-1 = 0x7FFFFFFF for 32-bit CPUs This is a parameter which is used for debugging purpose only. Its value has no effect on program execution, but may be remembered in debug builds to allow runtime analysis of memory allocation problems. Table 13.5: OS_MEMF_AllocTimed() Return value !=NULL pointer to the allocated block NULL if no block could be allocated within the specified time. Additional Information If there is no free memory block in the pool, the calling task is suspended until a memory block becomes available or the timeout has expired. The retrieved pointer must be delivered to OS_MEMF_Release() as parameter to free the memory block. The pointer must not be modified. When the calling task is blocked by higher priority tasks for a longer period than the timeout value, it may happen, that the memory block becomes available after the timeout time before the calling task continues. In this case, the function returns with timeout, because the memory block was not availbale within the requested time. Note The parameter Purpose is never used because additional debug code is not implemented. It is only designed for future use. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 220 CHAPTER 13 Fixed block size memory pools 13.2.5 OS_MEMF_Request() Description Requests allocation of a memory block. Continues execution in any case. Prototype void* OS_MEMF_Request (OS_MEMF* pMEMF, int Purpose); Parameter pMEMF Purpose Description Pointer to the control data structure of memory pool. This is a parameter which is used for debugging purpose only. Its value has no effect on program execution, but may be remembered in debug builds to allow runtime analysis of memory allocation problems. Table 13.6: OS_MEMF_Request() parameter list Return value !=NULL pointer to the allocated block NULL if no block has been allocated. Additional Information The calling task is never suspended by calling OS_MEMF_Request(). The retrieved pointer must be delivered to OS_MEMF_Release() as parameter to free the memory block. The pointer must not be modified. Note The parameter Purpose is never used because additional debug code is not implemented. It is only designed for future use. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 221 13.2.6 OS_MEMF_Release() Description Releases a memory block that was previously allocated. Prototype void OS_MEMF_Release (OS_MEMF* pMEMF, void* pMemBlock); Parameter pMEMF pMemBlock Description Pointer to the control data structure of memory pool. Pointer to the memory block to free. Table 13.7: OS_MEMF_Release() parameter list Additional Information The pMemBlock pointer must be the one that was delivered from any retrieval function described above. The pointer must not be modified between allocation and release. The memory block becomes available for other tasks waiting for a memory block from the pool. If any task is waiting for a fixed memory block, it is activated according to the rules of the scheduler. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 222 CHAPTER 13 Fixed block size memory pools 13.2.7 OS_MEMF_FreeBlock() Description Releases a memory block that was previously allocated. The memory pool does not need to be denoted. Prototype void OS_MEMF_FreeBlock (void* pMemBlock); Parameter pMemBlock Description Pointer to the memory block to free. Table 13.8: OS_MEMF_FreeBlock() parameter list Additional Information The pMemBlock pointer must be the one that was delivered form any retrieval function described above. The pointer must not be modified between allocation and release. This function may be used instead of OS_MEMF_Release(). It has the advantage that only one parameter is needed. embOS itself will find the associated memory pool. The memory block becomes available for other tasks waiting for a memory block from the pool. If any task is waiting for a fixed memory block, it is activated according to the rules of the scheduler. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 223 13.2.8 OS_MEMF_GetNumBlocks() Description Information routine to examine the total number of available memory blocks in the pool. Prototype int OS_MEMF_GetNumBlocks (const OS_MEMF* pMEMF); Parameter pMEMF Description Pointer to the control data structure of memory pool. Table 13.9: OS_MEMF_GetNumBlocks() parameter list Return value Returns the number of blocks in the specified memory pool. This is the value that was given as parameter during creation of the memory pool. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 224 CHAPTER 13 Fixed block size memory pools 13.2.9 OS_MEMF_GetBlockSize() Description Information routine to examine the size of one memory block in the pool. Prototype int OS_MEMF_GetBlockSize (const OS_MEMF* pMEMF); Parameter pMEMF Description Pointer to the control data structure of memory pool. Table 13.10: OS_MEMF_GetBlockSize() parameter list Return value Size in bytes of one memory block in the specified memory pool. This is the value of the parameter when the memory pool was created. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 225 13.2.10 OS_MEMF_GetNumFreeBlocks() Description Information routine to examine the number of free memory blocks in the pool. Prototype int OS_MEMF_GetNumFreeBlocks (OS_MEMF* pMEMF); Parameter pMEMF Description Pointer to the control data structure of memory pool. Table 13.11: OS_MEMF_GetNumFreeBlocks() parameter list Return value The number of free blocks actually available in the specified memory pool. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 226 CHAPTER 13 Fixed block size memory pools 13.2.11 OS_MEMF_GetMaxUsed() Description Information routine to examine the amount of memory blocks in the pool that were used concurrently since creation of the pool. Prototype int OS_MEMF_GetMaxUsed (const OS_MEMF* pMEMF); Parameter pMEMF Description Pointer to the control data structure of memory pool. Table 13.12: OS_MEMF_GetMaxUsed() parameter list Return value Maximum number of blocks in the specified memory pool that were used concurrently since the pool was created. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 227 13.2.12 OS_MEMF_IsInPool() Description Information routine to examine whether a memory block reference pointer belongs to the specified memory pool. Prototype char OS_MEMF_IsInPool (const OS_MEMF* pMEMF, const void* pMemBlock); Parameter pMEMF pMemBlock Description Pointer to the control data structure of memory pool. Pointer to a memory block that should be checked Table 13.13: OS_MEMF_IsInPool() parameter list Return value 0: Pointer does not belong to memory pool. 1: Pointer belongs to the pool. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 228 UM01001 User & Reference Guide for embOS CHAPTER 13 Fixed block size memory pools (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 229 Chapter 14 Stacks UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 230 CHAPTER 14 Stacks 14.1 Introduction The stack is the memory area used for storing the return address of function calls, parameters, and local variables, as well as for temporary storage. Interrupt routines also use the stack to save the return address and flag registers, except in cases where the CPU has a separate stack for interrupt functions. Refer to the CPU & Compiler Specifics manual of embOS documentation for details on your processor's stack. A "normal" single-task program needs exactly one stack. In a multitasking system, every task must have its own stack. The stack needs to have a minimum size which is determined by the sum of the stack usage of the routines in the worst-case nesting. If the stack is too small, a section of the memory that is not reserved for the stack will be overwritten, and a serious program failure is most likely to occur. embOS monitors the stack size (and, if available, also interrupt stack size in a debug build), and calls the failure routine OS_Error() if it detects a stack overflow. However, embOS cannot reliably detect a stack overflow. A stack that has been defined larger than necessary does not hurt; it is only a waste of memory. To detect a stack overflow, the debug and stack-check builds of embOS fill the stack with control characters when it is created and check these characters every time the task is deactivated. If an overflow is detected, OS_Error() is called. 14.1.1 System stack Before embOS takes over control (before the call to OS_Start()), a program uses the so-called system stack. This is the same stack that a non-embOS program for this CPU would use. After transferring control to the embOS scheduler by calling OS_Start(), the system stack is used when no task is executed for the following: * * embOS scheduler embOS software timers (and the callback). For details regarding required size of your system stack, refer to the CPU & Compiler Specifics manual of embOS documentation. 14.1.2 Task stack Each embOS task has a separate stack. The location and size of this stack is defined when creating the task. The minimum size of a task stack pretty much depends on the CPU and the compiler. For details, see the CPU & Compiler Specifics manual of embOS documentation. 14.1.3 Interrupt stack To reduce stack size in a multitasking environment, some processors use a specific stack area for interrupt service routines (called a hardware interrupt stack). If there is no interrupt stack, you will need to add stack requirements of your interrupt service routines to each task stack. Even if the CPU does not support a hardware interrupt stack, embOS may support a separate stack for interrupts by calling the function OS_EnterIntStack() at beginning of an interrupt service routine and OS_LeaveIntStack() at its very end. In case the CPU already supports hardware interrupt stacks or if a separate interrupt stack is not supported at all, these function calls are implemented as empty macros. We recommend using OS_EnterIntStack() and OS_LeaveIntStack() even if there is currently no additional benefit for your specific CPU, because code that uses them might reduce stack size on another CPU or a new version of embOS with support for an interrupt stack for your CPU. For details about interrupt stacks, see the CPU & Compiler Specifics manual of embOS documentation. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 231 14.1.4 Stack size calculation embOS includes stack size calculation routines. embOS fills the task stacks as also the system stack and the interrupt stack with a pattern byte. embOS checks at runtime how many bytes at the end of the stack still include the pattern byte. With it the amount of used and unused stack can be calculated. 14.1.5 Stack-check embOS includes stack-check routines. embOS fills the task stacks as also the system stack and the interrupt stack with a pattern byte. embOS checks periodically if the last pattern byte at the end of the stack is overwritten. embOS calls OS_Error() when this bytes is overwritten. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 232 CHAPTER 14 Stacks 14.2 API functions OS_GetStackBase() OS_GetStackSize() OS_GetStackSpace() OS_GetStackUsed() OS_GetSysStackBase() OS_GetSysStackSize() OS_GetSysStackSpace() OS_GetSysStackUsed() OS_GetIntStackBase() OS_GetIntStackSize() OS_GetIntStackSpace() OS_GetIntStackUsed() Description Returns Returns Returns Returns Returns Returns Returns stack. Returns Returns stack. Returns Returns stack. Returns stack. the the the the the the the base address of a task stack. size of a task stack. unused portion of a task stack. used portion of a task stack. base address of the system stack. size of the system stack. unused portion of the system the used portion of the system stack. the base address of the interrupt the size of the interrupt stack. the unused portion of the interrupt the used portion of the interrupt Timer ISR Task main Routine X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X Table 14.1: Stacks API functions UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 233 14.2.1 OS_GetStackBase() Description Returns a pointer to the base of a task stack. Prototype void* OS_GetStackBase (OS_TASK* pTask); Parameter pTask Description The task who's stack base should be returned. NULL denotes the current task. Table 14.2: OS_GetStackBase() parameter list Return value The pointer to the base address of the task stack. Additional Information This function is only available in the debug and stack-check builds of embOS, because only these builds initialize the stack space used for the tasks. Example void CheckStackBase(void) { printf("Addr Stack[0] %x", OS_GetStackBase(&TCB[0]); OS_Delay(1000); printf("Addr Stack[1] %x", OS_GetStackBase(&TCB[1]); OS_Delay(1000); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 234 CHAPTER 14 Stacks 14.2.2 OS_GetStackSize() Description Returns the size of a task stack. Prototype unsigned int OS_GetStackSize (OS_TASK* pTask); Parameter pTask Description The task who's stack size should be checked. NULL means current task. Table 14.3: OS_GetStackSize() parameter list Return value The size of the task stack in bytes. Additional Information This function is only available in the debug and stack-check builds of embOS, because only these builds initialize the stack space used for the tasks. Example void CheckStackSize(void) { printf("Size Stack[0] %d", OS_GetStackSize(&TCB[0]); OS_Delay(1000); printf("Size Stack[1] %d", OS_GetStackSize(&TCB[1]); OS_Delay(1000); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 235 14.2.3 OS_GetStackSpace() Description Returns the unused portion of a task stack. Prototype unsigned int OS_GetStackSpace (OS_TASK* pTask); Parameter pTask Description The task who's stack space should be checked. NULL denotes the current task. Table 14.4: OS_GetStackSpace() parameter list Return value The unused portion of the task stack in bytes. Additional Information In most cases, the stack size required by a task cannot be easily calculated, because it takes quite some time to calculate the worst-case nesting and the calculation itself is difficult. However, the required stack size can be calculated using the function OS_GetStackSpace(), which returns the number of unused bytes on the stack. If there is a lot of space left, you can reduce the size of this stack and vice versa. This function is only available in the debug and stack-check builds of embOS, because only these builds initialize the stack space used for the tasks. Important This routine does not reliably detect the amount of stack space left, because it can only detect modified bytes on the stack. Unfortunately, space used for register storage or local variables is not always modified. In most cases, this routine will detect the correct amount of stack bytes, but in case of doubt, be generous with your stack space or use other means to verify that the allocated stack space is sufficient. Example void CheckStackSpace(void) { printf("Unused Stack[0] %d", OS_GetStackSpace(&TCB[0]); OS_Delay(1000); printf("Unused Stack[1] %d", OS_GetStackSpace(&TCB[1]); OS_Delay(1000); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 236 CHAPTER 14 Stacks 14.2.4 OS_GetStackUsed() Description Returns the used portion of a task stack. Prototype unsigned int OS_GetStackUsed (OS_TASK* pTask); Parameter pTask Description The task who's stack usage should be checked. NULL denotes the current task. Table 14.5: OS_GetStackUsed() parameter list Return value The used portion of the task stack in bytes. Additional Information In most cases, the stack size required by a task cannot be easily calculated, because it takes quite some time to calculate the worst-case nesting and the calculation itself is difficult. However, the required stack size can be calculated using the function OS_GetStackUsed(), which returns the number of used bytes on the stack. If there is a lot of space left, you can reduce the size of this stack and vice versa. This function is only available in the debug and stack-check builds of embOS, because only these builds initialize the stack space used for the tasks. Important This routine does not reliably detect the amount of stack space used, because it can only detect modified bytes on the stack. Unfortunately, space used for register storage or local variables is not always modified. In most cases, this routine will detect the correct amount of stack bytes, but in case of doubt, be generous with your stack space or use other means to verify that the allocated stack space is sufficient. Example void CheckStackUsed(void) { printf("Used Stack[0] %d", OS_GetStackUsed(&TCB[0]); OS_Delay(1000); printf("Used Stack[1] %d", OS_GetStackUsed(&TCB[1]); OS_Delay(1000); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 237 14.2.5 OS_GetSysStackBase() Description Returns a pointer to the base of the system stack. Prototype void* OS_GetSysStackBase (void); Return value The pointer to the base address of the system stack. Example void CheckSysStackBase(void) { printf("Addr System Stack %x", OS_GetSysStackBase()); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 238 CHAPTER 14 Stacks 14.2.6 OS_GetSysStackSize() Description Returns the size of the system stack. Prototype unsigned int OS_GetSysStackSize (void); Return value The size of the system stack in bytes. Example void CheckSysStackSize(void) { printf("Size System Stack %d", OS_GetSysStackSize()); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 239 14.2.7 OS_GetSysStackSpace() Description Returns the unused portion of the system stack. Prototype unsigned int OS_GetSysStackSpace (void); Return value The unused portion of the system stack in bytes. Additional Information This function is only available in the debug and stack-check builds of embOS. Important This routine does not reliably detect the amount of stack space left, because it can only detect modified bytes on the stack. Unfortunately, space used for register storage or local variables is not always modified. In most cases, this routine will detect the correct amount of stack bytes, but in case of doubt, be generous with your stack space or use other means to verify that the allocated stack space is sufficient. Example void CheckSysStackSpace(void) { printf("Unused System Stack %d", OS_GetSysStackSpace()); UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 240 CHAPTER 14 Stacks 14.2.8 OS_GetSysStackUsed() Description Returns the used portion of the system stack. Prototype unsigned int OS_GetSysStackUsed (void); Return value The used portion of the system stack in bytes. Additional Information This function is only available in the debug and stack-check builds of embOS. Important This routine does not reliably detect the amount of stack space used, because it can only detect modified bytes on the stack. Unfortunately, space used for register storage or local variables is not always modified. In most cases, this routine will detect the correct amount of stack bytes, but in case of doubt, be generous with your stack space or use other means to verify that the allocated stack space is sufficient. Example void CheckSysStackUsed(void) { printf("Used System Stack %d", OS_GetSysStackUsed()); UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 241 14.2.9 OS_GetIntStackBase() Description Returns a pointer to the base of the interrupt stack. Prototype void* OS_GetIntStackBase (void); Return value The pointer to the base address of the interrupt stack. Additional Information This function is only available when an interrupt stack exists. Example void CheckIntStackBase(void) { printf("Addr Interrupt Stack %x", OS_GetIntStackBase()); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 242 CHAPTER 14 Stacks 14.2.10 OS_GetIntStackSize() Description Returns the size of the interrupt stack. Prototype unsigned int OS_GetIntStackSize (void); Return value The size of the interrupt stack in bytes. Additional Information This function is only available when an interrupt stack exists. Example void CheckIntStackSize(void) { printf("Size Interrupt Stack %d", OS_GetIntStackSize()); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 243 14.2.11 OS_GetIntStackSpace() Description Returns the unused portion of the interrupt stack. Prototype unsigned int OS_GetIntStackSpace (void); Return value The unused portion of the interrupt stack in bytes. Additional Information This function is only available in the debug and stack-check builds and when an interrupt stack exists. Important This routine does not reliably detect the amount of stack space left, because it can only detect modified bytes on the stack. Unfortunately, space used for register storage or local variables is not always modified. In most cases, this routine will detect the correct amount of stack bytes, but in case of doubt, be generous with your stack space or use other means to verify that the allocated stack space is sufficient. Example void CheckIntStackSpace(void) { printf("Unused Interrupt Stack %d", OS_GetIntStackSpace()); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 244 CHAPTER 14 Stacks 14.2.12 OS_GetIntStackUsed() Description Returns the used portion of the interrupt stack. Prototype unsigned int OS_GetIntStackUsed (void); Return value The used portion of the interrupt stack in bytes. Additional Information This function is only available in the debug and stack-check builds and when an interrupt stack exists. Important This routine does not reliably detect the amount of stack space used, because it can only detect modified bytes on the stack. Unfortunately, space used for register storage or local variables is not always modified. In most cases, this routine will detect the correct amount of stack bytes, but in case of doubt, be generous with your stack space or use other means to verify that the allocated stack space is sufficient. Example void CheckIntStackUsed(void) { printf("Used Interrupt Stack %d", OS_GetIntStackUsed()); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 245 Chapter 15 Interrupts This chapter explains how to use interrupt service routines (ISRs) in cooperation with embOS. Specific details for your CPU and compiler can be found in the CPU & Compiler Specifics manual of the embOS documentation. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 246 CHAPTER 15 Interrupts 15.1 What are interrupts? Interrupts are interruptions of a program caused by hardware. When an interrupt occurs, the CPU saves its registers and executes a subroutine called an interrupt service routine, or ISR. After the ISR is completed, the program returns to the highest-priority task in the READY state. Normal interrupts are maskable; they can occur at any time unless they are disabled with the CPU's "disable interrupt" instruction. ISRs are also nestable - they can be recognized and executed within other ISRs. There are quickly to hardware interface, cessed as several good reasons for using interrupt routines. They can respond very external events such as the status change on an input, the expiration of a timer, reception or completion of transmission of a character via serial or other types of events. Interrupts effectively allow events to be prothey occur. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 247 15.2 Interrupt latency Interrupt latency is the time between an interrupt request and the execution of the first instruction of the interrupt service routine. Every computer system has an interrupt latency. The latency depends on various factors and differs even on the same computer system. The value that one is typically interested in is the worst case interrupt latency. The interrupt latency is the sum of a lot of different smaller delays explained below. 15.2.1 Causes of interrupt latencies * * * * * The first delay is typically in the hardware: The interrupt request signal needs to be synchronized to the CPU clock. Depending on the synchronization logic, typically up to 3 CPU cycles can be lost before the interrupt request has reached the CPU core. The CPU will typically complete the current instruction. This instruction can take a lot of cycles; on most systems, divide, push-multiple, or memory-copy instructions are the instructions which require most clock cycles. On top of the cycles required by the CPU, there are in most cases additional cycles required for memory access. In an ARM7 system, the instruction STMDB SP!,{R0-R11,LR}; (Push parameters and perm. register) is typically the worst case instruction. It stores 13 32-bit registers on the stack. The CPU requires 15 clock cycles. The memory system may require additional cycles for wait states. After the current instruction is completed, the CPU performs a mode switch or pushes registers (typically, PC and flag registers) on the stack. In general, modern CPUs (such as ARM) perform a mode switch, which requires less CPU cycles than saving registers. Pipeline fill Most modern CPUs are pipelined. Execution of an instruction happens in various stages of the pipeline. An instruction is executed when it has reached its final stage of the pipeline. Because the mode switch has flushed the pipeline, a few extra cycles are required to refill the pipeline. 15.2.2 Additional causes for interrupt latencies There can be additional causes for interrupt latencies. These depend on the type of system used, but we list a few of them. * * * * * * Latencies caused by cache line fill. If the memory system has one or multiple caches, these may not contain the required data. In this case, not only the required data is loaded from memory, but in a lot of cases a complete line fill needs to be performed, reading multiple words from memory. Latencies caused by cache write back. A cache miss may cause a line to be replaced. If this line is marked as dirty, it needs to be written back to main memory, causing an additional delay. Latencies caused by MMU translation table walks. Translation table walks can take a considerable amount of time, especially as they involve potentially slow main memory accesses. In real-time interrupt handlers, translation table walks caused by the TLB not containing translations for the handler and/or the data it accesses can increase interrupt latency significantly. Application program. Of course, the application program can cause additional latencies by disabling interrupts. This can make sense in some situations, but of course causes add. latencies. Interrupt routines. On most systems, one interrupt disables further interrupts. Even if the interrupts are re-enabled in the ISR, this takes a few instructions, causing add. latency. RTOS (Real-time Operating system). An RTOS also needs to temporarily disable the interrupts which can call API-functions of the RTOS. Some RTOSes disable all interrupts, effectively increasing UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 248 CHAPTER 15 Interrupts interrupt latencies for all interrupts, some (like embOS) disable only low-priority interrupts and do thereby not affect the latency of high priority interrupts. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 249 15.3 Zero interrupt latency Zero interrupt latency in the strict sense is not possible as explained above. What we mean when we say "Zero interrupt latency" is that the latency of high-priority interrupts is not affected by the RTOS; a system using embOS will have the same worstcase interrupt latency for high priority interrupts as a system running without embOS. Why is Zero latency important? In some systems, a maximum interrupt response time or latency can be clearly defined. This max. latency can arise from requirements such as maximum reaction time for a protocol or a software UART implementation that requires very precise timing. One customer implemented a UART receiving at up to 800KHz in software using FIQ (fast interrupt) on a 48 MHz ARM7. This would be impossible to do if fast interrupts were disabled even for short periods of time. In a lot of embedded systems, the quality of the product depends on the reaction time and therefor latency. Typical examples would be systems which periodically read a value from an A/D converter at high speed, where the accuracy depends on accurate timing. Less jitter means a better product. Why can a high priority ISR not use the OS API ? embOS disables low priority interrupts when embOS data structures are modified. During this time high priority ISR are enabled. If they would call an embOS function, which also modifies embOS data, the embOS data structures would be corrupted. How can a high priority ISR communicate with a task ? The most common way is to use global variables, e.g. a periodically read from an ADC and the result is stored in a global variable Another way is to set an interrupt request for a low priority interrupt in your high priority ISR, which can then communicate or wake up one or more tasks. This might be helpful if you want to receive several data in your high priority ISR. The low priority ISR may then store the data bytes in a message queue or mailbox for example. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 250 CHAPTER 15 Interrupts 15.4 High / low priority interrupts Most CPUs support interrupts with different priorities. Different priorities have two effects: * * If different interrupts occur simultaneously, the interrupt with higher priority takes precedence and its ISR is executed first. Interrupts can never be interrupted by other interrupts of the same or lower level of priority. How many different levels of interrupts there are depend on the CPU and the interrupt controller. Details are explained in the CPU/MCU/SOC manuals and the CPU & Compiler Specifics manual of embOS. embOS distinguishes two different levels of interrupts: High / Low priority interrupts. The embOS port specific documentation explains where "the line is drawn", which interrupts are considered high and which interrupts are considered low priority. In general, the differences are: Low priority interrupts * * May call embOS API functions Latencies caused by embOS High priority interrupts * * May not call embOS API functions No Latencies caused by embOS (Zero latency) Example of different interrupt priority levels Let's assume we have a CPU which support 8 interrupt priority levels. With embOS, the 3 highest priority levels are treated as "High priority interrupts". ARM CPUs support normal interrupts (IRQ) and fast interrupt (FIQ). Using embOS, the FIQ is treated as "High priority interrupt". With most implementations, the high-priority threshold is adjustable. For details, refer to the processor specific embOS manual. 15.4.1 Using OS functions from high priority interrupts High priority interrupts may not use embOS functions at all. This is a limitation which results from zero-latency: embOS does never disable high priority interrupts. This means that high priority interrupts can interrupt the operating system at any time, even in critical situations such as the modification of linked lists and double linked list. This is a design decision that has been taken because zero interrupt latencies for high priority interrupts are usually more important than the ability to call OS functions. There is a way to still use OS functions from high priority interrupts indirectly: High priority interrupt triggers a low priority interrupt usually by setting an interrupt requestflag. That low priority interrupt may now call OS functions. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 251 Task1 Task2 High priority interrupt Low priority interrupt Task1 is interrupted by a high priority interrupt High priority interrupt triggers low priority interrupt Time Low priority interrupt calls embOS API function to resume Task2 The task 1 is interrupted by a high priority interrupt. This high priority interrupt is not allowed to call an embOS API function directly. Therefore the high priority interrupt triggers a low priority interrupt, which is allowed to call embOS API functions. The low priority interrupt calls an embOS API function to resume task 2. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 252 CHAPTER 15 Interrupts 15.5 Rules for interrupt handlers 15.5.1 General rules There are some general rules for interrupt service routines (ISRs). These rules apply to both single-task programming as well as to multitask programming using embOS. * * ISR preserve all registers. Interrupt handlers must restore the environment of a task completely. This environment normally consists of the registers only, so the ISR must make sure that all registers modified during interrupt execution are saved at the beginning and restored at the end of the interrupt routine Interrupt handlers must be finished quickly. Intensive calculations should be kept out of interrupt handlers. An interrupt handler should only be used for storing a received value or to trigger an operation in the regular program (task). It should not wait in any form or perform a polling operation. 15.5.2 Additional rules for preemptive multitasking A preemptive multitasking system like embOS needs to know if the program that is executing is part of the current task or an interrupt handler. This is because embOS cannot perform a task switch during the execution of an ISR; it can only do so at the end of an ISR. If a task switch were to occur during the execution of an ISR, the ISR would continue as soon as the interrupted task became the current task again. This is not a problem for interrupt handlers that do not allow further interruptions (which do not enable interrupts) and that do not call any embOS functions. This leads us to the following rule: * ISR that re-enable interrupts or use any embOS function need to call OS_EnterInterrupt() at the beginning, before executing any other command, and before they return, call OS_LeaveInterrupt() as last command. If a higher priority task is made ready by the ISR, the task switch then occurs in the routine OS_LeaveInterrupt(). The end of the ISR is executed at a later point, when the interrupted task is made ready again. If you debug an interrupt routine, do not be confused. This has proven to be the most efficient way of initiating a task switch from within an interrupt service routine. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 253 15.6 API functions The following table lists all interrupt related API functions of embOS. OS_DI() OS_EI() OS_IncDI() OS_RestoreI() OS_DecRI() OS_EnterInterrupt() OS_LeaveInterrupt() OS_EnterNestableInterrupt() OS_LeaveNestableInterrupt() OS_CallISR() OS_CallNestableISR() OS_INTERRUPT_MaskGlobal() OS_INTERRUPT_UnmaskGlobal() OS_INTERRUPT_PreserveGlobal() OS_INTERRUPT_PreserveAndMaskGlobal() OS_INTERRUPT_RestoreGlobal() Description Disables interrupts. Does not change the interrupt disable counter. Unconditionally enables Interrupt. Increments the interrupt disable counter (OS_DICnt) and disables interrupts. Restores the state of the interrupt flag, based on the interrupt disable counter. Decrements the counter and enables interrupts if the counter reaches 0. Informs embOS that interrupt code is executing. Informs embOS that the end of the interrupt routine has been reached; executes task switching within ISR. Informs embOS that interrupt code is executing and reenables interrupts. Informs embOS that the end of the interrupt routine has been reached; executes task switching within ISR. Interrupt entry function. Interrupt entry function supporting nestable interrupts. Disable all interrupts (high and low priority) unconditionally. Enable all interrupts (high and low priority) unconditionally. Preserves the current interrupt enable state Preserves the current interrupt enable state and then disables all interrupts. Restores the interrupt enable state which was preserved before. Timer ISR Task main Routine X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X Table 15.1: Interrupt API functions UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 254 CHAPTER 15 Interrupts 15.6.1 OS_CallISR() Description Entry function for use in an embOS interrupt handler. Nestable interrupts disabled. Prototype void OS_CallISR (void (*pRoutine)(void)); Parameter pRoutine Description Pointer to a routine that should run on interrupt. Table 15.2: OS_CallISR() parameter list Additional Information OS_CallISR() can be used as entry function in an embOS interrupt handler, when the corresponding interrupt should not be interrupted by another embOS interrupt. OS_CallISR() sets the interrupt priority of the CPU to the user definable 'fast' interrupt priority level, thus locking any other embOS interrupt. Fast interrupts are not disabled. Note: For some specific CPUs OS_CallISR() must be used to call an interrupt handler because OS_EnterInterrupt() / OS_LeaveInterrupt() may not be available. Refer to the CPU specific manual. Example #pragma interrupt void OS_ISR_Tick(void) { OS_CallISR(_IsrTickHandler); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 255 15.6.2 OS_CallNestableISR() Description Entry function for use in an embOS interrupt handler. Nestable interrupts enabled. Prototype void OS_CallNestableISR (void (*pRoutine)(void)); Parameter pRoutine Description Pointer to a routine that should run on interrupt. Table 15.3: OS_CallNestableISR() parameter list Additional Information OS_CallNestableISR() can be used as entry function in an embOS interrupt handler, when interruption by higher prioritized embOS interrupts should be allowed. OS_CallNestableISR() does not alter the interrupt priority of the CPU, thus keeping all interrupts with higher priority enabled. Note: For some specific CPUs OS_CallNestableISR() must be used to call an interrupt handler because OS_EnterNestableInterrupt() / OS_LeaveNestableInterrupt() may not be available. Refer to the CPU specific manual. Example #pragma interrupt void OS_ISR_Tick(void) { OS_CallNestableISR(_IsrTickHandler); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 256 CHAPTER 15 Interrupts 15.6.3 OS_EnterInterrupt() Note: This function may not be available in all ports. Description Informs embOS that interrupt code is executing. Prototype void OS_EnterInterrupt (void); Additional Information If OS_EnterInterrupt() is used, it should be the first function to be called in the interrupt handler. It must be used with OS_LeaveInterrupt() as the last function called. The use of this function has the following effects, it: * * disables task switches keeps interrupts in internal routines disabled. An example is shown in the the description of OS_LeaveInterrupt(). UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 257 15.6.4 OS_LeaveInterrupt() Note: This function may not be available in all ports. Description Informs embOS that the end of the interrupt routine has been reached; executes task switching within ISR. Prototype void OS_LeaveInterrupt (void); Additional Information If OS_LeaveInterrupt() is used, it should be the last function to be called in the interrupt handler. If the interrupt has caused a task switch, it will be executed (unless the program which was interrupted was in a critical region). Example using OS_EnterInterrupt()/OS_LeaveInterrupt() _interrupt void ISR_Timer(void) { OS_EnterInterrupt(); OS_SignalEvent(1,&Task);/* Any functionality could be here */ OS_LeaveInterrupt(); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 258 CHAPTER 15 Interrupts 15.7 Enabling / disabling interrupts from C During the execution of a task, maskable interrupts are normally enabled. In certain sections of the program, however, it can be necessary to disable interrupts for short periods of time to make a section of the program an atomic operation that cannot be interrupted. An example would be the access to a global volatile variable of type long on an 8/16-bit CPU. To make sure that the value does not change between the two or more accesses that are needed, interrupts must be temporarily disabled: Bad example: volatile long lvar; void routine (void) { lvar ++; } The problem with disabling and re-enabling interrupts is that functions that disable/ enable the interrupt cannot be nested. Your C compiler offers two intrinsic functions for enabling and disabling interrupts. These functions can still be used, but it is recommended to use the functions that embOS offers (to be precise, they only look like functions, but are macros in reality). If you do not use these recommended embOS functions, you may run into a problem if routines which require a portion of the code to run with disabled interrupts are nested or call an OS routine. We recommend disabling interrupts only for short periods of time, if possible. Also, you should not call routines when interrupts are disabled, because this could lead to long interrupt latency times (the longer interrupts are disabled, the higher the interrupt latency). As long as you only call embOS functions with interrupts enabled, you may also safely use the compiler-provided intrinsics to disable interrupts. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 259 15.7.1 OS_IncDI() / OS_DecRI() The following functions are actually macros defined in RTOS.h, so they execute very quickly and are very efficient. It is important that they are used as a pair: first OS_IncDI(), then OS_DecRI(). OS_IncDI() Short for Increment and Disable Interrupts. Increments the interrupt disable counter (OS_DICnt) and disables interrupts. OS_DecRI() Short for Decrement and Restore Interrupts. Decrements the counter and enables interrupts if the counter reaches 0. Example volatile long lvar; void routine (void) { OS_IncDI(); lvar ++; OS_DecRI(); } OS_IncDI() increments the interrupt disable counter which is used for the entire OS and is therefore consistent with the rest of the program in that any routine can be called and the interrupts will not be switched on before the matching OS_DecRI() has been executed. If you need to disable interrupts for a short moment only where no routine is called, as in the example above, you could also use the pair OS_DI() and OS_RestoreI(). These are a bit more efficient because the interrupt disable counter OS_DICnt is not modified twice, but only checked once. They have the disadvantage that they do not work with routines because the status of OS_DICnt is not actually changed, and they should therefore be used with great care. In case of doubt, use OS_IncDI() and OS_DecRI(). UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 260 CHAPTER 15 Interrupts 15.7.2 OS_DI() / OS_EI() / OS_RestoreI() OS_DI() Short for Disable Interrupts. Disables interrupts. Does not change the interrupt disable counter. OS_EI() Short for Enable Interrupts. Refrain from using this function directly unless you are sure that the interrupt enable count has the value zero, because it does not take the interrupt disable counter into account. OS_RestoreI() Short for Restore Interrupts. Restores the status of the interrupt flag, based on the interrupt disable counter. Example volatile long lvar; void routine (void) { OS_DI(); lvar++; OS_RestoreI(); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 261 15.8 Definitions of interrupt control macros (in RTOS.h) #define OS_IncDI() #define OS_DecRI() #define OS_RestoreI() { OS_ASSERT_DICnt(); OS_DI(); OS_DICnt++; } { OS_ASSERT_DICnt(); if (--OS_DICnt==0) OS_EI(); } { OS_ASSERT_DICnt(); if (OS_DICnt==0) OS_EI(); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 262 CHAPTER 15 Interrupts 15.9 Nesting interrupt routines By default, interrupts are disabled in an ISR because the CPU disables interrupts with the execution of the interrupt handler. Re-enabling interrupts in an interrupt handler allows the execution of further interrupts with equal or higher priority than that of the current interrupt. These are known as nested interrupts, illustrated in the diagram below: Task ISR 1 ISR 2 ISR 3 Interrupt 1 Interrupt 2 Interrupt 3 Time For applications requiring short interrupt latency, you may re-enable interrupts inside an ISR by using OS_EnterNestableInterrupt() and OS_LeaveNestableInterrupt() within the interrupt handler. Nested interrupts can lead to problems that are difficult to track; therefore it is not really recommended to enable interrupts within an interrupt handler. As it is important that embOS keeps track of the status of the interrupt enable/disable flag, the enabling and disabling of interrupts from within an ISR must be done using the functions that embOS offers for this purpose. The routine OS_EnterNestableInterrupt() enables interrupts within an ISR and prevents further task switches; OS_LeaveNestableInterrupt() disables interrupts right before ending the interrupt routine again, thus restores the default condition. Re-enabling interrupts will make it possible for an embOS scheduler interrupt to shortly interrupt this ISR. In this case, embOS needs to know that another ISR is still running and that it may not perform a task switch. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 263 15.9.1 OS_EnterNestableInterrupt() Note: This function may not be available in all ports. Description Re-enables interrupts and increments the embOS internal critical region counter, thus disabling further task switches. Prototype void OS_EnterNestableInterrupt (void); Additional Information This function should be the first call inside an interrupt handler when nested interrupts are required. The function OS_EnterNestableInterrupt() is implemented as a macro and offers the same functionality as OS_EnterInterrupt() in combination with OS_DecRI(), but is more efficient, resulting in smaller and faster code. Example Refer to the example for OS_LeaveNestableInterrupt(). UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 264 CHAPTER 15 Interrupts 15.9.2 OS_LeaveNestableInterrupt() Note: This function may not be available in all ports. Description Disables further interrupts, then decrements the embOS internal critical region count, thus re-enabling task switches if the counter has reached zero again. Prototype void OS_LeaveNestableInterrupt (void); Additional Information This function is the counterpart of OS_EnterNestableInterrupt(), and must be the last function call inside an interrupt handler when nested interrupts have been enabled by OS_EnterNestableInterrupt(). The function OS_LeaveNestableInterrupt() is implemented as a macro and offers the same functionality as OS_LeaveInterrupt() in combination with OS_IncDI(), but is more efficient, resulting in smaller and faster code. Example using OS_EnterNestableInterrupt()/OS_LeaveNestableInterrupt() _interrupt void ISR_Timer(void) { OS_EnterNestableInterrupt(); OS_SignalEvent(1,&Task);/* Any functionality could be here */ OS_LeaveNestableInterrupt(); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 265 15.9.3 OS_InInterrupt() Description This function can be called to examine if the calling function is running in an interrupt context. Prototype unsigned char OS_InInterrupt (void); Return value 0: Code is not executed in interrupt handler. !=0: Code is executed in an interrupt handler. Additional Information The function delivers the value of the embOS variable OS_InInt which is incremented in OS_EnterInterrupt() and OS_EnterNestableInterrupt(). The variable OS_InInt is decremented in OS_LeaveInterrupt() and OS_LeaveNestableInterrupt(). Previous versions of embOS implemented this functionallity in debug libraries only. Since version 3.88c, the internal variable is included in all libraries and can be examined by a call of OS_InInterrupt(). For application code, it may be useful to know if it is called from interrupt or task, because some functions must not be called from an interrupt-handler. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 266 CHAPTER 15 Interrupts 15.10 Global interrupt enable / disable The embOS interrupt enable and disable functions enable and disable embOS interrupts only. If a system is setup to support high and low priority interrupts and embOS is configured to suppport "zero latency" interrupts as described before, the embOS functions to enable and disable interrupts affect the low priority interrupts only. High priority interrupts, called "zero latency interrupts" are never enabled or disabled by the previous described embOS functions. In an application it may be required to disable and enable all interrupts. Since version 3.90, embOS comes with API functions which allows enabling and disabling all interrupts. These functions have the prefix OS_INTERRUPT_ and allow a "global" handling of the interrupt enable / disable state of the CPU. These functions affect the state of the CPU unconditionally. They should be used carefully. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 267 15.10.1 OS_INTERRUPT_MaskGlobal() Description This function disables high and low priority interrupts unconditionally. Prototype void OS_INTERRUPT_MaskGlobal (void); Additional Information OS_INTERRUPT_MaskGlobal() disables all interrupts in a fast and efficient way. Note that the system does not track the interrupt state when calling the function. Therefore the function should not be called when the state is unknown. Interrupts can be re-enabled by calling OS_INTERRUPT_UnmaskGlobal(). After calling OS_INTERRUPT_MaskGlobal(), no embOS function except the interrupt enable function OS_INTERRUPT_UnmaskGlobal() should be called, because the interrupt state is not saved by the function and not noticed by embOS. An embOS API function may re-enable interrupts. The excat behaviour depends on the CPU. 15.10.2 OS_INTERRUPT_UnmaskGlobal() Description This function enables high and low priority interrupts unconditionally. Prototype void OS_INTERRUPT_UnmaskGlobal (void); Additional Information OS_INTERRUPT_UnmaskGlobal() must be called to re-enable interrupts which were disabled before by a call of OS_INTERRUPT_MaskGlobal(). The function re-enables high and low priority interrupts unconditionally. OS_INTERRUPT_MaskGlobal() and OS_INTERRUPT_UnmaskGlobal() should be used as a pair. The call cannot be nested, because the state is not saved. This kind of global interrupt disable/enable should only be used when the interrupt enable state is well known and interrupts are enabled. Between OS_INTERRUPT_MaskGlobal() and OS_INTERRUPT_UnmaskGlobal(), no function should be called when it is not known if the function alters the interrupt enable state. If the interrupt state is not known, the functions OS_INTERRUPT_PreserveGlobal() or OS_INTERRUPT_PreserveAndMaskGlobal() and OS_INTERRUPT_RestoreGlobal() shall be used as decribed later on. Example void Sample(void) { OS_INTERRUPT_MaskGlobal(); // Disable interrupts // // Execute any code that should be executed with interrupts disabled // No embOS function should be called // ... OS_INTERRUPT_UnmaskGlobal(); // Re-enable interrupts unconditionally } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 268 CHAPTER 15 Interrupts 15.10.3 OS_INTERRUPT_PreserveGlobal() Description This function can be called to preserve the current interrupt enable state of the CPU. Prototype void OS_INTERRUPT_PreserveGlobal (OS_U32 *pState); Parameter pState Description Pointer to an OS_U32 variable that receives the interrupt state. Table 15.4: OS_CallNestableISR() parameter list Additional Information If the interrupt enable state is not known and interrupts should be disabled by a call of OS_INTERRUPT_MaskGlobal(), the current interrupt enbale state can be preserved and restored later by a call of OS_INTERRUPT_RestoreGlobal(). Note that the interrupt state is not kept by embOS. After disabling the interrupts by a call of OS_INTERRUPT_MaskGlobal(), no embOS API function should be called, because embOS functions might re-enable interrupts. Example void Sample(void) { OS_U32 IntState; OS_INTERRUPT_PreserveGlobal(&IntState); // OS_INTERRUPT_MaskGlobal(); // // // Execute any code that should be executed // No embOS function should be called // ... OS_INTERRUPT_RestoreGlobal(&IntState); // Remember the interrupt enable state. Disable interrupts with interrupts disabled Restore the interrupt enable state } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 269 15.10.4 OS_INTERRUPT_PreserveAndMaskGlobal() Description This function preserves the current interrupt enable state of the CPU and then disables high and low priority interrupts. Prototype void OS_INTERRUPT_PreserveAndMaskGlobal (OS_U32 *pState); Parameter pState Description Pointer to an OS_32 variable that receives the interrupt state. Table 15.5: OS_CallNestableISR() parameter list Additional Information The function store the current interrupt enable state into the variable pointed to by pState and then disables high and low priority interrupts. The interrupt state can be restored later by a corresponding call of OS_INTERRUPT_RestoreGlobal(). The pair of function calls OS_INTERRUPT_PreserveAndMaskGlobal() and OS_INTERRUPT_RestoreGlobal() can be nested, as long as the interrupt enable state is stored into an individual variable on each call of OS_INTERRUPT_PreserveAndMaskGlobal(). This function pair should be used when the interrupt enable state is not known when interrupts shall be enabled. 15.10.5 OS_INTERRUPT_RestoreGlobal() Description This function must be called to restore the interrupt enable state of the CPU which was preserved before. Prototype void OS_INTERRUPT_RestoreGlobal (OS_U32 *pState); Parameter pState Description Pointer to an OS_U32 that holds the interrupt enable state. Table 15.6: OS_CallNestableISR() parameter list Additional Information Restores the interrupt enable state which was saved before by a call of OS_INTERRUPT_PreserveGlobal() or OS_INTERRUPT_PreserveAndMaskGlobal(). If interrupts were enabled before they were disabled globally, the function reenables them. Example void Sample(void) { OS_U32 IntState; OS_INTERRUPT_PreserveGlobal(&IntState); // OS_INTERRUPT_MaskGlobal(); // // // Execute any code that should be executed // No embOS function should be called // ... OS_INTERRUPT_RestoreGlobal(&IntState); // Remember the interrupt enable state. Disable interrupts with interrupts disabled Restore the interrupt enable state } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 270 CHAPTER 15 Interrupts 15.11 Non-maskable interrupts (NMIs) embOS performs atomic operations by disabling interrupts. However, a non-maskable interrupt (NMI) cannot be disabled, meaning it can interrupt these atomic operations. Therefore, NMIs should be used with great care and may under no circumstances call any embOS routines. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 271 Chapter 16 Critical Regions UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 272 CHAPTER 16 Critical Regions 16.1 Introduction Critical regions are program sections during which the scheduler is switched off, meaning that no task switch and no execution of software timers are allowed except in situations where the running task must wait. Effectively, preemptions are switched off. A typical example for a critical region would be the execution of a program section that handles a time-critical hardware access (for example writing multiple bytes into an EEPROM where the bytes must be written in a certain amount of time), or a section that writes data into global variables used by a different task and therefore needs to make sure the data is consistent. A critical region can be defined anywhere during the execution of a task. Critical regions can be nested; the scheduler will be switched on again after the outermost loop is left. Interrupts are still legal in a critical region. Software timers and interrupts are executed as critical regions anyhow, so it does not hurt but does not do any good either to declare them as such. If a task switch becomes due during the execution of a critical region, it will be performed right after the region is left. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 273 16.2 API functions OS_EnterRegion() OS_LeaveRegion() Description Timer ISR Task main Routine Indicates to the OS the beginning of a critical X X X X region. Indicates to the OS the end of a critical region. X X X X Table 16.1: Critical regions API functions UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 274 CHAPTER 16 Critical Regions 16.2.1 OS_EnterRegion() Description Indicates to the OS the beginning of a critical region. Prototype void OS_EnterRegion (void); Additional Information OS_EnterRegion() is not actually a function but a macro. However, it behaves very much like a function but is much more efficient. Using the macro indicates to embOS the beginning of a critical region. A critical region counter (OS_Global.Counters.Cnt.Region), which is 0 by default, is incremented so that the routine can be nested. The counter will be decremented by a call to the routine OS_LeaveRegion(). If this counter reaches 0 again, the critical region ends. Interrupts are not disabled using OS_EnterRegion(); however, preemptive task switches are disabled in a critical region. If any interrupt triggers a task switch, the task switch is delayed and kept pending until the final call of OS_LeaveRegion(). When the OS_RegionCnt reaches 0 again, a pending task switch is executed. Cooperative task switches are not affected and will be executed in critical regions. When the task is running in a critical region and then calls any blocking embOS function, the task will be suspended. When the task is resumed again, the task-specific OS_RegionCnt is restored, the task continues to run in a critical region until OS_LeaveRegion() is called. Example void SubRoutine(void) { OS_EnterRegion(); /* The following code will not be interrupted by the OS */ /* Preemptive task switches are blocked until the call of OS_leaveRegion() */ OS_LeaveRegion(); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 275 16.2.2 OS_LeaveRegion() Description Indicates to the OS the end of a critical region. Prototype void OS_LeaveRegion (void); Additional Information OS_LeaveRegion() is not actually a function but a macro. However, it behaves very much like a function but is much more efficient. Usage of the macro indicates to embOS the end of a critical region. A critical region counter (OS_Global.Counters.Cnt.Region), which is 0 by default, is decremented. If this counter reaches 0 again, the critical region ends. A task switch which became pending during a critical region will be executed in OS_Enterregion() when the OS_RegionCnt reaches 0 again. Example Refer to the example for OS_EnterRegion(). UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 276 UM01001 User & Reference Guide for embOS CHAPTER 16 Critical Regions (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 277 Chapter 17 Time measurement embOS supports 2 types of time measurement: * * Low resolution (using a time variable) High resolution (using a hardware timer) Both are explained in this chapter. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 278 CHAPTER 17 Time measurement 17.1 Introduction embOS supports two basic types of run-time measurement which may be used for calculating the execution time of any section of user code. Low-resolution measurements use a time base of ticks, while high-resolution measurements are based on a time unit called a cycle. The length of a cycle depends on the timer clock frequency. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 279 17.2 Low-resolution measurement The system time variable OS_Global.Time is measured in ticks, or ms. The low-resolution functions OS_GetTime() and OS_GetTime32() are used for returning the current contents of this variable. The basic idea behind low-resolution measurement is quite simple: The system time is returned once before the section of code to be timed and once after, and the first value is subtracted from the second to obtain the time it took for the code to execute. The term low-resolution is used because the time values returned are measured in completed ticks. Consider the following: with a normal tick of one ms, the variable OS_Time is incremented with every tick-interrupt, or once every ms. This means that the actual system time can potentially be more than what a low-resolution function will return (for example, if an interrupt actually occurs at 1.4 ticks, the system will still have measured only one tick as having elapsed). The problem becomes even greater with runtime measurement, because the system time must be measured twice. Each measurement can potentially be up to one tick less than the actual time, so the difference between two measurements could theoretically be inaccurate by up to one tick. The following diagram illustrates how low-resolution measurement works. We can see that the section of code actually begins at 0.5 ms and ends at 5.2 ms, which means that its actual execution time is (5.2 - 0.5) = 4.7 ms. However with a tick of one ms, the first call to OS_GetTime() returns 0, and the second call returns 5. The measured execution time of the code would therefore result in (5 - 0) = 5 ms. OS_GetTime() => 0 OS_GetTime() => 5 Code to be timed OS_Time 0.5 ms 0 ms 1 ms 5.2 ms 2 ms 3 ms 4 ms 5 ms 6 ms For many applications, low-resolution measurement may be fully sufficient for your needs. In some cases, it may be more desirable than high-resolution measurement due to its ease of use and faster computation time. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 280 CHAPTER 17 Time measurement 17.2.1 API functions OS_GetTime() OS_GetTime32() Description Returns the current system time in ticks. Returns the current system time in ticks as a 32-bit value. Timer ISR Task main Routine X X X X X X X X Table 17.1: Low-resolution measurement API functions UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 281 17.2.1.1 OS_GetTime() Description Returns the current system time in ticks. Prototype int OS_GetTime (void); Return value The system variable OS_Global.Time as a 16- or 32-bit integer value. Additional Information This function returns the system time as a 16-bit value on 8/16-bit CPUs, and as a 32-bit value on 32-bit CPUs. The OS_Global.Time variable is a 32-bit value. Therefore, if the return value is 32-bit, it is simply the entire contents of the OS_Time variable. If the return value is 16-bit, it is the lower 16 bits of the OS_Global.OS_Time variable. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 282 CHAPTER 17 Time measurement 17.2.1.2 OS_GetTime32() Description Returns the current system time in ticks as a 32-bit value. Prototype int OS_GetTime32 (void); Return value The system variable OS_Global.Time as a 32-bit integer value. Additional Information This function always returns the system time as a 32-bit value. Because the OS_Global.Time variable is also a 32-bit value, the return value is simply the entire contents of the OS_Global.Time variable. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 283 17.3 High-resolution measurement High-resolution measurement uses the same routines as those used in profiling builds of embOS, allowing for fine-tuning of time measurement. While system resolution depends on the CPU used, it is typically about one s, making high-resolution measurement about 1000 times more accurate than low-resolution calculations. Instead of measuring the number of completed ticks at a given time, an internal count is kept of the number of cycles that have been completed. Look at the illustration below, which measures the execution time of the same code used in the low-resolution calculation. For this example, we assume that the CPU has a timer running at 10 MHz and is counting up. The number of cycles per tick is therefore (10 MHz / 1 kHz) = 10,000. This means that with each tick-interrupt, the timer restarts at 0 and counts up to 10,000. OS_GetTime() => 0 OS_GetTime() => 5 Code to be timed OS_Time 0.5 ms 0 ms 1 ms 5.2 ms 2 ms 3 ms 4 ms 5 ms 6 ms The call to OS_Timing_Start() calculates the starting value at 5,000 cycles, while the call to OS_Timing_End() calculates the ending value at 52,000 cycles (both values are kept track of internally). The measured execution time of the code in this example would therefore be (52,000 - 5,000) = 47,000 cycles, which corresponds to 4.7 ms. Although the function OS_Timing_GetCycles() may be used for returning the execution time in cycles as above, it is typically more common to use the function OS_Timing_Getus(), which returns the value in microseconds (s). In the above example, the return value would be 4,700 s. Data structure All high-resolution routines take as parameter a pointer to a data structure of type OS_TIMING, defined as follows: #define OS_TIMING OS_U32 UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 284 CHAPTER 17 Time measurement 17.3.1 API functions OS_Timing_Start() OS_Timing_End() OS_Timing_Getus() OS_Timing_GetCycles() Description Marks the beginning of a code section to be timed. Marks the end of a code section to be timed. Returns the execution time of the code between OS_Timing_Start() and OS_Timing_End() in microseconds. Returns the execution time of the code between OS_Timing_Start() and OS_Timing_End() in cycles. Timer ISR Task main Routine X X X X X X X X X X X X X X X X Table 17.2: High-resolution measurement API functions UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 285 17.3.1.1 OS_Timing_Start() Description Marks the beginning of a section of code to be timed. Prototype void OS_Timing_Start (OS_TIMING* pCycle); Parameter pCycle Description Pointer to a data structure of type OS_TIMING. Table 17.3: OS_TimingStart() parameter list Additional Information This function must be used with OS_Timing_End(). UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 286 CHAPTER 17 Time measurement 17.3.1.2 OS_Timing_End() Description Marks the end of a section of code to be timed. Prototype void OS_Timing_End (OS_TIMING* pCycle); Parameter pCycle Description Pointer to a data structure of type OS_TIMING. Table 17.4: OS_TimingEnd() parameter list Additional Information This function must be used with OS_Timing_Start(). UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 287 17.3.1.3 OS_Timing_Getus() Description Returns the execution time of OS_Timing_End() in microseconds. the code between OS_Timing_Start() and Prototype OS_U32 OS_Timing_Getus (const OS_TIMING* pCycle); Parameter pCycle Description Pointer to a data structure of type OS_TIMING. Table 17.5: OS_Timing_Getus() parameter list Additional Information The execution time in microseconds (s) as a 32-bit integer value. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 288 CHAPTER 17 Time measurement 17.3.1.4 OS_Timing_GetCycles() Description Returns the execution time OS_Timing_End() in cycles. of the code between OS_Timing_Start() and Prototype OS_U32 OS_Timing_GetCycles (OS_TIMING* pCycle); Parameter pCycle Description Pointer to a data structure of type OS_TIMING. Table 17.6: OS_Timing_GetCycles() parameter list Return value The execution time in cycles as a 32-bit integer. Additional Information Cycle length depends on the timer clock frequency. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 289 17.4 Example The following sample demonstrates the use of low-resolution and high-resolution measurement to return the execution time of a section of code: /********************************************************** * SEGGER MICROCONTROLLER SYSTEME GmbH * Solutions for real time microcontroller applications *********************************************************** File : SampleHiRes.c Purpose : Demonstration of embOS Hires Timer --------------END-OF-HEADER------------------------------*/ #include "RTOS.H" #include OS_STACKPTR int Stack[1000]; /* Task stacks */ OS_TASK TCB; /* Task-control-blocks */ volatile int Dummy; void UserCode(void) { for (Dummy=0; Dummy < 11000; Dummy++); } /* Burn some time */ /* * Measure the execution time with low resolution and return it in ms (ticks) */ int BenchmarkLoRes(void) { OS_TIME t; t = OS_GetTime(); UserCode(); /* Execute the user code to be benchmarked */ t = OS_GetTime() - t; return (int)t; } /* * Measure the execution time with hi resolution and return it in us */ OS_U32 BenchmarkHiRes(void) { OS_TIMING t; OS_Timing_Start(&t); UserCode(); /* Execute the user code to be benchmarked */ OS_Timing_End(&t); return OS_Timing_Getus(&t); } void Task(void) { int tLo; OS_U32 tHi; char ac[80]; while (1) { tLo = BenchmarkLoRes(); tHi = BenchmarkHiRes(); sprintf(ac, "LoRes: %d ms\n", tLo); OS_SendString(ac); sprintf(ac, "HiRes: %d us\n", tHi); OS_SendString(ac); } } /********************************************************** * * main * **********************************************************/ void main(void) { OS_InitKern(); /* Initialize OS OS_InitHW(); /* Initialize Hardware for OS /* You need to create at least one task here ! OS_CREATETASK(&TCB, "HP Task", Task, 100, Stack); OS_Start(); /* Start multitasking } UM01001 User & Reference Guide for embOS */ */ */ */ (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 290 CHAPTER 17 Time measurement The output of the sample is as follows: LoRes: HiRes: LoRes: HiRes: LoRes: 7 ms 6641 us 7 ms 6641 us 6 ms UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 291 17.5 Micro second precise system time The following functions return the current system time in micro second resolution. The function OS_Config_SysTimer() setups the necessary parameters. The following functions are not available when the compiler does not support a 64bit data type (long long). 17.5.1 API functions OS_GetTime_us() OS_GetTime_us64() OS_Config_SysTimer() Description Timer ISR Task main Routine Returns the current system time in usec as a X X X X 32 bit value. Returns the current system time in usec as a 64 bit value. This function is not available with X X X X all embOS ports. Configures system time parameters. In genX X X X eral called from RTOSInit.c. Table 17.7: Micro second accurate system time API functions UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 292 CHAPTER 17 Time measurement 17.5.2 OS_GetTime_us() Description Returns the current system time in micro seconds as a 32 bit value. Prototype OS_U32 OS_GetTime_us(); Return value The execution time in micro seconds as a 32-bit unsigned integer value. Additional Information OS_GetTime_us() returns only correct values if the function OS_Config_SysTimer() was called at initialization time. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 293 17.5.3 OS_GetTime_us64() Description Returns the current system time in micro seconds as a 64 bit value. Prototype OS_U64 OS_GetTime_us(); Return value The execution time in micro seconds as a 64-bit unsigned integer value. Additional Information OS_GetTime_us64() returns only correct values if the function OS_Config_SysTimer() was called at initialization time. This function is not available with all embOS ports. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 294 CHAPTER 17 Time measurement 17.5.4 OS_Config_SysTimer() Description Configures the system time parameters for the functions OS_GetTime_us() and OS_GetTime_us64(). This function should be called once at initialization time, e.g. in RTOSInit.c. Prototype void OS_Config_SysTimer(const OS_SYSTIMER_CONFIG *pConfig) Parameter Description Pointer to a data structure of type OS_SYSTIMER_CONFIG pConfig Table 17.8: OS_Config_SysTimer() parameter list Additional Information OS_Config_SysTimer() uses the struct OS_SYSTIMER_CONFIG: Member TimerFreq TickFreq IsUpCounter pfGetTimerCycles pfGetTimerIntPending Description Timer frequency in Hz Tick frequency in Hz 0: for hardware timer which counts down 1: for hardware timer which counts up Pointer to a function which returns the current hardware timer count value Pointer to a function which returns if the hardware timer interrupt pending flag is set Table 17.9: OS_Config_SysTimer() parameter list 17.5.4.1 pfGetTimerCycles() Description This callback function must be implemented by the user. It returns the current hardware timer count value. Prototype unsigned int (*pfGetTimerCycles) (void); Return value The current hardware timer count value. 17.5.4.2 pfGetTimerIntPending() Description This callback function must be implemented by the user. It returns a value unequal to zero if the hardware timer interrupt pending flag is set. Prototype unsigned int (*pfGetTimerIntPending)(void); Return value It returns zero if the hardware timer interrupt pending flag is not set and any other value when the pending flag is set. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 295 17.5.4.3 Example #define OS_FSYS #define OS_PCLK_TIMER #define OS_TICK_FREQ 72000000u (OS_FSYS) 1000u // 72 MHz CPU main clock // HW timer runs at CPU speed // 1 KHz => 1 msc per system tick static unsigned int _OS_GetHWTimerCycles(void) { return HW_TIMER_VALUE_REG; } static unsigned int _OS_GetHWTimer_IntPending(void) { return HW_TIMER_INT_REG & (1uL << PENDING_BIT); } void OS_InitHW(void) { OS_SYSTIMER_CONFIG Tick_Config = {OS_PCLK_TIMER, OS_TICK_FREQ, 0, _OS_GetHWTimerCycles, _OS_GetHWTimer_IntPending}; OS_Config_SysTimer(&Tick_Config); ... ... } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 296 UM01001 User & Reference Guide for embOS CHAPTER 17 Time measurement (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 297 Chapter 18 System variables The system variables are described here for a deeper understanding of how the OS works and to make debugging easier. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 298 CHAPTER 18 System variables 18.1 Introduction Note: Do not change the value of any system variables. These variables are accessible and are not declared constant, but they should only be altered by functions of embOS. However, some of these variables can be very useful, especially the time variables. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 299 18.2 Time variables 18.2.1 OS_Global OS_Global is a structure which includes embOS internal variables. The following variables OS_Global.Time and OS_Global.TimeDex are part of OS_Global. Any other part of OS_Global is not explained here as they are not required to use embOS. 18.2.2 OS_Global.Time Description This is the time variable which contains the current system time in ticks (usually equivalent to ms). Additional Information The time variable has a resolution of one time unit, which is normally 1/1000 sec (1 ms) and is normally the time between two successive calls to the embOS timer interrupt handler. Instead of accessing this variable directly, use OS_GetTime() or OS_GetTime32() as explained in the Chapter Time measurement on page 277. 18.2.3 OS_Global.TimeDex Basically, for internal use only. Contains the time at which the next task switch or timer activation is due. If ((int)(OS_Global.Time - OS_Global.TimeDex)) >= 0, the task list and timer list will be checked for a task or timer to activate. After activation, OS_Global.TimeDex will be assigned the time stamp of the next task or timer to be activated. Note that the value of OS_Global.TimeDex may be invalid during task execution. it shows correct values during execution of OS_Idle() and when used internally in the embOS scheduler. The value of OS_Global.TimeDex should not be used by the application. If you need any information about the next time scheduled action from embOS, the function OS_GetNumIdleTicks() can be used to get the number of ticks spent idle. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 300 CHAPTER 18 System variables 18.3 OS internal variables and data-structures embOS internal variables are not explained here as they are in no way required to use embOS. Your application should not rely on any of the internal variables, as only the documented API functions are guaranteed to remain unchanged in future versions of embOS. Important Do not alter any system variables. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 301 Chapter 19 System tick This chapter explains the concept of the system tick, generated by a hardware timer and all options available for it. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 302 CHAPTER 19 System tick 19.1 Introduction Typically a hardware timer generates periodic interrupts used as a time base for the OS. The interrupt service routine then calls one of the tick handlers of the OS. embOS offers tick handlers with different functionality as well as a way to call a hook function from within the system tick handler. Generating timer interrupts The hardware timer is normally initialized in the OS_InitHW() function which is delivered with the BSP. The BSP also includes the interrupt handler which is called by the hardware timer interrupt. This interrupt handler must call one of the embOS system tick handler functions which are explained in this chapter. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 303 19.2 Tick handler The interrupt service routine used as time base needs to call a tick handler. There are different tick handlers available; one of these need to be called. The reason why there are different tick handlers is simple: They differ in capabilities, code size and execution speed. Most application use the standard tick handler OS_TICK_Handle(), which increments the tick count by one every time it is called. This tick handler is small and efficient, but it cannot handle situations where the interrupt rate is different from the tick rate. OS_TICK_HandleEx() is capable of handling even fractional interrupt rates, such as 1.6 interrupts per tick. 19.2.1 API functions OS_TICK_Handle() OS_TICK_HandleEx() OS_TICK_HandleNoHook() OS_TICK_Config() Description Timer ISR Task main Routine Standard embOS tick handler. X Extended embOS tick handler. X embOS tick handler without hook functionality. X Configures the extended embOS tick handler. X X Table 19.1: API functions UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 304 CHAPTER 19 System tick 19.2.1.1 OS_TICK_Handle() Description The default embOS timer tick handler which is typically called by the hardware timer interrupt handler. Prototype void OS_TICK_Handle ( void ); Additional Information The embOS tick handler must not be called by the application, it must be called from an interrupt handler. OS_EnterInterrupt(), or OS_EnterNestableInterrupt() must be called, before calling the embOS tick handler Example /* Example of a timer interrupt handler */ /********************************************************************* * * OS_ISR_Tick */ __interrupt void OS_ISR_Tick(void) { OS_EnterNestableInterrupt(); OS_TICK_Handle(); OS_LeaveNestableInterrupt(); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 305 19.2.1.2 OS_TICK_HandleEx() Description An alternate tick handler which may be used instead of the standard tick handler. It can be used in situations where the basic timer-interrupt interval (tick) is a multiple of one ms and the time values used as parameter for delays still should use one ms as the time base. Prototype void OS_TICK_HandleEx ( void ); Additional Information The embOS tick handler must not be called by the application, it must be called from an interrupt handler. OS_EnterInterrupt(), or OS_EnterNestableInterrupt() must be called before calling the embOS tick handler. Refer to OS_TICK_Config() on page 307 about how to configure OS_TICK_HandleEx(). Example /* Example of a timer interrupt handler using OS_HandleTickEx */ /********************************************************************* * * OS_ISR_Tick */ __interrupt void OS_ISR_Tick(void) { OS_EnterNestableInterrupt(); OS_TICK_HandleEx(); OS_LeaveNestableInterrupt(); } Assuming the hardware timer runs at a frequency of 500Hz, thus interrupting the system every 2ms, the embOS tick handler configuration function OS_TICK_Config() should be called as demonstrated in the Example section of OS_TICK_Config(). This should be done during OS_InitHW(), before the embOS timer is started. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 306 CHAPTER 19 System tick 19.2.1.3 OS_TICK_HandleNoHook() Description The alternate speed optimized embOS timer tick handler without hook function which is typically called by the hardware timer interrupt handler. Prototype void OS_TICK_HandleNoHook ( void ); Additional Information The embOS tick handler must not be called by the application, it must be called from an interrupt handler. OS_EnterInterrupt(), or OS_EnterNestableInterrupt() must be called before calling the embOS tick handler Example /* Example of a timer interrupt handler */ /********************************************************************* * * OS_ISR_Tick */ __interrupt void OS_ISR_Tick(void) { OS_EnterNestableInterrupt(); OS_TICK_HandleNoHook(); OS_LeaveNestableInterrupt(); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 307 19.2.1.4 OS_TICK_Config() Description Configures the tick to interrupt ratio. The "normal" tick handler OS_TICK_Handle() assumes a 1:1 ratio, meaning one interrupt increments the tick count (OS_Time) by one. For other ratios, OS_TICK_HandleEx() needs to be used; the ratio is defined by calling the OS_TICK_Config(). Prototype void OS_TICK_Config ( unsigned FractPerInt, unsigned FractPerTick ); Parameter FractPerInt FractPerTick Description Number of Fractions per interrupt Number of Fractions per tick Table 19.2: OS_TICK_Config() parameter list Additional Information FractPerInt/FractPerTick = Time between two tick interrupts / Time for one tick Note that fractional values are supported, such as tick is 1 ms, where an interrupt is generated every 1.6ms. This means that FractPerInt and FractPerTick are: FractPerInt = 16; FractPerTick = 10; or FractPerInt = 8; FractPerTick = 5; Examples: OS_TICK_Config(2, OS_TICK_Config(8, OS_TICK_Config(1, OS_TICK_Config(1, OS_TICK_Config(1, 1); 5); 10); 1); 100); // 500 Hz interrupts (2ms), 1ms tick // Interrupts once per 1.6ms, 1ms tick // 10 kHz interrupts (0.1ms), 1ms tick // 10 kHz interrupts (0.1ms), 0.1 ms tick // 10 kHz interrupts (0.1ms), 1 us tick UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 308 CHAPTER 19 System tick 19.3 Hooking into the system tick There are various situations in which it can be desirable to call a function from the tick handler. Some examples are: * * * Watchdog update Periodic status check Periodic I/O update The same functionality can be achieved with a high-priority task or a software timer with one tick period time. Advantage of using a hook function Using a hook function is much faster than performing a task switch or activating a software timer, because the hook function is directly called from the embOS timer interrupt handler and does not cause a context switch. 19.3.1 API functions OS_TICK_AddHook() OS_TICK_RemoveHook() Description Adds a tick hook handler. Removes a tick hook handler. Timer ISR Task main Routine X X X X Table 19.3: API functions UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 309 19.3.1.1 OS_TICK_AddHook() Description Adds a tick hook handler. Prototype void OS_TICK_AddHook ( OS_TICK_HOOK * pHook, OS_TICK_HOOK_ROUTINE * pfUser ); Parameter pHook pfUser Description Pointer to a structure of OS_TICK_HOOK. Pointer to an OS_TICK_HOOK_ROUTINE function. Table 19.4: OS_TICK_AddHook() parameter list Additional Information The hook function is called directly from the interrupt handler. The function therefore should execute as fast as possible. The function called by the tick hook must not re-enable interrupts. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 310 CHAPTER 19 System tick 19.3.1.2 OS_TICK_RemoveHook() Description Removes a tick hook handler. Prototype void OS_TICK_RemoveHook ( const OS_TICK_HOOK * pHook ); Parameter pHook Description Pointer to a structure of OS_TICK_HOOK. Table 19.5: OS_TICK_RemoveHook() parameter list Additional Information The function may be called to dynamically remove a tick hook function which was installed by a call of OS_TICK_AddHook(). UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 311 19.4 Tickless support The embOS tickless support stops the periodic system tick interrupt during idle periods. Idle periods are periods of time when there are no tasks or software timer ready for execution. Stopping the system tick allows the microcontroller to remain in a deep power saving state until an interrupt occurs. embOS tickless support comes with the three functions OS_GetNumIdleTicks(), OS_AdjustTime() and OS_StartTicklessMode(). They can be used to add tickless support to any embOS start project. 19.4.1 OS_Idle() In order to use the tickless support the OS_Idle() function needs to be modified. The default OS_Idle() function is just an endless loop which starts a low power mode: void OS_Idle(void) { while (1) { _EnterLowPowerMode(); } } The tickless OS_Idle() function depends on the actual hardware: void OS_Idle(void) { OS_TIME IdleTicks; OS_DI(); IdleTicks = OS_GetNumIdleTicks(); if (IdleTicks > 1) { if ((OS_U32)IdleTicks > TIMER1_MAX_TICKS) { IdleTicks = TIMER1_MAX_TICKS; } OS_StartTicklessMode(IdleTicks, &_EndTicklessMode); _SetHWTimer(IdleTicks); } OS_EI(); while (1) { _EnterLowPowerMode(); } } The following description explains the tickless OS_Idle() function step by step: void OS_Idle(void) { OS_TIME IdleTicks; OS_DI(); Interrupts are disabled to avoid a timer interrupt. IdleTicks = OS_GetNumIdleTicks(); if (IdleTicks > 1) { The OS_Idle() function reads the idle ticks with OS_GetNumIdleTicks(). The tickless mode is only used when there is more than one idle tick. If there are zero or one idle ticks the scheduler is executed at the next system tick hence it makes no sense to enter the tickless mode. if ((OS_U32)IdleTicks > TIMER_MAX_TICKS) { IdleTicks = TIMER_MAX_TICKS; } If it is not possible due to hardware timer limitations to generate the timer interrupt at the specified time the idle ticks can be reduced to any lower value. For example OS_GetNumIdleTicks() returns 200 idle ticks but the hardware timer is limited to 100 ticks. The variable IdleTicks will be set to 100 ticks and the system will wake up after UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 312 CHAPTER 19 System tick 100 ticks. OS_Idle() will be again executed and OS_GetNumIdleTicks() returns the remaining 100 idle ticks. This means that the system wakes up two times before the complete 200 idle ticks are expired. if (IdleTicks > 1) { ... OS_StartTicklessMode(IdleTicks, &_EndTicklessMode); _SetHWTimer(IdleTicks); } OS_StartTicklessMode() sets the idle ticks and the callback function. The idle ticks information is later used in the callback function. The callback function is described below. _SetHWTimer() is a hardware dependend function which reprograms the hardware timer to generate a system tick interrupt at the time defined by idle ticks. OS_EI(); while (1) { _EnterLowPowerMode(); } Interrupts are reenabled and the CPU enters in the endless while loop the low power mode. _EnterLowPowerMode() is a hardware depending function which activates the low power mode. 19.4.2 Callback Function The callback function calculates how long we actually stayed in low power mode and corrects the system time accordingly. The hardware timer will be reset to the default system tick time. static void _EndTicklessMode(void) { OS_U32 NumTicks; if (OS_Global.TicklessExpired) { OS_AdjustTime(OS_Global.TicklessFactor); } else { NumTicks = _GetLowPowerTicks(); OS_AdjustTime(NumTicks); } _SetHWTimer(OS_TIMER_RELOAD); } The following description explains the callback function step by step: static void _EndTicklessMode(void) { OS_U32 NumTicks; if (OS_Global.TicklessExpired) { OS_AdjustTime(OS_Global.TicklessFactor); If the hardware timer expired and the system tick interrupt was executed the flag OS_Global.TicklessExpired is set to 1. This can be used to determine if the system stayed in low power mode for the complete idle time. If this flag is set we can use the value in OS_Global.TicklessFactor to adjust the system time. } else { NumTicks = _GetLowPowerTicks(); OS_AdjustTime(NumTicks); } _GetLowPowerTicks() is a hardware depending function which returns the expired idle ticks if the low power mode was interrupted by any other interrupt than the system tick. We use that value to adjust the system time. _SetHWTimer(OS_TIMER_RELOAD); } _SetHWTimer() is a hardware depending function which reprograms the hardware timer to it's default value for one system tick. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 313 19.4.3 API functions Routine Description Retrieves the number of embOS timer ticks until the next time scheduled action will be started. OS_AdjustTime() Adjusts the embOS internal time. OS_StartTicklessMode() Starts the tickless mode. OS_StopTicklessMode() Stops the tickless mode. OS_GetNumIdleTicks() Table 19.6: API functions UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 314 CHAPTER 19 System tick 19.4.3.1 OS_GetNumIdleTicks() Description Retrieves the number of embOS timer ticks until the next time scheduled action will be started. Prototype OS_TIME OS_GetNumIdleTicks(void) Return value The number of ticks until the next time scheduled action. Additional Information The function may be useful when the embOS timer and CPU shall be halted by the application and restarted after the idle time to save power. This works, when the application has its own time base and a special interrupt that can wake up the CPU. When the embOS timer is started again the internal time must be adjusted to guarantee time scheduled actions to be executed. This can be done by a call of OS_AdjustTime(). UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 315 19.4.3.2 OS_AdjustTime() Description This function may be used to adjust the embOS internal time by adding an amount of time to the internal time variable. Prototype void OS_AdjustTicks(OS_TIME Time) Parameter Time Description The amount of time which should be added to the embOS internal time variable. Table 19.7: OS_AdjsutTime() parameter list Additional Information The function may be useful when the embOS timer was halted by the application for a certain known interval of time. When the embOS timer is started again the internal time must be adjusted to guarantee time scheduled actions to be executed. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 316 CHAPTER 19 System tick 19.4.3.3 OS_StartTicklessMode() Description This function may be used to start the tickless mode. Prototype void OS_StartTicklessMode(OS_TIME Time, voidRoutine *Callback) Parameter Time Callback Description Time in ticks which will be spent in low power mode. Callback function to stop the tickless mode. Table 19.8: OS_StartTicklessMode() parameter list Additional Information This function starts the tickless mode. It must be called in OS_Idle() before the CPU enters a low power mode. The callback function must stop the tickless mode. It must calculate how many system ticks are actually spent in lower power mode and adjust the system time by calling OS_AdjustTime(). It also must reset the system tick timer to it's default tick period. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 317 19.4.3.4 OS_StopTicklessMode() Description This function may be used to stop the tickless mode. Prototype void OS_StopTicklessMode(void) Additional Information This function stops the tickless mode. It calls the callback function when the tickless mode was enabled. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 318 CHAPTER 19 System tick 19.4.4 Frequently Asked Questions 1. Q: Where can I find more information about tickless support for a specific CPU? A: Segger provides Application Notes for tickless support for different CPUs. 2. Q: Can I use embOS without tickless support? A: Yes, you can use embOS without tickless support. There is no change required in your project. 3. Q: What hardware depending functions must be implemented and where? A: OS_Idle() must be modified and the callback function must be implemented. OS_Idle() is part of the RTOSInit.c file. We suppose to implement the callback function in the same file. 4. Q: What triggers the callback function? A: The callback function is executed once from the scheduler when the tickless operation ends and normal operation resumes. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 319 Chapter 20 Configuration of target system (BSP) This chapter explains the target system specific parts of embOS, also called BSP (board support package). If the system is up and running on your target system, there is no need to read this chapter. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 320 CHAPTER 20 Configuration of target system (BSP) 20.1 Introduction You do not need to configure anything to get started with embOS. The start project supplied will execute on your system. Small changes in the configuration will be necessary at a later point for system frequency or for the UART used for communication with the optional embOSView. The file RTOSInit.c is provided in source code and can be modified to match your target hardware needs. It is compiled and linked with your application program. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 321 20.2 Hardware-specific routines Description Required for embOS Initializes the hardware timer used for generating interrupts. embOS needs a timer-interrupt to determine when to activate tasks that OS_InitHW() wait for the expiration of a delay, when to call a software timer, and to keep the time variable up-to-date. The idle loop is always executed whenever no OS_Idle() other task (and no interrupt service routine) is ready for execution. The embOS timer-interrupt handler. When OS_ISR_Tick() using a different timer, always check the specified interrupt vector. Converts cycles into s (used with profiling OS_ConvertCycles2us() only). Reads the timestamp in cycles. Cycle length OS_GetTime_Cycles() depends on the system. This function is used for system information sent to embOSView. Optional for run-time OS-View Initializes communication for embOSView OS_COM_Init() (used with embOSView only). Rx Interrupt service handler for embOSView OS_ISR_rx() (used with embOSView only). Tx Interrupt service handler for embOSView OS_ISR_tx() (used with embOSView only). Send one byte via a UART (used with embOSOS_COM_Send1() View only). Do not call this function from your application. Timer ISR Task main Routine X X X X X X X X X X Table 20.1: Hardware specific routines 20.2.1 OS_Idle() The embOS function OS_Idle() is called when no task is ready for execution. The function OS_Idle() is part of the target CPU specific RTOSInit.c file delivered with embOS. Normally it is programmed as an endless loop without any functionality. In most embOS ports, it activates a power saving sleep mode of the target CPU. The embOS OS_Idle() function is not a task, it has no task context and does not have its own stack. The OS_Idle() function runs on the normal CSTACK which is also used for the kernel. Exceptions and interrupts which occur during OS_Idle() are no problem as long as they don't trigger a task switch. They return into OS_Idle() and the code is continued where it was interrupted. When a task switch occurs during the execution of OS_Idle(), the OS_Idle() function is interrupted and does not continue execution when it is activated again. When OS_Idle() is activated, it always starts from the beginning. Interrupted code is not continued. You might create your own idle task running as endless loop with the lowest task priority in the system. When you don't call any blocking or suspending function in this idle task, you will never arrive in OS_Idle(). UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 322 CHAPTER 20 Configuration of target system (BSP) You might alternatively use OS_EnterRegion() and OS_LeaveRegion() to avoid task switches during the execution of your ..doStuff() in OS_Idle(). Running in a critical region does not block interrupts, but disables task switches until OS_LeaveRegion() is called. Using a critical region during OS_Idle() will affect task activation time, but will not affect interrupt latency. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 323 20.3 Configuration defines For most embedded systems, configuration is done by simply modifying the following defines, located at the top of the RTOSInit.c file: Define OS_FSYS OS_UART OS_BAUDRATE Description System frequency (in Hz). Example: 20000000 for 20MHz. Selection of UART to be used with embOSView (-1 will disable communication), Selection of baudrate for communication with embOSView. Table 20.2: Configuration defines overview UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 324 CHAPTER 20 Configuration of target system (BSP) 20.4 How to change settings The only file which you may need to change is RTOSInit.c. This file contains all hardware-specific routines. The one exception is that some ports of embOS require an additional interrupt vector table file (details can be found in the CPU & Compiler Specifics manual of embOS documentation). 20.4.1 Setting the system frequency OS_FSYS Relevant defines OS_FSYS Relevant routines OS_ConvertCycles2us() (used with profiling only) For most systems it should be sufficient to change the OS_FSYS define at the top of RTOSInit.c. When using profiling, certain values may require a change in OS_ConvertCycles2us(). The RTOSInit.c file contains more information about in which cases this is necessary and what needs to be done. 20.4.2 Using a different timer to generate the tick-interrupts for embOS Relevant routines OS_InitHW() embOS usually generates one interrupt per ms, making the timer-interrupt, or tick, normally equal to 1 ms. This is done by a timer initialized in the routine OS_InitHW(). If you want to use a different timer for your application, you must modify OS_InitHW() to initialize the appropriate timer. For details about initialization, read the comments in RTOSInit.c. 20.4.3 Using a different UART or baudrate for embOSView Relevant defines OS_UART OS_BAUDRATE Relevant routines: OS_COM_Init() OS_COM_Send1() OS_ISR_rx() OS_ISR_tx() In some cases, this is done by simply changing the define OS_UART. Refer to the contents of the RTOSInit.c file for more information about which UARTS that are supported for your CPU. 20.4.4 Changing the tick frequency Relevant defines OS_FSYS As noted above, embOS usually generates one interrupt per ms. OS_FSYS defines the clock frequency of your system in Hz (times per second). The value of OS_FSYS is used for calculating the desired reload counter value for the system timer for 1000 interrupts/sec. The interrupt frequency is therefore normally 1 kHz. Different (lower or higher) interrupt rates are possible. If you choose an interrupt frequency different from 1 kHz, the value of the time variable OS_Time will no longer be equivalent to multiples of 1 ms. However, if you use a multiple of 1 ms as tick UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 325 time, the basic time unit can be made 1 ms by using the function OS_TICK_Config(). The basic time unit does not need to be 1 ms; it might just as well be 100 s or 10 ms or any other value. For most applications, 1 ms is an appropriate value. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 326 CHAPTER 20 Configuration of target system (BSP) 20.5 STOP / HALT / IDLE modes Most CPUs support power-saving STOP, HALT, or IDLE modes. Using these types of modes is one possible way to save power consumption during idle times. As long as the timer-interrupt will wake up the system with every embOS tick, or as long as other interrupts will activate tasks, these modes may be used for saving power consumption. If required, you may modify the OS_Idle() routine, which is part of the hardwaredependant module RTOSInit.c, to switch the CPU to power-saving mode during idle times. Refer to the CPU & Compiler Specifics manual of embOS documentation for details about your processor. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 327 Chapter 21 Profiling This chapter explains the profiling functions that can be used by an application. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 328 CHAPTER 21 Profiling 21.0.1 API functions OS_STAT_Sample() OS_STAT_GetLoad() OS_AddLoadMeasurement() OS_GetLoadMeasurement() OS_STAT_Enable() OS_STAT_Disable() OS_STAT_GetTaskExecTime() Description Starts a new task cpu load measurement. Returns the task-specific cpu load. Adds total CPU load measurement functinality. Returns the total CPU load. Enables profiling Disables profiling Returns the total task execution time Timer ISR Task main Routine X X X X X X X X X X X X X X X X X X X X X X X X X X Table 21.1: API functions UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 329 21.0.1.1 OS_STAT_Sample() Description OS_STAT_Sample() starts profiling and calculates the absolute task run time since the last call to OS_STAT_Sample(). Prototype void OS_STAT_Sample ( void ); Additional Information OS_STAT_Sample() starts the profiling for 5 seconds, the next call to OS_STAT_Sample() must be within this 5 seconds. Please use the embOS function OS_STAT_GetLoad() to get the task-specific cpu load in 1/10 percent. OS_STAT_Sample() cannot be used from multiple tasks at a time, because it uses a global variable. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 330 CHAPTER 21 Profiling 21.0.1.2 OS_STAT_GetLoad() Description OS_STAT_GetLoad() calculates the current tasks cpu load in 1/10 percent. Prototype int OS_STAT_GetLoad(OS_TASK * pTask); Parameter pTask Description Pointer to task control block Table 21.2: OS_STAT_GetLoad() parameter list Return value OS_STAT_GetLoad() returns the current tasks cpu load in 1/10 percent. Additional Information OS_STAT_GetLoad() requires that OS_STAT_Sample() is called periodically. OS_STAT_GetLoad() cannot be used from multiple tasks at a time, because it uses a global variable. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 331 21.0.1.3 Sample application for OS_STAT_Sample() and OS_STAT_GetLoad() #include "RTOS.h" #include "stdio.h" OS_STACKPTR int StackHP[128], StackLP[128], StackMP[128]; /* Task stacks */ OS_TASK TCBHP, TCBLP, TCBMP; /* Task-control-blocks */ static void HPTask(void) { volatile int r; while (1) { OS_Delay (1000); OS_STAT_Sample(); r = OS_STAT_GetLoad(&TCBMP); printf("CPU Usage of MP Task: %d\n", r); } } static void MPTask(void) { while (1) { } } static void LPTask(void) { while (1) { } } int main(void) { OS_IncDI(); OS_InitKern(); OS_InitHW(); /* You need to create OS_CREATETASK(&TCBHP, OS_CREATETASK(&TCBMP, OS_CREATETASK(&TCBLP, OS_Start(); return 0; } /* Initially disable interrupts /* Initialize OS /* Initialize Hardware for OS at least one task before calling OS_Start() "HP Task", HPTask, 100, StackHP); "MP Task", MPTask, 50, StackMP); "LP Task", LPTask, 50, StackLP); /* Start multitasking */ */ */ */ */ Output: 500 499 501 500 500 ... UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 332 CHAPTER 21 Profiling 21.0.1.4 OS_AddLoadMeasurement() Description OS_AddLoadMeasurement() may be used to start calculation of the total CPU load of an application. Prototype void OS_AddLoadMeasurement(int Period, OS_U8 AutoAdjust, int DefaultMaxValue); Parameter Description Period for measurement in embOS timer ticks When != 0, the measurement is autoadjusted once initially. May be used to set a default counter value when AutoAdjust is DefaultMaxValue not used. (See additional information) Period AutoAdjust Table 21.3: OS_STAT_GetLoad() parameter list Additional Information OS_AddLoadMeasurement() creates a task running at highest priority. The task suspends itself periodically by calling OS_Delay(Period). When the task is resumed after the delay, it calculates the CPU load by comparison of two counter values. The CPU load is the percentage not spent in OS_Idle(). For the calculation, it is required that OS_Idle() is called. OS_Idle() must increment a counter by calling OS_INC_IDLE_CNT(); The maximum value of this counter is stored and is compared against the current value of the counter, every time the measurement task is activated. It is assumed, that the maximum value of the counter reperesents a CPU load of 0, all time spent in OS_Idle(). When AutoAdjust is set, the task will initially suspend all other tasks for the Periodtime and than call OS_Delay(Period). This way, the whole period is spent in OS_Idle() and the counter incremented in OS_Idle() reaches its maximum value initially. If this behavior is not wanted, because it blocks all tasks for the Period-time once initially, the maximum value for the counter may be examined once and then be set by the parameter DefaultMaxValue with AutoAdjust disabled. The value for DefaultMaxValue can be examined once from one task before any other tasks are created: void MainTask(void) { OS_I32 DefaultMax; OS_Delay(100); DefaultMax = OS_IdleCnt; /* This value can be used as DefaultMaxValue. */ /* Now other tasks can be created and started. */ The calculation does not work when OS_Idle() puts the CPU in Low-power (Stop) mode. OS_Idle() must look like follows: void OS_Idle(void) { /* Idle loop: No task is ready to execute */ while (1) { OS_INC_IDLE_CNT(); } } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 333 21.0.1.5 OS_GetLoadMeasurement() Description OS_GetLoadMeasurement() can be called from the application to retrieve the result of the CPU load measurement. Prototype int OS_GetLoadMeasurement(void) Return value OS_GetLoadMeasurement returns the total CPU load in percent. Additional Information OS_GetLoadMeasurement() delivers correct results when the CPU load measurement was started by calling OS_AddLoadMeasurement() with auot-adjustment before, and OS_Idle() updates the measurement by calling OS_INC_IDLE_CNT(). The calculation does not work when OS_Idle() puts the CPU in Low-power (Stop) mode. OS_Idle() must look like follows: void OS_Idle(void) { /* Idle loop: No task is ready to execute */ while (1) { OS_INC_IDLE_CNT(); } } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 334 CHAPTER 21 Profiling 21.0.1.6 OS_CPU_Load Description This global variable shows the total CPU load in percent. It may be usefull to show the variable in a debugger with life-watch capability during programm development. Declaration volatile OS_INT OS_CPU_Load; Additional Information This variable may not exist and will not show correct results, when the CPU load measurement was not started by a call of OS_AddLoadMeasurement(). As an additional condition embOS must be running and OS_Idle must call OS_INC_IDLE_CNT() to update the CPU load measurement. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 335 21.0.1.7 OS_STAT_Enable() Description OS_STAT_Enable() may be used to start the profiling for an infinite time. Prototype void OS_STAT_Enable(void); Additional Information The profiling is started and does not disable itself after 5 seconds. The function OS_STAT_Disable() may be used to stop the profiling. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 336 CHAPTER 21 Profiling 21.0.1.8 OS_STAT_Disable() Description OS_STAT_Disable() may be used to stop the profiling. Prototype void OS_STAT_Disable(void); Additional Information The function OS_STAT_Enable() may be used to start the profiling. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 337 21.0.1.9 OS_STAT_GetTaskExecTime() Description OS_STAT_GetTaskExecTime() may be used to return the total task execution time. Prototype OS_U32 OS_STAT_GetTaskExecTime(const OS_TASK *pTask); Parameter pTask Description Pointer to a task control block. Return value OS_STAT_GetTaskExecTime() returns the total task execution time. Additional Information This function only returns valid values when the profiling is enabled before with OS_STAT_Enable(). If pTask is the NULL pointer, the function returns the total task execution time of the currently running task. If pTask does not specify a valid task, a debug build of embOS calls OS_Error(). A release build of embOS cannot check the validity of pTask and may therefore return invalid values if pTask does not specify a valid task. Example OS_U32 ExecTime; void MyTask(void) { OS_STAT_Enable(); while (1) { ExecTime = OS_STAT_GetTaskExecTime(NULL); OS_Delay(100); } } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 338 UM01001 User & Reference Guide for embOS CHAPTER 21 Profiling (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 339 Chapter 22 embOSView: Profiling and analyzing UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 340 CHAPTER 22 embOSView: Profiling and analyzing 22.1 Overview embOSView displays the state of a running application using embOS. A serial interface (UART) is normally used for communication with the target. But there are also other communication channels like ethernet or memory read/write for Cortex M CPUs or DCC for ARM7/9 CPUs. The hardware-dependent routines and defines available for communication with embOSView are located in RTOSInit.c. This file must be configured properly. For details on how to configure this file, refer the CPU & Compiler Specifics manual of embOS documentation. The embOSView utility is shipped as embOSView.exe with embOS and runs under Windows 9x / NT / 2000 / Vista and Windows 7/8. The latest version is available on our website at www.segger.com embOSView is a very helpful tool for analysis of the running target application. The CPU load feature assumes that an embOS library with profiling feature is used like "stack-check plus profiling", "debug plus profiling" or "debug including trace plus profiling". Name SP DP DT Description Stack-checking plus profiling Debug plus profiling Debug including trace plus profiling Table 22.1: embOS libraries with support for profiling used for CPU load UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 341 22.2 Task list window embOSView shows the state of every created task of the target application in the Task list window. The information shown depends on the library used in your application. Item Description Builds Prio Current priority of task. All Id Task ID, which is the address of the task control block. All Name Name assigned during creation. All Status Current state of task (ready, executing, delay, reason for suspension). All Data Depends on status. All Timeout Time of next activation. All Stack Used stack size/max. stack size/stack location. S, SP, D, DP, DT CPULoad Percentage CPU load caused by task. SP, DP, DT Context Switches Number of activations since reset. SP, DP, DT Table 22.2: Task list window overview The Task list window is helpful in analysis of stack usage and CPU load for every running task. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 342 CHAPTER 22 embOSView: Profiling and analyzing 22.3 System variables window embOSView shows the actual state of major system variables in the System variables window. The information shown also depends on the library used in your application: Item Description Builds OS_VERSION Current version of embOS. All CPU Target CPU and compiler. All LibMode Library mode used for target application. All OS_Time Current system time in timer ticks. All OS_NUM_TASKS Current number of defined tasks. All OS_Status Current error code (or O.K.). All OS_pActiveTask Active task that should be running. SP, D, DP, DT OS_pCurrentTask Actual currently running task. SP, D, DP, DT SysStack Used size/max. size/location of system stack. SP, DP, DT IntStack Used size/max. size/location of interrupt stack. SP, DP, DT TraceBuffer Current count/maximum size and current state of trace buffer. All trace builds Table 22.3: System variables window overview UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 343 22.4 Sharing the SIO for terminal I/O The serial input/output (SIO) used by embOSView may also be used by the application at the same time for both input and output. This can be very helpful. Terminal input is often used as keyboard input, where terminal output may be used for outputting debug messages. Input and output is done via the Terminal window, which can be shown by selecting View/Terminal from the menu. To ensure communication via the Terminal window in parallel with the viewer functions, the application uses the function OS_SendString() for sending a string to the Terminal window and the function OS_SetRxCallback() to hook a reception routine that receives one byte. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 344 CHAPTER 22 embOSView: Profiling and analyzing 22.5 API functions OS_SendString() OS_SetRxCallback() Description Timer ISR Task main Routine Sends a string over SIO to the Terminal winX X dow. Sets a callback hook to a routine for receiving X X one character. X Table 22.4: Shared SIO API functions UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 345 22.5.1 OS_SendString() Description Sends a string over SIO to the embOSView terminal window. Prototype void OS_SendString (const char* s); Parameter s Description Pointer to a zero-terminated string that should be sent to the Terminal window. Table 22.5: OS_SendString() parameter list Additional Information This function uses OS_COM_Send1() which is defined in RTOSInit.c. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 346 CHAPTER 22 embOSView: Profiling and analyzing 22.5.2 OS_SetRxCallback() Description Sets a callback hook to a routine for receiving one character. Prototype typedef void OS_RX_CALLBACK (OS_U8 Data) OS_RX_CALLBACK* OS_SetRxCallback (OS_RX_CALLBACK* cb); Parameter cb Description Pointer to the application routine that should be called when one character is received over the serial interface. Table 22.6: OS_SetRxCallback() parameter list Return value OS_RX_CALLBACK* as described above. This is the pointer to the callback function that was hooked before the call. Additional Information The user function is called from embOS. The received character is passed as parameter. See the example below. Example void GUI_X_OnRx(OS_U8 Data); /* Callback ... called from Rx-interrupt */ void GUI_X_Init(void) { OS_SetRxCallback( &GUI_X_OnRx); } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 347 22.6 Using the API trace embOS versions 3.06 or higher contain a trace feature for API calls. This requires the use of the trace build libraries in the target application. The trace build libraries implement a buffer for 100 trace entries. Tracing of API calls can be started and stopped from embOSView via the Trace menu, or from within the application by using the functions OS_TraceEnable() and OS_TraceDiasable(). Individual filters may be defined to determine which API calls should be traced for different tasks or from within interrupt or timer routines. Once the trace is started, the API calls are recorded in the trace buffer, which is periodically read by embOSView. The result is shown in the Trace window: Every entry in the Trace list is recorded with the actual system time. In case of calls or events from tasks, the task ID (TaskId) and task name (TaskName) (limited to 15 characters) are also recorded. Parameters of API calls are recorded if possible, and are shown as part of the APIName column. In the example above, this can be seen with OS_Delay(3). Once the trace buffer is full, trace is automatically stopped. The Trace list and buffer can be cleared from embOSView. Setting up trace from embOSView Three different kinds of trace filters are defined for tracing. These filters can be set up from embOSView via the menu Options/Setup/Trace. Filter 0 is not task-specific and records all specified events regardless of the task. As the Idle loop is not a task, calls from within the idle loop are not traced. Filter 1 is specific for interrupt service routines, software timers and all calls that occur outside a running task. These calls may come from the idle loop or during startup when no task is running. Filters 2 to 4 allow trace of API calls from named tasks. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 348 CHAPTER 22 embOSView: Profiling and analyzing To enable or disable a filter, simply check or uncheck the corresponding checkboxes labeled Filter 4 Enable to Filter 0 Enable. For any of these five filters, individual API functions can be enabled or disabled by checking or unchecking the corresponding checkboxes in the list. To speed up the process, there are two buttons available: * * Select all - enables trace of all API functions for the currently enabled (checked) filters. Deselect all - disables trace of all API functions for the currently enabled (checked) filters. Filter 2, Filter 3, and Filter 4 allow tracing of task-specific API calls. A task name can therefore be specified for each of these filters. In the example above, Filter 4 is configured to trace calls of OS_Delay() from the task called MainTask. After the settings are saved (via the Apply or OK button), the new settings are sent to the target application. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 349 22.7 Trace filter setup functions Tracing of API or user function calls can be started or stopped from embOSView. By default, trace is initially disabled in an application program. It may be very helpful to control the recording of trace events directly from the application, using the following functions. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 350 CHAPTER 22 embOSView: Profiling and analyzing 22.8 API functions OS_TraceEnable() OS_TraceDisable() OS_TraceEnableAll() OS_TraceDisableAll() OS_TraceEnableId() OS_TraceDisableId() OS_TraceEnableFilterId() OS_TraceDisableFilterId() Description Enables tracing of filtered API calls. Disables tracing of API and user function calls. Sets up Filter 0 (any task), enables tracing of all API calls and then enables the trace function. Sets up Filter 0 (any task), disables tracing of all API calls and also disables trace. Sets the specified ID value in Filter 0 (any task), thus enabling trace of the specified function, but does not start trace. Resets the specified ID value in Filter 0 (any task), thus disabling trace of the specified function, but does not stop trace. Sets the specified ID value in the specified trace filter, thus enabling trace of the specified function, but does not start trace. Resets the specified ID value in the specified trace filter, thus disabling trace of the specified function, but does not stop trace. Timer ISR Task main Routine X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X Table 22.7: Trace filter API functions UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 351 22.8.1 OS_TraceEnable() Description Enables tracing of filtered API calls. Prototype void OS_TraceEnable (void); Additional Information The trace filter conditions should have been set up before calling this function. This functionality is available in trace builds only. In non-trace builds, the API call is removed by the preprocessor. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 352 CHAPTER 22 embOSView: Profiling and analyzing 22.8.2 OS_TraceDisable() Description Disables tracing of API and user function calls. Prototype void OS_TraceDisable (void); Additional Information This functionality is available in trace builds only. In non-trace builds, the API call is removed by the preprocessor. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 353 22.8.3 OS_TraceEnableAll() Description Sets up Filter 0 (any task), enables tracing of all API calls and then enables the trace function. Prototype void OS_TraceEnableAll (void); Additional Information The trace filter conditions of all the other trace filters are not affected. This functionality is available in trace builds only. In non-trace builds, the API call is removed by the preprocessor. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 354 CHAPTER 22 embOSView: Profiling and analyzing 22.8.4 OS_TraceDisableAll() Description Sets up Filter 0 (any task), disables tracing of all API calls and also disables trace. Prototype void OS_TraceDisableAll (void); Additional Information The trace filter conditions of all the other trace filters are not affected, but tracing is stopped. This functionality is available in trace builds only. In non-trace builds, the API call is removed by the preprocessor. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 355 22.8.5 OS_TraceEnableId() Description Sets the specified ID value in Filter 0 (any task), thus enabling trace of the specified function, but does not start trace. Prototype void OS_TraceEnableId (OS_U8 Id); Parameter Id Description ID value of API call that should be enabled for trace: 0 <= Id <= 127 Values from 0 to 99 are reserved for embOS. Table 22.8: OS_TraceEnableId() parameter list Additional Information To enable trace of a specific embOS API function, you must use the correct Id value. These values are defined as symbolic constants in RTOS.h. This function may also enable trace of your own functions. This functionality is available in trace builds only. In non-trace builds, the API call is removed by the preprocessor. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 356 CHAPTER 22 embOSView: Profiling and analyzing 22.8.6 OS_TraceDisableId() Description Resets the specified ID value in Filter 0 (any task), thus disabling trace of the specified function, but does not stop trace. Prototype void OS_TraceDisableId (OS_U8 Id); Parameter Id Description ID value of API call that should be enabled for trace: 0 <= Id <= 127 Values from 0 to 99 are reserved for embOS. Table 22.9: OS_TraceDisabledId() parameter list Additional Information To disable trace of a specific embOS API function, you must use the correct Id value. These values are defined as symbolic constants in RTOS.h. This function may also be used for disabling trace of your own functions. This functionality is available in trace builds only. In non-trace builds, the API call is removed by the preprocessor. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 357 22.8.7 OS_TraceEnableFilterId() Description Sets the specified ID value in the specified trace filter, thus enabling trace of the specified function, but does not start trace. Prototype void OS_TraceEnableFilterId (OS_U8 FilterIndex, OS_U8 Id) Parameter FilterIndex Id Description Index of the filter that should be affected: 0 <= FilterIndex <= 4 0 affects Filter 0 (any task) and so on. ID value of API call that should be enabled for trace: 0 <= Id <= 127 Values from 0 to 99 are reserved for embOS. Table 22.10: OS_TraceEnabledFilterId() parameter list Additional Information To enable trace of a specific embOS API function, you must use the correct Id value. These values are defined as symbolic constants in RTOS.h. This function may also be used for enabling trace of your own functions. This functionality is available in trace builds only. In non-trace builds, the API call is removed by the preprocessor. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 358 CHAPTER 22 embOSView: Profiling and analyzing 22.8.8 OS_TraceDisableFilterId() Description Resets the specified ID value in the specified trace filter, thus disabling trace of the specified function, but does not stop trace. Prototype void OS_TraceDisableFilterId (OS_U8 FilterIndex, OS_U8 Id) Parameter FilterIndex Id Description Index of the filter that should be affected: 0 <= FilterIndex <= 4 0 affects Filter 0 (any task) and so on. ID value of API call that should be enabled for trace: 0 <= Id <= 127 Values from 0 to 99 are reserved for embOS. Table 22.11: OS_TraceDisableFilterId() parameter list Additional Information To disable trace of a specific embOS API function, you must use the correct Id value. These values are defined as symbolic constants in RTOS.h. This function may also be used for disabling trace of your own functions. This functionality is available in trace builds only. In non-trace builds, the API call is removed by the preprocessor. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 359 22.9 Trace record functions The following functions are used for writing (recording) data into the trace buffer. As long as only embOS API calls should be recorded, these functions are used internally by the trace build libraries. If, for some reason, you want to trace your own functions with your own parameters, you may call one of these routines. All of these functions have the following points in common: * * * * To record data, trace must be enabled. An ID value in the range from 100 to 127 must be used as the ID parameter. ID values from 0 to 99 are internally reserved for embOS. The events specified as ID must be enabled in any of the trace filters. Active system time and the current task are automatically recorded together with the specified event. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 360 CHAPTER 22 embOSView: Profiling and analyzing 22.10 API functions OS_TraceVoid() OS_TracePtr() OS_TraceData() OS_TraceDataPtr() OS_TraceU32Ptr() Description Writes an entry identified only by its ID into the trace buffer. Writes an entry with ID and a pointer as parameter into the trace buffer. Writes an entry with ID and an integer as parameter into the trace buffer. Writes an entry with ID, an integer, and a pointer as parameter into the trace buffer. Writes an entry with ID, a 32-bit unsigned integer, and a pointer as parameter into the trace buffer. Timer ISR Task main Routine X X X X X X X X X X X X X X X X X X X X Table 22.12: Trace record API functions UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 361 22.10.1 OS_TraceVoid() Description Writes an entry identified only by its ID into the trace buffer. Prototype void OS_TraceVoid (OS_U8 Id); Parameter Id Description ID value of API call that should be enabled for trace: 0 <= Id <= 127 Values from 0 to 99 are reserved for embOS. Table 22.13: OS_TraceVoid() parameter list Additional Information This functionality is available in trace builds only, and the API call is not removed by the preprocessor. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 362 CHAPTER 22 embOSView: Profiling and analyzing 22.10.2 OS_TracePtr() Description Writes an entry with ID and a pointer as parameter into the trace buffer. Prototype void OS_TracePtr (OS_U8 Id, void* p); Parameter Id p Description ID value of API call that should be enabled for trace: 0 <= Id <= 127 Values from 0 to 99 are reserved for embOS. Any void pointer that should be recorded as parameter. Table 22.14: OS_TracePtr() parameter list Additional Information The pointer passed as parameter will be displayed in the trace list window of embOSView. This functionality is available in trace builds only. In non-trace builds, the API call is removed by the preprocessor. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 363 22.10.3 OS_TraceData() Description Writes an entry with ID and an integer as parameter into the trace buffer. Prototype void OS_TraceData (OS_U8 Id, int v); Parameter Id v Description ID value of API call that should be enabled for trace: 0 <= Id <= 127 Values from 0 to 99 are reserved for embOS. Any integer value that should be recorded as parameter. Table 22.15: OS_TraceData() parameter list Additional Information The value passed as parameter will be displayed in the trace list window of embOSView.This functionality is available in trace builds only. In non-trace builds, the API call is removed by the preprocessor. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 364 CHAPTER 22 embOSView: Profiling and analyzing 22.10.4 OS_TraceDataPtr() Description Writes an entry with ID, an integer, and a pointer as parameter into the trace buffer. Prototype void OS_TraceDataPtr (OS_U8 Id, int v, void* p); Parameter Id v p Description ID value of API call that should be enabled for trace: 0 <= Id <= 127 Values from 0 to 99 are reserved for embOS. Any integer value that should be recorded as parameter. Any void pointer that should be recorded as parameter. Table 22.16: OS_TraceDataPtr() parameter list Additional Information The values passed as parameters will be displayed in the trace list window of embOSView. This functionality is available in trace builds only. In non-trace builds, the API call is removed by the preprocessor. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 365 22.10.5 OS_TraceU32Ptr() Description Writes an entry with ID, a 32-bit unsigned integer, and a pointer as parameter into the trace buffer. Prototype void OS_TraceU32Ptr (OS_U8 Id, OS_U32 p0, void* p1); Parameter Id p0 p1 Description ID value of API call that should be enabled for trace: 0 <= Id <= 127 Values from 0 to 99 are reserved for embOS. Any unsigned 32-bit value that should be recorded as parameter. Any void pointer that should be recorded as parameter. Table 22.17: OS_TraceU32Ptr() parameter list Additional Information This function may be used for recording two pointers. The values passed as parameters will be displayed in the trace list window of embOSView. This functionality is available in trace builds only. In non-trace builds, the API call is removed by the preprocessor. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 366 CHAPTER 22 embOSView: Profiling and analyzing 22.11 Application-controlled trace example As described in the previous section, the user application can enable and set up the trace conditions without a connection or command from embOSView. The trace record functions can also be called from any user function to write data into the trace buffer, using ID numbers from 100 to 127. Controlling trace from the application can be very helpful for tracing API and user functions just after starting the application, when the communication to embOSView is not yet available or when the embOSView setup is not complete. The example below shows how a trace filter can be set up by the application. The function OS_TraceEnableID() sets the trace filter 0 which affects calls from any running task. Therefore, the first call to SetState() in the example would not be traced because there is no task running at that moment. The additional filter setup routine OS_TraceEnableFilterId() is called with filter 1, which results in tracing calls from outside running tasks. Example code #include "RTOS.h" #ifndef OS_TRACE_FROM_START #define OS_TRACE_FROM_START 1 #endif /* Application specific trace id numbers #define APP_TRACE_ID_SETSTATE 100 */ char MainState; /* Sample of application routine with trace */ void SetState(char* pState, char Value) { #if OS_TRACE OS_TraceDataPtr(APP_TRACE_ID_SETSTATE, Value, pState); #endif * pState = Value; } /* Sample main routine, that enables and setup API and function call trace from start */ void main(void) { OS_InitKern(); OS_InitHW(); #if (OS_TRACE && OS_TRACE_FROM_START) /* OS_TRACE is defined in trace builds of the library */ OS_TraceDisableAll(); /* Disable all API trace calls */ OS_TraceEnableId(APP_TRACE_ID_SETSTATE); /* User trace */ OS_TraceEnableFilterId(0, APP_TRACE_ID_SETSTATE); /* User trace */ OS_TraceEnable(); #endif /* Application specific initialization */ SetState(&MainState, 1); OS_CREATETASK(&TCBMain, "MainTask", MainTask, PRIO_MAIN, MainStack); OS_Start(); /* Start multitasking -> MainTask() */ } By default, embOSView lists all user function traces in the trace list window as Routine, followed by the specified ID and two parameters as hexadecimal values. The example above would result in the following: Routine100(0xabcd, 0x01) where 0xabcd is the pointer address and 0x01 is the parameter recorded from OS_TraceDataPtr(). UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 367 22.12 User-defined functions To use the built-in trace (available in trace builds of embOS) for application program user functions, embOSView can be customized. This customization is done in the setup file embOS.ini. This setup file is parsed at the startup of embOSView. It is optional; you will not see an error message if it cannot be found. To enable trace setup for user functions, embOSView needs to know an ID number, the function name and the type of two optional parameters that can be traced. The format is explained in the following sample embOS.ini file: Example code # # # # # # # # # # File: embOS.ini embOSView Setup file embOSView loads this file at startup. It must reside in the same directory as the executable itself. Note: The file is not required to run embOSView. You will not get an error message if it is not found. However, you will get an error message if the contents of the file are invalid. # # Define add. API functions. # Syntax: API( , [parameters]) # Index: Integer, between 100 and 127 # Routinename: Identifier for the routine. Should be no more than 32 characters # parameters: Optional paramters. A max. of 2 parameters can be specified. # Valid parameters are: # int # ptr # Every parameter must be placed after a colon. # API( 100, "Routine100") API( 101, "Routine101", int) API( 102, "Routine102", int, ptr) UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 368 UM01001 User & Reference Guide for embOS CHAPTER 22 embOSView: Profiling and analyzing (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 369 Chapter 23 Performance and resource usage This chapter covers the performance and resource usage of embOS. It explains how to benchmark embOS and contains information about the memory requirements in typical systems which can be used to obtain sufficient estimates for most target systems. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 370 CHAPTER 23 Performance and resource usage 23.1 Introduction High performance combined with low resource usage has always been a major design consideration. embOS runs on 8/16/32-bit CPUs. Depending on which features are being used, even single-chip systems with less than 2 Kbytes ROM and 1 Kbyte RAM can be supported by embOS. The actual performance and resource usage depends on many factors (CPU, compiler, memory model, optimization, configuration, etc.). UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 371 23.2 Memory requirements The memory requirements of embOS (RAM and ROM) differs depending on the used features of the library. The following table shows the memory requirements for the different modules. Module Memory type Memory requirements embOS kernel ROM 1100 - 1600 bytes * embOS kernel RAM 18 - 50 bytes * Mailbox RAM 8 - 20 bytes * Semaphore RAM 2 bytes Resource semaphore RAM 8 bytes * Timer RAM 8 - 20 bytes * Event RAM 0 bytes Table 23.1: embOS memory requirements * These values are typical values for a 32 bit cpu and depends on CPU, compiler, and library model used. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 372 CHAPTER 23 Performance and resource usage 23.3 Performance The following section shows how to benchmark embOS with the supplied example programs. 23.4 Benchmarking embOS is designed to perform fast context switches. This section describes two different methods to calculate the execution time of a context switch from a task with lower priority to a task with a higher priority. The first method uses port pins and requires an oscilloscope. The second method uses the high-resolution measurement functions. Example programs for both methods are supplied in the \Sample directory of your embOS shipment. Segger uses these programs to benchmark the embOS performance. You can use these examples to evaluate the benchmark results. Note, that the actual performance depends on many factors (CPU, clock speed, toolchain, memory model, optimization, configuration, etc.). Please be aware that the amount of cycles are not equal to the amount of instructions. Many instructions on ARM7 need two or three cycles even at zero waitstates, e.g. LDR needs 3 cycles. The following table gives an overview about the variations of the context switch time depending on the memory type and the CPU mode: Target Memory CPU mode Time / Cycles ATMEL AT91SAM7S256 @ 48Mhz RAM ARM 4.09us / 196 ATMEL AT91SAM7S256 @ 48Mhz Flash ARM 6.406us / 307 ATMEL AT91SAM7S256 @ 48Mhz RAM Thumb 5.28us / 253 ATMEL AT91SAM7S256 @ 48Mhz Flash Thumb 6.823us / 327 NXP LPC3180 @ 208Mhz RAM ARM 0.948us / 197 Table 23.2: embOS context switch times All named example performance values in the following section are determined with the following system configuration: All sources are compiled with IAR Embedded Workbench version 5.40 using thumb or arm mode, XR library and high optimization level. embOS version 3.82 has been used; values may differ for different builds. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 373 23.4.1 Measurement with port pins and oscilloscope The example file MeasureCST_Scope.c uses the LED.c module to set and clear a port pin. This allows measuring the context switch time with an oscilloscope. The following source code is excerpt from MeasureCST_Scope.c: #include "RTOS.h" #include "LED.h" static OS_STACKPTR int StackHP[128], StackLP[128]; static OS_TASK TCBHP, TCBLP; // Task stacks // Task-control-blocks /********************************************************************* * * HPTask */ static void HPTask(void) { while (1) { OS_Suspend(NULL); // Suspend high priority task LED_ClrLED0(); // Stop measurement } } /********************************************************************* * * LPTask */ static void LPTask(void) { while (1) { OS_Delay(100); // Synchronize to tick to avoid jitter // // Display measurement overhead // LED_SetLED0(); LED_ClrLED0(); // // Perform measurement // LED_SetLED0(); // Start measurement OS_Resume(&TCBHP); // Resume high priority task to force task switch } } /********************************************************************* * * main */ int main(void) { OS_IncDI(); // Initially disable interrupts OS_InitKern(); // Initialize OS OS_InitHW(); // Initialize Hardware for OS LED_Init(); // Initialize LED ports OS_CREATETASK(&TCBHP, "HP Task", HPTask, 100, StackHP); OS_CREATETASK(&TCBLP, "LP Task", LPTask, 99, StackLP); OS_Start(); // Start multitasking return 0; } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 374 CHAPTER 23 Performance and resource usage 23.4.1.1 Oscilloscope analysis The context switch time is the time between switching the LED on and off. If the LED is switched on with an active high signal, the context switch time is the time between the rising and the falling edge of the signal. If the LED is switched on with an active low signal, the signal polarity is reversed. The real context switch time is shorter, because the signal also contains the overhead of switching the LED on and off. The time of this overhead is also displayed on the oscilloscope as a small peak right before the task switch time display and must be subtracted from the displayed context switch time. The picture below shows a simplified oscilloscope signal with an active-low LED signal (low means LED is illuminated). There are switching points to determine: * * * * A B C D = = = = LED LED LED LED is is is is switched switched switched switched on for overhead measurement off for overhead measurement on right before context switch in low-prio task off right after context switch in high-prio task The time needed to switch the LED on and off in subroutines is marked as time tAB. The time needed for a complete context switch including the time needed to switch the LED on and off in subroutines is marked as time tCD. The context switching time t CS is calculated as follows: t CS = tCD - tAB Voltage [V] A B C tAB UM01001 User & Reference Guide for embOS D tCD (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 375 23.4.1.2 Example measurements AT91SAM7S, ARM code in RAM Task switching time has been measured with the parameters listed below: embOS Version V3.82 Application program: MeasureCST_Scope.c Hardware: AT91SAM7SE512 processor with 48MHz Program is executing in RAM ARM mode is used Compiler used: IAR V5.40 CPU frequency (fCPU): 47.9232MHz CPU clock cycle (t Cycle): t Cycle = 1 / f CPU = 1 / 47.9232MHz = 20,866ns Measuring tAB and tCD tAB is measured as 312ns. The number of cycles calculates as follows: Cycles AB = t AB / tCycle =332ns / 20.866ns = 15.911Cycles => 16Cycles tCD is measured as 4420.0ns. The number of cycles calculates as follows: Cycles CD = t CD / t Cycle = 4420.0ns / 20.866ns = 211.83Cycles => 212Cycles Resulting context switching time and number of cycles The time which is required for the pure context switch is: t CS = tCD - tAB = 212Cycles - 16Cycles = 196Cycles => 196Cycles (4.09us @48MHz). UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 376 CHAPTER 23 Performance and resource usage 23.4.1.3 Example measurements AT91SAM7S, Thumb code in FLASH Task switching time has been measured with the parameters listed below: embOS Version V3.82 Application program: MeasureCST_Scope.c Hardware: AT91SAM7E512 processor with 48MHz Program is executing in FLASH Thumb mode is used Compiler used: IAR V5.40 CPU frequency (f CPU): 47.9232MHz CPU clock cycle (tCycle): t Cycle = 1 / f CPU = 1 / 47.9232MHz = 20,866ns Measuring tAB and tCD tAB is measured as 436.8ns. The number of cycles calculates as follows: Cycles AB = t AB / t Cycle =416.0ns / 20.866ns = 19.937Cycles => 20Cycles tCD is measured as 7250ns. The number of cycles calculates as follows: Cycles CD = t CD / t Cycle = 7250ns / 20.866ns = 347.46Cycles => 347Cycles Resulting context switching time and number of cycles The time which is required for the pure context switch is: t CS = tCD - tAB = 347Cycles - 20Cycles = 327Cycles => 327Cycles (6.83us @48MHz). UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 377 23.4.1.4 Measurement with high-resolution timer The context switch time may be measured with the high-resolution timer. Refer to section High-resolution measurement on page 283 for detailed information about the embOS high-resolution measurement. The example MeasureCST_HRTimer_embOSView.c uses a high resolution timer to measure the context switch time from a low priority task to a high priority task and displays the results on embOSView. #include "RTOS.h" #include "stdio.h" static OS_STACKPTR int StackHP[128], StackLP[128]; static OS_TASK TCBHP, TCBLP; static OS_U32 _Time; // Task stacks // Task-control-blocks // Timer values /********************************************************************* * * HPTask */ static void HPTask(void) { while (1) { OS_Suspend(NULL); // Suspend high priority task OS_Timing_End(&_Time); // Stop measurement } } /********************************************************************* * * LPTask */ static void LPTask(void) { char acBuffer[100]; // Output buffer OS_U32 MeasureOverhead; // Time for Measure Overhead OS_U32 v; // // Measure Overhead for time measurement so we can take // this into account by subtracting it // OS_Timing_Start(&MeasureOverhead); OS_Timing_End(&MeasureOverhead); // // Perform measurements in endless loop // while (1) { OS_Delay(100); // Sync. to tick to avoid jitter OS_Timing_Start(&_Time); // Start measurement OS_Resume(&TCBHP); // Resume high priority task to force task switch v = OS_Timing_GetCycles(&_Time) - OS_Timing_GetCycles(&MeasureOverhead); v = OS_ConvertCycles2us(1000 * v); // Convert cycles to nano-seconds sprintf(acBuffer, "Context switch time: %u.%.3u usec\r", v / 1000, v % 1000); OS_SendString(acBuffer); } } The example program calculates and subtracts the measurement overhead itself, so there is no need to do this. The results will be transmitted to embOSView, so the example runs on every target that supports UART communication to embOSView. The example program MeasureCST_HRTimer_Printf.c is equal to the example program MeasureCST_HRTimer_embOSView.c but displays the results with the printf() function for those debuggers which support terminal output emulation. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 378 UM01001 User & Reference Guide for embOS CHAPTER 23 Performance and resource usage (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 379 Chapter 24 Debugging UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 380 CHAPTER 24 Debugging 24.1 Runtime errors Some error conditions can be detected during runtime. These are: * * * * * Usage of uninitialized data structures Invalid pointers Unused resource that has not been used by this task before OS_LeaveRegion() called more often than OS_EnterRegion() Stack overflow (this feature is not available for some processors) Which runtime errors that can be detected depend on how much checking is performed. Unfortunately, additional checking costs memory and speed (it is not that significant, but there is a difference). If embOS detects a runtime error, it calls the following routine: void OS_Error(int ErrCode); This routine is shipped as source code as part of the module OS_Error.c. It simply disables further task switches and then, after re-enabling interrupts, loops forever as follows: Example /* Run time error reaction */ void OS_Error(int ErrCode) { OS_EnterRegion(); /* Avoid further task switches */ OS_DICnt =0; /* Allow interrupts so we can communicate */ OS_EI(); OS_Status = ErrCode; while (OS_Status); } If you are using embOSView, you can see the value and meaning of OS_Status in the system variable window. When using an emulator, you should set a breakpoint at the beginning of this routine or simply stop the program after a failure. The error code is passed to the function as parameter. You can modify the routine to accommodate your own hardware; this could mean that your target hardware sets an error-indicating LED or shows a little message on the display. Note: When modifying the OS_Error() routine, the first statement needs to be the disabling of scheduler via OS_EnterRegion(); the last statement needs to be the infinite loop. If you look at the OS_Error() routine, you will see that it is more complicated than necessary. The actual error code is assigned to the global variable OS_Status. The program then waits for this variable to be reset. Simply reset this variable to 0 using your in circuit-emulator, and you can easily step back to the program sequence causing the problem. Most of the time, looking at this part of the program will make the problem clear. 24.1.1 OS_DEBUG_LEVEL The define OS_DEBUG_LEVEL defines the embOS debug level. The default value is 1. With higher debug level more debug code is included. The debug level 2 checks if OS_RegionCnt overflows. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 381 24.2 List of error codes Value Define 100 OS_ERR_ISR_INDEX 101 OS_ERR_ISR_VECTOR 102 103 OS_ERR_ISR_PRIO OS_ERR_WRONG_STACK 104 OS_ERR_ISR_NO_HANDLER 105 OS_ERR_TLS_INIT 106 OS_ERR_MB_BUFFER_SIZE 116 OS_ERR_EXTEND_CONTEXT 117 OS_ERR_TIMESLICE 118 OS_ERR_INTERNAL 119 120 121 OS_ERR_IDLE_RETURNS OS_ERR_STACK OS_ERR_CSEMA_OVERFLOW 122 OS_ERR_POWER_OVER 123 OS_ERR_POWER_UNDER 124 OS_ERR_POWER_INDEX 125 126 OS_ERR_SYS_STACK OS_ERR_INT_STACK 128 OS_ERR_INV_TASK 129 OS_ERR_INV_TIMER 130 OS_ERR_INV_MAILBOX 132 OS_ERR_INV_CSEMA Explanation Index value out of bounds during interrupt controller initialization or interrupt installation. Default interrupt handler called, but interrupt vector not initialized. Wrong interrupt priority Wrong stack used before main() No interrupt handler was defined for this interrupt OS_TLS_Init() called multiple times for one task. (Port specific error message) The maximum buffer size of 64KB for one mailbox buffer is exceed by call of OS_CreateMB(). This limit exists on 8 and 16bit CPUs only. OS_ExtendTaskContext called multiple times from one task An illegal time slice value of zero was used when calling OS_CreateTask(), OS_CreateTaskEx() or OS_SetTimeSlice(). Since version 3.86f of embOS, a time slice of zero is legal (as described in chapter 4). The error is not generated when a task is created with a time slice value of zero. OS_ChangeTask called without RegionCnt set (or other internal error) Idle loop should not return Stack overflow or invalid stack. Counting semaphore overflow. Counter overflows when calling OS_POWER_UsageInc() Counter underflows when calling OS_POWER_UsageDec() Index to high, exceeds (OS_POWER_NUM_COUNTERS - 1) System stack overflow Interrupt stack overflow Task control block invalid, not initialized or overwritten. Timer control block invalid, not initialized or overwritten. Mailbox control block invalid, not initialized or overwritten. Control block for counting semaphore invalid, not initialized or overwritten. Table 24.1: Error code list UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 382 CHAPTER 24 Value 133 135 136 137 138 140 142 143 144 145 146 150 151 152 153 154 155 156 157 Define Debugging Explanation Control block for resource semaphore invalid, not initialized or overwritten. One of the following 1-byte mailbox functions has been used on a multibyte mailbox: OS_PutMail1() OS_ERR_MAILBOX_NOT1 OS_PutMailCond1() OS_GetMail1() OS_GetMailCond1(). OS_DeleteMB() was called on a mailOS_ERR_MAILBOX_DELETE box with waiting tasks. OS_DeleteCSema() was called on a OS_ERR_CSEMA_DELETE counting semaphore with waiting tasks. OS_DeleteRSema() was called on a OS_ERR_RSEMA_DELETE resource semaphore which is claimed by a task. The mailbox is not in the list of mailboxes as expected. Possible reasons OS_ERR_MAILBOX_NOT_IN_LIST may be that one mailbox data structure was overwritten. The OS internal task list is OS_ERR_TASKLIST_CORRUPT destroyed. OS_ERR_QUEUE_INUSE Queue in use OS_ERR_QUEUE_NOT_INUSE Queue not in use OS_ERR_QUEUE_INVALID Queue invalid A queue was deleted by a call of OS_ERR_QUEUE_DELETE OS_Q_Delete() while tasks are waiting at the queue. OS_Unuse() has been called before OS_ERR_UNUSE_BEFORE_USE OS_Use(). OS_ERR_LEAVEREGION_BEFORE_ENTERR OS_LeaveRegion() has been called EGION before OS_EnterRegion(). OS_ERR_LEAVEINT Error in OS_LeaveInterrupt(). The interrupt disable counter (OS_DICnt) is out of range (0-15). The counter is affected by the following API calls: OS_ERR_DICNT OS_IncDI() OS_DecRI() OS_EnterInterrupt() OS_LeaveInterrupt() OS_Delay() or OS_DelayUntil() OS_ERR_INTERRUPT_DISABLED called from inside a critical region with interrupts disabled. OS_ERR_TASK_ENDS_WITHOUT_TERMINA Task routine returns without TE 0S_TerminateTask() OS_Unuse() has been called from a OS_ERR_RESOURCE_OWNER task which does not own the resource. OS_ERR_REGIONCNT The Region counter overflows (>255) OS_ERR_INV_RSEMA Table 24.1: Error code list (Continued) UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 383 Value Define 160 OS_ERR_ILLEGAL_IN_ISR 161 OS_ERR_ILLEGAL_IN_TIMER 162 OS_ERR_ILLEGAL_OUT_ISR 163 OS_ERR_NOT_IN_ISR 164 OS_ERR_IN_ISR 165 OS_ERR_INIT_NOT_CALLED 166 OS_ERR_CPU_STATE_ISR_ILLEGAL 167 OS_ERR_CPU_STATE_ILLEGAL 168 OS_ERR_CPU_STATE_UNKNOWN 170 OS_ERR_2USE_TASK 171 OS_ERR_2USE_TIMER 172 OS_ERR_2USE_MAILBOX 174 OS_ERR_2USE_CSEMA 175 OS_ERR_2USE_RSEMA 176 OS_ERR_2USE_MEMF 180 OS_ERR_NESTED_RX_INT 190 OS_ERR_MEMF_INV 191 OS_ERR_MEMF_INV_PTR 192 OS_ERR_MEMF_PTR_FREE Explanation Illegal function call in an interrupt service routine: A routine that must not be called from within an ISR has been called from within an ISR. Illegal function call in an interrupt service routine: A routine that must not be called from within a software timer has been called from within a timer. embOS timer tick handler or UART handler for embOSView was called without a call of OS_EnterInterrupt(). OS_EnterInterrupt() has been called, but CPU is not in ISR state OS_EnterInterrupt() has not been called, but CPU is in ISR stat OS_InitKern() was not called OS-function called from ISR with high priority CPU runs in illegal mode CPU runs in unknown mode or mode could not be read Task control block has been initialized by calling a create function twice. Timer control block has been initialized by calling a create function twice. Mailbox control block has been initialized by calling a create function twice. Counting semaphore has been initialized by calling a create function twice. Resource semaphore has been initialized by calling a create function twice. Fixed size memory pool has been initialized by calling a create function twice. OS_Rx interrupt handler for embOSView is nested. Disable nestable interrupts. Fixed size memory block control structure not created before use. Pointer to memory block does not belong to memory pool on Release Pointer to memory block is already free when calling OS_MEMF_Release(). Possibly, same pointer was released twice. Table 24.1: Error code list (Continued) UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 384 CHAPTER 24 Value Define Debugging Explanation 193 OS_ERR_MEMF_RELEASE 194 OS_ERR_POOLADDR 195 OS_ERR_BLOCKSIZE 200 OS_ERR_SUSPEND_TOO_OFTEN 201 OS_ERR_RESUME_BEFORE_SUSPEND 202 OS_ERR_TASK_PRIORITY 203 OS_ERR_TASK_PRIORITY_INVALID 210 OS_ERR_EVENT_INVALID 211 OS_ERR_2USE_EVENTOBJ 212 OS_ERR_EVENT_DELETE 223 224 OS_ERR_TICKHOOK_INVALID OS_ERR_TICKHOOK_FUNC_INVALID 230 OS_ERR_NON_ALIGNED_INVALIDATE 235 OS_ERR_NON_TIMERCYCLES_FUNC 236 OS_ERR_NON_TIMERINTPENDING_FUNC 254 OS_ERR_TRIAL_LIMIT OS_MEMF_Release() was called for a memory pool, that had no memory block allocated (all available blocks were already free before). OS_MEMF_Create() was called with a memory pool base address which is not located at a word aligned base address OS_MEMF_Create() was called with a data block size which is not a multiple of processors word size. Nested call of OS_Suspend() exceeded OS_MAX_SUSPEND_CNT OS_Resume() called on a task that was not suspended. OS_CreateTask() was called with a task priority which is already assigned to another task. This error can only occur when embOS was compiled without round robin support. The value 0 was used as task priority. An OS_EVENT object was used before it was created. An OS_EVENT object was created twice. This error should not be reported. Contact Segger support. An OS_EVENT object was deleted with waiting tasks Invalid tick hook. Invalid tick hook function Cache invalidation needs to be cache line aligned Callback function for timer counter value has not been set. Required by OS_GetTime_us(). Callback function for timer interrupt pending flag has not been set. Required by OS_GetTime_us(). Trial time limit reached Table 24.1: Error code list (Continued) The latest version of the defined error table is part of the comment just before the OS_Error() function declaration in the source file OS_Error.c. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 385 24.3 Application defined error codes The embOS error codes begin at 100. The range 1 - 99 can be used for application defined error codes. With it you can call OS_Error() with you own defined error code from your application. Example #define OS_ERR_APPL 0x02 void UserAppFunc(void) { int r; r = DoSomething() if (r == 0) { OS_Error(OS_ERR_APPL) } } UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 386 UM01001 User & Reference Guide for embOS CHAPTER 24 Debugging (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 387 Chapter 25 Supported development tools UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 388 CHAPTER 25 Supported development tools 25.1 Overview embOS has been developed with and for a specific C compiler version for the selected target processor. Check the file RELEASE.HTML for details. It works with the specified C compiler only, because other compilers may use different calling conventions (incompatible object file formats) and therefore might be incompatible. However, if you prefer to use a different C compiler, contact us and we will do our best to satisfy your needs in the shortest possible time. Reentrance All routines that can be used from different tasks at the same time must be fully reentrant. A routine is in use from the moment it is called until it returns or the task that has called it is terminated. All routines supplied with your real-time operating system are fully reentrant. If for some reason you need to have non-reentrant routines in your program that can be used from more than one task, it is recommended to use a resource semaphore to avoid this kind of problem. C routines and reentrance Normally, the C compiler generates code that is fully reentrant. However, the compiler may have options that force it to generate non-reentrant code. It is recommended not to use these options, although it is possible to do so under certain circumstances. Assembly routines and reentrance As long as assembly functions access local variables and parameters only, they are fully reentrant. Everything else needs to be thought about carefully. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 389 Chapter 26 Limitations UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 390 CHAPTER 26 Limitations The following limitations exist for embOS: Max. no. of tasks: Max. no. of priorities: Max. no. of semaphores: Max. no. of mailboxes: Max. no. of queues: Max. size. of queues: Max. no. of timers Task-specific event flags: limited by available RAM only 255 limited by available RAM only limited by available RAM only limited by available RAM only limited by available RAM only limited by available RAM only 8 bits / task (32 bits on 32 bit CPU) We appreciate your feedback regarding possible additional functions and we will do our best to implement these functions if they fit into the concept. Do not hesitate to contact us. If you need to make changes to embOS, the full source code is available. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 391 Chapter 27 Source code of kernel and library UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 392 CHAPTER 27 Source code of kernel and library 27.1 Introduction embOS is available in two versions: 1. 2. Object version: Object code + hardware initialization source. Full source version: Complete source code. Because this document describes the object version, the internal data structures are not explained in detail. The object version offers the full functionality of embOS including all supported memory models of the compiler, the debug libraries as described and the source code for idle task and hardware initialization. However, the object version does not allow source-level debugging of the library routines and the kernel. The full source version gives you the ultimate options: embOS can be recompiled for different data sizes; different compile options give you full control of the generated code, making it possible to optimize the system for versatility or minimum memory requirements. You can debug the entire system and even modify it for new memory models or other CPUs. The source code distribution of embOS contains the following additional files: * * The CPU folder contains all CPU and compiler specific source code and header files used for building the embOS libraries. It also contains the sample start project, workspace, and source files for the embOS demo project delivered in the Start folder. Normally, you should not modify any of the files in the CPU folder. The GenOSSrc folder contains all embOS sources and a batch file used for compiling all of them in batch mode as described in the following section. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 393 27.2 Building embOS libraries The embOS libraries can only be built if you have purchased a source code version of embOS. In the root path of embOS, you will find a DOS batch file PREP.BAT, which needs to be modified to match the installation directory of your C compiler. Once this is done, you can call the batch file M.BAT to build all embOS libraries for your CPU. Note: Rebuilding the embOS libraries using the M.bat file will delete and rebuild the entire Start folder. If you made any modifications or built own projects in the Start folder, make a copy of your start folder before rebuilding embOS. The build process should run without any error or warning message. If the build process reports any problem, check the following: * * * Are you using the same compiler version as mentioned in the file RELEASE.HTML? Can you compile a simple test file after running PREP.BAT and does it really use the compiler version you have specified? Is there anything mentioned about possible compiler warnings in the RELEASE.HTML? If you still have a problem, let us know. The whole build process is controlled with a few amount of batch files which are located in the root directory of your source code distribution: * * * * * * * * Prep.bat: Sets up the environment for the compiler, assembler, and linker. Ensure, that this file sets the path and additional include directories which are needed for your compiler. Normally, this batch file is the only one which might need to be modified to build the embOS libraries. Normally, this file is called from M.bat during the build process of all libraries. Clean.bat: Deletes the whole output of the embOS library build process. It is called automatically during the build process, before new libraries are generated. Normally it deletes the Start folder. Therefore, be careful not to call this batch file accidentally. Normally, this file is called initially by M.bat during the build process of all libraries. cc.bat: This batch file calls the compiler and is used for compiling one embOS source file without debug information output. Most compiler options are defined in this file and should normally not be modified. For your purposes, you might activate debug output and may also modify the optimization level. All modifications should be done with care. Normally, this file is called from the embOS internal batch file CC_OS.bat and cannot be called directly. ccd.bat: This batch file calls the compiler and is used for compiling OS_Global.c which contains all global variables. All compiler settings are equal to those used in cc.bat, except debug output is activated to enable debugging of global variables when using embOS libraries. Normally, this file is called from the embOS internal batch file CC_OS.bat and cannot be called directly. asm.bat: This batch file calls the assembler and is used for assembling the assembly part of embOS which normally contains the task switch functionality. Normally this file is called from the embOS internal batch file CC_OS.bat and cannot be called directly. MakeH.bat: Builds the embOS header file RTOS.h which is composed from the CPU/compiler-specific part OS_Chip.h and the generic part OS_RAW.h. Normally, RTOS.h is output in the subfolder Start\Inc. M1.bat: This batch file is called from M.bat and is used for building one specific embOS library, it cannot be called directly. M.bat: This batch file must be called to generate all embOS libraries. It initially calls Clean.bat and therefore deletes the whole Start folder. The generated libraries are then placed in a new Start folder which contains start projects, libraries, header, and sample start programs. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 394 CHAPTER 27 Source code of kernel and library 27.3 Major compile time switches Many features of embOS may be modified by compile-time switches. All of them are predefined to reasonable values in the distribution of embOS. The compile-time switches must not be changed in RTOS.h. When the compile-time switches should be modified to alter any of the embOS features, the modification must be done in OS_RAW.h or must be passed as parameters during the library build process. embOS sources must be recompiled and RTOS.h must be rebuilt with the modified switches. 27.3.1 OS_RR_SUPPORTED This switch defines whether round robin scheduling algorithm is supported. All embOS versions enable round robin scheduling by default. If you never use round robin scheduling and all of your tasks run on different individual priorities, you may disable round robin scheduling by defining this switch to 0. This will save RAM and ROM and will also speed up the task-switching process. Ensure that none of your tasks ever run on the same priority when you disable round robin scheduling. This compile time switch must not be modified in RTOS.h. It must be modified in OS_RAW.h before embOS libraries are rebuilt. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 395 Chapter 28 FAQ (frequently asked questions) UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 396 CHAPTER 28 FAQ (frequently asked questions) Q: A: Can I implement different priority scheduling algorithms? Yes, the system is fully dynamic, which means that task priorities can be changed while the system is running (using OS_SetPriority()). This feature can be used for changing priorities in a way so that basically every desired algorithm can be implemented. One way would be to have a task control task with a priority higher than that of all other tasks that dynamically changes priorities. Normally, the priority-controlled round-robin algorithm is perfect for real-time applications. Q: A: Can I use a different interrupt source for embOS? Yes, any periodic signal can be used, that is any internal timer, but it could also be an external signal. Q: A: What interrupt priorities can I use for the interrupts my program uses? Any. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 397 Chapter 29 Support This chapter should help if any problem occurs. This could be a problem with the tool chain, with the hardware or the use of the embOS functions and it describes how to contact the embOS support. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 398 CHAPTER 29 Support 29.1 Contacting support If you are a registered embOS user and you need to contact the embOS support please send the following information via email to support_embos@segger.com: * * * * * * Which embOS do you use? (CPU, compiler). The embOS version. Your embOS registration number. If you are unsure about the above information you can also use the name of the embOS zip file (which contains the above information). A detailed description of the problem. Optionally a project with which we can reproduce the problem. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 399 Chapter 30 Glossary UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 400 CHAPTER 30 Glossary Cooperative multitasking A scheduling system in which each task is allowed to run until it gives up the CPU; an ISR can make a higher priority task ready, but the interrupted task will be returned to and finished first. Counting semaphore A type of semaphore that keeps track of multiple resources. Used when a task must wait for something that can be signaled more than once. CPU Central Processing Unit. The "brain" of a microcontroller; the part of a processor that carries out instructions. Critical region A section of code which must be executed without interruption. Event A message sent to a single, specified task that something has occurred. The task then becomes ready. Interrupt Handler Interrupt Service Routine. The routine is called automatically by the processor when an interrupt is acknowledged. ISRs must preserve the entire context of a task (all registers). ISR Interrupt Service Routine. The routine is called automatically by the processor when an interrupt is acknowledged. ISRs must preserve the entire context of a task (all registers). Mailbox A data buffer managed by the RTOS, used for sending messages to a task or interrupt handler. Message An item of data (sent to a mailbox, queue, or other container for data). Multitasking The execution of multiple software routines independently of one another. The OS divides the processor's time so that the different routines (tasks) appear to be happening simultaneously. NMI Non-Maskable Interrupt. An interrupt that cannot be masked (disabled) by software. Example: Watchdog timer-interrupt. Preemptive multitasking A scheduling system in which the highest priority task that is ready will always be executed. If an ISR makes a higher priority task ready, that task will be executed before the interrupted task is returned to. Process Processes are tasks with their own memory layout. 2 processes cannot normally access the same memory locations. Different processes typically have different access rights and (in case of MMUs) different translation tables. Processor Short for microprocessor. The CPU core of a controller UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 401 Priority Priority inversion The relative importance of one task to another. Every task in an RTOS has a priority. A situation in which a high priority task is delayed while it waits for access to a shared resource which is in use by a lower priority task. A task with medium priority in the ready state may run, instead of the high priority task. embOS avoids this situation by priority inheritance. Queue Like a mailbox, but used for sending larger messages, or messages of individual size, to a task or an interrupt handler. Ready Any task that is in "ready state" will be activated when no other task with higher priority is in "ready state". Resource Anything in the computer system with limited availability (for example memory, timers, computation time). Essentially, anything used by a task. Resource semaphore A type of semaphore used for managing resources by ensuring that only one task has access to a resource at a time. RTOS Real-time Operating System. Running task Only one task can execute at any given time. The task that is currently executing is called the running task. Scheduler The program section of an RTOS that selects the active task, based on which tasks are ready to run, their relative priorities, and the scheduling system being used. Semaphore A data structure used for synchronizing tasks. Software timer A data structure which calls a user-specified routine after a specified delay. Stack An area of memory with LIFO storage of parameters, automatic variables, return addresses, and other information that needs to be maintained across function calls. In multitasking systems, each task normally has its own stack. Superloop A program that runs in an infinite loop and uses no real-time kernel. ISRs are used for real-time parts of the software. Task A program running on a processor. A multitasking system allows multiple tasks to execute independently from one another. Thread Threads are tasks which share the same memory layout. 2 threads can access the same memory locations. If virtual memory is used, the same virtual to physical translation and access rights are used (-> Thread, Process) UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 402 CHAPTER 30 Glossary Tick The OS timer interrupt. Usually equals 1 ms. Time slice The time (number of ticks) for which a task will be executed until a round-robin task change may occur. UM01001 User & Reference Guide for embOS (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 403 Index B Baudrate for embOSView .................... 324 C C startup ............................................37 Compiler .......................................... 388 Configuration defines ......................... 323 Configuration, of embOS .......301, 319-327 Counting Semaphores ........................ 125 Critical regions ......................30, 271-275 D Debug build, of embOS .........................38 Debugging ................................. 379-384 error codes ..............................381, 385 runtime errors ................................ 380 Development tools ............................. 387 E embOS building libraries of .......................... 393 different builds of ..............................38 features of .......................................21 embOS features ..................................21 embOS profiling ..................................38 embOSView ............................... 339-367 API trace ........................................ 347 overview ........................................ 340 SIO ............................................... 343 system variables window .................. 342 task list window .............................. 341 trace filter setup functions ................ 349 trace record functions ...................... 359 Error codes ................................381, 385 Events ................... 33, 177-187, 189-206 I Internal data-structures ...................... 300 Interrupt control macros ..................... 261 Interrupt level .....................................25 Interrupt service routines ..............25, 245 UM01001 User & Reference Guide for embOS Interrupts ..................................245-270 enabling/disabling ............................258 interrupt handler .............................252 ISR ..................................................245 L Libraries, building ..............................393 Limitations, of embOS ........................389 M Mailboxes ............................. 33, 139-158 basics ............................................141 single-byte .....................................143 Measurement ....................................279 high-resolution ................................283 low-resolution .................................279 Memory management fixed block size ................................213 heap memory ..................................207 Memory pools .............................213-227 Multitasking systems ........................... 27 cooperative multitasking .................... 29 preemptives multitasking ................... 28 N Nesting interrupts ..............................262 Non-maskable interrupts ............. 266, 270 O OS_AddLoadMeasurement() ................332 OS_AddOnTerminateHook() .................. 50 OS_AdjustTime() ...............................315 OS_BAUDRATE ..................................323 OS_CallISR() .....................................254 OS_CallNestableISR() .........................255 OS_ClearEvents() ..............................187 OS_ClearMB() ...................................156 OS_COM_Init() ..................................321 OS_COM_Send1() ..............................321 OS_ConvertCycles2us() ......................321 OS_CPU_Load ...................................334 OS_CREATECSEMA() ..........................128 (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 404 OS_CreateCSema() ........................... 129 OS_CREATEMB() ............................... 145 OS_CREATERSEMA() .......................... 115 OS_CREATETASK() .............................. 51 OS_CreateTask() ................................. 53 OS_CREATETASK_EX() ......................... 55 OS_CreateTaskEx() .............................. 57 OS_CREATETIMER() ............................. 88 OS_CreateTimer() ............................... 89 OS_CREATETIMER_EX() ....................... 99 OS_CreateTimerEx() .......................... 100 OS_CSemaRequest() ......................... 134 OS_DecRI() ...................................... 259 OS_Delay() ........................................ 58 OS_DelayUntil() .................................. 59 OS_Delayus() ..................................... 60 OS_DeleteCSema() ........................... 137 OS_DeleteMB() ................................. 158 OS_DeleteTimer() ............................... 94 OS_DeleteTimerEx() .......................... 105 OS_DI() ........................................... 260 OS_EI() ........................................... 260 OS_EnterInterrupt() .......................... 256 OS_EnterNestableInterrupt() .............. 263 OS_EnterRegion() ............................. 274 OS_EVENT_Create() .......................... 192 OS_EVENT_CreateEx() ....................... 193 OS_EVENT_Delete() .......................... 201 OS_EVENT_Get() .............................. 200 OS_EVENT_GetResetMode() ............... 203 OS_EVENT_Pulse() ............................ 199 OS_EVENT_Reset() ............................ 198 OS_EVENT_RESET_MODE_AUTO .. 193, 202 OS_EVENT_RESET_MODE_MANUAL 193, 202 OS_EVENT_RESET_MODE_SEMIAUTO . 193, 202 OS_EVENT_Set() ............................... 197 OS_EVENT_SetResetMode() ................ 202 OS_EVENT_Wait() ............................. 194 OS_EVENT_WaitTimed() ..................... 195 OS_ExtendTaskContext() ...................... 61 OS_free() ......................................... 209 OS_FSYS .......................................... 323 OS_GetCSemaValue() ........................ 135 OS_GetEventsOccurred() .................... 186 OS_GetIntStackBase() ....................... 241 OS_GetIntStackSize() ........................ 242 OS_GetIntStackSpace() ..................... 243 OS_GetIntStackUsed() ....................... 244 OS_GetLoadMeasurement() ................ 333 OS_GetMail() .................................... 150 OS_GetMail1() .................................. 150 OS_GetMailCond() ............................. 151 OS_GetMailCond1() ........................... 151 OS_GetMailTimed() ........................... 152 OS_GetMessageCnt() ......................... 157 OS_GetNumIdleTicks() ....................... 314 OS_GetpCurrentTask() ......................... 64 OS_GetpCurrentTimer() ....................... 98 OS_GetpCurrentTimerEx() .................. 109 OS_GetPriority() ................................. 65 OS_GetResourceOwner() .................... 122 OS_GetSemaValue() .......................... 121 OS_GetStackBase() ........................... 233 OS_GetStackSize() ............................ 234 OS_GetStackSpace() ......................... 235 OS_GetStackUsed() ........................... 236 UM01001 User & Reference Guide for embOS Index OS_GetSysStackBase() ...................... 237 OS_GetSysStackSize() ....................... 238 OS_GetSysStackSpace() ..................... 239 OS_GetSysStackUsed() ...................... 240 OS_GetTaskID() .................................. 67 OS_GetTaskName() ............................. 68 OS_GetTime() ................................... 281 OS_GetTime_Cycles() ........................ 321 OS_GetTime32() ............................... 282 OS_GetTimerPeriod() ........................... 95 OS_GetTimerPeriodEx() ...................... 106 OS_GetTimerStatus() ........................... 97 OS_GetTimerStatusEx() ..................... 108 OS_GetTimerValue() ............................ 96 OS_GetTimerValueEx() ....................... 107 OS_GetTimeSliceRem() ........................ 69 OS_Global.Time ................................ 299 OS_Global.TimeDex ........................... 299 OS_Idle() .................................. 321, 326 OS_IncDI() ....................................... 259 OS_InInterrupt() ............................... 265 OS_InitHW() ..................................... 321 OS_INTERRUPT_MaskGlobal() ............. 267 OS_INTERRUPT_PreserveAndMaskGlobal() . 269 OS_INTERRUPT_PreserveGlobal() ........ 268 OS_INTERRUPT_RestoreGlobal() .......... 269 OS_INTERRUPT_UnmaskGlobal() ......... 267 OS_ISR_rx() ..................................... 321 OS_ISR_tx() ..................................... 321 OS_IsRunning() .................................. 70 OS_IsTask() ........................................ 71 OS_LeaveInterrupt() .......................... 257 OS_LeaveNestableInterrupt() .............. 264 OS_LeaveRegion() ............................. 275 OS_malloc() ..................................... 209 OS_MEMF_Alloc() .............................. 218 OS_MEMF_AllocTimed() ...................... 219 OS_MEMF_Create() ............................ 216 OS_MEMF_Delete() ............................ 217 OS_MEMF_FreeBlock() ....................... 222 OS_MEMF_GetBlockSize() ................... 224 OS_MEMF_GetMaxUsed() ................... 226 OS_MEMF_GetNumBlocks() ................. 223 OS_MEMF_GetNumFreeBlocks() ........... 225 OS_MEMF_IsInPool() ......................... 227 OS_MEMF_Release() .......................... 221 OS_MEMF_Request() .......................... 220 OS_ON_TERMINATE_FUNC .................... 50 OS_PeekMail() .................................. 155 OS_PutMail() .................................... 146 OS_PutMail1() ................................... 146 OS_PutMailCond() ............................. 147 OS_PutMailCond1() ............................ 147 OS_PutMailFront() ............................. 148 OS_PutMailFront1() ........................... 148 OS_PutMailFrontCond() ...................... 149 OS_PutMailFrontCond1() .................... 149 OS_Q_Clear() ................................... 171 OS_Q_Create() ................................. 163 OS_Q_Delete() .................................. 173 OS_Q_GetMessageCnt() ..................... 172 OS_Q_GetPtr() ........................... 167, 175 OS_Q_GetPtrCond() ........................... 168 OS_Q_GetPtrTimed() ......................... 169 OS_Q_IsInUse() ................................ 174 OS_Q_Purge() ................................... 170 (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG Index OS_Q_Put() ...............................164, 335 OS_Q_PutTimed() .............................. 166 OS_realloc() ..................................... 209 OS_Request() ................................... 120 OS_RestoreI() ................................... 260 OS_Resume() ......................................72 OS_ResumeAllSuspendedTasks() ...........73 OS_RetriggerTimer() ............................92 OS_RetriggerTimerEx() ...................... 103 OS_SendString() ............................... 345 OS_SetCSemaValue() ......................... 136 OS_SetInitialSuspendCnt() ...................74 OS_SetPriority() ..................................75 OS_SetRxCallback() ........................... 346 OS_SetTaskName() ..............................76 OS_SetTimerPeriod() ...........................93 OS_SetTimerPeriodEx() ...................... 104 OS_SetTimeSlice() ...............................77 OS_SignalCSema() ............................ 130 OS_SignalCSemaMax() ....................... 131 OS_SignalEvent() .............................. 184 OS_Start() ..........................................78 OS_StartTimer() ..................................90 OS_StartTimerEx() ............................ 101 OS_STAT_GetLoad() .......................... 330 OS_STAT_Sample() ............................ 329 OS_StopTimer() ..................................91 OS_StopTimerEx() ............................. 102 OS_Suspend() .....................................79 OS_SuspendAllTasks() ..........................80 OS_TASK_EVENT ............................... 178 OS_TerminateTask() .............................81 OS_TICK_AddHook() .......................... 309 OS_TICK_Config() ............................. 307 OS_TICK_Handle() ............................ 304 OS_TICK_HandleEx() ......................... 305 OS_TICK_HandleNoHook() .................. 306 OS_TICK_RemoveHook() .................... 310 OS_Timing_End() .............................. 286 OS_Timing_GetCycles() ...................... 288 OS_Timing_Getus() ........................... 287 OS_Timing_Start() ............................. 285 OS_TraceData() ................................. 363 OS_TraceDataPtr() ............................. 364 OS_TraceDisable() ............................. 352 OS_TraceDisableAll() .......................... 354 OS_TraceDisableFilterId() ................... 358 OS_TraceDisableId() .......................... 356 OS_TraceEnable() .............................. 351 OS_TraceEnableAll() ........................... 353 OS_TraceEnableFilterId() .................... 357 OS_TraceEnableId() ........................... 355 OS_TracePtr() ................................... 362 OS_TraceU32Ptr() .............................. 365 OS_TraceVoid() ................................. 361 OS_UART .......................................... 323 OS_Unuse() ...................................... 119 OS_Use() ......................................... 116 OS_UseTimed() ................................. 118 OS_WaitCSema() ............................... 132 OS_WaitCSemaTimed() ...................... 133 OS_WaitEvent() ................................. 180 OS_WaitEventTimed() ........................ 182 OS_WaitMail() ................................... 153 OS_WaitMailTimed() .......................... 154 OS_WaitSingleEvent() ........................ 181 OS_WaitSingleEventTimed() ................ 183 UM01001 User & Reference Guide for embOS 405 OS_WakeTask() .................................. 82 P Preemptive multitasking ....................... Priority .............................................. Priority inheritance .............................. priority inversion ................................. Profiling ............................................. 28 30 31 31 38 Q Queues ................................ 33, 159-174 R Reentrance ........................................388 Release build, of embOS ...................... 38 Resource semaphores .........................111 Round-robin ....................................... 30 RTOSInit.c configuration .....................320 Runtime errors ..................................380 S Scheduler .......................................... 30 Semaphores ....................................... 33 Counting .................................125-137 Resource .................................111-123 Software timer .............................. 85-98 Software timer API functions ................ 87 Stack .................................. 34, 229-244 Stack pointer ...................................... 34 Stacks switching ......................................... 35 Superloop .......................................... 25 Switching stacks ................................. 35 Syntax, conventions used ....................... 9 System variables ........................297-300 T Task communication ............................ 33 Task control block .......................... 34, 44 Task routines ??- ................................. 83 Tasks .......................................24, 42-43 communication ................................. 33 global variables ................................ 33 multitasking systems ........................ 27 periodic polling ................................. 33 single-task systems .......................... 25 status ............................................. 36 superloop ........................................ 25 switching ......................................... 34 TCB ................................................... 34 Time measurement .....................277-291 Time variables ...................................299 U UART ................................................340 UART, for embOS ...............................324 V Vector table file .................................324 (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG 406 UM01001 User & Reference Guide for embOS Index (c) 1995 - 2015 SEGGER Microcontroller GmbH & Co. KG