embOS & embOS-MPU Real-Time Operating System User Guide & Reference Manual Document: UM01001 Software Version: 5.02 Revision: 0 Date: June 26, 2018 A product of SEGGER Microcontroller GmbH www.segger.com 2 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 (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-2018 SEGGER Microcontroller GmbH, 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 In den Weiden 11 D-40721 Hilden Germany Tel. Fax. E-mail: Internet: +49 2103-2878-0 +49 2103-2878-28 support@segger.com www.segger.com UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 3 Manual versions This manual describes the current software version. If you find an error in the manual or a problem in the software, please inform us and we will try to assist you as soon as possible. Contact us for further information on topics or functions that are not yet documented. Print date: June 26, 2018 Software Revision Date By Description 5.02 0 180626 TS New API function OS_STAT_AddLoadMeasurementEx(). Minor spelling & wording corrections. 5.00 1 180524 TS OS_TASK_Delay() parameter description corrected. TimeOut parameter description added where necessary. 5.00 0 180508 TS New API names. Chapter "Debugging" updated. Minor spelling & wording corrections. 4.40 0 171220 MC Introductory description in chapter "Software timers" expanded. Description of limitations in chapter "Mailboxes" corrected. Description of limitations in chapter "Queues" added. Description of embOS trial edition in chapter "Shipment" updated. Decription of OS_WD_Config() updated for change in parameters. List of error codes in chapter "Debugging" updated. Minor spelling & wording corrections. 4.38 1 170928 MC Minor spelling & wording corrections. TS First version generated with emDoc. New function in chapter "Tasks" added: * OS_SetDefaultTaskStartHook() New functions in chapter "Debugging" added: * OS_SetObjName() * OS_GetObjName() Minor corrections/updates. 4.38 0 170919 4.36 0 170711 TS New library mode OS_LIBMODE_SAFE added in chapter "Basic Concepts". New functions in chapter "Stacks" added: * OS_GetStackCheckLimit() * OS_SetStackCheckLimit() New functions in chapter "MPU" added: * OS_MPU_AddSanityCheckBuffer() * OS_MPU_SanityCheck() Chapter "Source Code" updated. New functions in chapter "Task Routines" added: * OS_Config_Stop() * OS_Stop() Minor corrections/updates 4.34 0 170308 TS New functions in chapter "Event Objects" added: * OS_EVENT_GetMaskMode() * OS_EVENT_SetMaskMode() RH/TS Chapter "Watchdog" added. New functions in chapter "Event Objects" added: * OS_EVENT_GetMask() * OS_EVENT_SetMask() * OS_EVENT_WaitMask() * OS_EVENT_WaitMaskTimed() New functions in chapter "Mailboxes" added: * OS_PutMailTimed() * OS_PutMailTimed1() Chapter "Basic Concepts", "Time Measurement", "MPU", "Profiling" and "Updates" updated. Chapters, "System Tick", "Low Power Support", "Configuration (BSP)" updated and re-structured. Chapter "Resource Semaphores" updated. 4.32 0 170105 4.30 0 161130 MC/TS 4.26 0 160907 RH Chapter "embOSView", "Interrupts" and "MPU" updated. Minor corrections/updates. 4.24 0 160628 MC Chapter "Multi-core Support" added. Chapter "Debugging" updated. 4.22 0 160525 MC New functions in chapter "Queues" added: * OS_Q_PutEx() * OS_Q_PutBlockedEx() UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 4 Software Revision Date By Description * OS_Q_PutTimedEx() 4.20 0 160421 TS Chapter "MPU - Memory Protection" added. OS_AddExtendTaskContext() added. 4.16 0 160210 TS Minor corrections/updates 4.14a 0 160115 TS Minor corrections/updates 4.14 0 151029 TS Chapter "Interrupts" updated. Description of new API function OS_SetDefaultTaskContextExtension() added. Chapter "System Variables": embOS info routines added. Chapter "Shipment" updated. Chapter "Low Power Support" updated. Chapter "Interrupts": Description of * OS_INT_PRIO_PRESERVE() and * OS_INT_PRIO_RESTORE() added. Chapter "Software Timerss": Description of * OS_TriggerTimer() and * OS_TriggerTimerEx() added. 4.12b 0 150922 TS Update to latest software version. 4.12a 0 150916 TS Description of API function OS_InInterrupt() added. 4.12 0 150715 TS New funtions in chapter "Mailboxes" added: * OS_Mail_GetPtr() * OS_Mail_getPtrCond() * OS_Mail_Purge() Chapter "Debugging" with new error codes updated. 4.10b 1 150703 MC Minor spelling and wording corrections. 4.10b 0 150527 TS Minor spelling and wording corrections. Chapter "Source Code of Kernel and Library" updated. New chapter "embOS Shipment". New chapter "Update". New chapter "Low Power Support". 4.10a 0 150519 MC Minow spelling and wording corrections. Chapter "embOSView": added JTAG Chain configuration. 4.10 0 150430 TS Chapter "embOSView" updated. 4.06b 0 150324 MC Minow spelling and wording corrections. 4.06a 0 150318 MC Minow spelling and wording corrections. 4.06 0 150312 TS Updated to latest software version. 4.04a 0 141201 TS Updated 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. 4.02 0 140818 TS New functions in chapter "Time Measurement" added: * OS_Config_SysTimer() * OS_GetTime_us() * OS_GetTime_us64() 4.00a 0 140723 TS New functions added in chapter "System Tick": * OS_StopTicklesMode() New functions added in chapter "Profiling": * OS_STAT_Start() * OS_STAT_Stop() * OS_STAT_GetTaskExecTime() 4.00 0 140606 TS Tickless support added. 3.90a 0 140410 AW Software-Update, OS_TerminateTask() modified / corrected. 3.90 1 140312 SC Added cross-references to the API-lists. 3.90 0 140303 AW New functions to globally enable / disable Interrupts: * OS_INTERRUPT_MaskGlobal() * OS_INTERRUPT_UnmaskGlobal() UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 5 Software Revision Date By Description * OS_INTERRUPT_PreserveGlobal() * OS_INTERRUPT_RestoreGlobal() * OS_INTERRUPT_PreserveAndMaskGlobal() 3.88h 0 131220 AW New functions added, chapter "System Tick": * OS_GetNumIdleTicks() * OS_AdjustTime() Chapter "System Variables": Description of internal variable OS_Global.TimeDex corrected. 3.88g 1 131104 TS Corrections. 3.88g 0 131030 TS Update to latest software version. 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. 3.88a 0 130503 AW Software update. Event handling modified, the reset behaviour of events can be controlled. New functions added, chapter "Events": * OS_EVENT_CreateEx() * OS_EVENT_SetResetMode() * OS_EVENT_GetResetMode() Mailboxes message size limits enlarged. 3.88 0 130219 TS Minor corrections. 3.86n 0 121210 AW/TS 3.86l 0 121122 AW Software update. OS_AddTickHook() function corrected. Several functions modified to allow most of MISRA rule checks. 3.86k 0 121004 TS Chapter "Queue": * OS_Q_GetMessageSize() and * OS_Q_PeekPtr() added. 3.86i 0 120926 TS Update to latest software version. 3.86h 0 120906 AW Software update, OS_EVENT handling with timeout corrected. 3.86g 0 120806 AW Software update, OS_RetriggerTimer() corrected. Task events explained more in detail. Additional software examples in the manual. AW Task event modified, default set to 32bit on 32bit CPUs. Chapter 4: * New API function OS_AddOnTerminateHook() * OS_ERR_TIMESLICE removed. A time slice value of zero is legal when creating tasks. 3.86f 0 120723 Update to latest software version. 3.86e 0 120529 AW Update to latest software version with corrected functions: * OS_GetSysStackBase() * OS_GetSysStackSize() * OS_GetSysStackSpace() * OS_GetSysStackUsed() * OS_GetIntStackBase() * 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 Update to latest software version. 3.86c 0 120508 TS Update to latest software version. TS Chapter "Mailbox" * OS_PeekMail() added. Chapter "Support" added. Chapter "Debugging": 3.86b 0 120502 UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 6 Software Revision Date By Description * Application defined error codes added. 3.86 0 120323 AW Timeout handling for waitable objects modified. A timeout will be returned from the waiting function, when the object was not available 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() * OS_WaitCSemaTimed() * OS_GetMailTimed() * OS_WaitMailTimed() * OS_Q_GetPtrTimed() * OS_EVENT_WaitTimed() * OS_MEMF_AllocTimed() New chapter "Extending the Task Context" added. New functions added and described in the manual: * OS_GetTaskName() * OS_GetTimeSliceRem() Handling of queues described more in detail: * OS_Q_GetPtr() * OS_Q_GetPtrCond() * OS_Q_GetPtrTimed() * OS_Q_Purge() Chapter "Priority Inversion / Inheritance" updated. Function names OS_Timing_Start() and OS_Timing_End() corrected in the API table. Since version 3.822 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_GetEventsOccured() * OS_GetCSemaValue() * 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_CREATEMB() changed to OS_CreateMB() Chapter "Queues": * Typos corrected 3.84c 1 120130 AW/TS 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. TS Chapter "Stacks": * OS_GetSysStackBase() added * OS_GetSysStackSize() added * OS_GetSysStackUsed() added * OS_GetSysStackSpace() added * OS_GetIntStackBase() added * OS_GetIntStackSize() added * OS_GetIntStackUsed() added 3.84 0 110927 UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 7 Software Revision Date By Description * 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 "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. 3.82s 0 110318 AW Chapter "Timer" API functions table corrected. All functions can be called from main(), task, ISR or Timer. Chapter 6: OS_UseTimed() added. Chapter 9: OS_Q_IsInUse() added. 3.82p 0 110112 AW Chapter "Mailboxes": * OS_PutMail() * OS_PutMailCond() * OS_PutMailFront() * OS_PutMailFrontCond() parameter decklaration changed. Chapter 4.3 API functions table corrected. OS_Suspend() cannot be called from ISR or Timer. 3.82o 0 110104 AW Chapter "Mailboxes": * OS_WaitMailTimed() added 3.82n 0 101206 AW Chapter "Taskroutines": * OS_ResumeAllSuspendedTasks() added * OS_SetInitialSuspendCnt() added * OS_SuspendAllTasks() added 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 AW Chapter "Event Objects": * Samples added Chapter "Configuration of Target System": * Detailed description of OS_Idle() added 3.82f 1 100505 TS Chapter "Profiling" added Chapter "System Tick": * OS_TickHandleNoHook() added 3.82f 0 100419 AW Chapter "Tasks": * OS_IsRunning() added * 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 cuntion usage (main, task, ISR or timer) TOC format corrected 3.80 0 090612 AW Scheduler optimized for higher task switching speed. 3.62c 0 080903 SK Chapter structure updated. Chapter "Interrupts": * OS_LeaveNestableInterruptNoSwitch() removed * OS_LeaveInterruptNoSwitch() removed Chapter "System Tick": * OS_TICK_Config() added 3.60 2 080722 SK Contact address updated. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 8 Software Revision Date By Description 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": * OS_SetTaskName() added 3.52 0 070824 OO Chapter "Task Routines": * OS_ExtendTaskContext() added Chapter "Interrupts": * Updated * OS_CallISR() added * OS_CallNestableISR() added 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. 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 3.40c 3.40a 2 1 070625 070608 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" renames to "Time Measurement". 3.32o 9 070422 SK Chapter 4: OS_CREATETIMER_EX(), additional information corrected. 3.32m 8 070402 AW Chapter 4: Extended timer added. Chapter 8: API overview corrected, OS_Q_GetMessageCount() 3.32j 7 070216 AW Chapter 6: OS_CSemaRequest() function added. 3.32e 6 061220 SK About: Company description added. Some minor formatting changes. 3.32e 5 061107 AW Chapter 7: OS_GetMessageCnt() return value corrected to unsigned int. 3.32d 4 061106 AW Chapter 8: OS_Q_GetPtrTimed() function added. 3.32a 3 061012 AW Chapter 3: OS_CreateTaskEx() function, description of parameter pContext corrected. Chapter 3: OS_CreateTaskEx() function, type of parameter TimeSlice corrected. Chapter 3: OS_CreateTask() function, type of parameter TimeSlice corrected. Chapter 9: OS_GetEventOccured() renamed to OS_GetEventsOccured(). Chapter 10: OS_EVENT_WaitTimed() added. 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. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 9 Software Revision Date By Description 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 embOS version. Chapter 18.1.2: Type return value of OS_GetTime32() corrected. 3.26 0 050209 AW Chapter 4: OS_Terminate() modified due to new features of version 2.26. Chapter 24: Source code version: additional compile time switches and build process of libraries explained more in detail. 3.24 0 011115 AW Chapter 6: Some prototype declarations showed in OS_SEMA instead of OS_RSEMA. Corrected. AW Chapter 8: New Mailbox functions added * OS_PutMailFront() * OS_PutMailFront1() * OS_PutMailFrontCond() * OS_PutMailFrontCond1() 3.22 3.20 1 5 040816 040621 RS/AW Software timers: Maximum timeout values and OS_TIMER_MAX_TIME described. Chapter 14: Description of rules for interrupt handlers revised. OS_LeaveNestableInterruptNoSwitch() added which was not described before. 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.20 1 040831 AW Code samples modified: Task stacks defined as array of int, because most CPUs require alignment of stakc on integer aligned addresses. AW Chapter Chapter Chapter Chapter Chapter Chapter Chapter Chapter ed. Chapter Chapter 3.20 3.12 3.10 1 1 3 031016 021015 020926 020924 020910 4: 4: 4: 4: 5: 6: 6: 8: Type of task priority parameter corrected to unsigned char. OS_DelayUntil(): Sample program modified. OS_Suspend() added. OS_Resume() added. OS_GetTimerValue(): Range of return value corrected. Sample program for usage of resource semaphores modified. OS_GetResourceOwner(): Type of return value corrected. OS_CREATEMB(): Types and valid range of parameter correct- 8: OS_WaitMail() added 10: OS_WaitEventTimed(): Range of timeout value specified. AW Chapter 8: OS_GetMailTimed() added Chapter 11 (Heap type memory management) inserted Chapter 12 (Fixed block size memory pools) inserted KG 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 nad 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. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 10 UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 11 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 program examples. Reference Reference to chapters, sections, tables and figures or other documents. GUIElement Buttons, dialog boxes, menu names, menu commands. Emphasis Very important sections. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 12 UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 13 Table of contents 1 Introduction and basic concepts ................................................................................. 17 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 1.10 1.11 1.12 1.13 2 Tasks ........................................................................................................................... 42 2.1 2.2 2.3 2.4 3 Introduction ............................................................................................... 120 API functions ............................................................................................. 121 Event Objects ............................................................................................................130 5.1 5.2 6 Introduction .................................................................................................91 API functions ............................................................................................... 93 Task Events ...............................................................................................................119 4.1 4.2 5 Introduction .................................................................................................43 Cooperative vs. preemptive task switches ....................................................... 44 Extending the task context ............................................................................45 API functions ............................................................................................... 47 Software Timers ..........................................................................................................90 3.1 3.2 4 What is embOS? .......................................................................................... 18 Tasks .......................................................................................................... 20 Single-task systems (superloop) .................................................................... 21 Multitasking systems .................................................................................... 23 Scheduling .................................................................................................. 25 Communication between tasks .......................................................................27 How task switching works ............................................................................. 28 Change of task status .................................................................................. 30 How the OS gains control ............................................................................. 31 Different builds of embOS ........................................................................... 32 Valid context for embOS API ....................................................................... 34 Blocking and Non blocking embOS API ..........................................................35 API functions ............................................................................................. 36 Introduction ............................................................................................... 131 API functions ............................................................................................. 134 Mutexes ..................................................................................................................... 154 6.1 6.2 Introduction ............................................................................................... 155 API functions ............................................................................................. 157 UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 14 7 Semaphores .............................................................................................................. 167 7.1 7.2 8 Mailboxes .................................................................................................................. 180 8.1 8.2 9 Introduction ............................................................................................. 318 API functions ........................................................................................... 319 Fixed Block Size Memory Pool ............................................................................... 323 17.1 17.2 18 Introduction ............................................................................................. 302 Starting power save modes in OS_Idle() ..................................................... 303 Tickless support ....................................................................................... 304 Peripheral power control ............................................................................ 312 Heap Type Memory Management .......................................................................... 317 16.1 16.2 17 Introduction ............................................................................................. 285 Low-resolution measurement ..................................................................... 286 High-resolution measurement .....................................................................289 Example .................................................................................................. 295 Microsecond precise system time ................................................................296 Low Power Support ................................................................................................ 301 15.1 15.2 15.3 15.4 16 Introduction ............................................................................................. 280 API functions ........................................................................................... 281 Time Measurement ................................................................................................. 284 14.1 14.2 14.3 14.4 14.5 15 What are interrupts? ................................................................................. 253 Interrupt latency ...................................................................................... 254 Rules for interrupt handlers ....................................................................... 258 Interrupt control .......................................................................................268 Critical Regions .......................................................................................................279 13.1 13.2 14 Introduction ............................................................................................. 243 API functions ........................................................................................... 245 Interrupts ................................................................................................................. 252 12.1 12.2 12.3 12.4 13 Introduction ............................................................................................. 235 API functions ........................................................................................... 236 Multi-core Support .................................................................................................. 242 11.1 11.2 12 Introduction ............................................................................................... 213 API functions ............................................................................................. 215 Watchdog ................................................................................................................ 234 10.1 10.2 11 Introduction ............................................................................................... 181 API functions ............................................................................................. 184 Queues ......................................................................................................................212 9.1 9.2 10 Introduction ............................................................................................... 168 API functions ............................................................................................. 169 Introduction ............................................................................................. 324 API functions ........................................................................................... 326 System Tick ............................................................................................................ 339 18.1 18.2 Introduction ............................................................................................. 340 API functions ........................................................................................... 340 UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 15 18.3 18.5 19 Debugging ............................................................................................................... 349 19.1 19.2 20 Introduction ............................................................................................. 463 Time variables ..........................................................................................464 OS information routines ............................................................................ 465 Supported Development Tools ................................................................................471 26.1 27 Introduction ............................................................................................. 449 Hardware-specific routines ......................................................................... 450 How to change settings .............................................................................461 System Variables .................................................................................................... 462 25.1 25.2 25.3 26 Introduction ............................................................................................. 431 API functions ........................................................................................... 433 Board Support Packages ........................................................................................ 448 24.1 24.2 24.3 25 Introduction ............................................................................................. 404 Memory Access permissions ....................................................................... 405 ROM placement of embOS ......................................................................... 406 Allowed embOS API in unprivileged tasks .................................................... 407 Device driver ........................................................................................... 412 API functions ........................................................................................... 414 Stacks ......................................................................................................................430 23.1 23.2 24 Overview ................................................................................................. 372 Task list window ....................................................................................... 373 System variables window ...........................................................................374 Sharing the SIO for terminal I/O ................................................................ 375 Enable communication to embOSView ......................................................... 378 Select the communication channel .............................................................. 379 Setup embOSView for communication ......................................................... 380 Using the API trace .................................................................................. 384 Trace filter setup functions .........................................................................386 Trace record functions ............................................................................. 395 Application-controlled trace example ......................................................... 401 User-defined functions ............................................................................. 402 MPU - Memory Protection ...................................................................................... 403 22.1 22.2 22.3 22.4 22.5 22.6 23 Introduction ............................................................................................. 360 API functions ........................................................................................... 361 embOSView ............................................................................................................ 371 21.1 21.2 21.3 21.4 21.5 21.6 21.7 21.8 21.9 21.10 21.11 21.12 22 Runtime application errors ......................................................................... 350 Human readable object identifiers ...............................................................356 Profiling ................................................................................................................... 359 20.1 20.2 21 Hooking into the system tick ..................................................................... 345 Disabling the system tick .......................................................................... 348 Overview ................................................................................................. 472 Source Code ........................................................................................................... 473 27.1 27.2 27.3 27.4 Introduction ............................................................................................. 474 Building embOS libraries ........................................................................... 475 Compile time switches .............................................................................. 476 Source code project .................................................................................. 478 UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 16 28 Shipment ................................................................................................................. 479 28.1 28.2 28.3 28.4 29 Update .....................................................................................................................484 29.1 29.2 29.3 30 Contacting support ................................................................................... 496 Performance and Resource Usage .........................................................................497 31.1 31.2 31.3 31.4 32 Introduction ............................................................................................. 485 How to update an existing project .............................................................. 486 embOS API Migration guide ....................................................................... 487 Support ....................................................................................................................495 30.1 31 General information .................................................................................. 480 Library variant ..........................................................................................481 Free variant ............................................................................................. 482 Source code variant .................................................................................. 483 Introduction ............................................................................................. 498 Memory requirements ............................................................................... 499 Performance .............................................................................................500 Benchmarking .......................................................................................... 500 Glossary .................................................................................................................. 505 UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 1 Introduction and basic concepts UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 18 CHAPTER 1 1.1 What is 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. 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.7 Kbyte of ROM and about 70 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 libraries 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 in which 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: Mutex and counting semaphores. 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 1 msec). Easily accessible time variable. Power management. Calculation time in which embOS is idle can automatically be spent in power save mode. Power-consumption is minimized. Full interrupt support: Interrupts may 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, optional interrupt stack. 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. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 19 CHAPTER 1 * * * * What is embOS? Very fast and efficient, yet small code. Minimal RAM usage. API can be called from assembly, C or C++ code. Board support packages (BSP) as source code available. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 20 CHAPTER 1 1.2 Tasks 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. This is called a single-task system. A real-time operating system, on the other hand, allows the execution of multiple tasks on a single CPU. All tasks execute as if they completely "owned" 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. 1.2.1 Threads vs. Processes Threads are tasks that share the same memory layout, hence any two threads can access the same memory locations. If virtual memory is used, the same virtual to physical translation and access rights are used. With embOS, all tasks are threads: they all have the same memory access rights and translation (in systems with virtual memory). Processes 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 with the current version of embOS. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 21 CHAPTER 1 1.3 Single-task systems (superloop) 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, since no real-time kernel and only one stack is used, both program (ROM) size and RAM size are smaller for simple applications when compared to using an RTOS. Obviously, 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. 1.3.1 Advantages & disadvantages Advantages * * Simple structure (for small applications) Low stack usage (only one stack required) Disadvantages * * * * * * 1.3.2 No "delay" capability Higher power consumption due to the lack of a power save mode in most architectures Difficult to maintain as program grows Timing of all software components depends on all other software components: Small change in one place can have major side effects in other places Defeats modular programming Real time behavior only with interrupts Using embOS in superloop applications In a true superloop application, no tasks are used, hence the biggest advantage of using an RTOS cannot be utilized unless the application is re-written for multitasking. However, even with just one single task, using embOS offers the following advantages: * * * 1.3.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 a single-task super-loop-application. At some point, the disadvantages of this approach result in a decision to use an RTOS. The typical question now usually is: How do I do this? The easiest way is to start with one of the sample applications that come with embOS and to add the existing "super-loop code" into one task. At this point, you should also ensure that the stack size of this task is sufficient. Later, additional functionality is added to the UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 22 CHAPTER 1 Single-task systems (superloop) software and can be put in one or more additional tasks; the functionality of the super-loop can also be distributed over multiple tasks. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 23 CHAPTER 1 1.4 Multitasking systems Multitasking systems In a multitasking system, there are different ways to distribute CPU time amongst different tasks. This process is called scheduling. 1.4.1 Task switches There are two types of task switches, also called context switches: Cooperative and preemptive task switches. A cooperative task switch is performed by the task itself. As its name indicates, it requires the cooperation of the task: it suspends itself by calling a blocking RTOS function, e.g. OS_TASK_Delay() or OS_TASKEVENT_GetBlocked(). A preemptive task switch, on the other hand, is a task switch that is caused externally. For example, a task of higher priority becomes ready for execution and, as a result, the scheduler suspends the current task in favor of that task. 1.4.2 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_TASK_Delay() or OS_MAILBOX_GetBlocked(). 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. 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 Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 24 CHAPTER 1 1.4.3 Multitasking systems 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 blocking operating system function. A high-priority task waiting for an event is signaled 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) for as long as the high-priority task is executing. Usually, real-time operating systems such as embOS utilize a timer interrupt that interrupts tasks at periodic intervals and thereby allows to perform task switches whenever timed task switches are necessary. Preemptive multitasking may be switched off in sections of a program where task switches are prohibited, known as critical regions. embOS itself will also temporarily disable preemptive task switches during critical operations, which might be performed during the execution of some embOS API functions. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 25 CHAPTER 1 1.5 Scheduling 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, etc). 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. 1.5.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 each task. 1.5.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 the display. E.g., even while the display is being updated, the motor needs to be controlled. This renders preemptive multitasking essential. Round-robin might work, but as it cannot guarantee any specific reaction time, a more suitable algorithm should be used. In priority-controlled scheduling, every task is assigned a priority. Depending on these priorities, a task is chosen for execution according to one simple rule: Note The scheduler activates the task that has the highest priority of all tasks and is ready for execution. This means that every time a task with a priority higher than the running task becomes ready, it becomes the running task, and 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 periods 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, because execution constantly switches between the identical-priority tasks. It usually is more efficient to assign distinct priority to each task, thereby avoiding unnecessary task switches. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 26 CHAPTER 1 1.5.3 Scheduling 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 lowpriority 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. The low priority task claims the semaphore with OS_MUTEX_LockBlocked(). An interrupt activates the high priority task, which also calls OS_MUTEX_LockBlocked(). 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_TASK_Delay() and is therefore suspended. The task with lower priority now continues and calls OS_MUTEX_Unlock() to release the mutex. 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. With priority inheritance, the low priority task inherits the priority of the waiting high priority task as long as it holds the mutex. The lower priority task is activated instead of the medium priority task when the high priority task tries to claim the semaphore. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 27 CHAPTER 1 1.6 Communication between tasks 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. 1.6.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. 1.6.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. 1.6.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 180 and Queues on page 212. 1.6.4 Semaphores and Mutexes Semaphores and mutexes are used for task synchronization and to manage resources of any kind. The most common are mutex, although semaphores are also used. For details and samples, refer to the chapters Mutexes on page 154 and Semaphores on page 167. 1.6.5 Events A task can wait for a particular event without consuming any CPU time. The idea is as simple as it is convincing, there is no sense in polling if we can simply activate a task once 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 119 and Event Objects on page 130. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 28 CHAPTER 1 1.7 How task switching works 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 430. 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 Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 29 CHAPTER 1 1.7.1 How task switching works Switching stacks The following diagram demonstrates the process of switching from one stack to another. 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 1) by loading the stack pointer (SP) and the processor registers from the values stored on Task 1's stack. Deactivating a task The scheduler deactivates the task to be suspended (Task 0) as follows: 1. Save (push) the processor registers on the task's stack. 2. Save the stack pointer in the Task Control Block. Activating a task The scheduler activates the higher-priority task (Task 1) by performing the sequence in reverse order: 1. Load (pop) the stack pointer (SP) from the Task Control Block. 2. Load the processor registers from the values stored on Task 1's stack. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 30 1.8 CHAPTER 1 Change of task status 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 nexthighest-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. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 31 CHAPTER 1 1.9 How the OS gains control How the OS gains control Upon CPU 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_Init(); OS_InitHW(); OS_TASK_CREATE(); 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 void main(void) { OS_Init(); // Initialize embOS (must be first) OS_InitHW(); // Initialize hardware for embOS (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 Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 32 CHAPTER 1 1.10 Different builds of embOS 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. The following features are included in the different embOS builds: Debug code The embOS debug code is mainly implemented as assertions which detect application programming errors like calling an API function from an invalid context. Stack check The stack check detects stack overflows of task stacks, system stack and interrupt stack. Also the maximum amount of used stack can be calculated. 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 and additional runtime overhead. This overhead is usually acceptable, but for best performance you may want to use nonprofiling builds of embOS if you do not use this feature. Trace embOS API trace saves information about called API in a trace buffer. The trace data can be visualized in embOSView. Round-Robin Round-Robin lets all task at the same priority periodically run with an according time slice. Object names Tasks and OS object names can be used to easily identify a task or e.g. a mailbox in tools like embOSView, SystemView or IDE RTOS plug-ins. Task context extension For some applications it might be useful or required to have individual data in tasks that are unique to the task. With the task context extension support each task control block includes function pointer to save and restore routines which are executed during context switch. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 33 CHAPTER 1 1.10.1 Different builds of embOS List of builds In your application program, you need to let the compiler know which build of embOS you are using. This is done by adding the corresponding Define to your preprocessor settings and linking the according library file. The actual library file name depends on the embOS port. Please check the according CPU and compiler specific embOS manual for more details. Stack Check OS_LIBMODE_S Stackcheck + Profiling OS_LIBMODE_SP Debug OS_LIBMODE_D Debug + Profiling Task context extension OS_LIBMODE_R Object names Release Round-Robin OS_LIBMODE_XR Trace Extreme Release Profiling Define Stack Check Debug Code Name Description Smallest fastest build. 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. OS_LIBMODE_DP Maximum runtime checking, plus profiling. Debug + Trace + Profiling OS_LIBMODE_DT Maximum runtime checking, plus tracing API callss and profiling. Safe Library OS_LIBMODE_SAFE Additional safety features for certified embOS. 1.10.2 OS_Config.h OS_Config.h is part of every embOS port and located in the Start\Inc folder. Use of OS_Config.h makes it easier to define the embOS library mode: Instead of defining OS_LIBMODE_* in your preprocessor settings, you may define DEBUG=1 in your preprocessor settings in debug compile configuration and define nothing in the preprocessor settings in release compile configuration. Subsequently, OS_Config.h will automatically define OS_LIBMODE_DP for debug compile configuration and OS_LIBMODE_R for release compile configuration. Compile Configuration Debug Preprocessor Define DEBUG=1 Release UM01001 User Guide & Reference Manual for embOS Define Set by OS_Config.h OS_LIBMODE_DP OS_LIBMODE_R (c) 1995-2018 SEGGER Microcontroller GmbH 34 CHAPTER 1 1.11 Valid context for embOS API Valid context for embOS API Some embOS functions may only be called from specific locations inside your application. We distinguish between main() (before the call of OS_Start()), task, interrupt routines and embOS software timer. Note Please consult the embOS API tables to determine whether an embOS function is allowed from within a specific execution context. Please find the API tables at beginning of each chapter. An embOS debug build will check for violations of these rules and calls OS_Error() with an according error code. Example Timer ISR Suspends the calling task for a specified period of time, or waits actively when called from main(). Task OS_TASK_Delay() Description main Routine This table entry says it is allowed to call OS_TASK_Delay() from main() and a task but not from an embOS software timer or an interrupt handler. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 35 CHAPTER 1 1.12 Blocking and Non blocking embOS API Blocking and Non blocking embOS API Most embOS API comes in three different version: Non blocking, blocking and blocking with a timeout. The embOS API uses a specific naming convention for those API functions. API functions which do not block a task have no suffix. API functions which could block a task have the suffix "Blocked". API functions which could block a task but have a timeout have the suffix "Timed". Non blocking API Non blocking API functions always return at once, irrespective of the state of the OS object. The return value can be checked in order to find out if e.g. new data is available in a mailbox. static OS_MAILBOX MyMailbox; static char Buffer[10]; void Task(void) { char r; while (1) { r = OS_MAILBOX_Get(MyMailbox, Buffer); if (r == 0u) { // Process message } } } Blocking API Blocking API functions suspend the task until it is activated again by another embOS API function. The task does not cause any CPU load while it is waiting for the next activation. static OS_MAILBOX MyMailbox; static char Buffer[10]; void Task(void) { while (1) { // Suspend task until a new message is available OS_MAILBOX_GetBlocked(MyMailbox, Buffer); // Process message } } Blocking API with timeout These API functions have an additional timeout. They are blocking until the timeout occurs. static OS_MAILBOX MyMailbox; static char Buffer[10]; void Task(void) { char r; while (1) { // Suspend task until a new message is available or the timeout occurs r = OS_MAILBOX_GetTimed(MyMailbox, Buffer, 10); if (r == 0u) { // Process message } } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 36 CHAPTER 1 1.13 API functions API functions Timer ISR Task Description main Routine OS_ConfigStop() Configures the OS_Stop() function. OS_Init() Initializes the embOS kernel. OS_IsRunning() Returns whether OS_Start() was called. OS_Start() Starts the embOS kernel. OS_Stop() Stops the embOS scheduler and returns from OS_Start(). UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 37 CHAPTER 1 1.13.1 API functions OS_ConfigStop() Description Configures the OS_Stop() function. Prototype void OS_ConfigStop(OS_MAIN_CONTEXT* pContext, void* Addr, OS_U32 Size); Parameters Parameter Description pContext Pointer to an object of type OS_MAIN_CONTEXT. Addr Address of the buffer which is used to save the main() stack. Size Size of the buffer. Additional information This function configures the OS_Stop() function. When configured, OS_Start() saves the context and stack from within main(), which subsequently are restored by OS_Stop(). The main() context and stack are saved to the resources configured by OS_ConfigStop(). Only the stack that was actually used during main() is saved. Therefore, the size of the buffer depends on the used stack. If the buffer is too small, debug builds of embOS will call OS_Error() with the error code OS_ERR_OSSTOP_BUFFER. The structure OS_MAIN_CONTEXT is core and compiler specific; it is specifically defined with each embOS port. Example #include "RTOS.h" #include "stdio.h" #define BUFFER_SIZE static OS_U8 static OS_MAIN_CONTEXT static OS_STACKPTR int static OS_TASK (32u) Buffer[BUFFER_SIZE]; MainContext; StackHP[128]; TCBHP; // // // // Buffer for main stack copy Main context control structure Task stack Task control block static void HPTask(void) { OS_TASK_Delay(50); OS_INT_Disable(); OS_Stop(); } int main(void) { int TheAnswerToEverything = 42; OS_Init(); // Initialize embOS OS_InitHW(); // Initialize required hardware OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP); OS_ConfigStop(&MainContext, Buffer, BUFFER_SIZE); OS_Start(); // Start embOS // // We arrive here because OS_Stop() was called. // The local stack variable still has its value. // printf("%d", TheAnswerToEverything); while (TheAnswerToEverything == 42) { } return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 38 CHAPTER 1 1.13.2 API functions OS_Init() Description Initializes the embOS kernel. Prototype void OS_Init(void); Additional information In library mode OS_LIBMODE_SAFE all RTOS variables are explicitly initialized. All other library modes presume that, according to the C standard, all initialized variables have their initial value and all non initialized variables are set to zero. Note OS_Init() must be called in main() prior to any other embOS API. Example #include "RTOS.h" static OS_STACKPTR int StackHP[128], StackLP[128]; static OS_TASK TCBHP, TCBLP; // Task stacks // Task control blocks static void HPTask(void) { while (1) { OS_TASK_Delay(50); } } static void LPTask(void) { while (1) { OS_TASK_Delay(200); } } /********************************************************************* * * main() */ int main(void) { OS_Init(); // Initialize embOS OS_InitHW(); // Initialize required hardware OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP); OS_TASK_CREATE(&TCBLP, "LP Task", 50, LPTask, StackLP); OS_Start(); // Start embOS return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 39 CHAPTER 1 1.13.3 API functions OS_IsRunning() Description Determines whether the embOS scheduler was started by a call of OS_Start(). Prototype OS_BOOL OS_IsRunning(void); Return value =0 0 Scheduler is not started. 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 subsequent call to a blocking API function is allowed. Example void PrintStatus() { OS_BOOL b; b = OS_ISRunning(); if (b == 0) { printf("embOS scheduler not started, yet.\n"); } else { printf("embOS scheduler is running.\n"); } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 40 CHAPTER 1 1.13.4 API functions OS_Start() Description Starts the embOS scheduler. Prototype void OS_Start(void); Additional information This function starts the embOS scheduler, which will activate and start the task with the highest priority. OS_Start() marks embOS as running; this may be examined by a call of the function OS_IsRunning(). OS_Start() automatically enables interrupts. It must be called from main() only. #include "RTOS.h" static OS_STACKPTR int StackHP[128], StackLP[128]; static OS_TASK TCBHP, TCBLP; // Task stacks // Task control blocks static void HPTask(void) { while (1) { OS_TASK_Delay(50); } } static void LPTask(void) { while (1) { OS_TASK_Delay(200); } } /********************************************************************* * * main() */ int main(void) { OS_Init(); // Initialize embOS OS_InitHW(); // Initialize required hardware OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP); OS_TASK_CREATE(&TCBLP, "LP Task", 50, LPTask, StackLP); OS_Start(); // Start embOS return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 41 CHAPTER 1 1.13.5 API functions OS_Stop() Description Stops the embOS scheduler and returns from OS_Start(). Prototype void OS_Stop(void); Additional information This function stops the embOS scheduler and the application returns from OS_Start(). OS_ConfigStop() must be called prior to OS_Stop(). If OS_ConfigStop() was not called, debug builds of embOS will call OS_Error() with the error code OS_ERR_CONFIG_OSSTOP. OS_Stop() restores context and stack to their state prior to calling OS_Start(). OS_Stop() does not deinitialize any hardware. It's the application's responsibility to deinitialize all hardware that was initialzed during OS_InitHW(). It is possible to restart embOS after OS_Stop(). To do so, OS_Init() must be called and any task must be recreated. It also is the application's responsibility to initialize all embOS variables to their default values. With the embOS source code, this can easily be achived using the compile time switch OS_INIT_EXPLICITLY. With some cores it is not possible to save and restore the main() stack. This is e.g. true for 8051. Hence, in that case no functionality should be implemented that relies on the stack to be preserved. But OS_Stop() can be used anyway. Example #include "RTOS.h" #include "stdio.h" #define BUFFER_SIZE (32u) static OS_U8 Buffer[BUFFER_SIZE]; static OS_MAIN_CONTEXT MainContext; static OS_STACKPTR int StackHP[128]; static OS_TASK TCBHP; static void HPTask(void) { OS_TASK_Delay(50); OS_Stop(); } int main(void) { int TheAnswerToEverything = 42; OS_Init(); OS_InitHW(); OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP); OS_ConfigStop(&MainContext, Buffer, BUFFER_SIZE); OS_Start(); // // We arrive here because OS_Stop() was called. // The local stack variable still has its value. // printf("%d", TheAnswerToEverything); while (1) { } return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 2 Tasks UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 43 CHAPTER 2 2.1 Introduction Introduction A task that should run under embOS needs a task control block (TCB), a task stack, and a task body written in C. The following rules apply to task routines: * The task routine can either not take parameters (void parameter list), in which case OS_TASK_Create() is used to create it, or take a single void pointer as parameter, in which case OS_TASK_CreateEx() 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). * * 2.1.1 Example of a task routine as an endless loop void Task1(void) { while(1) { DoSomething(); // Do something OS_TASK_Delay(10); // Give other tasks a chance to run } } 2.1.2 Example of a task routine that terminates itself void Task2(void) { char DoSomeMore; do { DoSomeMore = DoSomethingElse(); OS_TASK_Delay(10); } while (DoSomeMore); OS_TASK_Terminate(NULL); } // Do something // Give other tasks a chance to run // Terminate yourself There are different ways to create a task: On the one hand, embOS offers a simple macro to facilitate task creation 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, we recommend using the macro as in the sample start projects. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 44 CHAPTER 2 2.2 Cooperative vs. preemptive task switches 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, time critical tasks. However, it may be desirable to disable preemptive task switches for certain tasks in some circumstances. The default behavior of embOS is to always allow preemptive task switches. 2.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 desirable. 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 static OS_STACKPTR int StackHP[128], StackLP[128]; static OS_TASK TCBHP, TCBLP; // Task stacks // Task control blocks static void TaskEx(void* pData) { while (1) { OS_TASK_Delay ((OS_TIME) pData); } } /********************************************************************* * * main() */ int main(void) { OS_Init(); // Initialize embOS OS_InitHW(); // Initialize required hardware BSP_Init(); // Initialize LED ports OS_TASK_CreateEx(&TCBHP, "HP Task", PRIO_COOP, TaskEx, StackHP, sizeof(StackHP), TIME_SLICE_NULL, (void *) 50); OS_TASK_CreateEx(&TCBLP, "LP Task", PRIO_COOP, TaskEx, StackLP, sizeof(StackLP), TIME_SLICE_NULL, (void *) 200); OS_Start(); // Start embOS return 0; } 2.2.2 Completely disabling preemptions for a task This is simple: The first line of code should be OS_TASK_EnterRegion() as shown in the following sample: void MyTask(void* pContext) { OS_TASK_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. } } 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 Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 45 CHAPTER 2 2.3 Extending the task context 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. 2.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_TASK_CREATEEX() or OS_TASK_CreateEx() 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. 2.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_TASK_SetContextExtension(). The sample application file OS_ExtendTaskContext.c delivered in the application samples folder of embOS demonstrates how the individual task context extension can be used. 2.3.3 Extending the task context by using own task structures When complex data is needed for an individual task context, the OS_TASK_CREATEEX() or OS_TASK_CreateEx() 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 OS_ExtendedTask.c which is delivered in the sample application folder of embOS. /********************************************************************* * SEGGER Microcontroller GmbH & Co. KG * * The Embedded Experts * ********************************************************************** -------------------------- END-OF-HEADER ----------------------------File : OS_ExtendedTask.c Purpose : embOS sample program demonstrating the extension of tasks. */ #include "RTOS.h" #include "BSP.h" /****** Custom task typedef struct { OS_TASK Task; OS_TIME Timeout; char* pString; } MY_APP_TASK; structure with extended task context ************/ // OS_TASK has to be the first element // Any other data type may be used to extend the context // Any number of elements may be used to extend the context /****** Static data *************************************************/ static OS_STACKPTR int StackHP[128], StackLP[128]; // Task stacks static MY_APP_TASK TCBHP, TCBLP; // Task control blocks /****** Task function ***********************************************/ static void MyTask(void) { UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 46 CHAPTER 2 Extending the task context MY_APP_TASK* pThis; OS_TIME Timeout; char* pString; pThis = (MY_APP_TASK*)OS_TASK_GetID(); while (1) { Timeout = pThis->Timeout; pString = pThis->pString; printf(pString); OS_TASK_Delay(Timeout); } } /********************************************************************* * * main() */ int main(void) { OS_Init(); // Initialize embOS OS_InitHW(); // Initialize required hardware // // Create the extended tasks just as normal tasks. // Note that the first parameter has to be of type OS_TASK // OS_TASK_CREATE(&TCBHP.Task, "HP Task", 100, MyTask, StackHP); OS_TASK_CREATE(&TCBLP.Task, "LP Task", 50, MyTask, 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 embOS return 0; } /****** End Of File *************************************************/ UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 47 2.4 CHAPTER 2 API functions API functions Timer ISR Task Description main Routine OS_TASK_AddContextExtension() Adds an additional task context extension. OS_TASK_AddTerminateHook() Adds a hook (callback) function to the list of functions which are called when a task is terminated. OS_TASK_CREATE() Creates a new task. OS_TASK_Create() Creates a new task. OS_TASK_CREATEEX() Creates a new task and passes a parameter to the task. OS_TASK_CreateEx() Creates a new task and passes a parameter to the task. OS_TASK_Delay() Suspends the calling task for a specified period of time, or waits actively when called from main(). OS_TASK_DelayUntil() Suspends the calling task until a specified time, or waits actively when called from main(). OS_TASK_Delayus() Waits for the given time in microseconds. OS_TASK_GetName() Returns a pointer to the name of a task. OS_TASK_GetNumTasks() Returns the number of tasks. OS_TASK_GetPriority() Returns the task priority of a specified task. OS_TASK_GetSuspendCnt() Returns the suspension count and thus suspension state of the specified task. OS_TASK_GetID() Returns a pointer to the task control block structure of the currently running task. OS_TASK_GetTimeSliceRem() Returns the remaining time slice value of a task. OS_TASK_IsTask() Determines whether a task control block belongs to a valid task. OS_TASK_Index2Ptr() Returns the task control block of the task with the specified Index. OS_TASK_RemoveAllTerminateHooks() Removes all hook functions from the OS_ON_TERMINATE_HOOK list which contains the list of functions that are called when a task is terminated. OS_TASK_RemoveTerminateHook() This function removes a hook function from the OS_ON_TERMINATE_HOOK list which contains the list of functions that are called when a task is terminated. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 48 CHAPTER 2 Timer ISR Task Description main Routine API functions OS_TASK_Resume() Decrements the suspend count of the specified task and resumes it if the suspend count reaches zero. OS_TASK_ResumeAll() Decrements the suspend count of all tasks that have a nonzero suspend count and resumes these tasks when their respective suspend count reaches zero. OS_TASK_SetContextExtension() Makes global variables or processor registers task-specific. OS_TASK_SetDefaultContextExtension() Sets the default task context extension for newly created tasks. OS_TASK_SetDefaultStartHook() Sets a default hook routine which is executed before a task starts. OS_TASK_SetInitialSuspendCnt() Sets the initial suspend count for newly created tasks to 1 or 0. OS_TASK_SetName() Allows modification of a task name at runtime. OS_TASK_SetPriority() Assigns a priority to a specified task. OS_TASK_SetTimeSlice() Assigns a specified timeslice period to a specified task. OS_TASK_Suspend() Suspends the specified task and increments a counter. OS_TASK_SuspendAll() Suspends all tasks except the running task. OS_TASK_Terminate() Ends (terminates) a task. OS_TASK_Wake() Ends delay of a specified task immediately. OS_TASK_Yield() Calls the scheduler to force a task switch. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 49 CHAPTER 2 2.4.1 API functions OS_TASK_AddContextExtension() Description Adds an additional task context extension. The task context can be extended with OS_TASK_SetContextExtension() only once. Additional task context extensions can be added with OS_TASK_AddContextExtension(). The function OS_TASK_AddContextExtension() requires an additional parameter of type OS_EXTEND_TASK_CONTEXT_LINK which is used to create a task specific linked list of task context extensions. Prototype void OS_TASK_AddContextExtension (OS_EXTEND_TASK_CONTEXT_LINK* pExtendContextLink, OS_CONST_PTR OS_EXTEND_TASK_CONTEXT *pExtendContext); Parameters Parameter Description pExtendContextLink Pointer to the OS_EXTEND_TASK_CONTEXT_LINK structure. pExtendContext 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. Additional information The object of type OS_EXTEND_TASK_CONTEXT_LINK is task specific and must only be used for one task. It can be located e.g. on the task stack. OS_TASK_AddContextExtension() must only be used when OS_TASK_SetContextExtension() has been called before. Example static void HPTask(void) { OS_EXTEND_TASK_CONTEXT_LINK p; // // Extend task context by VFP registers // OS_TASK_SetContextExtension(&_SaveRestoreVFP); // // Extend task context by global variable // OS_TASK_AddContextExtension(&p, &_SaveRestoreGlobalVar); a = 1.2; while (1) { b = 3 * a; GlobalVar = 1; OS_TASK_Delay(10); } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 50 CHAPTER 2 2.4.2 API functions OS_TASK_AddTerminateHook() Description Adds a hook (callback) function to the list of functions which are called when a task is terminated. Prototype void OS_TASK_AddTerminateHook(OS_ON_TERMINATE_HOOK* pHook, OS_ON_TERMINATE_FUNC* pfUser); Parameters Parameter Description pHook 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_TASK_Terminate(). pfUser Pointer to the function of type OS_TERMINATE_FUNC which shall be called when a task is terminated. 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_TASK_Terminate() by calling OS_TASK_AddTerminateHook() 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); Note 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 _TerminateHook; void TerminateHookFunc(OS_CONST_PTR OS_TASK* pTask) { // This function is executed upon calling OS_TASK_Terminate(). if (pTask == &MyTask) { free(MytaskBuffer); } } ... int main(void) { OS_TASK_AddTerminateHook(&_TerminateHook, TerminateHookFunc); ... } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 51 CHAPTER 2 2.4.3 API functions OS_TASK_CREATE() Description Creates a new task. Prototype void OS_TASK_CREATE(OS_TASK* char* OS_PRIO void* void* pTask, pName, Priority, pRoutine, pStack); Parameters Parameter Description pTask Pointer to a task control block structure. pName Pointer to the name of the task. Can be NULL (or 0) if not used. Priority Priority of the task. Must be within the following range: 1 Priority 28-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. pRoutine Pointer to a function that should run as the task body. pStack 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. Additional information OS_TASK_CREATE() 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_TASK_Create() because it has fewer parameters and is therefore easier to use. OS_TASK_CREATE() 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_TASK_CREATE() determines the size of the stack automatically, using sizeof(). This is possible only if the memory area has been defined at compile time. Note 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 Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 52 CHAPTER 2 API functions Example #include "RTOS.h" static OS_STACKPTR int StackHP[128], StackLP[128]; static OS_TASK TCBHP, TCBLP; // Task stacks // Task control blocks static void HPTask(void) { while (1) { OS_TASK_Delay(50); } } static void LPTask(void) { while (1) { OS_TASK_Delay(200); } } int main(void) { OS_Init(); // Initialize embOS OS_InitHW(); // Initialize required hardware OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP); OS_TASK_CREATE(&TCBLP, "LP Task", 50, LPTask, StackLP); OS_Start(); // Start embOS return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 53 CHAPTER 2 2.4.4 API functions OS_TASK_Create() Description Creates a new task. Prototype void OS_TASK_Create( OS_TASK* const char* OS_PRIO void void OS_UINT OS_UINT pTask, pName, Priority, ( *pRoutine)(), OS_STACKPTR *pStack, StackSize, TimeSlice); Parameters Parameter Description pTask Pointer to a task control block structure. pName Pointer to the name of the task. Can be NULL (or 0) if not used. When using an embOS build without task name support, this parameter does not exist and must be omitted. The embOS OS_LIBMODE_XR libraries do not support task names. Priority Priority of the task. Must be within the following range: 1 Priority 28 - 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. pRoutine Pointer to a function that should run as the task body. pStack 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. StackSize Size of stack in bytes. TimeSlice Time slice value for round-robin scheduling. Has an effect only if other tasks are running at the same priority. It denotes the time (in embOS embOS system ticks) that the task will run before it suspends, and must be in the following range: 0 TimeSlice 255. When using an embOS build without round-robin support, this parameter does not exist and must be omitted. The embOS OS_LIBMODE_XR libraries do not support round-robin and time slice. Additional information This function works the same way as OS_TASK_CREATE(), 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 44) UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 54 CHAPTER 2 API functions Note 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. Example #include "RTOS.h" static OS_STACKPTR int StackHP[128], StackLP[128]; static OS_TASK TCBHP, TCBLP; // Task stacks // Task control blocks static void HPTask(void) { while (1) { OS_TASK_Delay(50); } } static void LPTask(void) { while (1) { OS_TASK_Delay(200); } } int main(void) { OS_Init(); // Initialize embOS OS_InitHW(); // Initialize required hardware OS_TASK_Create(&TCBHP, "HP Task", 100, HPTask, StackHP, sizeof(StackHP), 2); OS_TASK_Create(&TCBLP, "LP Task", 50, LPTask, StackLP, sizeof(StackLP), 2); OS_Start(); // Start embOS return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 55 CHAPTER 2 2.4.5 API functions OS_TASK_CREATEEX() Description Creates a new task and passes a parameter to the task. Prototype void OS_TASK_CREATEEX(OS_TASK* char* OS_PRIO void* void* void* pTask, pName, Priority, pRoutine, pStack, pContext); Parameters Parameter Description pTask Pointer to a task control block structure. pName Pointer to the name of the task. Can be NULL (or 0) if not used. Priority Priority of the task. Must be within the following range: 1 Priority 28-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. pRoutine Pointer to a function that should run as the task body. pStack 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. pContext Parameter passed to the created task function. Additional information OS_TASK_CREATEEX() is a macro calling an embOS library function. It works like OS_TASK_CREATE() 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. Note 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 Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 56 CHAPTER 2 API functions Example The following example is delivered in the Application folder of embOS. #include "RTOS.h" static OS_STACKPTR int StackHP[128], StackLP[128]; static OS_TASK TCBHP, TCBLP; // Task stacks // Task control blocks static void Task(void* pContext) { while (1) { OS_TASK_Delay((int)pContext); } } int main(void) { OS_Init(); // Initialize embOS OS_InitHW(); // Initialize required hardware OS_TASK_CREATEEX(&TCBHP, "HP Task", 100, Task, StackHP, (void*) 50); OS_TASK_CREATEEX(&TCBLP, "LP Task", 50, Task, StackLP, (void*)200); OS_Start(); // Start embOS return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 57 CHAPTER 2 2.4.6 API functions OS_TASK_CreateEx() Description Creates a new task and passes a parameter to the task. Prototype void OS_TASK_CreateEx( OS_TASK* const char* OS_PRIO void void OS_UINT OS_UINT void* pTask, pName, Priority, ( *pRoutine)(void * pVoid ), OS_STACKPTR *pStack, StackSize, TimeSlice, pContext); Parameters Parameter Description pTask Pointer to a task control block structure. pName Pointer to the name of the task. Can be NULL (or 0) if not used. When using an embOS build without task name support, this parameter does not exist and must be omitted. The embOS OS_LIBMODE_XR libraries do not support task names. Priority Priority of the task. Must be within the following range: 1 Priority 28 - 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. pRoutine Pointer to a function that should run as the task body. pStack 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. StackSize Size of stack in bytes. TimeSlice Time slice value for round-robin scheduling. Has an effect only if other tasks are running at the same priority. It denotes the time (in embOS embOS system ticks) that the task will run before it suspends, and must be in the following range: 0 TimeSlice 255. When using an embOS build without round-robin support, this parameter does not exist and must be omitted. The embOS OS_LIBMODE_XR libraries do not support round-robin and time slice. pContext Parameter passed to the created task. Additional information This function works the same way as OS_TASK_CREATE(), 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 44) Note 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 UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 58 CHAPTER 2 API functions 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. #include "RTOS.h" static OS_STACKPTR int StackHP[128], StackLP[128]; static OS_TASK TCBHP, TCBLP; // Task stacks // Task control blocks static void Task(void* pContext) { while (1) { OS_TASK_Delay((int)pContext); } } int main(void) { OS_Init(); // Initialize embOS OS_InitHW(); // Initialize required hardware OS_TASK_CreateEx(&TCBHP, "HP Task", 100, Task, StackHP, sizeof(StackHP), 2, (void*) 50); OS_TASK_CreateEx(&TCBLP, "LP Task", 50, Task, StackLP, sizeof(StackLP), 2, (void*)200); OS_Start(); // Start embOS return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 59 CHAPTER 2 2.4.7 API functions OS_TASK_Delay() Description Suspends the calling task for a specified period of time, or waits actively when called from main(). Prototype void OS_TASK_Delay(OS_TIME t); Parameters Parameter t Description Time interval to delay. Must be within the following range: 0 t 215 - 1 = 0x7FFF for 8/16 bit CPUs 0 t 231 - 1 = 0x7FFFFFFF for 32 bit CPUs Please note that these are signed values. Additional information The parameter t specifies the time interval in system ticks during which the task is suspended. The actual delay will be in the following range: t - 1 delay t, 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_TASK_Wake(). If OS_TASK_Delay() is called from main(), it will actively wait for the timeout to expire. Therefore, interrupts must be enabled. Example void Hello(void) { printf("Hello"); printf("The next output will occur in 5000 system ticks"); OS_TASK_Delay(5000); printf("Delay is over"); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 60 CHAPTER 2 2.4.8 API functions OS_TASK_DelayUntil() Description Suspends the calling task until a specified time, or waits actively when called from main(). Prototype void OS_TASK_DelayUntil(OS_TIME t); Parameters Parameter t Description Time to delay until. Must be within the following range: 0 t 216 - 1 = 0xFFFF for 8/16 bit CPUs 0 t 232 - 1 = 0xFFFFFFFF for 32 bit CPUs Also, the following additional condition must be met: 1 (t - OS_GLOBAL.Time) 215 - 1 = 0x7FFF for 8/16 bit CPUs 1 (t - OS_GLOBAL.Time) 231 - 1 = 0x7FFFFFFF for 32 bit CPUs Please note that these are signed values. Additional information OS_TASK_DelayUntil() suspends the calling task until the global time-variable OS_Global.Time (see OS_Global.Time on page 464) reaches the specified value. The main advantage of this function is that it avoids potentially accumulating delays. The additional condition towards parameter t ensures proper behavior even when a overflow of the embOS system tick timer occurs. If OS_TASK_DelayUntil() is called from main(), it will actively wait for the timeout to expire. Therefore, interrupts must be enabled. Example int sec, min; void TaskShowTime(void) { OS_TIME t0; t0 = OS_TIME_GetTicks(); while (1) { ShowTime(); // Routine to display time t0 += 1000; OS_TASK_DelayUntil(t0); if (sec < 59) { sec++; } else { sec = 0; min++; } } } In the example above, using OS_TASK_Delay() could lead to accumulating delays and would cause the simple "clock" to be slow. Using OS_TASK_DelayUntil() instead avoids accumulating delays. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 61 CHAPTER 2 2.4.9 API functions OS_TASK_Delayus() Description Waits for the given time in microseconds. Prototype void OS_TASK_Delayus(OS_U16 us); Parameters Parameter us Description Number of microseconds to delay. Must be within the following range: 1 us 215 - 1 = 0x7FFF. Please note that these are signed values. Additional information This function can be used for short delays. OS_TASK_Delayus() must only be called with interrupts enabled and after OS_Init() and OS_InitHW() have been called. This only works when the embOS system timer is running. An debug build of OS_TASK_Delayus() checks whether interrupts are enabled and calls OS_Error() if they are not. OS_TASK_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. OS_TASK_Delayus() does not suspend the calling task, thus all tasks with lower priority can not interrupt OS_TASK_Delayus() and will not be executed before OS_TASK_Delayus() returns. Example void Hello(void) { printf("Hello"); printf("The next output will occur in 500 microseconds"); OS_TASK_Delayus(500); printf("Delay is over"); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 62 CHAPTER 2 2.4.10 API functions OS_TASK_GetName() Description Returns a pointer to the name of a task. Prototype char *OS_TASK_GetName(OS_CONST_PTR OS_TASK *pTask); Parameters Parameter pTask Description Pointer to a task control block structure. Return value A pointer to the name of the task. NULL indicates that the task has no name. When using an embOS build without task name support, OS_TASK_GetName() returns "n/ a" in any case. The embOS OS_LIBMODE_XR libraries do not support task names. Additional information If pTask is NULL, the function returns the name of the running task. If there is no currently running task, the return value is "OS_Idle()". If pTask is not NULL and does not specify a valid task, a 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. Example void PrintTaskName(void) { char* s; s = OS_TASK_GetName(NULL); printf("Task name: %s\n", s); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 63 CHAPTER 2 2.4.11 API functions OS_TASK_GetNumTasks() Description Returns the number of tasks. Prototype int OS_TASK_GetNumTasks(void); Return value Number of tasks. Example void PrintNumberOfTasks(void) { int NumTasks; NumTasks = OS_TASK_GetNumTasks(); printf("Number of tasks %d\n", NumTasks); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 64 CHAPTER 2 2.4.12 API functions OS_TASK_GetPriority() Description Returns the task priority of a specified task. Prototype OS_PRIO OS_TASK_GetPriority(OS_CONST_PTR OS_TASK *pTask); Parameters Parameter pTask Description Pointer to a task control block structure or NULL for current task. Return value Priority of the specified task (range 1 to 255 for 8/16 bit CPUs and up to 4294967295 for 32 bit CPUs). 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. Note This function can be called from within an interrupt handler with OS_TASK_GetPriority(NULL) but if the handler interrupts OS_Idle() no task is currently running and no valid task is specified. The debug build of embOS calls OS_Error() in this case. We suggest to call OS_TASK_GetPriority() from an interrupt handler with a pointer to a valid task control block only. Example void PrintPriority(const OS_TASK* pTask) { OS_PRIO Prio; Prio = OS_TASK_GetPriority(pTask); printf("Priority of task 0x%x = %u\n", pTask, Prio); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 65 CHAPTER 2 2.4.13 API functions OS_TASK_GetSuspendCnt() Description 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_TASK_Suspend(). Prototype OS_U8 OS_TASK_GetSuspendCnt(OS_CONST_PTR OS_TASK *pTask); Parameters Parameter Description Pointer to task control block structure. pTask Return value Suspension count of the specified task. =0 >0 Task is not suspended. Task is suspended by at least one call of OS_TASK_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_TASK_IsTask() may be called prior to calling OS_TASK_GetSuspendCnt() to determine whether a task is valid. The returned value can be used to resume a suspended task by calling OS_TASK_Resume() as often as indicated by the returned value. Example void ResumeTask(OS_TASK* pTask) { OS_U8 SuspendCnt; SuspendCnt = OS_TASK_GetSuspendCnt(pTask); while (SuspendCnt > 0u) { OS_TASK_Resume(pTask); // May cause a task switch SuspendCnt--; } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 66 CHAPTER 2 2.4.14 API functions OS_TASK_GetID() 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_TASK_GetID(void); Return value A pointer to the task control block. 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. Example void PrintCurrentTaskID(void) { OS_TASK* pTask; pTask = OS_TASK_GetID(); printf("Task ID 0x%x\n", pTask); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 67 CHAPTER 2 2.4.15 API functions OS_TASK_GetTimeSliceRem() Description Returns the remaining time slice value of a task. Prototype OS_U8 OS_TASK_GetTimeSliceRem(OS_CONST_PTR OS_TASK *pTask); Parameters Parameter pTask Description Pointer to a task control block structure. Return value Remaining time slice value of the task. Additional information If NULL is passed for pTask, the currently running task is used. However, NULL must not be passed for pTask from main(), a timer callback or from an interrupt handler. A debug build of embOS will call OS_Error() in case pTask does not indicate a valid task. 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 OS_LIBMODE_XR libraries do not support round-robin. In that case OS_TASK_GetTimeSliceRem() returns zero. Example void PrintRemainingTimeSlices(void) { OS_U8 slices; slices = OS_TASK_GetTimeSliceRem(NULL); printf("Remaining Time Slices: %d\n", slices); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 68 CHAPTER 2 2.4.16 API functions OS_TASK_IsTask() Description Determines whether a task control block belongs to a valid task. Prototype OS_BOOL OS_TASK_IsTask(OS_CONST_PTR OS_TASK *pTask); Parameters Parameter Description Pointer to a task control block structure. pTask Return value 0 1 TCB is not used by any task. 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. Example void PrintTCBStatus(OS_TASK* pTask) { OS_BOOL b; b = OS_TASK_IsTask(pTask); if (b == 0) { printf("TCB can be reused for another task.\n"); } else { printf("TCB refers to a valid task.\n"); } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 69 CHAPTER 2 2.4.17 API functions OS_TASK_Index2Ptr() Description Returns the task control block of the task with the specified Index. Prototype OS_TASK *OS_TASK_Index2Ptr(int TaskIndex); Parameters Parameter TaskIndex Description Index of a task control block in the task list. This is a zero based index. TaskIndex 0 identifies the first task control block. Return value = NULL NULL No task control block with this index found. Pointer to the task control block with the index TaskIndex. Example void PrintTaskName(int TaskIndex) { OS_TASK* pTask; pTask = OS_TASK_Index2Ptr(TaskIndex); if (pTask != NULL) { printf("%s", pTask->Name); } } void HPTask(void) { // // Print the task name of the first task in the task list // PrintTaskName(0); while (1) { OS_TASK_Delay(100); } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 70 CHAPTER 2 2.4.18 API functions OS_TASK_RemoveAllTerminateHooks() Description Removes all hook functions from the OS_ON_TERMINATE_HOOK list which contains the list of functions that are called when a task is terminated. Prototype void OS_TASK_RemoveAllTerminateHooks(void); Additional information OS_TASK_RemoveAllTerminateHooks() removes all hook functions which were previously added by OS_TASK_AddTerminateHook(). Example OS_ON_TERMINATE_HOOK _TerminateHook; void TerminateHookFunc(OS_CONST_PTR OS_TASK* pTask) { // This function is called when OS_TASK_Terminate() is called. if (pTask == &MyTask) { free(MytaskBuffer); } } ... int main(void) { OS_TASK_AddTerminateHook(&_TerminateHook, TerminateHookFunc); OS_TASK_RemoveAllTerminateHooks(); ... } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 71 CHAPTER 2 2.4.19 API functions OS_TASK_RemoveTerminateHook() Description This function removes a hook function from the OS_ON_TERMINATE_HOOK list which contains the list of functions that are called when a task is terminated. Prototype void OS_TASK_RemoveTerminateHook(OS_CONST_PTR OS_ON_TERMINATE_HOOK *pHook); Parameters Parameter pHook Description Pointer to a variable of type OS_ON_TERMINATE_HOOK. Additional information OS_TASK_RemoveTerminateHook() removes the specified hook function which was previously added by OS_TASK_AddTerminateHook(). Example OS_ON_TERMINATE_HOOK _TerminateHook; void TerminateHookFunc(OS_CONST_PTR OS_TASK* pTask) { // This function is called when OS_TASK_Terminate() is called. if (pTask == &MyTask) { free(MytaskBuffer); } } ... int main(void) { OS_TASK_AddTerminateHook(&_TerminateHook, TerminateHookFunc); OS_TASK_RemoveTerminateHook(&_TerminateHook); ... } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 72 CHAPTER 2 2.4.20 API functions OS_TASK_Resume() Description Decrements the suspend count of the specified task and resumes it if the suspend count reaches zero. Prototype void OS_TASK_Resume(OS_TASK* pTask); Parameters Parameter pTask Description Pointer to a task control block structure. 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_TASK_Resume() checks the suspend count of the specified task. If the suspend count is zero when OS_TASK_Resume() is called, OS_Error() is called with error OS_ERR_RESUME_BEFORE_SUSPEND. Example Please refer to the example of OS_TASK_Suspend(). UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 73 CHAPTER 2 2.4.21 API functions OS_TASK_ResumeAll() 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_TASK_ResumeAll(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_TASK_SuspendAll() and OS_TASK_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. The function may be called even when no task is suspended. Example Please refer to the example of OS_TASK_SetInitialSuspendCnt(). UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 74 CHAPTER 2 2.4.22 API functions OS_TASK_SetContextExtension() Description Makes global variables or processor registers task-specific. 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_TASK_SetContextExtension (OS_CONST_PTR OS_EXTEND_TASK_CONTEXT *pExtendContext); Parameters 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. Additional information 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_TASK_SetContextExtension() is not available in the XR libraries. Note The task context can be extended only once per task with OS_TASK_SetContextExtension(). The function must not be called multple times for one task. Additional task context extensions can be set with OS_TASK_AddContextExtension(). 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; UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 75 CHAPTER 2 API functions Note In embOS V4.16 and earlier the OS_EXTEND_TASK_CONTEXT structure was defined as follows: typedef struct OS_EXTEND_TASK_CONTEXT_STRUCT { void (*pfSave) ( void OS_STACKPTR * pStack); void (*pfRestore)(const void OS_STACKPTR * pStack); } OS_EXTEND_TASK_CONTEXT; The Save/Restore functions did not return the stack pointer. When updating from embOS V4.16 and earlier to embOS V4.20 and later please update your Save/Restore functions accordingly. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 76 CHAPTER 2 API functions Example The following example is delivered in the Application folder of embOS. -------------------------- END-OF-HEADER ----------------------------File : OS_ExtendTaskContext.c Purpose : embOS sample program demonstrating the dynamic extension of tasks' contexts. This is done by adding a global variable to the task context of certain tasks. */ #include "RTOS.h" /********************************************************************* * * Types, local * ********************************************************************** */ // // Custom structure with task context extension. // 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 data * ********************************************************************** */ static OS_STACKPTR int StackHP[128], StackLP[128]; static OS_TASK TCBHP, TCBLP; static int GlobalVar; // Task stacks // Task control blocks /********************************************************************* * * Local functions * ********************************************************************** */ /********************************************************************* * * _Save() * * Function description * This function saves an extended task context. */ static void OS_STACKPTR* _Save(void OS_STACKPTR* pStack) { CONTEXT_EXTENSION* p; // // Create pointer to our structure // p = ((CONTEXT_EXTENSION*)pStack) - (1 - OS_STACK_AT_BOTTOM); // // Save all members of the structure // p->GlobalVar = GlobalVar; return (void OS_STACKPTR*)p; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 77 CHAPTER 2 API functions /********************************************************************* * * _Restore() * * Function description * This function restores an extended task context. */ static void OS_STACKPTR* _Restore(const void OS_STACKPTR* pStack) { const CONTEXT_EXTENSION* p; // // Create pointer to our structure // p = ((const CONTEXT_EXTENSION *)pStack) - (1 - OS_STACK_AT_BOTTOM); // // Restore all members of the structure // GlobalVar = p->GlobalVar; return (void OS_STACKPTR*)p; } /********************************************************************* * * Public API structure */ const OS_EXTEND_TASK_CONTEXT _SaveRestore = { _Save, // Function pointer to save the task context _Restore // Function pointer to restore the task context }; /********************************************************************* * * HPTask() * * Function description * During the execution of this function, the thread-specific * global variable GlobalVar always has the same value of 1. */ static void HPTask(void) { OS_TASK_SetContextExtension(&_SaveRestore); GlobalVar = 1; while (1) { OS_TASK_Delay(10); } } /********************************************************************* * * LPTask() * * Function description * During the execution of this function, the thread-specific * global variable GlobalVar always has the same value of 2. */ static void LPTask(void) { OS_TASK_SetContextExtension(&_SaveRestore); GlobalVar = 2; while (1) { OS_TASK_Delay(50); } } /********************************************************************* * * main() */ int main(void) { OS_Init(); // Initialize embOS OS_InitHW(); // Initialize required hardware UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 78 CHAPTER 2 API functions OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP); OS_TASK_CREATE(&TCBLP, "LP Task", 50, LPTask, StackLP); OS_Start(); // Start embOS return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 79 CHAPTER 2 2.4.23 API functions OS_TASK_SetDefaultContextExtension() Description Sets the default task context extension for newly created tasks. Prototype void OS_TASK_SetDefaultContextExtension (OS_CONST_PTR OS_EXTEND_TASK_CONTEXT *pExtendContext); Parameters 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. Additional information After calling this function all newly started tasks will automatically use this context extension. The same task context extension is used for all tasks. Example extern const OS_EXTEND_TASK_CONTEXT _SaveRestore; int main(void) { OS_Init(); // Initialize embOS OS_InitHW(); // Initialize required hardware OS_TASK_SetDefaultContextExtension(&_SaveRestore); OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP); OS_TASK_CREATE(&TCBLP, "LP Task", 50, LPTask, StackLP); OS_Start(); // Start embOS return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 80 CHAPTER 2 2.4.24 API functions OS_TASK_SetDefaultStartHook() Description Sets a default hook routine which is executed before a task starts. May be used to perform additional initialization for newly created tasks. Prototype void OS_TASK_SetDefaultStartHook(voidRoutine* pfHook); Parameters Parameter pfHook Description Pointer to the hook routine. If NULL is passed no hook routine gets executed. Additional information After calling OS_TASK_SetDefaultStartHook() all newly created tasks will automatically call this hook routine before the tasks are started for the first time. The same hook function is used for all tasks. Example void _HookRoutine(void) { DoSomeThing(); } // This routine is automatically executed before // HPTask() gets executed void HPTask(void) { while (1) { OS_TASK_Delay(10); } } int main(void) { OS_Init(); // Initialize embOS OS_InitHW(); // Initialize required hardware OS_TASK_SetDefaultStartHook(_HookRoutine); // Set task start hook routine OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP); OS_Start(); // Start embOS return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 81 CHAPTER 2 2.4.25 API functions OS_TASK_SetInitialSuspendCnt() Description Sets the initial suspend count for newly created tasks to 1 or 0. May be used to create tasks which are initially suspended. Prototype void OS_TASK_SetInitialSuspendCnt(OS_U8 SuspendCnt); Parameters Parameter SuspendCnt Description 1: Tasks will be created in suspended state. 0: Tasks will be created normally, unsuspended. 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. Note 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 // // High priority task started first after OS_Start(). // void InitTask(void) { OS_TASK_SuspendAll(); // Prevent execution of all other existing tasks. OS_TASK_SetInitialSuspendCnt(1); // Prevent execution of subsequently created tasks. ... // New tasks may be created, but will not execute. ... // Even when InitTask() blocks itself, no other task may execute. OS_TASK_SetInitialSuspendCnt(0); // Reset initial suspend count for new tasks. OS_TASK_ResumeAll(); // Resume all tasks that were blocked before or // were created in suspended state. May cause a // task switch. while (1) { ... // Do the normal work. } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 82 CHAPTER 2 2.4.26 API functions OS_TASK_SetName() Description Allows modification of a task name at runtime. Prototype void OS_TASK_SetName( OS_TASK* pTask, const char* s); Parameters Parameter Description pTask Pointer to a task control block structure. s Pointer to a null-terminated string which is used as task name. Additional information If NULL is passed for pTask, the currently running task is modified. However, NULL must not be passed for pTask from main(), from a timer callback or from an interrupt handler. A debug build of embOS will call OS_Error() in case pTask does not indicate a valid task. When using an embOS build without task name support, OS_TASK_SetName() performs no modifications at all. The embOS OS_LIBMODE_XR libraries do not support task names. Example void Task(void) { OS_TASK_SetName(NULL, "Initializer Task"); while (1) { OS_TASK_Delay(100); } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 83 CHAPTER 2 2.4.27 API functions OS_TASK_SetPriority() Description Assigns a priority to a specified task. Prototype void OS_TASK_SetPriority(OS_TASK* pTask, OS_PRIO Priority); Parameters Parameter Description pTask Pointer to a task control block structure or NULL for current task. Priority Priority of the task. Must be within the following range: 1 Priority 28 - 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. Additional information If NULL is passed for pTask, the currently running task is modified. However, NULL must not be passed for pTask from main(). A debug build of embOS will call OS_Error() in case pTask does not indicate a valid task. Calling this function might lead to an immediate task switch. Example void Task(void) { OS_TASK_SetPriority(NULL, 20); while (1) { OS_TASK_Delay(100); } } UM01001 User Guide & Reference Manual for embOS // Change priority of this task to 20. (c) 1995-2018 SEGGER Microcontroller GmbH 84 CHAPTER 2 2.4.28 API functions OS_TASK_SetTimeSlice() Description Assigns a specified timeslice period to a specified task. Prototype OS_U8 OS_TASK_SetTimeSlice(OS_TASK* pTask, OS_U8 TimeSlice); Parameters Parameter Description pTask Pointer to a task control block structure. TimeSlice New time slice period for the task. Must be within the following range: 0 TimeSlice 255. Return value Previous time slice period of the task. Additional information If NULL is passed for pTask, the currently running task is modified. However, NULL must not be passed for pTask from main(), a timer callback or from an interrupt handler. A debug build of embOS will call OS_Error() in case pTask does not indicate a valid task. Setting the time slice period only affects tasks running in round-robin mode. The new time slice period is interpreted as a reload value: It is used with the next activation of the task, but does 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 44). The function is unavailable when using an embOS build without round-robin support. The embOS OS_LIBMODE_XR libraries do not support round-robin. In that case OS_TASK_SetTimeSlice() does nothing and returns zero. Example void Task(void) { OS_TASK_SetTimeSlice(NULL, 4); while (1) { OS_TASK_Delay(100); } } UM01001 User Guide & Reference Manual for embOS // Give this task a higher time slice (c) 1995-2018 SEGGER Microcontroller GmbH 85 CHAPTER 2 2.4.29 API functions OS_TASK_Suspend() Description Suspends the specified task and increments a counter. Prototype void OS_TASK_Suspend(OS_TASK* pTask); Parameters Parameter pTask Description Pointer to a task control block structure. 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_TASK_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_TASK_Suspend() more often than the maximum value without calling OS_TASK_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 main(), an interrupt handler or software timer as this function may cause an immediate task switch. The debug build of embOS will call the OS_Error() function when OS_TASK_Suspend() is not called from a task. Example void HighPrioTask(void) { OS_TASK_Suspend(NULL); // Suspends itself, low priority task will be executed } void LowPrioTask(void) { OS_TASK_Resume(&HighPrioTCB); } // Resumes the high priority task UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 86 CHAPTER 2 2.4.30 API functions OS_TASK_SuspendAll() Description Suspends all tasks except the running task. Prototype void OS_TASK_SuspendAll(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_TASK_SuspendAll(), 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_TASK_Resume() or all at once by a call of OS_TASK_ResumeAll(). Example Please refer to the example of OS_TASK_SetInitialSuspendCnt(). UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 87 CHAPTER 2 2.4.31 API functions OS_TASK_Terminate() Description Ends (terminates) a task. Prototype void OS_TASK_Terminate(OS_TASK* pTask); Parameters Parameter pTask Description Pointer to the task control block structure of the task that shall be terminated. A value of NULL terminates the current task. Additional information The specified task will terminate immediately. The memory used for stack and task control block can be reassigned. All resources which are held by a task are released upon its termination. Any task may be terminated regardless of its state. Example void Task(void) { DoSomething(); OS_TASK_Terminate(NULL); } // Terminate itself UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 88 CHAPTER 2 2.4.32 API functions OS_TASK_Wake() Description Ends delay of a specified task immediately. Prototype void OS_TASK_Wake(OS_TASK* pTask); Parameters Parameter pTask Description Pointer to a task control block structure. Additional information Places the specified task, which is already suspended for a certain amount of time by a call of OS_TASK_Delay() or OS_TASK_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 (e.g. when it has already been activated, or the delay has already expired, or for some other reason), calling this function has no effect. Example #include "RTOS.h" static OS_STACKPTR int StackHP[128], StackLP[128]; static OS_TASK TCBHP, TCBLP; // Task stacks // Task control blocks static void HPTask(void) { while (1) { OS_TASK_Delay(50); } } static void LPTask(void) { while (1) { OS_TASK_Delay(10); OS_TASK_Wake(&TCBHP); // Wake HPTask which is in delay state } } /********************************************************************* * * main() */ int main(void) { OS_Init(); // Initialize embOS OS_InitHW(); // Initialize required hardware OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP); OS_TASK_CREATE(&TCBLP, "LP Task", 50, LPTask, StackLP); OS_Start(); // Start embOS return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 89 CHAPTER 2 2.4.33 API functions OS_TASK_Yield() Description Calls the scheduler to force a task switch. Prototype void OS_TASK_Yield(void); Additional information If the task is running on round-robin, it will be suspended if there is another task with equal priority ready for execution. Example #include "RTOS.h" static OS_STACKPTR int StackHP[128], StackLP[128]; static OS_TASK TCBHP, TCBLP; // Task stacks // Task control blocks static void HPTask(void) { while (1) { DoSomething(); } } static void LPTask(void) { while (1) { DoSomethingElse(); // // This task don't need the complete time slice. // Give another task with the same priority the chance to run // OS_TASK_Yield(); } } /********************************************************************* * * main() */ int main(void) { OS_Init(); // Initialize embOS OS_InitHW(); // Initialize required hardware OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP); OS_TASK_CREATE(&TCBLP, "LP Task", 100, LPTask, StackLP); OS_Start(); // Start embOS return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 3 Software Timers UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 91 3.1 CHAPTER 3 Introduction 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_TIMER_CREATE(). 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 exactly once and call their callback routine exactly once. By calling OS_TIMER_Restart() 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_TIMER_GetStatus(), OS_TIMER_GetRemainingPeriod() and OS_TIMER_GetPeriod(). Example #include "RTOS.h" #include "BSP.h" static OS_TIMER TIMER50, TIMER200; static void Timer50(void) { BSP_ToggleLED(0); OS_TIMER_Restart(&TIMER50); } static void Timer200(void) { BSP_ToggleLED(1); OS_TIMER_Restart(&TIMER200); } int main(void) { OS_Init(); // Initialize embOS OS_InitHW(); // Initialize required hardware BSP_Init(); // Initialize LED ports OS_TIMER_CREATE(&TIMER50, Timer50, 50); OS_TIMER_CREATE(&TIMER200, Timer200, 200); OS_Start(); // Start embOS return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 92 CHAPTER 3 Introduction Minimum timeout / period Software timer periods elapse with the appropriate embOS system tick. This means that the actual timeout period can actually be slightly shorter than the configured timeout period. For example, if the system tick is configured to occur once every msec, and the timer is configured for a timeout of 1, the actual timeout duration is somewhere between 0 and 1 msec. The following diagram illustrates how software timer timeouts work. We can see that the timer configuration is performed prior to the first system tick, that is: at system time 0. The timeout period is configured to 5 system ticks, therefore the callback is called upon the 5th system tick. For example, if the the system ticks occurs at 1 msec, 2 msec, (...), 5 msec, and the timer was started at 0.8 msec, the actual timer period would equal 4.2 msec. Maximum timeout / period The timeout value is stored as an integer, thus a 16 bit value on 8/16 bit CPUs, a 32 bit 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 system ticks in a critical region and defined a macro for 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 ensure 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 Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 93 3.2 CHAPTER 3 API functions API functions Timer ISR Task Description main Routine OS_TIMER_CREATE() Macro that creates and starts a software timer. OS_TIMER_Create() Creates a software timer without starting it. OS_TIMER_CREATEEX() Macro that creates and starts an extended software timer. OS_TIMER_CreateEx() Creates an extended software timer without starting it. OS_TIMER_Delete() Stops and deletes a software timer. OS_TIMER_DeleteEx() Stops and deletes an extended software timer. OS_TIMER_GetCurrent() Returns a pointer to the data structure of the timer that just expired. OS_TIMER_GetCurrentEx() Returns a pointer to the data structure of the extended software timer that just expired. OS_TIMER_GetPeriod() Returns the current reload value of a software timer. OS_TIMER_GetPeriodEx() Returns the current reload value of an extended software timer. OS_TIMER_GetRemainingPeriod() Returns the remaining timer value of a software timer. OS_TIMER_GetRemainingPeriodEx() Returns the remaining timer value of an extended software timer. OS_TIMER_GetStatus() Returns the current timer status of a software timer. OS_TIMER_GetStatusEx() Returns the current timer status of an extended software timer. OS_TIMER_Restart() Restarts a software timer with its initial time value. OS_TIMER_RestartEx() Restarts an extended software timer with its initial time value. OS_TIMER_SetPeriod() Sets a new timer reload value for a software timer. OS_TIMER_SetPeriodEx() Sets a new timer reload value for an extended software timer. OS_TIMER_Start() Starts a software timer. OS_TIMER_StartEx() Starts an extended software timer. OS_TIMER_Stop() Stops a software timer. OS_TIMER_StopEx() Stops an extended software timer. OS_TIMER_Trigger() Ends a software timer at once and calls the timer callback function. OS_TIMER_TriggerEx() Ends an extended software timer at once and calls the timer callback function. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 94 CHAPTER 3 3.2.1 API functions OS_TIMER_CREATE() Description Macro that creates and starts a software timer. Prototype void OS_TIMER_CREATE(OS_TIMER* pTimer, OS_TIMERROUTINE* Callback, OS_TIME Period); Parameters Parameter Description pTimer Pointer to the OS_TIMER data structure which contains the data of the timer. Callback 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 parameters and does not return any value. Period Initial period in embOS system ticks. The data type OS_TIME is defined as an integer, therefore valid values are: 1 Period 215 - 1 = 0x7FFF for 8/16 bit CPUs 1 Period 231 - 1 = 0x7FFFFFFF for 32 bit CPUs Additional information embOS keeps track of the timers by using a linked list. Once the period 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_TIMER_Create() and OS_TIMER_Start(). 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_TIMER_CREATE(pTimer, c, d) \ OS_TIMER_Create(pTimer, c, d); \ OS_TIMER_Start(pTimer); Example static OS_TIMER TIMER100; static void Timer100(void) { BSP_ToggleLED(0); OS_TIMER_Restart(&TIMER100); } // Make timer periodic void InitTask(void) { // // Create and implicitly start Timer100 // OS_TIMER_CREATE(&TIMER100, Timer100, 100); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 95 CHAPTER 3 3.2.2 API functions OS_TIMER_Create() Description Creates a software timer without starting it. Prototype void OS_TIMER_Create(OS_TIMER* pTimer, OS_TIMERROUTINE* Callback, OS_TIME Period); Parameters Parameter Description pTimer Pointer to the OS_TIMER data structure which contains the data of the timer. Callback Pointer to the callback routine to be called by the RTOS after expiration of the delay. Period Initial period in embOS system ticks. The data type OS_TIME is defined as an integer, therefore valid values are: 1 Period 215 - 1 = 0x7FFF for 8/16 bit CPUs. 1 Period 231 - 1 = 0x7FFFFFFF for 32 bit CPUs. Additional information embOS keeps track of the timers by using a linked list. Once the period 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_TIMER_Start() or OS_TIMER_Restart(). OS_TIMERROUTINE is defined in RTOS.h as follows: typedef void OS_TIMERROUTINE(void); Example static OS_TIMER TIMER100; static void Timer100(void) { BSP_ToggleLED(0); OS_TIMER_Restart(&TIMER100); } // Make timer periodic void InitTask(void) { // // Create Timer100, but start it seperately // OS_TIMER_Create(&TIMER100, Timer100, 100); OS_TIMER_Start(&TIMER100); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 96 CHAPTER 3 3.2.3 API functions OS_TIMER_CREATEEX() Description Macro that creates and starts an extended software timer. Prototype void OS_TIMER_CREATEEX(OS_TIMER_EX* OS_TIMER_EX_ROUTINE* OS_TIME void* pTimerEx, Callback, Period, pData); Parameters Parameter Description pTimerEx Pointer to the OS_TIMER_EX data structure which contains the data of the extended software timer. Callback 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. Period Initial period in embOS system ticks. The data type OS_TIME is defined as an integer, therefore valid values are: 1 Period 215 - 1 = 0x7FFF for 8/16 bit CPUs 1 Period 231 - 1 = 0x7FFFFFFF for 32 bit CPUs pData A void pointer which is used as parameter for the extended timer callback function. Additional information embOS keeps track of the timers by using a linked list. Once the period 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_TIMER_CreateEx() and OS_TIMER_StartEx(). 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_TIMER_CREATEEX(pTimerEx, cb, Period, pData) OS_TIMER_CreateEx(pTimerEx, cb, Period, pData); OS_TIMER_StartEx(pTimerEx) \ \ Example static OS_TIMER_EX TIMER100; static OS_TASK TCB_HP; static void Timer100(void* pTask) { if (pTask != NULL) { OS_TASKEVENT_Set(0x01, (OS_TASK*)pTask); } OS_TIMER_RestartEx(&TIMER100); // Make timer periodic } void InitTask(void) { // UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 97 CHAPTER 3 API functions // Create and implicitly start Timer100 // OS_TIMER_CREATEEX(&TIMER100, Timer100, 100, (void*)&TCB_HP); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 98 CHAPTER 3 3.2.4 API functions OS_TIMER_CreateEx() Description Creates an extended software timer without starting it. Prototype void OS_TIMER_CreateEx(OS_TIMER_EX* OS_TIMER_EX_ROUTINE* OS_TIME void* pTimerEx, Callback, Period, pData); Parameters Parameter Description pTimerEx Pointer to the OS_TIMER_EX data structure which contains the data of the extended software timer. Callback Pointer to the callback routine of type OS_TIMER_EX_ROUTINE to be called by the RTOS after expiration of the timer. Period Initial period in embOS system ticks. The data type OS_TIME is defined as an integer, therefore valid values are: 1 Period 215 - 1 = 0x7FFF for 8/16 bit CPUs. 1 Period 231 - 1 = 0x7FFFFFFF for 32 bit CPUs. pData A void pointer which is used as parameter for the extended timer callback function. Additional information embOS keeps track of the timers by using a linked list. Once the period 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_TIMER_StartEx() or OS_TIMER_RestartEx(). OS_TIMER_EX_ROUTINE is defined in RTOS.h as follows: typedef void OS_TIMER_EX_ROUTINE(void *pVoid); Example static OS_TIMER_EX TIMER100; static OS_TASK TCB_HP; static void Timer100(void* pTask) { if (pTask != NULL) { OS_TASKEVENT_Set(0x01, (OS_TASK*)pTask); } OS_TIMER_RestartEx(&TIMER100); // Make timer periodic } void InitTask(void) { // // Create Timer100, but start it seperately // OS_TIMER_CreateEx(&TIMER100, Timer100, 100, (void*)&TCB_HP); OS_TIMER_Start(&TIMER100); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 99 CHAPTER 3 3.2.5 API functions OS_TIMER_Delete() Description Stops and deletes a software timer. Prototype void OS_TIMER_Delete(OS_TIMER* pTimer); Parameters Parameter pTimer Description Pointer to the OS_TIMER data structure which contains the data of the timer. 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 Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 100 CHAPTER 3 3.2.6 API functions OS_TIMER_DeleteEx() Description Stops and deletes an extended software timer. Prototype void OS_TIMER_DeleteEx(OS_TIMER_EX* pTimerEx); Parameters Parameter pTimerEx Description Pointer to the OS_TIMER_EX data structure which contains the data of the timer. 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 Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 101 CHAPTER 3 3.2.7 API functions OS_TIMER_GetCurrent() Description Returns a pointer to the data structure of the software timer that just expired. Prototype OS_TIMER* OS_TIMER_GetCurrent(void); Return value A pointer to the control structure of a timer. Additional information The return value of OS_TIMER_GetCurrent() 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_TIMER_GetCurrent(). 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" typedef struct { OS_TIMER Timer; void* pUser; } TIMER_EX; // OS_TIMER has to be the first element // Any other data type may be used to extend the struct static TIMER_EX Timer_User; static int a; static void _cb(void) { TIMER_EX* p = (TIMER_EX*)OS_TIMER_GetCurrent(); void* pUser = p->pUser; // Examine user data OS_TIMER_Restart(&p->Timer); // Make timer periodic } static void _CreateTimer(TIMER_EX* timer, OS_TIMERROUTINE* Callback, OS_UINT Period, void* pUser) { timer->pUser = pUser; OS_TIMER_Create(&timer->Timer, Callback, Period); } int main(void) { OS_Init(); // Initialize embOS OS_InitHW(); // Initialize required hardware _CreateTimer(&Timer_User, _cb, 100, &a); OS_Start(); // Start embOS return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 102 CHAPTER 3 3.2.8 API functions OS_TIMER_GetCurrentEx() Description Returns a pointer to the data structure of the extended software timer that just expired. Prototype OS_TIMER_EX* OS_TIMER_GetCurrentEx(void); Return value A pointer to the control structure of an extended software timer. Additional information The return value of OS_TIMER_GetCurrentEx() 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 OS_TIMER_EX MyTimerEx; static void _cbTimerEx(void* pData) { OS_TIMER_EX* pTimerEx = OS_TIMER_GetCurrentEx(); OS_TASKEVENT_Set(0x01, (OS_TASK*)pData); OS_TIMER_Restart(pTimerEx); // Make timer periodic } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 103 CHAPTER 3 3.2.9 API functions OS_TIMER_GetPeriod() Description Returns the current reload value of a software timer. Prototype OS_TIME OS_TIMER_GetPeriod(OS_CONST_PTR OS_TIMER *pTimer); Parameters Parameter pTimer Description Pointer to the OS_TIMER data structure which contains the data of the timer. Return value Type OS_TIME, which is defined as an integer between * * 1 and 215 - 1 = 0x7FFF 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_TIMER_SetPeriod(). This reload value will be used as time period when the timer is retriggered by OS_TIMER_Restart(). UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 104 CHAPTER 3 3.2.10 API functions OS_TIMER_GetPeriodEx() Description Returns the current reload value of an extended software timer. Prototype OS_TIME OS_TIMER_GetPeriodEx(OS_TIMER_EX* pTimerEx); Parameters Parameter pTimerEx Description Pointer to the OS_TIMER_EX data structure which contains the data of the extended timer. Return value Type OS_TIME, which is defined as an integer between * * 1 and 215 - 1 = 0x7FFF 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_TIMER_SetPeriodEx(). This reload value will be used as time period when the timer is retriggered by OS_TIMER_RestartEx(). UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 105 CHAPTER 3 3.2.11 API functions OS_TIMER_GetRemainingPeriod() Description Returns the remaining timer value of a software timer. Prototype OS_TIME OS_TIMER_GetRemainingPeriod(OS_CONST_PTR OS_TIMER *pTimer); Parameters Parameter pTimer Description Pointer to the OS_TIMER data structure which contains the data of the timer. Return value Type OS_TIME, which is defined as an integer between * * 1 and 215 - 1 = 0x7FFF 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 timer value is the remaining timer time in embOS system ticks until expiration of the timer. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 106 CHAPTER 3 3.2.12 API functions OS_TIMER_GetRemainingPeriodEx() Description Returns the remaining timer value of an extended software timer. Prototype OS_TIME OS_TIMER_GetRemainingPeriodEx(OS_TIMER_EX* pTimerEx); Parameters Parameter pTimerEx Description Pointer to the OS_TIMER_EX data structure which contains the data of the timer. Return value Type OS_TIME, which is defined as an integer between * * 1 and 215 - 1 = 0x7FFF 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 system ticks until expiration of the extended software timer. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 107 CHAPTER 3 3.2.13 API functions OS_TIMER_GetStatus() Description Returns the current timer status of a software timer. Prototype OS_BOOL OS_TIMER_GetStatus(OS_CONST_PTR OS_TIMER *pTimer); Parameters Parameter Description Pointer to the OS_TIMER data structure which contains the data of the timer. pTimer Return value Denotes whether the specified timer is running or not: =0 0 Timer has stopped. Timer is running. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 108 CHAPTER 3 3.2.14 API functions OS_TIMER_GetStatusEx() Description Returns the current timer status of an extended software timer. Prototype OS_BOOL OS_TIMER_GetStatusEx(OS_TIMER_EX* pTimerEx); Parameters Parameter pTimerEx Description Pointer to the OS_TIMER_EX data structure which contains the data of the extended timer. Return value Denotes whether the specified timer is running or not: =0 0 Timer has stopped. Timer is running. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 109 CHAPTER 3 3.2.15 API functions OS_TIMER_Restart() Description Restarts a software timer with its initial time value. Prototype void OS_TIMER_Restart(OS_TIMER* pTimer); Parameters Parameter pTimer Description Pointer to the OS_TIMER data structure which contains the data of the timer. Additional information OS_TIMER_Restart() restarts the timer using the initial time value programmed at creation of the timer or with the function OS_TIMER_SetPeriod(). OS_TIMER_Restart() 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 Please refer to the example for OS_TIMER_CREATE(). UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 110 CHAPTER 3 3.2.16 API functions OS_TIMER_RestartEx() Description Restarts an extended software timer with its initial time value. Prototype void OS_TIMER_RestartEx(OS_TIMER_EX* pTimerEx); Parameters Parameter pTimerEx Description Pointer to the OS_TIMER_EX data structure which contains the data of the extended software timer. Additional information OS_TIMER_RestartEx() 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_TIMER_SetPeriodEx(). OS_TIMER_RestartEx() 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 Please refer to the example for OS_TIMER_CREATEEX(). UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 111 CHAPTER 3 3.2.17 API functions OS_TIMER_SetPeriod() Description Sets a new timer reload value for a software timer. Prototype void OS_TIMER_SetPeriod(OS_TIMER* pTimer, OS_TIME Period); Parameters Parameter Description pTimer Pointer to the OS_TIMER data structure which contains the data of the timer. Period Timer period in embOS system ticks. The data type OS_TIME is defined as an integer, therefore valid values are: 1 Period 215 - 1 = 0x7FFF for 8/16 bit CPUs. 1 Period 231 - 1 = 0x7FFFFFFF for 32 bit CPUs. Additional information OS_TIMER_SetPeriod() 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_TIMER_Restart(). Example static OS_TIMER TIMERPulse; static void TimerPulse(void) { TogglePulseOutput(); OS_TIMER_Restart(&TIMERPulse); } // Toggle output // Make timer periodic void InitTask(void) { // // Create and implicitly start timer with first pulse in 500 system ticks // OS_TIMER_CREATE(&TIMERPulse, TimerPulse, 500); // // Set timer period to 200 system ticks for further pulses // OS_TIMER_SetPeriod(&TIMERPulse, 200); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 112 CHAPTER 3 3.2.18 API functions OS_TIMER_SetPeriodEx() Description Sets a new timer reload value for an extended software timer. Prototype void OS_TIMER_SetPeriodEx(OS_TIMER_EX* pTimerEx, OS_TIME Period); Parameters Parameter Description pTimerEx Pointer to the OS_TIMER_EX data structure which contains the data of the extended software timer. Period Initial period in embOS system ticks. The data type OS_TIME is defined as an integer, therefore valid values are: 1 Period 215 - 1 = 0x7FFF for 8/16 bit CPUs 1 Period 231 - 1 = 0x7FFFFFFF for 32 bit CPUs Additional information OS_TIMER_SetPeriodEx() 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_TIMER_RestartEx(). A call of OS_TIMER_SetPeriodEx() does not affect the remaining time period of an extended software timer. Example static OS_TIMER_EX TIMERPulse; static OS_TASK TCB_HP; static void TimerPulse(void* pTask) { if (pTask != NULL) { OS_TASKEVENT_Set(0x01, (OS_TASK*)pTask); } OS_TIMER_RestartEx(&TIMERPulse); // Make timer periodic } void InitTask(void) { // // Create and implicitly start Pulse Timer with first pulse in 500 system ticks // OS_TIMER_CREATEEX(&TIMERPulse, TimerPulse, 500, (void*)&TCB_HP); // // Set timer period to 200 system ticks for further pulses // OS_TIMER_SetPeriodEx(&TIMERPulse, 200); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 113 CHAPTER 3 3.2.19 API functions OS_TIMER_Start() Description Starts a software timer. Prototype void OS_TIMER_Start(OS_TIMER* pTimer); Parameters Parameter pTimer Description Pointer to the OS_TIMER data structure which contains the data of the timer. Additional information OS_TIMER_Start() is used for the following reasons: * * Start a timer which was created by OS_TIMER_Create(). The timer will start with its initial timer value. Restart a timer which was stopped by calling OS_TIMER_Stop(). In this case, the timer will continue with the remaining time value which was preserved upon stopping the timer. Note This function has no effect on running timers. It also has no effect on timers that are not running, but have expired: use OS_TIMER_Restart() to restart those timers. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 114 CHAPTER 3 3.2.20 API functions OS_TIMER_StartEx() Description Starts an extended software timer. Prototype void OS_TIMER_StartEx(OS_TIMER_EX* pTimerEx); Parameters Parameter pTimerEx Description Pointer to the OS_TIMER_EX data structure which contains the data of the extended software timer. Additional information OS_TIMER_StartEx() is used for the following reasons: * * Start an extended software timer which was created by OS_TIMER_CreateEx(). The timer will start with its initial timer value. Restart a timer which was stopped by calling OS_TIMER_StopEx(). In this case, the timer will continue with the remaining time value which was preserved upon stopping the timer. Note This function has no effect on running timers. It also has no effect on timers that are not running, but have expired. Use OS_TIMER_RestartEx() to restart those timers. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 115 CHAPTER 3 3.2.21 API functions OS_TIMER_Stop() Description Stops a software timer. Prototype void OS_TIMER_Stop(OS_TIMER* pTimer); Parameters Parameter pTimer Description Pointer to the OS_TIMER data structure which contains the data of the timer. Additional information The actual value of the timer (the time until expiration) is maintained until OS_TIMER_Start() lets the timer continue. The function has no effect on timers that are not running, but have expired. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 116 CHAPTER 3 3.2.22 API functions OS_TIMER_StopEx() Description Stops an extended software timer. Prototype void OS_TIMER_StopEx(OS_TIMER_EX* pTimerEx); Parameters Parameter pTimerEx Description Pointer to the OS_TIMER_EX data structure which contains the data of the extended software timer. Additional information The actual time value of the extended software timer (the time until expiration) is maintained until OS_TIMER_StartEx() lets the timer continue. The function has no effect on timers that are not running, but have expired. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 117 CHAPTER 3 3.2.23 API functions OS_TIMER_Trigger() Description Ends a software timer at once and calls the timer callback function. Prototype void OS_TIMER_Trigger(OS_TIMER* pTimer); Parameters Parameter pTimer Description Pointer to the OS_TIMER data structure which contains the data of the timer. Additional information OS_TIMER_Trigger() can be called regardless of the state of the timer. A running timer will be stopped and the callback function is called. For a timer that was stopped before or had expired the callback function will not be executed. Example static OS_TIMER TIMERUartRx; void TimerUart(void) { HandleUartRx(); } void UartRxIntHandler(void) { OS_TIMER_Trigger(&TIMERUartRx); } // Character received, stop the software timer void UartSendNextCharachter(void) { OS_TIMER_Start(&TIMERUartRx); // Send next uart character and wait for Rx character } int main(void) { OS_TIMER_Create(&TIMERUartRx, TimerUart, 20); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 118 CHAPTER 3 3.2.24 API functions OS_TIMER_TriggerEx() Description Ends an extended software timer at once and calls the timer callback function. Prototype void OS_TIMER_TriggerEx (OS_TIMER_EX* pTimerEx); Parameters Parameter pTimerEx Description Pointer to the OS_TIMER_EX data structure which contains the data of the extended software timer. Additional information OS_TIMER_TriggerEx() can be called regardless of the state of the timer. A running timer will be stopped and the callback function is called. For a timer that was stopped before or had expired the callback function will not be executed. Example static OS_TIMER_EX TIMERUartRx; static OS_U32 UartNum; void TimerUart(void* pNum) { HandleUartRx((OS_U32)pNum); } void UartRxIntHandler(void) { OS_TIMER_TriggerEx(&TIMERUartRx); // Character received, stop the software timer } void UartSendNextCharachter(void) { OS_TIMER_StartEx(&TIMERUartRx); // Send next uart character and wait for Rx character } int main(void) { UartNum = 0; OS_TIMER_CreateEx(&TIMERUartRx, TimerUart, 20, (void*)&UartNum); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 4 Task Events UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 120 4.1 CHAPTER 4 Introduction Introduction Task events are another way of communicating 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 software timer or an interrupt handler. An event can be, 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 by default is the width of an unsigned integer, usually the word size of the target processor. This means that 32 or 8 different events can be signaled to and distinguished by every task. By calling OS_TASKEVENT_GetBlocked(), 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_TASKEVENT_Set(). 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 tasks in the READY state. By changing the definition of OS_TASKEVENT, which is defined as unsigned long on 32 bit 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 individual events, or reduced to smaller data types on 32 bit CPUs. Changing the definition of OS_TASKEVENT can only be done when using the embOS sources in a project, or when the libraries are rebuilt from sources with the modified definition. Example #include "RTOS.h" static OS_STACKPTR int StackHP[128], StackLP[128]; static OS_TASK TCBHP, TCBLP; static OS_TASKEVENT MyEvents; static void HPTask(void) { while (1) { MyEvents = OS_TASKEVENT_GetBlocked(3); if (MyEvents & 1) { _HandleEvent0(); } else _HandleEvent1(); } } } // Task stacks // Task control blocks // Wait for event bits 0 or 1 static void LPTask(void) { while (1) { OS_TASK_Delay(200); OS_TASKEVENT_Set(&TCBHP, 1); } } int main(void) { OS_Init(); // Initialize embOS OS_InitHW(); // Initialize required hardware OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP); OS_TASK_CREATE(&TCBLP, "LP Task", 50, LPTask, StackLP); OS_Start(); // Start embOS return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 121 4.2 CHAPTER 4 API functions API functions Timer ISR Task Description main Routine OS_TASKEVENT_Clear() Returns the actual state of events and then clears all events of a specified task. OS_TASKEVENT_ClearEx() Returns the actual state of events and then clears the specified events for the specified task. OS_TASKEVENT_Get() Returns a list of events that have occurred for a specified task. Waits for one of the events specified in the OS_TASKEVENT_GetBlocked() bitmask and clears the event memory when the function returns. OS_TASKEVENT_GetSingleBlocked() Waits for one of the specified events and clears only those events that were specified in the event mask. OS_TASKEVENT_GetSingleTimed() Waits for one of the specified events for a given time and clears only those events that were specified in the event mask. OS_TASKEVENT_GetTimed() Waits for the specified events for a given time, and clears the event memory when the function returns. OS_TASKEVENT_Set() Signals event(s) to a specified task. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 122 CHAPTER 4 4.2.1 API functions OS_TASKEVENT_Clear() Description Returns the actual state of events and then clears all events of a specified task. Prototype OS_TASKEVENT OS_TASKEVENT_Clear(OS_TASK* pTask); Parameters Parameter pTask Description The task whose event mask is to be returned, NULL means current task. Return value All events that have been signaled before clearing. If pTask is NULL, the function clears all events of the currently running task. Additional information If NULL is passed for pTask, the currently running task is used. However, NULL must not be passed for pTask from main(), a timer callback or from an interrupt handler. A debug build of embOS will call OS_Error() in case pTask does not indicate a valid task. Example void Task(void) { OS_TASKEVENT MyEvents; MyEvents = OS_TASKEVENT_Clear(NULL); while (1) { // Wait for event 0 or 1 to be signaled MyEvents = OS_TASKEVENT_GetBlocked(3); } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 123 CHAPTER 4 4.2.2 API functions OS_TASKEVENT_ClearEx() Description Returns the actual state of events and then clears the specified events for the specified task. Prototype OS_TASKEVENT OS_TASKEVENT_ClearEx(OS_TASK* pTask, OS_TASKEVENT EventMask); Parameters Parameter Description pTask The task whose event mask is to be returned, NULL means current task. EventMask The bit mask containing the event bits which shall be cleared. Return value All events that have been signaled before clearing. If pTask is NULL, the function clears the events of the currently running task. Additional information If NULL is passed for pTask, the currently running task is used. However, NULL must not be passed for pTask from main(), a timer callback or from an interrupt handler. A debug build of embOS will call OS_Error() in case pTask does not indicate a valid task. Example void Task(void) { OS_TASKEVENT MyEvents; MyEvents = OS_TASKEVENT_ClearEx(NULL, 1); while (1) { // Wait for event 0 or 1 to be signaled MyEvents = OS_TASKEVENT_GetBlocked(3); } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 124 CHAPTER 4 4.2.3 API functions OS_TASKEVENT_Get() Description Returns a list of events that have occurred for a specified task. Prototype OS_TASKEVENT OS_TASKEVENT_Get(OS_CONST_PTR OS_TASK *pTask); Parameters Parameter pTask Description The task whose event mask is to be returned, NULL means current task. Return value All events that have been signaled. Additional information If NULL is passed for pTask, the currently running task is used. However, NULL must not be passed for pTask from main(), a timer callback or from an interrupt handler. A debug build of embOS will call OS_Error() in case pTask does not indicate a valid task. By calling this function, all events remain signaled: event memory is not cleared. This is one way for a task to query which events are signaled. The task is not suspended if no events are signaled. If pTask is NULL, the function clears the events of the currently running task. void PrintEvents(void) { OS_TASKEVENT MyEvents; MyEvents = OS_TASKEVENT_Get(NULL); printf("Events %u\n", MyEvents); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 125 CHAPTER 4 4.2.4 API functions OS_TASKEVENT_GetBlocked() Description Waits for one of the events specified in the bitmask and clears the event memory when the function returns. Prototype OS_TASKEVENT OS_TASKEVENT_GetBlocked(OS_TASKEVENT EventMask); Parameters Parameter EventMask Description The event bit mask containing the event bits, which shall be waited for. Return value All events that have been signaled. 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 software timer or an interrupt handler. Any bit that is set in the event mask enables the corresponding event. When a task waits on multiple events, all of the specified events shall be requested by a single call of OS_TASKEVENT_GetBlocked() 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 set in the parameters in the eventmask. Consecutive calls of OS_TASKEVENT_GetBlocked() with different event masks will not work, as all events are cleared when the function returns. Events may be lost. OS_TASKEVENT_GetSingleBlocked() may be used for this case. Example void Task(void) { OS_TASKEVENT MyEvents; while(1) { MyEvents = OS_TASKEVENT_GetBlocked(3); 1 to be signaled // // Handle ALL events // if (MyEvents & (1 << 0)) { _HandleEvent0(); } if (MyEvents & (1 << 1)) { _HandleEvent1(); } } } // Wait for event 0 or For another example, see OS_TASKEVENT_Set(). UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 126 CHAPTER 4 4.2.5 API functions OS_TASKEVENT_GetSingleBlocked() Description Waits for one of the specified events and clears only those events that were specified in the event mask. Prototype OS_TASKEVENT OS_TASKEVENT_GetSingleBlocked(OS_TASKEVENT EventMask); Parameters Parameter EventMask Description The event bit mask containing the event bits, which shall be waited for and reset. Return value All requested events that have been signaled and were specified in the EventMask. 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 software 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_TASKEVENT_GetSingleBlocked() 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. Example void Task(void) { OS_TASKEVENT MyEvents; while(1) { MyEvents = OS_TASKEVENT_GetSingleBlocked(3); 1 to be signaled // // Handle ALL events // if (MyEvents & (1 << 0)) { _HandleEvent0(); } if (MyEvents & (1 << 1)) { _HandleEvent1(); } OS_TASKEVENT_GetSingleBlocked(1 << 2); 2 to be signaled _HandleEvent2(); OS_TASKEVENT_GetSingleBlocked(1 << 3); 3 to be signaled _HandleEvent3(); } } UM01001 User Guide & Reference Manual for embOS // Wait for event 0 or // Wait for event // Wait for event (c) 1995-2018 SEGGER Microcontroller GmbH 127 CHAPTER 4 4.2.6 API functions OS_TASKEVENT_GetSingleTimed() Description Waits for one of the specified events for a given time and clears only those events that were specified in the event mask. Prototype OS_TASKEVENT OS_TASKEVENT_GetSingleTimed(OS_TASKEVENT EventMask, OS_TIME TimeOut); Parameters Parameter Description EventMask The event bit mask containing the event bits, which shall be waited for and reset. TimeOut Maximum time in embOS system 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 for 8/16 bit CPUs. 1 TimeOut 231 - 1 = 0x7FFFFFFF for 32 bit CPUs. Return value All requested events that have been signaled and were specified in the EventMask. 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 software 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. Example void Task(void) { OS_TASKEVENT MyEvents; while(1) { MyEvents = OS_TASKEVENT_GetSingleTimed(3, 10); 1 to be // Wait for event 0 or // signaled within 10ms /* Handle requested events */ if (MyEvents == 0) { _HandleTimeout; } else { if (MyEvents & (1 << 0)) { _HandleEvent0(); } if (MyEvents & (1 << 1)) { _HandleEvent1(); } } if (OS_TASKEVENT_GetSingleBlocked((1 << 2), 10) == 0) { _HandleTimeout(); } else { _HandleEvent2(); } } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 128 CHAPTER 4 4.2.7 API functions OS_TASKEVENT_GetTimed() Description Waits for the specified events for a given time, and clears the event memory when the function returns. Prototype OS_TASKEVENT OS_TASKEVENT_GetTimed(OS_TASKEVENT EventMask, OS_TIME TimeOut); Parameters Parameter Description EventMask The event bit mask containing the event bits, which shall be waited for. TimeOut Maximum time in embOS system ticks waiting for events to be signaled. The data type OS_TIME is defined as an integer, therefore valid values are: 1 TimeOut 215 - 1 = 0x7FFF for 8/16 bit CPUs. 1 TimeOut 231 - 1 = 0x7FFFFFFF for 32 bit CPUs. Return value All events that have been signaled. 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 software 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 signaled 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 handle the returned value. Consecutive calls of OS_TASKEVENT_GetTimed() with different event masks will not work, as all events are cleared when the function returns. Events may got lost. OS_TASKEVENT_GetSingleTimed() may be used for this case. Example void Task(void) { OS_TASKEVENT MyEvents; while(1) { MyEvents = OS_TASKEVENT_GetTimed(3, 10); if ((MyEvents & 0x3) == 0) { _HandleTimeout(); } else { if (MyEvents & (1 << 0)) { _HandleEvent0(); } if (MyEvents & (1 << 1)) { _HandleEvent1(); } } } // Wait for events 0+1 for 10 msec } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 129 CHAPTER 4 4.2.8 API functions OS_TASKEVENT_Set() Description Signals event(s) to a specified task. Prototype void OS_TASKEVENT_Set(OS_TASK* pTask, OS_TASKEVENT Event); Parameters Parameter Description pTask Pointer to the task control block. Event The event bit mask containing the event bits, which shall be signaled. 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. 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): #define EVENT_KEYPRESSED (1u << 0) #define EVENT_SERIN (1u << 1) static OS_STACKPTR int Stack0[96]; static OS_TASK TCB0; // Task stacks // Data area for tasks (task control blocks) void Task0(void) { OS_TASKEVENT MyEvent; while(1) MyEvent = OS_TASKEVENT_GetBlocked(EVENT_KEYPRESSED | EVENT_SERIN) if (MyEvent & EVENT_KEYPRESSED) { // Handle key press } if (MyEvent & EVENT_SERIN) { // Handle serial reception } } } void Key_ISR(void) { OS_TASKEVENT_Set(&TCB0, EVENT_KEYPRESSED); } // ISR for external interrupt // Notify task that key was pressed void UART_ISR(void) { // ISR for uart interrupt OS_TASKEVENT_Set(&TCB0, EVENT_SERIN); // Notify task that a character was received } void InitTask(void) { OS_TASK_CREATE(&TCB0, "HPTask", 100, Task0, Stack0); } If the task was only waiting for a key to be pressed, OS_MAILBOX_GetBlocked() could simply be called. The task would then be deactivated until a key is pressed. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 5 Event Objects UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 131 CHAPTER 5 5.1 Introduction Introduction Event objects are another type of communication and synchronization object. 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 software timer, or an interrupt handler. An event can be, 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. Compared to a task event, the signaling function does not need to know which task is waiting for the event to occur. Reset mode 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. An exception to this is when a task called OS_EVENT_GetTimed() and the timeout expired before the event was signaled, in which case the function returns with timeout and the event is not cleared automatically. 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. Mask mode Since version 4.34 of embOS, the mask bits behavior of the event object can be controlled by different mask modes which may be passed to the new function OS_EVENT_CreateEx() or may be modified by a call of OS_EVENT_SetMaskMode(). * * OS_EVENT_MASK_MODE_OR_LOGIC: This mask mode is the default mode. Only one of the bits specified in the event object bit mask must be signaled. OS_EVENT_MASK_MODE_AND_LOGIC: With this mode all specified event object mask bits must be signaled. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 132 CHAPTER 5 5.1.1 Introduction Examples of using event objects This section shows some examples on how to use event objects in an application. 5.1.1.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 _Event; static void _ISRHandler(void) { OS_INT_Enter(); // // Wake up task to do the rest of the work // OS_EVENT_Set(&_Event); OS_INT_LEAVE(); } static void Task(void) { while (1) { OS_EVENT_GetBlocked(&_Event); // // Do the rest of the work (which has not been done in the ISR) // ... } } 5.1.1.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" folder. #include "RTOS.h" /********************************************************************* * * Static data * ********************************************************************** */ static OS_STACKPTR int StackHP[128], StackLP[128], StackHW[128]; static OS_TASK TCBHP, TCBLP, TCBHW; static OS_EVENT HW_Event; /********************************************************************* * * HPTask() */ static void HPTask(void) { // // Wait until HW module is set up // OS_EVENT_GetBlocked(&HW_Event); while (1) { OS_TASK_Delay(50); } } /********************************************************************* * * LPTask() */ UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 133 CHAPTER 5 Introduction static void LPTask(void) { // // Wait until HW module is set up // OS_EVENT_GetBlocked(&HW_Event); while (1) { OS_TASK_Delay(200); } } /********************************************************************* * * HWTask() */ static void HWTask(void) { // // Wait until HW module is set up // OS_TASK_Delay(100); // // Init done, send broadcast to waiting tasks // OS_EVENT_Set(&HW_Event); while (1) { OS_TASK_Delay(40); } } /********************************************************************* * * main() */ int main(void) { OS_Init(); // Initialize embOS OS_InitHW(); // Initialize required hardware OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP); OS_TASK_CREATE(&TCBLP, "LP Task", 50, LPTask, StackLP); OS_TASK_CREATE(&TCBHW, "HWTask", 25, HWTask, StackHW); OS_EVENT_Create(&HW_Event); OS_Start(); // Start multitasking return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 134 5.2 CHAPTER 5 API functions API functions Timer ISR Task Description main Routine OS_EVENT_Create() Creates an event object and resets the event. OS_EVENT_CreateEx() Creates an extended event object and sets its reset behavior as well as mask bits behavior. OS_EVENT_Delete() Deletes an event object and releases all waiting tasks. OS_EVENT_Get() Retrieves current state of an event object without modification or suspension. OS_EVENT_GetBlocked() Waits for an event object and suspends task if event is not signaled. OS_EVENT_GetMask() Returns the bits of an event object that match the given EventMask. OS_EVENT_GetMaskBlocked() Waits for the specified event bits, depending on the current mask mode. OS_EVENT_GetMaskMode() Retrieves the current mask mode (mask bits behavior) of an event object. OS_EVENT_GetMaskTimed() Waits for the specified event bits with timeout, depending on the current mask mode. OS_EVENT_GetResetMode() Returns the reset mode (reset behavior) of an event object. OS_EVENT_GetTimed() Waits for an event and suspends the task for a specified time or until the event has been signaled. OS_EVENT_Pulse() Signals an event object and resumes waiting tasks, then resets the event object to non-signaled state. OS_EVENT_Reset() Resets the specified event object to nonsignaled state. OS_EVENT_Set() Sets an event object to signaled state, or resumes tasks which are waiting at the event object. OS_EVENT_SetMask() Sets the event mask bits of an event object. OS_EVENT_SetMaskMode() Sets the mask mode of an event object to OR/AND logic. OS_EVENT_SetResetMode() Sets the reset behavior of an event object to auto-matic, manual or semiauto. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 135 CHAPTER 5 5.2.1 API functions OS_EVENT_Create() Description Creates an event object and resets the event. Must be called before the event object can be used. Prototype void OS_EVENT_Create(OS_EVENT* pEvent); Parameters Parameter pEvent Description Pointer to an event object data structure. 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 empty. Therefore, OS_EVENT_Create() must not be called for an event object which is already created. 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 static OS_EVENT _Event; void HPTask(void) { OS_EVENT_GetMaskBlocked(&_Event, 3); } // Wait for bit 0 AND 1 to be set void LPTask(void) { OS_EVENT_SetMask(&_Event, 1); } // Resumes HPTask due to OR logic int main(void) { ... OS_EVENT_Create(&_Event); ... return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 136 CHAPTER 5 5.2.2 API functions OS_EVENT_CreateEx() Description Creates an extended event object and sets its reset behavior as well as mask bits behavior. Prototype void OS_EVENT_CreateEx(OS_EVENT* pEvent, unsigned int Mode); Parameters Parameter Description pEvent Pointer to an event object data structure. Mode Specifies the reset and mask bits behavior of the event object. You can use one of the predefined reset modes: OS_EVENT_RESET_MODE_SEMIAUTO OS_EVENT_RESET_MODE_MANUAL OS_EVENT_RESET_MODE_AUTO and one of the mask modes: OS_EVENT_MASK_MODE_OR_LOGIC OS_EVENT_MASK_MODE_AND_LOGIC which are described under additional information. 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 empty. Therefore, OS_EVENT_CreateEx() must not be called for an event object which is already created. 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. An exception to this is when a task called OS_EVENT_GetTimed() and the timeout expired before the event was signaled, in which case the function returns with timeout and the event is not cleared automatically. 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. Since version 4.34 of embOS, the mask bits behavior of the event object can be controlled by different mask modes which may be passed to the new function OS_EVENT_CreateEx() or may be modified by a call of OS_EVENT_SetMaskMode(). * * OS_EVENT_MASK_MODE_OR_LOGIC: This mask mode is the default mode. Only one of the bits specified in the event object bit mask must be signaled. OS_EVENT_MASK_MODE_AND_LOGIC: With this mode all specified event object mask bits must be signaled. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 137 CHAPTER 5 API functions Example static OS_EVENT _Event; void HPTask(void) { OS_EVENT_GetMaskBlocked(&_Event, 3); } // Wait for bit 0 AND 1 to be set void LPTask(void) { OS_EVENT_SetMask(&_Event, 1); // Does not resume HPTask OS_EVENT_SetMask(&_Event, 2); // Resume HPTask since both bits are now set } int main(void) { ... OS_EVENT_CreateEx(&_Event, OS_EVENT_RESET_MODE_AUTO | OS_EVENT_MASK_MODE_AND_LOGIC); ... return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 138 CHAPTER 5 5.2.3 API functions OS_EVENT_Delete() Description Deletes an event object and releases all waiting tasks. Prototype void OS_EVENT_Delete(OS_EVENT* pEvent); Parameters Parameter pEvent Description Pointer to an event object which should be deleted. 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. Example static OS_EVENT _Event; void Task(void) { ... OS_EVENT_Delete(&_Event); ... } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 139 CHAPTER 5 5.2.4 API functions OS_EVENT_Get() Description Retrieves current state of an event object without modification or suspension. Prototype OS_BOOL OS_EVENT_Get(OS_CONST_PTR OS_EVENT *pEvent); Parameters Parameter Description Pointer to an event object whose state should be examined. pEvent Return value 0 1 Event object is not set to signaled state. 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. Example static OS_EVENT _Event; void Task(void) { OS_BOOL Status; Status = OS_EVENT_Get(&_Event); printf("Event Object Status: %d\n", Status); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 140 CHAPTER 5 5.2.5 API functions OS_EVENT_GetBlocked() Description Waits for an event object and suspends task if event is not signaled. Prototype void OS_EVENT_GetBlocked(OS_EVENT* pEvent); Parameters Parameter pEvent Description Pointer to the event object that the task will be waiting for. Additional information pEvent addresses an existing event object, which must be created before the call of OS_EVENT_GetBlocked(). 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_GetBlocked() depends on the reset mode of the event object which was set by creating the event object by a call of OS_EVENT_CreateEx() or OS_EVENT_SetResetMode(). The event is consumed when OS_EVENT_RESET_MODE_AUTO is selected. The event is not consumed when OS_EVENT_RESET_MODE_MANUAL is selected. With OS_EVENT_RESET_MODE_SEMIAUTO the event is consumed only when it was already set before. Example static OS_EVENT _Event; void HPTask(void) { OS_EVENT_GetBlocked(&_Event); } // Suspends the task void LPTask(void) { OS_EVENT_Pulse(&_Event); } // Signals the HPTask UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 141 CHAPTER 5 5.2.6 API functions OS_EVENT_GetMask() Description Returns the bits of an event object that match the given EventMask. Prototype OS_TASKEVENT OS_EVENT_GetMask(OS_EVENT* pEvent, OS_TASKEVENT EventMask); Parameters Parameter Description pEvent Pointer to an event object whose state should be examined. EventMask The bit mask containing the event bits which shall be retrieved. Return value Matching event object mask bits. Additional information The signaled event mask bits are consumed unless OS_EVENT_RESET_MODE_MANUAL is selected. 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. Example static OS_EVENT _Event; void Task(void) { OS_TASKEVENT EventMask; EventMask = ~0; // Request all event bits EventMask = OS_EVENT_GetMask(&_Event, EventMask); printf("Signales Event Bits: 0x%X\n", EventMask); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 142 CHAPTER 5 5.2.7 API functions OS_EVENT_GetMaskBlocked() Description Waits for the specified event bits, depending on the current mask mode. The signaled event mask bits are consumed unless OS_EVENT_RESET_MODE_MANUAL is selected. Prototype OS_TASKEVENT OS_EVENT_GetMaskBlocked(OS_EVENT* pEvent, OS_TASKEVENT EventMask); Parameters Parameter Description pEvent Pointer to the event object that the task will be waiting for. EventMask The event bit mask containing the event bits, which shall be waited for. Return value All requested events that have been signaled and were specified in the EventMask. Additional information pEvent addresses an existing event object, which must be created before the call of OS_EVENT_GetMaskBlocked(). 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_GetMaskBlocked() depends on the reset mode of the event object which was set by creating the event object by a call of OS_EVENT_CreateEx() or OS_EVENT_SetResetMode(). Example static OS_EVENT _Event; void Task(void) { ... // // Waits either for the first or second, or for // both event bits to be singaled, depending on // the specified mask mode. // OS_EVENT_GetMaskBlocked(&_Event, 0x3); ... } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 143 CHAPTER 5 5.2.8 API functions OS_EVENT_GetMaskMode() Description Retrieves the current mask mode (mask bits behavior) of an event object. Prototype OS_EVENT_MASK_MODE OS_EVENT_GetMaskMode(OS_CONST_PTR OS_EVENT *pEvent); Parameters Parameter pEvent Description Pointer to an event object. Return value The mask mode which is currently set. Modes are defined in enum OS_EVENT_MASK_MODE. OS_EVENT_MASK_MODE_OR_LOGIC (0x00u): Mask bits are used with OR logic (default). OS_EVENT_MASK_MODE_AND_LOGIC (0x04u): Mask bits are used with AND logic. 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 4.34 of embOS, the mask mode of an event object can be controlled by the OS_EVENT_CreateEx() function or set after creation using the new function OS_EVENT_SetMaskMode(). If needed, the current setting of the mask mode can be retrieved with OS_EVENT_GetMaskMode(). Example static OS_EVENT _Event; void Task(void) { OS_EVENT_MASK_MODE MaskMode; MaskMode = OS_EVENT_GetMaskMode(&_Event); if (MaskMode == OS_EVENT_MASK_MODE_OR_LOGIC) { printf("Logic: OR\n"); } else { printf("Logic: AND\n"); } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 144 CHAPTER 5 5.2.9 API functions OS_EVENT_GetMaskTimed() Description Waits for the specified event bits with timeout, depending on the current mask mode. The task is suspended for the specified time or until the event(s) have been signaled. The signaled event mask bits are consumed unless OS_EVENT_RESET_MODE_MANUAL is selected. Prototype OS_TASKEVENT OS_EVENT_GetMaskTimed(OS_EVENT* pEvent, OS_TASKEVENT EventMask, OS_TIME Timeout); Parameters Parameter Description pEvent Pointer to the event object that the task will be waiting for. EventMask The event bit mask containing the event bits, which shall be waited for. Timeout Maximum time in embOS system 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 for 8/16 bit CPUs. 1 TimeOut 231 - 1 = 0x7FFFFFFF for 32 bit CPUs. Return value Matching event object mask bits or 0 when a timeout occurred. Additional information pEvent addresses an existing event object, which must be created before the call of OS_EVENT_GetMaskTimed(). 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. Example static OS_EVENT _Event; void Task(void) { ... // // Waits either for the first or second, or for // both event bits to be singaled, depending on // the specified mask mode. The task resumes after // 1000 system ticks, if the needed event bits were not // signaled. // OS_EVENT_GetMaskTimed(&_Event, 0x3, 1000); ... } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 145 CHAPTER 5 5.2.10 API functions OS_EVENT_GetResetMode() Description Returns the reset mode (reset behavior) of an event object. Prototype OS_EVENT_RESET_MODE OS_EVENT_GetResetMode(OS_CONST_PTR OS_EVENT *pEvent); Parameters Parameter pEvent Description Pointer to event object control structure. Return value The reset mode which is currently set. Modes are defined in enum OS_EVENT_RESET_MODE. OS_EVENT_RESET_MODE_SEMIAUTO (0x00u): As previous mode (default). OS_EVENT_RESET_MODE_MANUAL (0x01u): Event remains set, has to be reset by task. OS_EVENT_RESET_MODE_AUTO (0x02u): Event is reset automatically. 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 static OS_EVENT _Event; void Task(void) { OS_EVENT_RESET_MODE ResetMode; ResetMode = OS_EVENT_GetResetMode(&_Event); if (ResetMode == OS_EVENT_RESET_MODE_SEMIAUTO) { printf("Reset Mode: SEMIAUTO\n"); } else if (ResetMode == OS_EVENT_RESET_MODE_MANUAL) { printf("Reset Mode: MANUAL\n"); } else { printf("Reset Mode: AUTO\n"); } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 146 CHAPTER 5 5.2.11 API functions OS_EVENT_GetTimed() Description Waits for an event and suspends the task for a specified time or until the event has been signaled. The event is consumed unless OS_EVENT_RESET_MODE_MANUAL is selected. Prototype char OS_EVENT_GetTimed(OS_EVENT* pEvent, OS_TIME Timeout); Parameters Parameter Description pEvent Pointer to the event object that the task will be waiting for. Timeout Maximum time in embOS system 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 for 8/16 bit CPUs. 1 TimeOut 231 - 1 = 0x7FFFFFFF for 32 bit CPUs. Return value 0 1 Success, the event was signaled within the specified time. If the event was not signaled within the specified time. Additional information pEvent addresses an existing event object, which must be created before the call of OS_EVENT_GetTimed(). 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. Example static OS_EVENT _Event; void Task(void) { ... if (OS_EVENT_GetTimed(&_Event, 1000) == 0) { // event was signaled within timeout time, handle event } else { // event was not signaled within timeout time, handle timeout } ... } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 147 CHAPTER 5 5.2.12 API functions OS_EVENT_Pulse() Description Signals an event object and resumes waiting tasks, then resets the event object to nonsignaled state. Prototype void OS_EVENT_Pulse(OS_EVENT* pEvent); Parameters Parameter pEvent Description Pointer to the event object which should be pulsed. 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. Example static OS_EVENT _Event; void HPTask(void) { OS_EVENT_GetBlocked(&_Event); } // Suspends the task void LPTask(void) { OS_Event_Pulse(&_Event); } // Signales the HPTask UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 148 CHAPTER 5 5.2.13 API functions OS_EVENT_Reset() Description Resets the specified event object to non-signaled state. Prototype void OS_EVENT_Reset(OS_EVENT* pEvent); Parameters Parameter pEvent Description Pointer to the event object which should be reset to non-signaled state. 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 static OS_EVENT _Event; void Task(void) { ... OS_EVENT_Reset(&_Event); ... } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 149 CHAPTER 5 5.2.14 API functions 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); Parameters Parameter pEvent Description Pointer to the event object. Additional information pEvent must address an existing event object, which must be created before by a call to 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. Any task that is already waiting for the event object will be 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 Examples of using event objects on page 132. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 150 CHAPTER 5 5.2.15 API functions OS_EVENT_SetMask() Description Sets the event mask bits of an event object. Prototype void OS_EVENT_SetMask(OS_EVENT* pEvent, OS_TASKEVENT EventMask); Parameters Parameter Description pEvent Pointer to the event object. EventMask The event bit mask containing the event bits, which shall be signaled. Additional information pEvent must address an existing event object, which must be created before by a call to 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. Any task that is already waiting for matching event mask bits on this event object will be resumed. OS_EVENT_SetMask() does not clear any event mask bits. Example static OS_EVENT _Event; void Task(void) { OS_TASKEVENT EventMask; ... EventMask = 1 << ((sizeof(OS_TASKEVENT) * 8) - 1); OS_EVENT_SetMask(&_Event, EventMask); ... // Set MSB event bit // Signal MSB event bit } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 151 CHAPTER 5 5.2.16 API functions OS_EVENT_SetMaskMode() Description Sets the mask mode of an event object to OR/AND logic. Prototype void OS_EVENT_SetMaskMode(OS_EVENT* pEvent, OS_EVENT_MASK_MODE MaskMode); Parameters Parameter Description pEvent Pointer to an event object. MaskMode Event Mask mode. Modes are defined in enum OS_EVENT_MASK_MODE. OS_EVENT_MASK_MODE_OR_LOGIC (0x00u): Mask bits are used with OR logic (default). OS_EVENT_MASK_MODE_AND_LOGIC (0x04u): Mask bits are used with AND logic. 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 4.34 of embOS, the mask bits behavior of the event object can be controlled by different mask modes which may be passed to the new function OS_EVENT_CreateEx() or may be modified by a call of OS_EVENT_SetMaskMode(). The following mask modes are defined and can be used as parameter: * * OS_EVENT_MASK_MODE_OR_LOGIC: This mask mode is the default mode. Only one of the bits specified in the event object bit mask must be signaled. OS_EVENT_MASK_MODE_AND_LOGIC: With this mode all specified event mask bits must be signaled. Example static OS_EVENT _Event; void Task(void) { ... // Set the mask mode for the event object to AND logic OS_EVENT_SetMaskMode(&_Event, OS_EVENT_MASK_MODE_AND_LOGIC); ... } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 152 CHAPTER 5 5.2.17 API functions OS_EVENT_SetResetMode() Description Sets the reset behavior of an event object to auto-matic, manual or semiauto. Prototype void OS_EVENT_SetResetMode(OS_EVENT* pEvent, OS_EVENT_RESET_MODE ResetMode); Parameters Parameter Description pEvent Pointer to an event object. ResetMode Controls the reset mode of the event object. OS_EVENT_RESET_DEFAULT (0x00u): As previous mode. OS_EVENT_RESET_MANUAL (0x01u): Event remains set, has to be reset by task. OS_EVENT_RESET_AUTO (0x02u): Event is reset automatically. 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_GetBlocked() 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 and 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. An exception to this is when a task called OS_EVENT_GetTimed() and the timeout expired before the event was signaled, in which case the function returns with timeout and the event is not cleared automatically. 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 static OS_EVENT _Event; void Task(void) { // Set the reset mode for the event object to manual OS_EVENT_SetResetMode(&_Event, OS_EVENT_RESET_MANUAL); UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 153 CHAPTER 5 API functions } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 6 Mutexes UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 155 6.1 CHAPTER 6 Introduction Introduction Mutexes 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_MUTEX_LockBlocked() or OS_MUTEX_Lock() routines of embOS. If the mutex is available, the program execution of the task continues, but the mutex is blocked for other tasks. If a second task now tries to acquire the same mutex while it is in use by the first task, this second task is suspended until the first task releases the mutex. However, if the first task that uses the mutex calls OS_MUTEX_LockBlocked() again for that mutex, it is not suspended because the mutex is blocked only for other tasks. The following diagram illustrates the process of using a mutex: A mutex contains a counter that keeps track of how many times the mutex has been claimed by calling OS_MUTEX_Lock() or OS_MUTEX_LockBlocked() by a particular task. It is released when that counter reaches zero, which means the OS_MUTEX_Unlock() routine must be called exactly the same number of times as OS_MUTEX_LockBlocked() or OS_MUTEX_Lock(). If it is not, the mutex remains blocked for other tasks. On the other hand, a task cannot release a mutex that it does not own by calling OS_MUTEX_Unlock(). In debug builds of embOS, a call of OS_MUTEX_Unlock() for a mutex that is not owned by this task will result in a call to the error handler OS_Error(). UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 156 CHAPTER 6 Introduction Example of using a mutex Here, two tasks access a (debug) terminal completely independently from each other. The terminal is a resource that needs to be protected with a mutex. One task may not interrupt another task which is writing to the terminal, as otherwise the following might occur: * * * Task A begins writing to the terminal Task B interrupts Task A and writes to the terminal Task A is resumed and its output is written at a wrong position To avoid this type of situation, every time the terminal is to be accessed by a task it is first claimed by a call to OS_MUTEX_LockBlocked() (and is automatically waited for if the mutex is blocked). After the terminal has been written to, it is released by a call to OS_MUTEX_Unlock(). The sample application file OS_RSema.c delivered in the application samples folder of embOS demonstrates how mutex can be used in the above scenario: #include "RTOS.h" #include static OS_STACKPTR int StackHP[128], StackLP[128]; /* Task stacks */ static OS_TASK TCBHP, TCBLP; /* Task-control-blocks */ /****** Local function **********************************************/ static void _Write(char const* s) { OS_MUTEX_LockBlocked(&Mutex); printf(s); OS_MUTEX_Unlock(&Mutex); } /****** Task functions **********************************************/ static void HPTask(void) { while (1) { _Write("HPTask\n"); OS_TASK_Delay(50); } } static void LPTask(void) { while (1) { _Write("LPTask\n"); OS_TASK_Delay(200); } } /********************************************************************* * * main() */ int main(void) { OS_Init(); // Initialize embOS OS_InitHW(); // Initialize hardware for embOS OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP); OS_TASK_CREATE(&TCBLP, "LP Task", 50, LPTask, StackLP); OS_MUTEX_Create(&Mutex); // Creates mutex OS_Start(); // Start multitasking return 0; } /****** End Of File *************************************************/ UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 157 6.2 CHAPTER 6 API functions API functions Creates a mutex. OS_MUTEX_Delete() Deletes a specified mutex. OS_MUTEX_GetOwner() Returns the mutex owner if any. OS_MUTEX_GetValue() Returns the value of the usage counter of a specified mutex. OS_MUTEX_Lock() Requests a specified mutex and blocks it for other tasks if it is available. OS_MUTEX_LockBlocked() Claims a mutex and blocks it for other tasks. OS_MUTEX_LockTimed() Tries to claim a mutex and blocks it for other tasks if it is available within a specified time. OS_MUTEX_Unlock() Releases a mutex currently in use by a task. UM01001 User Guide & Reference Manual for embOS Timer OS_MUTEX_Create() ISR Task Description main Routine (c) 1995-2018 SEGGER Microcontroller GmbH 158 CHAPTER 6 6.2.1 API functions OS_MUTEX_Create() Description Creates a mutex. Prototype void OS_MUTEX_Create(OS_MUTEX* pMutex); Parameters Parameter pMutex Description Pointer to the data structure for a mutex. Additional information After creation, the mutex is not blocked; the value of the counter is zero. Example static OS_MUTEX _Mutex; int main(void) { ... OS_MUTEX_Create(&_Mutex); ... return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 159 CHAPTER 6 6.2.2 API functions OS_MUTEX_Delete() Description Deletes a specified mutex. The memory of that mutex may be reused for other purposes or may be used for creating another mutex using the same memory. Prototype void OS_MUTEX_Delete(OS_MUTEX* pMutex); Parameters Parameter pMutex Description Pointer to a data structure of type OS_MUTEX. Additional information Before deleting a mutex, make sure that no task is claiming the mutex. A debug build of embOS will call OS_Error() with the error code OS_ERR_MUTEX_DELETE if a mutex is deleted when it is already in use. In systems with dynamic creation of mutexes, you must delete a mutex before recreating it. Failure to so may cause mutex handling to work incorrectly. Example static OS_MUTEX _Mutex; int Task(void) { ... OS_MUTEX_Delete(&_Mutex); ... return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 160 CHAPTER 6 6.2.3 API functions OS_MUTEX_GetOwner() Description Returns the mutex owner if any. When a task is currently using (blocking) the mutex the task Id (address of task according task control block) is returned. Prototype OS_TASK *OS_MUTEX_GetOwner(OS_CONST_PTR OS_MUTEX *pMutex); Parameters Parameter Description Pointer to the data structure for a mutex. pMutex Return value = NULL NULL The mutex is not used by any task. Task Id (address of the task control block). Additional information If a mutex was used in main() the return value of OS_MUTEX_GetOwner() is ambiguous. The return value NULL can mean it is currently used in main() or it is currently unused. Therefore, OS_MUTEX_GetOwner() must not be used to check if a mutex is available. Please use OS_MUTEX_GetValue() instead. It is also good practice to free all used mutexes in main() before calling OS_Start(). Example Please find an example at OS_MUTEX_GetValue(). UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 161 CHAPTER 6 6.2.4 API functions OS_MUTEX_GetValue() Description Returns the value of the usage counter of a specified mutex. Prototype int OS_MUTEX_GetValue(OS_CONST_PTR OS_MUTEX *pMutex); Parameters Parameter pMutex Description Pointer to the data structure for a mutex. Return value The counter value of the mutex. A value of zero means the mutex is available. Example static OS_MUTEX _Mutex; void CheckMutex(void) { int Value; OS_TASK* Owner; Value = OS_MUTEX_GetValue(&_Mutex); if (Value == 0) { printf("Mutex is currently unused"); } else { Owner = OS_MUTEX_GetOwner(&_Mutex); if (Owner == NULL) { printf("Mutex was used in main()"); } else { printf("Mutex is currently used in task 0x%X", Owner); } } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 162 CHAPTER 6 6.2.5 API functions OS_MUTEX_Lock() Description Requests a specified mutex and blocks it for other tasks if it is available. Continues execution in any case. Prototype char OS_MUTEX_Lock(OS_MUTEX* pMutex); Parameters Parameter Description Pointer to the data structure for a mutex. pMutex Return value 1 0 Mutex was available, now in use by calling task. Mutex was not available. Additional information The following diagram illustrates how OS_MUTEX_Lock() works: Example if (OS_MUTEX_Lock(&Mutex_LCD)) { DispTime(); // Access the resource LCD OS_MUTEX_Unlock(&Mutex_LCD); // Resource LCD is no longer needed } else { ... // Do something else } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 163 CHAPTER 6 6.2.6 API functions OS_MUTEX_LockBlocked() Description Claims a mutex and blocks it for other tasks. Prototype int OS_MUTEX_LockBlocked(OS_MUTEX* pMutex); Parameters Parameter pMutex Description Pointer to the data structure for a mutex. Return value The counter value of the mutex. A value greater than one denotes the mutex was already locked by the calling task. Additional information The following situations are possible: * * * Case A: The mutex is not in use. If the mutex is not used by a task, which means the counter of the mutex is zero, the mutex will be blocked for other tasks by incrementing the counter and writing a unique code for the task that uses it into the mutex. Case B: The mutex is used by this task. The counter of the mutex is incremented. The program continues without a break. Case C: The mutex is being used by another task. The execution of this task is suspended until the mutex is released. In the meantime if the task blocked by the mutex has a higher priority than the task blocking the mutex, the blocking task is assigned the priority of the task requesting the mutex. 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 mutex. According to the rules of the scheduler, of all the tasks waiting for the mutex the task with the highest priority will acquire the mutex and continue program execution. Example static OS_MUTEX _Mutex; void Task(void) { ... OS_MUTEX_LockBlocked(&_Mutex); ... OS_MUTEX_Unlock(&_Mutex); ... } The following diagram illustrates how OS_MUTEX_LockBlocked() works: UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 164 CHAPTER 6 6.2.7 API functions OS_MUTEX_LockTimed() Description Tries to claim a mutex and blocks it for other tasks if it is available within a specified time. Prototype int OS_MUTEX_LockTimed(OS_MUTEX* pMutex, OS_TIME TimeOut); Parameters Parameter Description pMutex Pointer to the data structure of a mutex. TimeOut Maximum time until the mutex should be available. Timer period in embOS system ticks. The data type OS_TIME is defined as an integer, therefore valid values are: 1 TimeOut 215 - 1 = 0x7FFF for 8/16 bit CPUs. 1 TimeOut 231 - 1 = 0x7FFFFFFF for 32 bit CPUs. Return value =0 0 Failed, mutex not available before timeout. Success, mutex available, current usage count of mutex. A value greater than one denotes the mutex was already locked by the calling task. Additional information The following situations are possible: * * * Case A: The mutex is not in use. If the mutex is not used by a task, which means the counter of the mutex is zero, the mutex will be blocked for other tasks by incrementing the counter and writing a unique code for the task that uses it into the mutex. Case B: The mutex is used by this task. The counter of the mutex is incremented. The program continues without a break. Case C: The mutex is being used by another task. The execution of this task is suspended until the mutex is released or the timeout time expired. In the meantime if the task blocked by the mutex mutex has a higher priority than the task blocking the mutex, the blocking task is assigned the priority of the task requesting the mutex. This is called priority inheritance. Priority inheritance can only temporarily increase the priority of a task, never reduce it. If the mutex becomes available during the timeout, the calling task claims the mutex and the function returns a value greater than zero, otherwise, if the mutex 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 mutex becomes available before the calling task is resumed. Anyhow, the function will not claim the mutex because it was not available within the requested time. An unlimited number of tasks can wait for a mutex. According to the rules of the scheduler, of all the tasks waiting for the mutex the task with the highest priority will acquire the mutex and continue program execution. OS_MUTEX_LockTimed() could cause a priority inheritance. In case of a timeout the priority inheritance must be handled. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 165 CHAPTER 6 API functions Example static OS_MUTEX _Mutex; void Task(void) { ... if (OS_MUTEX_LockTimed(&_Mutex, 100)) { ... // Mutex acquired } else { ... // Timeout } ... } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 166 CHAPTER 6 6.2.8 API functions OS_MUTEX_Unlock() Description Releases a mutex currently in use by a task. Prototype void OS_MUTEX_Unlock(OS_MUTEX* pMutex); Parameters Parameter pMutex Description Pointer to mutex control structure. Additional information OS_MUTEX_Unlock() may be used on a mutex only after that mutex has been used by calling OS_MUTEX_LockBlocked() or OS_MUTEX_Lock(). OS_MUTEX_Unlock() decrements the usage counter of the mutex 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_MUTEX_Unlock() is called from a task which does not own the mutex. The error code is OS_ERR_RESOURCE_OWNER in this case. Example Please find an example at OS_MUTEX_Lock(). UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 7 Semaphores UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 168 7.1 CHAPTER 7 Introduction Introduction A semaphore is a variable or abstract data type used to control access to a common resource by multiple processes in a multitasking operating system. While not as widely used as mutexes, events or mailboxes, semaphores can be very useful in specific situations. For example, they are commonly used in "credittracking synchronization" where a task needs to wait for something that can be signaled one or more times. Example of using semaphores Here, an interrupt is issued every time data is received from a peripheral source. The interrupt service routine then signals the arrival of data to a worker task, which subsequently processes that data. When the worker task is blocked from exection, e.g. by a higher-priority task, the semaphore's counter effectively tracks the number of data packets to be processed by the worker task, which will be executed for that exact number of times when resumed. The following sample application shows how semaphores can be used in the above scenario: #include "RTOS.h" #include static static static static OS_STACKPTR int OS_TASK OS_SEMAPHORE OS_TICK_HOOK Stack[128]; TCB; Sema; Hook; // // // // Task stack Task control block Semaphore Hook to emulate external interrupt void Task(void) { while(1) { OS_SEMAPHORE_TakeBlocked(&Sema); printf("Task is processing data"); } } // Wait for signaling of received data // Act on received data void OnTickHookFunction(void) { OS_SEMAPHORE_Give(&Sema); } // Signal data reception int main(void) { OS_Init(); // Initialize embOS OS_InitHW(); // Initialize required hardware // // Register tick hook function to emulate an external interrupt // OS_TICK_AddHook(&Hook, (OS_TICK_HOOK_ROUTINE*)OnTickHookFunction); OS_TASK_CREATE(&TCB, "Task", 100, Task, Stack); OS_SEMAPHORE_CREATE(&Sema); // Creates semaphore OS_Start(); // Start embOS return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 169 7.2 CHAPTER 7 API functions API functions Timer ISR Task Description main Routine OS_SEMAPHORE_CREATE() Macro that creates a semaphore with an initial count value of zero. OS_SEMAPHORE_Create() Creates a counting semaphore with a specified initial count value. OS_SEMAPHORE_Delete() Deletes a counting semaphore. OS_SEMAPHORE_Give() Increments the counter of a semaphore. OS_SEMAPHORE_GiveMax() Increments the counter of a semaphore up to a specified maximum value. OS_SEMAPHORE_GetValue() Returns the current counter value of a specified semaphore. OS_SEMAPHORE_SetValue() Sets the counter value of a specified semaphore. OS_SEMAPHORE_Take() Decrements the counter of a semaphore, if it was signaled. OS_SEMAPHORE_TakeBlocked() Decrements the counter of a semaphore. OS_SEMAPHORE_TakeTimed() Decrements a semaphore counter if the semaphore is available within a specified time. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 170 CHAPTER 7 7.2.1 API functions OS_SEMAPHORE_CREATE() Description Macro that creates a semaphore with an initial count value of zero. Prototype void OS_SEMAPHORE_CREATE(OS_SEMAPHORE* pSema); Parameters Parameter pSema Description Pointer to a data structure of type OS_SEMAPHORE. Additional information To create a semaphore a data structure of the type OS_SEMAPHORE must be defined in memory and initialized using OS_SEMAPHORE_CREATE(). The value of a semaphore created through this macro is zero. If you need to create a semaphore with an arbitrary initial counting value, use the function OS_SEMAPHORE_Create(). Example Please refer to the example in Introduction on page 168. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 171 CHAPTER 7 7.2.2 API functions OS_SEMAPHORE_Create() Description Creates a counting semaphore with a specified initial count value. Prototype void OS_SEMAPHORE_Create(OS_SEMAPHORE* pSema, OS_UINT InitValue); Parameters Parameter Description pSema Pointer to a data structure of type OS_SEMAPHORE. InitValue 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. Additional information To create a counting semaphore a data structure of the type OS_SEMAPHORE must be defined in memory and initialized using OS_SEMAPHORE_Create(). Example static OS_SEMA _Sema; int main(void) { ... OS_SEMAPHORE_Create(&_Sema, 8); ... return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 172 CHAPTER 7 7.2.3 API functions OS_SEMAPHORE_Delete() Description Deletes a counting semaphore. Prototype void OS_SEMAPHORE_Delete(OS_SEMAPHORE* pSema); Parameters Parameter pSema Description Pointer to a data structure of type OS_SEMAPHORE. 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. Example static OS_SEMA _Sema; void Task(void) { ... OS_SEMAPHORE_Delete(&_Sema); ... } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 173 CHAPTER 7 7.2.4 API functions OS_SEMAPHORE_Give() Description Increments the counter of a semaphore. Prototype void OS_SEMAPHORE_Give(OS_SEMAPHORE* pSema); Parameters Parameter pSema Description Pointer to a data structure of type OS_SEMAPHORE. Additional information OS_SEMAPHORE_Give() 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_SEMAPHORE_OVERFLOW if an overflow occurs. Example Please refer to the example in Introduction on page 168. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 174 CHAPTER 7 7.2.5 API functions OS_SEMAPHORE_GiveMax() Description Increments the counter of a semaphore up to a specified maximum value. Prototype void OS_SEMAPHORE_GiveMax(OS_SEMAPHORE* pSema, OS_UINT MaxValue); Parameters Parameter Description pSema Pointer to a data structure of type OS_SEMAPHORE. MaxValue Count value of the semaphore: 1 MaxValue 216 - 1 = 0xFFFF for 8/16 bit CPUs. 1 MaxValue 232 - 1 = 0xFFFFFFFF for 32 bit CPUs. Additional information As long as current value of the semaphore counter is below the specified maximum value, OS_SEMAPHORE_GiveMax() 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_SEMAPHORE_GiveMax() with a MaxValue of 1 makes a counting semaphore behave like a mutex. Consider using a mutex instead. Example static OS_SEMA _Sema; void Task(void) { ... OS_SEMAPHORE_GiveMax(&_Sema, 8); ... } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 175 CHAPTER 7 7.2.6 API functions OS_SEMAPHORE_GetValue() Description Returns the current counter value of a specified semaphore. Prototype int OS_SEMAPHORE_GetValue(OS_CONST_PTR OS_SEMAPHORE *pSema); Parameters Parameter pSema Description Pointer to a data structure of type OS_SEMAPHORE. Return value The current counter value of the semaphore. Example static OS_SEMA _Sema; void PrintSemaValue(void) { int Value; Value = OS_SEMAPHORE_GetValue(&_Sema); printf("Sema Value: %d\n", Value) } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 176 CHAPTER 7 7.2.7 API functions OS_SEMAPHORE_SetValue() Description Sets the counter value of a specified semaphore. Prototype OS_U8 OS_SEMAPHORE_SetValue(OS_SEMAPHORE* pSema, OS_UINT Value); Parameters Parameter Description pSema Pointer to a data structure of type OS_SEMAPHORE. Value Count value of the semaphore: 0 Value 216 - 1 = 0xFFFF for 8/16 bit CPUs. 0 Value 232 - 1 = 0xFFFFFFFF for 32 bit CPUs. Return value 0 In any case. The return value can safely be ignored. Example static OS_SEMA _Sema; void Task(void) { ... OS_SEMAPHORE_SetValue(&_Sema, 0); ... } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 177 CHAPTER 7 7.2.8 API functions OS_SEMAPHORE_Take() Description Decrements the counter of a semaphore, if it was signaled. Prototype OS_BOOL OS_SEMAPHORE_Take(OS_SEMAPHORE* pSema); Parameters Parameter Description Pointer to a data structure of type OS_SEMAPHORE. pSema Return value 0 1 Failed, semaphore was not signaled before the call. Success, 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_SEMAPHORE_Take() does not wait and does not modify the semaphore counter. Example static OS_SEMA _Sema; void Task(void) { ... if (OS_SEMAPHORE_Take(&_Sema) == 1) { printf("Semaphore decremented successfully.\n"); } else { printf("Semaphore not signaled.\n"); } ... } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 178 CHAPTER 7 7.2.9 API functions OS_SEMAPHORE_TakeBlocked() Description Decrements the counter of a semaphore. Prototype void OS_SEMAPHORE_TakeBlocked(OS_SEMAPHORE* pSema); Parameters Parameter pSema Description Pointer to a data structure of type OS_SEMAPHORE. 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_SEMAPHORE_TakeBlocked() waits until the counter is incremented by another task, a timer or an interrupt handler by a call to OS_SEMAPHORE_Give(). 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. Example Please refer to the example in Introduction on page 168. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 179 CHAPTER 7 7.2.10 API functions OS_SEMAPHORE_TakeTimed() Description Decrements a semaphore counter if the semaphore is available within a specified time. Prototype OS_BOOL OS_SEMAPHORE_TakeTimed(OS_SEMAPHORE* pSema, OS_TIME TimeOut); Parameters Parameter Description pSema Pointer to a data structure of type OS_SEMAPHORE. TimeOut Maximum time until semaphore should be available. Timer period in embOS system ticks. The data type OS_TIME is defined as an integer, therefore valid values are: 1 TimeOut 215 - 1 = 0x7FFF for 8/16 bit CPUs. 1 TimeOut 231 - 1 = 0x7FFFFFFF for 32 bit CPUs. Return value 0 1 Failed, semaphore not available before timeout. Success, 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, OS_SEMAPHORE_TakeTimed() waits until the semaphore is signaled by another task, a timer, or an interrupt handler by a call to OS_SEMAPHORE_Give(). 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 period longer than the timeout value, it may happen that the counting semaphore becomes available after the timeout expired, but before the calling task is resumed. Anyhow, the function returns with timeout, because the semaphore was not available within the requested time. In this case, the state of the semaphore is not modified by OS_SEMAPHORE_TakeTimed(). Example static OS_SEMA _Sema; void Task(void) { ... if (OS_SEMAPHORE_TakeTimed(&_Sema, 100)) { ... // Semaphore acquired } else { ... // Timeout } ... } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 8 Mailboxes UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 181 8.1 CHAPTER 8 Introduction 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 mutex 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 mutex. 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. 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. Limitations: Both the number of mailboxes and buffers are limited only by the amount of available memory. However, the number of messages per mailbox, the message size per mailbox, and the buffer size per mailbox are limited by software design. Number of messages on 8 or 16bit CPUs: 1 <= x <= 215 - 1 = 0x7FFF Number of messages on 32bit CPUs: 1 <= x <= 231 - 1 = 0x7FFFFFFF Message size in bytes on 8 or 16bit CPUs: 1 <= x <= 215 - 1 = 0x7FFF Message size in bytes on 32bit CPUs: 1 <= x <= 215 - 1 = 0x7FFF Maximum buffer size in bytes for one mailbox on 8 or 16bit CPUs: 216 = 0xFFFF Maximum buffer size in bytes for one mailbox on 32bit CPUs: 232 = 0xFFFFFFFF These limitations have been placed on mailboxes to guarantee efficient coding and also to ensure efficient management. These limitations are typically not a problem. A mailbox can be used by more than one producer, but must 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. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 182 CHAPTER 8 8.1.1 Introduction 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 typically 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_MAILBOX_PutBlocked(), OS_MAILBOX_Put(), OS_MAILBOX_GetBlocked(), and OS_MAILBOX_Get() can transfer messages of sizes between 1 and 32,767 bytes each. Their single-byte equivalents OS_MAILBOX_PutBlocked1(), OS_MAILBOX_Put1(), OS_MAILBOX_GetBlocked1(), and OS_MAILBOX_Get1() 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_MAILBOX_PutBlocked1(), OS_MAILBOX_Put1(), OS_MAILBOX_GetBlocked1(), and OS_MAILBOX_Get1() work exactly the same way as their universal equivalents. The only difference is that they must only be used for single-byte mailboxes. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 183 CHAPTER 8 Introduction Example #define MAX_MSG_SIZE #define MAX_MSG_NUM static static static static (9) (2) // Max. number of bytes per message // Max. number of messages per Mailbox OS_STACKPTR int StackHP[128], StackLP[128]; // Task stacks OS_TASK TCBHP, TCBLP; // Task control blocks OS_MAILBOX MyMailbox; char MyMailboxBuffer[MAX_MSG_SIZE * MAX_MSG_NUM]; static void HPTask(void) { char aData[MAX_MSG_SIZE]; while (1) { OS_MAILBOX_GetBlocked(&MyMailbox, (void *)aData); OS_COM_SendString(aData); } } static void LPTask(void) { while (1) { OS_MAILBOX_PutBlocked(&MyMailbox, "\nHello\0"); OS_MAILBOX_PutBlocked(&MyMailbox, "\nWorld !\0"); } } int main(void) { OS_Init(); // Initialize embOS OS_InitHW(); // Initialize required hardware OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP); OS_TASK_CREATE(&TCBLP, "LP Task", 50, LPTask, StackLP); OS_MAILBOX_Create(&MyMailbox, MAX_MSG_SIZE, MAX_MSG_NUM, &MyMailboxBuffer); OS_COM_SendString("embOS OS_Mailbox example"); OS_COM_SendString("\n\nDemonstrating message passing\n"); OS_Start(); // Start embOS return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 184 8.2 CHAPTER 8 API functions API functions Timer ISR Task Description main Routine OS_MAILBOX_Clear() Clears all messages in the specified mailbox. OS_MAILBOX_Create() Creates a new mailbox. OS_MAILBOX_Delete() Deletes a specified mailbox. OS_MAILBOX_Get() Retrieves a new message of a predefined size from a mailbox if a message is available. OS_MAILBOX_Get1() Retrieves a new message of size 1 from a mailbox if a message is available. OS_MAILBOX_GetBlocked() Retrieves a new message of a predefined size from a mailbox. OS_MAILBOX_GetBlocked1() Retrieves a new message of size 1 from a mailbox. OS_MAILBOX_GetMessageCnt() Returns the number of messages currently available in a specified mailbox. OS_MAILBOX_GetTimed() Retrieves a new message of a predefined size from a mailbox if a message is available within a given time. OS_MAILBOX_GetTimed1() Retrieves a new message of size 1 from a mailbox if a message is available within a given time. OS_MAILBOX_GetPtr() Retrieves a pointer to a new message of a predefined size from a mailbox, if a message is available. OS_MAILBOX_GetPtrBlocked() Retrieves a pointer to a new message of a predefined size from a mailbox. OS_MAILBOX_Peek() Peeks a mail from a mailbox without removing the mail. OS_MAILBOX_Purge() Deletes the last retrieved message in a mailbox. OS_MAILBOX_Put() Stores a new message of a predefined size in a mailbox if the mailbox is able to accept one more message. OS_MAILBOX_Put1() Stores a new message of size 1 in a mailbox if the mailbox is able to accept one more message. OS_MAILBOX_PutBlocked() Stores a new message of a predefined size in a mailbox. OS_MAILBOX_PutBlocked1() Stores a new message of size 1 in a mailbox. OS_MAILBOX_PutFront() 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. OS_MAILBOX_PutFront1() Stores a new message of size 1 into a mailbox in front of all other messages if UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 185 CHAPTER 8 Timer ISR Task Description main Routine API functions the mailbox is able to accept one more message. OS_MAILBOX_PutFrontBlocked() Stores a new message of a predefined size at the beginning of a mailbox in front of all other messages. OS_MAILBOX_PutFrontBlocked1() Stores a new message of size 1 at the beginning of a mailbox in front of all other messages. OS_MAILBOX_PutTimed() Stores a new message of a predefined size in a mailbox if the mailbox is able to accept one more message within a given time. OS_MAILBOX_PutTimed1() Stores a new message of size 1 in a mailbox if the mailbox is able to accept one more message within a given time. OS_MAILBOX_WaitBlocked() Waits until a mail is available, but does not retrieve the message from the mailbox. OS_MAILBOX_WaitTimed() Waits until a mail is available or the timeout has expired, but does not retrieve the message from the mailbox. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 186 CHAPTER 8 8.2.1 API functions OS_MAILBOX_Clear() Description Clears all messages in the specified mailbox. Prototype void OS_MAILBOX_Clear(OS_MAILBOX* pMB); Parameters Parameter pMB Description Pointer to the mailbox. Additional information When the mailbox is in use, a debug build of embOS will call OS_Error() with error code OS_ERR_MB_INUSE. OS_MAILBOX_Clear() may cause a task switch. Example static OS_MAILBOX _MBKey; void ClearKeyBuffer(void) { OS_MAILBOX_Clear(&_MBKey); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 187 CHAPTER 8 8.2.2 API functions OS_MAILBOX_Create() Description Creates a new mailbox. Prototype void OS_MAILBOX_Create(OS_MAILBOX* OS_U16 OS_UINT void* pMB, sizeofMsg, maxnofMsg, Buffer); Parameters Parameter Description pMB Pointer to the mailbox. sizeofMsg Size of a message in bytes. Valid values are 1 sizeofMsg 32,767. maxnofMsg Maximum number of messages. Valid values are 1 MaxnofMsg 32,767 on 8 or 16bit CPUs, or 1 MaxnofMsg 2,147,483,647 on 32bit CPUs. Buffer 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. Example Mailbox used as keayboard buffer: static OS_MAILBOX _MBKey; char MBKeyBuffer[6]; void InitKeyMan(void) { // // Create mailbox, functioning as type ahead buffer // OS_MAILBOX_Create(&_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_MAILBOX_Create(&MBMotor, sizeof(MOTORCMD), NUM_MOTORCMDS, &BufferMotor); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 188 CHAPTER 8 8.2.3 API functions OS_MAILBOX_Delete() Description Deletes a specified mailbox. Prototype void OS_MAILBOX_Delete(OS_MAILBOX* pMB); Parameters Parameter pMB Description Pointer to the mailbox. 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). When the mailbox is in use, a debug build of embOS will call OS_Error() with error code OS_ERR_MB_INUSE. In a debug build OS_Error() will also be called if OS_MAILBOX_Delete() is called while tasks are waiting for new data from the mailbox. The error code in this case is OS_ERR_MAILBOX_DELETE. Example static OS_MAILBOX _MBSerIn; void Cleanup(void) { OS_MAILBOX_Delete(&_MBSerIn); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 189 CHAPTER 8 8.2.4 API functions OS_MAILBOX_Get() Description Retrieves a new message of a predefined size from a mailbox if a message is available. Prototype char OS_MAILBOX_Get(OS_MAILBOX* pMB, void* pDest); Parameters Parameter Description pMB Pointer to the mailbox. pDest 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. Return value 0 1 Success; message retrieved. 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 static OS_MAILBOX _MBData; struct Data Buffer; char GetData(void) { return OS_MAILBOX_Get(&_MBData, &Buffer); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 190 CHAPTER 8 8.2.5 API functions OS_MAILBOX_Get1() Description Retrieves a new message of size 1 from a mailbox if a message is available. Prototype char OS_MAILBOX_Get1(OS_MAILBOX* pMB, char* pDest); Parameters Parameter Description pMB Pointer to the mailbox. pDest 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. Return value 0 1 Success; message retrieved. 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. See Single-byte mailbox functions on page 182 for differences between OS_MAILBOX_Get() and OS_MAILBOX_Get1(). Example static OS_MAILBOX _MBKey; // // If a key has been pressed, it is taken out of the mailbox // and returned to caller. Otherwise zero is returned. // char GetKey(void) { char c = 0; OS_MAILBOX_Get1(&_MBKey, &c); return c; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 191 CHAPTER 8 8.2.6 API functions OS_MAILBOX_GetBlocked() Description Retrieves a new message of a predefined size from a mailbox. Prototype void OS_MAILBOX_GetBlocked(OS_MAILBOX* pMB, void* pDest); Parameters Parameter Description pMB Pointer to the mailbox. pDest 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. 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_MAILBOX_Get()/OS_MAILBOX_Get1() instead if you need to retrieve data from a mailbox from within an ISR. Example static OS_MAILBOX _MBData; struct Data Buffer; void WaitData(void) { OS_MAILBOX_GetBlocked(&_MBData, &Buffer); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 192 CHAPTER 8 8.2.7 API functions OS_MAILBOX_GetBlocked1() Description Retrieves a new message of size 1 from a mailbox. Prototype void OS_MAILBOX_GetBlocked1(OS_MAILBOX* pMB, char* pDest); Parameters Parameter Description pMB Pointer to the mailbox. pDest 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. 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_MAILBOX_Get()/OS_MAILBOX_Get1() instead if you need to retrieve data from a mailbox from within an ISR. See Single-byte mailbox functions on page 182 for differences between OS_MAILBOX_GetBlocked() and OS_MAILBOX_GetBlocked1(). Example static OS_MAILBOX _MBKey; char WaitKey(void) { char c; OS_MAILBOX_GetBlocked1(&_MBKey, &c); return c; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 193 CHAPTER 8 8.2.8 API functions OS_MAILBOX_GetMessageCnt() Description Returns the number of messages currently available in a specified mailbox. Prototype OS_UINT OS_MAILBOX_GetMessageCnt(OS_CONST_PTR OS_MAILBOX *pMB); Parameters Parameter pMB Description Pointer to the mailbox. Return value The number of messages currently available in the mailbox. Example static OS_MAILBOX _MBData; void PrintAvailableMessages() { OS_UINT NumOfMsgs; NumOfMsgs = OS_MAILBOX_GetMessageCnt(&_MBData); printf("Mailbox contains %d messages.\n", NumOfMsgs); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 194 CHAPTER 8 8.2.9 API functions OS_MAILBOX_GetTimed() Description Retrieves a new message of a predefined size from a mailbox if a message is available within a given time. Prototype char OS_MAILBOX_GetTimed(OS_MAILBOX* pMB, void* pDest, OS_TIME Timeout); Parameters Parameter Description pMB Pointer to the mailbox. pDest 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. Timeout Maximum time until the requested mail must be available. Timer period in embOS system ticks. The data type OS_TIME is defined as an integer, therefore valid values are: 1 Timeout 215 - 1 = 0x7FFF for 8/16 bit CPUs. 1 Timeout 231 - 1 = 0x7FFFFFFF for 32 bit CPUs. Return value 0 1 Success; message retrieved. 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 after the timeout expired, but before the calling task is resumed. Anyhow, the function returns with timeout, because the mail was not available within the requested time. In this case, no mail is retrieved from the mailbox. Example static OS_MAILBOX _MBData; struct Data Buffer; char GetData(void) { return OS_MAILBOX_GetTimed(&_MBData, &Buffer, 10); } UM01001 User Guide & Reference Manual for embOS // Wait for 10 system ticks (c) 1995-2018 SEGGER Microcontroller GmbH 195 CHAPTER 8 8.2.10 API functions OS_MAILBOX_GetTimed1() Description Retrieves a new message of size 1 from a mailbox if a message is available within a given time. Prototype char OS_MAILBOX_GetTimed1(OS_MAILBOX* pMB, char* pDest, OS_TIME Timeout); Parameters Parameter Description pMB Pointer to the mailbox. pDest 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. Timeout Maximum time until the requested mail must be available. Timer period in embOS system ticks. The data type OS_TIME is defined as an integer, therefore valid values are: 1 Timeout 215 - 1 = 0x7FFF for 8/16 bit CPUs. 1 Timeout 231 - 1 = 0x7FFFFFFF for 32 bit CPUs. Return value 0 1 Success; message retrieved. 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 after the timeout expired, but before the calling task is resumed. Anyhow, the function returns with timeout, because the mail was not available within the requested time. In this case, no mail is retrieved from the mailbox. See Single-byte mailbox functions on page 182 for differences between OS_MAILBOX_GetTimed() and OS_MAILBOX_GetTimed1(). Example static OS_MAILBOX _MBKey; // // If a key has been pressed, it is taken out of the mailbox // and returned to caller. Otherwise zero is returned. // char GetKey(void) { char c = 0; OS_MAILBOX_GetTimed1(&_MBKey, &c, 10); // Wait for 10 system ticks return c; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 196 CHAPTER 8 8.2.11 API functions OS_MAILBOX_GetPtr() Description Retrieves a pointer to a new message of a predefined size from a mailbox, if a message is available. Non blocking function. Prototype char OS_MAILBOX_GetPtr(OS_MAILBOX* pMB, void** ppDest); Parameters Parameter Description pMB Pointer to the mailbox. ppDest Pointer to the memory area that a pointer to the message should be stored at. The message size (in bytes) was defined when the mailbox was created. Return value 0 1 Success; message retrieved. Message could not be retrieved (mailbox is empty); destination remains unchanged. Additional information If the mailbox is empty, no message is retrieved and ppDest remains unchanged, but the program execution continues. This function never suspends the calling task. It may therefore also be called from an interrupt routine. The retrieved message is not removed from the mailbox, this must be done by a call of OS_MAILBOX_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 mailbox, the mailbox is marked "in use". Following calls of OS_MAILBOX_Clear(), OS_MAILBOX_Delete(), OS_MAILBOX_GetBlocked*() and OS_MAILBOX_GetPtrBlocked*() functions are not allowed until OS_MAILBOX_Purge() is called and will call OS_Error() in debug builds of embOS. Example static OS_MAILBOX _MBKey; void PrintMessage(void) { char* p; char r; r = OS_MAILBOX_GetPtr(&_MBKey, (void**)&p); if (r == 0) { printf("%d\n", *p); OS_MAILBOX_Purge(&_MBKey); } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 197 CHAPTER 8 8.2.12 API functions OS_MAILBOX_GetPtrBlocked() Description Retrieves a pointer to a new message of a predefined size from a mailbox. Prototype void OS_MAILBOX_GetPtrBlocked(OS_MAILBOX* pMB, void** ppDest); Parameters Parameter Description pMB Pointer to the mailbox. ppDest Pointer to the memory area that a pointer to the message should be stored at. The message size (in bytes) was defined when the mailbox was created. 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_MAILBOX_GetPtr() instead if you need to retrieve data from a mailbox from within an ISR. The retrieved message is not removed from the mailbox, this must be done by a call of OS_MAILBOX_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 mailbox, the mailbox is marked "in use". Following calls of OS_MAILBOX_Clear(), OS_MAILBOX_Delete(), OS_MAILBOX_GetBlocked*() and OS_MAILBOX_GetPtrBlocked*() functions are not allowed until OS_MAILBOX_Purge() is called and will call OS_Error() in debug builds of embOS. Example static OS_MAILBOX _MBKey; void PrintMessage(void) { char* p; OS_MAILBOX_GetPtrBlocked(&_MBKey, (void**)&p); printf("%d\n", *p); OS_MAILBOX_Purge(&_MBKey); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 198 CHAPTER 8 8.2.13 API functions OS_MAILBOX_Peek() Description Peeks a mail from a mailbox without removing the mail. The mail is copied to *pDest if one was available. Prototype char OS_MAILBOX_Peek(OS_CONST_PTR OS_MAILBOX *pMB, void* pDest); Parameters Parameter Description pMB Pointer to the mailbox. pDest Pointer to a buffer that should receive the mail. Return value 0 1 Success, mail was available and is copied to *pDest. Mail 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. Example static OS_MAILBOX _MBData; struct Data Buffer; char PeekData(void) { return OS_MAILBOX_Peek(&_MBData, &Buffer); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 199 CHAPTER 8 8.2.14 API functions OS_MAILBOX_Purge() Description Deletes the last retrieved message in a mailbox. Prototype void OS_MAILBOX_Purge(OS_MAILBOX* pMB); Parameters Parameter pMB Description Pointer to the mailbox. Additional information This routine should be called by the task that retrieved the last message from the mailbox, after the message is processed. Once a message was retrieved by a call of OS_MAILBOX_GetPtrBlocked() or OS_MAILBOX_GetPtr(), the message must be removed from the mailbox by a call of OS_MAILBOX_Purge() before a following message can be retrieved from the mailbox. Following calls of OS_MAILBOX_Clear(), OS_MAILBOX_Delete(), OS_MAILBOX_GetBlocked*() and OS_MAILBOX_GetPtrBlocked*() functions are not allowed until OS_MAILBOX_Purge() is called and will call OS_Error() in debug builds of embOS. Consecutive calls of OS_MAILBOX_Purge() or calling OS_MAILBOX_Purge() without having retrieved a message from the mailbox will also call OS_Error() in embOS debug builds. Example static OS_MAILBOX _MBKey; void PrintMessage(void) { char* p; OS_MAILBOX_GetPtrBlocked(&_MBKey, (void**)&p); printf("%d\n", *p); OS_MAILBOX_Purge(&_MBKey); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 200 CHAPTER 8 8.2.15 API functions OS_MAILBOX_Put() 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_MAILBOX_Put(OS_MAILBOX* pMB, OS_CONST_PTR void *pMail); Parameters Parameter Description pMB Pointer to the mailbox. pMail Pointer to the message to store. Return value 0 1 Success; message stored. 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 static OS_MAILBOX _MBData; void AddMessage(struct Data* pSomeData) { char Result; Result = OS_MAILBOX_Put(&_MBData, pSomeData); if (Result == 1) { printf("Was not able to add the message to the mailbox.\n"); } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 201 CHAPTER 8 8.2.16 API functions OS_MAILBOX_Put1() Description Stores a new message of size 1 in a mailbox if the mailbox is able to accept one more message. Prototype char OS_MAILBOX_Put1(OS_MAILBOX* pMB, OS_CONST_PTR char *pMail); Parameters Parameter Description pMB Pointer to the mailbox. pMail Pointer to the message to store. Return value 0 1 Success; message stored. 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. See Single-byte mailbox functions on page 182 for differences between OS_MAILBOX_Put() and OS_MAILBOX_Put1(). Example static OS_MAILBOX _MBKey; static char _MBKeyBuffer[6]; char KEYMAN_StoreCond(char k) { return OS_MAILBOX_Put1(&_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 Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 202 CHAPTER 8 8.2.17 API functions OS_MAILBOX_PutBlocked() Description Stores a new message of a predefined size in a mailbox. Prototype void OS_MAILBOX_PutBlocked(OS_MAILBOX* pMB, OS_CONST_PTR void *pMail); Parameters Parameter Description pMB Pointer to the mailbox. pMail Pointer to the message to store. 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_MAILBOX_Put()/OS_MAILBOX_Put1() 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. Example static OS_MAILBOX _MBData; void AddMessage(struct Data* pSomeData) { OS_MAILBOX_PutBlocked(&_MBData, pSomeData); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 203 CHAPTER 8 8.2.18 API functions OS_MAILBOX_PutBlocked1() Description Stores a new message of size 1 in a mailbox. Prototype void OS_MAILBOX_PutBlocked1(OS_MAILBOX* pMB, OS_CONST_PTR char *pMail); Parameters Parameter Description pMB Pointer to the mailbox. pMail Pointer to the message to store. 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_MAILBOX_Put()/OS_MAILBOX_Put1() 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. See Single-byte mailbox functions on page 182 for differences between OS_MAILBOX_PutBlocked() and OS_MAILBOX_PutBlocked1(). Example Single-byte mailbox as keyboard buffer: static OS_MAILBOX _MBKey; static char MBKeyBuffer[6]; void KEYMAN_StoreKey(char k) { OS_MAILBOX_PutBlocked1(&_MBKey, &k); */ } /* Store key, wait if no space in buffer void KEYMAN_Init(void) { /* Create mailbox functioning as type ahead buffer */ OS_MAILBOX_Create(&_MBKey, 1, sizeof(MBKeyBuffer), &MBKeyBuffer); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 204 CHAPTER 8 8.2.19 API functions OS_MAILBOX_PutFront() 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_MAILBOX_PutFront(OS_MAILBOX* pMB, OS_CONST_PTR void *pMail); Parameters Parameter Description pMB Pointer to the mailbox. pMail Pointer to the message to store. Return value 0 1 Success; message stored. 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_MAILBOX_Put() to change the FIFO structure of a mailbox into a LIFO structure. Example static OS_MAILBOX _MBData; void AddMessage(struct Data* pSomeData) { char Result; Result = OS_MAILBOX_PutFront(&_MBData, pSomeData); if (Result == 1) { printf("Was not able to add the message to the mailbox.\n"); } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 205 CHAPTER 8 8.2.20 API functions OS_MAILBOX_PutFront1() Description Stores a new message of size 1 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_MAILBOX_PutFront1(OS_MAILBOX* pMB, OS_CONST_PTR char *pMail); Parameters Parameter Description pMB Pointer to the mailbox. pMail Pointer to the message to store. Return value 0 1 Success; message stored. 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_MAILBOX_Put() to change the FIFO structure of a mailbox into a LIFO structure. See Single-byte mailbox functions on page 182 for differences between OS_MAILBOX_PutFront() and OS_MAILBOX_PutFront1(). Example static OS_MAILBOX _MBData; void AddMessage(char c) { char Result; Result = OS_MAILBOX_PutFront1(&_MBData, &c); if (Result == 1) { printf("Was not able to add the message to the mailbox.\n"); } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 206 CHAPTER 8 8.2.21 API functions OS_MAILBOX_PutFrontBlocked() 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_MAILBOX_PutFrontBlocked(OS_MAILBOX* pMB, OS_CONST_PTR void *pMail); Parameters Parameter Description pMB Pointer to the mailbox. pMail Pointer to the message to store. 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_MAILBOX_PutFront()/ OS_MAILBOX_PutFront1() 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_MAILBOX_PutBlocked() to change the FIFO structure of a mailbox into a LIFO structure. Example static OS_MAILBOX _MBData; void AddMessage(struct Data* pSomeData) { OS_MAILBOX_PutFrontBlocked(&_MBData, pSomeData); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 207 CHAPTER 8 8.2.22 API functions OS_MAILBOX_PutFrontBlocked1() Description Stores a new message of size 1 at the beginning of a mailbox in front of all other messages. This new message will be retrieved first. Prototype void OS_MAILBOX_PutFrontBlocked1(OS_MAILBOX* pMB, OS_CONST_PTR char *pMail); Parameters Parameter Description pMB Pointer to the mailbox. pMail Pointer to the message to store. 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_MAILBOX_PutFront()/ OS_MAILBOX_PutFront1() 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_MAILBOX_PutBlocked() to change the FIFO structure of a mailbox into a LIFO structure. See Single-byte mailbox functions on page 182 for differences between OS_MAILBOX_PutFrontBlocked() and OS_MAILBOX_PutFrontBlocked1(). Example Single-byte mailbox as keyboard buffer which will follow the LIFO pattern: static OS_MAILBOX _MBCmd; static char _MBCmdBuffer[6]; void KEYMAN_StoreCommand(char k) { OS_MAILBOX_PutFrontBlocked1(&_MBCmd, &k); /* Store command, wait if no space in buffer*/ } void KEYMAN_Init(void) { /* Create mailbox for command buffer */ OS_MAILBOX_Create(&_MBCmd, 1, sizeof(_MBCmdBuffer), &_MBCmdBuffer); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 208 CHAPTER 8 8.2.23 API functions OS_MAILBOX_PutTimed() Description Stores a new message of a predefined size in a mailbox if the mailbox is able to accept one more message within a given time. Returns when a new message has been stored in the mailbox (mailbox not full) or a timeout occurred. Prototype OS_BOOL OS_MAILBOX_PutTimed(OS_MAILBOX* pMB, OS_CONST_PTR void *pMail, OS_TIME Timeout); Parameters Parameter Description pMB Pointer to the mailbox. pMail Pointer to the message to store. Timeout Maximum time in embOS system ticks until the given mail must be stored Timer period in embOS system ticks. The data type OS_TIME is defined as an integer, therefore valid values are: 1 Timeout 215 - 1 = 0x7FFF for 8/16 bit CPUs. 1 Timeout 231 - 1 = 0x7FFFFFFF for 32 bit CPUs. Return value 0 1 Success; message stored. Message could not be stored within the given timeout (mailbox is full). destination remains unchanged. Additional information If the mailbox is full, no message is stored and the task is suspended for the given timeout. The task continues execution according to the rules of the scheduler as soon as a new mail is accepted 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 the mailbox accepts new messages after the timeout expired, but before the calling task is resumed. Anyhow, the function returns with timeout, because the mailbox was not available within the requested time. In this case, no mail is stored in the mailbox. Example static OS_MAILBOX _MBData; void AddMessage(struct Data* pSomeData) { OS_MAILBOX_PutTimed(&_MBData, pSomeData, 10); } UM01001 User Guide & Reference Manual for embOS // Wait maximum 10 system ticks (c) 1995-2018 SEGGER Microcontroller GmbH 209 CHAPTER 8 8.2.24 API functions OS_MAILBOX_PutTimed1() Description Stores a new message of size 1 in a mailbox if the mailbox is able to accept one more message within a given time. Returns when a new message has been stored in the mailbox (mailbox not full) or a timeout occurred. Prototype OS_BOOL OS_MAILBOX_PutTimed1(OS_MAILBOX* pMB, OS_CONST_PTR char *pMail, OS_TIME Timeout); Parameters Parameter Description pMB Pointer to the mailbox. pMail Pointer to the message to store. Timeout Maximum time in embOS system ticks until the given mail must be stored Timer period in embOS system ticks. The data type OS_TIME is defined as an integer, therefore valid values are: 1 Timeout 215 - 1 = 0x7FFF for 8/16 bit CPUs. 1 Timeout 231 - 1 = 0x7FFFFFFF for 32 bit CPUs. Return value 0 1 Success; message stored. Message could not be stored within the given timeout (mailbox is full). destination remains unchanged. Additional information If the mailbox is full, no message is stored and the task is suspended for the given timeout. The task continues execution according to the rules of the scheduler as soon as a new mail is accepted 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 the mailbox accepts new messages after the timeout expired, but before the calling task is resumed. Anyhow, the function returns with timeout, because the mailbox was not available within the requested time. In this case, no mail is stored in the mailbox. See Single-byte mailbox functions on page 182 for differences between OS_MAILBOX_PutTimed() and OS_MAILBOX_PutTimed1(). Example static OS_MAILBOX _MBKey; void SetKey(char c) { OS_MAILBOX_PutTimed1(&_MBKey, &c, 10); // Wait maximum 10 system ticks } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 210 CHAPTER 8 8.2.25 API functions OS_MAILBOX_WaitBlocked() Description Waits until a mail is available, but does not retrieve the message from the mailbox. Prototype void OS_MAILBOX_WaitBlocked(OS_MAILBOX* pMB); Parameters Parameter pMB Description Pointer to the mailbox. 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. Example static OS_MAILBOX _MBData; void Task(void) { while (1) { OS_MAILBOX_WaitBlocked(&_MBData); ... } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 211 CHAPTER 8 8.2.26 API functions OS_MAILBOX_WaitTimed() Description Waits until a mail is available or the timeout has expired, but does not retrieve the message from the mailbox. Prototype char OS_MAILBOX_WaitTimed(OS_MAILBOX* pMB, OS_TIME Timeout); Parameters Parameter Description pMB Pointer to the mailbox. Timeout Maximum time in embOS system ticks until the requested mail must be available. Timer period in embOS system ticks. The data type OS_TIME is defined as an integer, therefore valid values are: 1 Timeout 215 - 1 = 0x7FFF for 8/16 bit CPUs. 1 Timeout 231 - 1 = 0x7FFFFFFF for 32 bit CPUs. Return value 0 1 Success; message available. 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 after the timeout expired, but before the calling task is resumed. Anyhow, the function returns with timeout, because the mail was not available within the requested time. Example static OS_MAILBOX _MBData; void Task(void) { char Result; Result = OS_MAILBOX_WaitTimed(&_MBData, 10); if (Result == 0) { // Compute message } else { // Timeout } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 9 Queues UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 213 9.1 CHAPTER 9 Introduction Introduction In the preceding chapter, inter-task communication using mailboxes was described. Mailboxes can handle small messages with fixed data size only. Queues enable inter-task communication with larger messages or with messages of differing lengths. 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. Queues accept messages of differing lengths. When depositing a message into a queue, the message size is passed as a parameter. 2. 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. 3. The retrieving function must delete every message after processing it. 4. A new message can only be retrieved from the queue when the previous message was deleted from the queue. 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. Limitations: Both the number of queues and buffers are limited only by the amount of available memory. However, the individual message size and the buffer size per queue are limited by software design. Message size in bytes on 8 or 16bit CPUs: 1 <= x <= 215 - (1 + OS_Q_SIZEOF_HEADER + MESSAGE_ALIGNMENT) Message size in bytes on 32bit CPUs: 1 <= x <= 231 - (1 + OS_Q_SIZEOF_HEADER + MESSAGE_ALIGNMENT) Maximum buffer size in bytes for one queue on 8 or 16bit CPUs: 216 = 0xFFFF Maximum buffer size in bytes for one queue on 32bit CPUs: 232 = 0xFFFFFFFF Similar to mailboxes, queues can be used by more than one producer, but must 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. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 214 CHAPTER 9 Introduction Example #define #define #define #define static static static static MESSAGE_ALIGNMENT MESSAGES_SIZE_HELLO MESSAGES_SIZE_WORLD QUEUE_SIZE (4u) // Depends on core/compiler (7u + OS_Q_SIZEOF_HEADER+ MESSAGE_ALIGNMENT) (9u + OS_Q_SIZEOF_HEADER+ MESSAGE_ALIGNMENT) (MESSAGES_SIZE_HELLO + MESSAGES_SIZE_WORLD) OS_STACKPTR int StackHP[128], StackLP[128]; OS_TASK TCBHP, TCBLP; OS_QUEUE MyQueue; char MyQBuffer[QUEUE_SIZE]; // Task stacks // Task-control-blocks static void HPTask(void) { char* pData; int Len; while (1) { Len = OS_QUEUE_GetPtrBlocked(&MyQueue, (void**)&pData); OS_TASK_Delay(10); // // Evaluate Message // if (Len) { OS_COM_SendString(pData); OS_QUEUE_Purge(&MyQueue); } } } static void LPTask(void) { while (1) { OS_QUEUE_Put(&MyQueue, "\nHello\0", 7); OS_QUEUE_Put(&MyQueue, "\nWorld !\0", 9); OS_TASK_Delay(500); } } int main(void) { OS_Init(); // Initialize embOS OS_InitHW(); // Initialize required hardware OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP); OS_TASK_CREATE(&TCBLP, "LP Task", 50, LPTask, StackLP); OS_QUEUE_Create(&MyQueue, &MyQBuffer, sizeof(MyQBuffer)); OS_COM_SendString("embOS OS_Queue example"); OS_COM_SendString("\n\nDemonstrating message passing\n"); OS_Start(); // Start embOS return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 215 9.2 CHAPTER 9 API functions API functions Timer ISR Task Description main Routine OS_QUEUE_Clear() Clears all messages in the specified queue. OS_QUEUE_Create() Creates and initializes a message queue. OS_QUEUE_Delete() Deletes a specific message queue. OS_QUEUE_GetMessageCnt() Returns the number of messages that are currently stored in a queue. OS_QUEUE_GetMessageSize() Returns the size of the first message in the queue. OS_QUEUE_GetPtr() Retrieve the pointer to a message from the message queue if a message is available. OS_QUEUE_GetPtrBlocked() Retrieve the pointer to a message from the message queue. OS_QUEUE_GetPtrTimed() Retrieve the pointer to a message from the message queue within a specified time if a message is available. OS_QUEUE_IsInUse() Delivers information whether the queue is actually in use. OS_QUEUE_PeekPtr() Retrieve the pointer to a message from the message queue. OS_QUEUE_Purge() Deletes the last retrieved message in a queue. OS_QUEUE_Put() Stors a new message of given size in a queue. OS_QUEUE_PutEx() Stores a new message, of which the distinct parts are distributed in memory as in dicated by a OS_QUEUE_SRCLIST structure, in a queue. OS_QUEUE_PutBlocked() Stores a new message of given size in a queue. OS_QUEUE_PutBlockedEx() Stores a new message, of which the distinct parts are distributed in memory as indicated by a OS_QUEUE_SRCLIST structure, in a queue. OS_QUEUE_PutTimed() Stores a new message of given size in a queue if space is available within a given time. OS_QUEUE_PutTimedEx() Stores a new message, of which the distinct parts are distributed in memory as in dicated by a OS_QUEUE_SRCLIST structure, in a queue. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 216 CHAPTER 9 9.2.1 API functions OS_QUEUE_Clear() Description Clears all messages in the specified queue. Prototype void OS_QUEUE_Clear(OS_QUEUE* pQ); Parameters Parameter pQ Description Pointer to the queue. Additional information When the queue is in use, a debug build of embOS will call OS_Error() with error code OS_ERR_QUEUE_INUSE. OS_QUEUE_Clear() may cause a task switch. Example static OS_QUEUE _Queue; void ClearQueue() { OS_QUEUE_Clear(&_Queue); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 217 CHAPTER 9 9.2.2 API functions OS_QUEUE_Create() Description Creates and initializes a message queue. Prototype void OS_QUEUE_Create(OS_QUEUE* pQ, void* pData, OS_UINT Size); Parameters Parameter Description pQ Pointer to a data structure of type OS_QUEUE reserved for the management of the message queue. pData Pointer to a memory area used as data buffer for the queue. Size Size in bytes of the data buffer. 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. Example #define MESSAGE_CNT 100 #define MESSAGE_SIZE 100 #define MEMORY_QSIZE (MESSAGE_CNT * (MESSAGE_SIZE + OS_Q_SIZEOF_HEADER)) static OS_QUEUE _MemoryQ; static char _acMemQBuffer[MEMORY_QSIZE]; void MEMORY_Init(void) { OS_QUEUE_Create(&_MemoryQ, &_acMemQBuffer, sizeof(_acMemQBuffer)); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 218 CHAPTER 9 9.2.3 API functions OS_QUEUE_Delete() Description Deletes a specific message queue. Prototype void OS_QUEUE_Delete(OS_QUEUE* pQ); Parameters Parameter Description Pointer to the queue. pQ 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 static OS_QUEUE _QSerIn; void Cleanup(void) { OS_QUEUE_Delete(&_QSerIn); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 219 CHAPTER 9 9.2.4 API functions OS_QUEUE_GetMessageCnt() Description Returns the number of messages that are currently stored in a queue. Prototype int OS_QUEUE_GetMessageCnt(OS_CONST_PTR OS_QUEUE *pQ); Parameters Parameter Description Pointer to the queue. pQ Return value The number of messages in the queue. Example static OS_QUEUE _Queue; void PrintNumberOfMessages() { int Cnt; Cnt = OS_QUEUE_GetMessageCnt(&_Queue); printf("%d messages available.\n", Cnt); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 220 CHAPTER 9 9.2.5 API functions OS_QUEUE_GetMessageSize() Description Returns the size of the first message in the queue. Prototype int OS_QUEUE_GetMessageSize(OS_CONST_PTR OS_QUEUE *pQ); Parameters Parameter Description Pointer to the queue. pQ Return value =0 >0 No data available. Size of message in bytes. Additional information If the queue is empty OS_QUEUE_GetMessageSize() returns zero. If a message is available OS_QUEUE_GetMessageSize() returns the size of that message. The message is not retrieved from the queue. Example static OS_QUEUE _MemoryQ; static void _MemoryTask(void) { int Len; while (1) { Len = OS_QUEUE_GetMessageSize(&_MemoryQ); // Get message length if (Len > 0) { printf("Message with size %d retrieved\n", Len); OS_QUEUE_Purge(&_MemoryQ); // Delete message } OS_TASK_Delay(10); } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 221 CHAPTER 9 9.2.6 API functions OS_QUEUE_GetPtr() Description Retrieve the pointer to a message from the message queue if a message is available. Prototype int OS_QUEUE_GetPtr(OS_QUEUE* pQ, void** ppData); Parameters Parameter Description pQ Pointer to the queue. ppData Address of the pointer which will be set to the addr. of the message. Return value =0 >0 No message available in queue. Size of the message that was retrieved from the queue. 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_QUEUE_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". Following calls of OS_QUEUE_Clear(), OS_QUEUE_Delete(), OS_QUEUE_GetPtr(), OS_QUEUE_GetPtrBlocked() and OS_QUEUE_GetPtrTimed() functions are not allowed until OS_QUEUE_Purge() is called and will call OS_Error() in debug builds of embOS. Example static OS_QUEUE _MemoryQ; static void _MemoryTask(void) { int Len; char* pData; while (1) { Len = OS_QUEUE_GetPtr(&_MemoryQ, &pData); if (Len > 0) { Memory_WritePacket(*(U32*)pData, Len); OS_QUEUE_Purge(&_MemoryQ); } else { DoSomethingElse(); } } // Check message // Process message // Delete message } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 222 CHAPTER 9 9.2.7 API functions OS_QUEUE_GetPtrBlocked() Description Retrieve the pointer to a message from the message queue. Prototype int OS_QUEUE_GetPtrBlocked(OS_QUEUE* pQ, void** ppData); Parameters Parameter Description pQ Pointer to the queue. ppData Addr. of the pointer which will be set to the addr. of the message. Return value Size of the message in bytes. 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_QUEUE_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". Following calls of OS_QUEUE_Clear(), OS_QUEUE_Delete(), OS_QUEUE_GetPtr(), OS_QUEUE_GetPtrBlocked() and OS_QUEUE_GetPtrTimed() functions are not allowed until OS_QUEUE_Purge() is called and will call OS_Error() in debug builds of embOS. Example static OS_QUEUE _MemoryQ; static void _MemoryTask(void) { int Len; char* pData; while (1) { Len = OS_QUEUE_GetPtrBlocked(&_MemoryQ, &pData); // Get message Memory_WritePacket(*(U32*)pData, Len); // Process message OS_QUEUE_Purge(&_MemoryQ); // Delete message } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 223 CHAPTER 9 9.2.8 API functions OS_QUEUE_GetPtrTimed() Description Retrieve the pointer to a message from the message queue within a specified time if a message is available. Prototype int OS_QUEUE_GetPtrTimed(OS_QUEUE* pQ, void** ppData, OS_TIME Timeout); Parameters Parameter Description pQ Pointer to the queue. ppData Address of the pointer which will be set to the addr. of the message. Timeout Maximum time until the requested message must be available. Timer period in embOS system ticks. The data type OS_TIME is defined as an integer, therefore valid values are: 1 TimeOut 215 - 1 = 0x7FFF for 8/16 bit CPUs. 1 TimeOut 231 - 1 = 0x7FFFFFFF for 32 bit CPUs. Return value =0 >0 No message available in queue. 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 after the timeout expired, but before the calling task is resumed. Anyhow, the function returns with timeout, because the message was not available within the requested time. In this case the state of the queue is not modified by OS_QUEUE_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". Following calls of OS_QUEUE_Clear(), OS_QUEUE_Delete(), OS_QUEUE_GetPtr(), OS_QUEUE_GetPtrBlocked() and OS_QUEUE_GetPtrTimed() functions are not allowed until OS_QUEUE_Purge() is called and will call OS_Error() in debug builds of embOS. Example static OS_QUEUE _MemoryQ; static void _MemoryTask(void) { int Len; char* pData; while (1) { Len = OS_QUEUE_GetPtrTimed(&_MemoryQ, &pData, 10); if (Len > 0) { Memory_WritePacket(*(U32*)pData, Len); UM01001 User Guide & Reference Manual for embOS // Check message // Process message (c) 1995-2018 SEGGER Microcontroller GmbH 224 CHAPTER 9 OS_QUEUE_Purge(&_MemoryQ); } else { DoSomethingElse(); } API functions // Delete message // Timeout } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 225 CHAPTER 9 9.2.9 API functions OS_QUEUE_IsInUse() Description Delivers information whether the queue is actually in use. Prototype OS_BOOL OS_QUEUE_IsInUse(OS_CONST_PTR OS_QUEUE *pQ); Parameters Parameter Description Pointer to the queue. pQ Return value =0 0 Queue is not in use. 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_QUEUE_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_QUEUE* pQ) { OS_INT_IncDI(); // Avoid state change of the queue by task or interrupt // // Wait until queue is not used // while (OS_QUEUE_IsInUse(pQ) != 0) { OS_TASK_Delay(1); } OS_QUEUE_Delete(pQ); OS_INT_DecRI(); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 226 CHAPTER 9 9.2.10 API functions OS_QUEUE_PeekPtr() Description Retrieve the pointer to a message from the message queue. The message must not be purged. Prototype int OS_QUEUE_PeekPtr(OS_CONST_PTR OS_QUEUE *pQ, void** ppData); Parameters Parameter Description pQ Pointer to the queue. ppData Address of the pointer which will be set to the address of the message. Return value =0 0 No message available. Size of message in bytes. Sets the pointer ppData to the message that should be retrieved. Additional information Note Ensure the queues state is not altered as long as a message is processed. That is the reason for calling OS_INT_IncDI() in the sample. Ensure no cooperative task switch is performed, as this may also alter the queue state and buffer. OS_TASK_EnterRegion() does not inhibit cooperative task switches! Example static OS_QUEUE _MemoryQ; static void _MemoryTask(void) { int Len; char* pData; while (1) { OS_INT_IncDI(); // Avoid state changes of the queue by task or interrupt Len = OS_QUEUE_PeekPtr(&_MemoryQ, &pData); // Get message if (Len > 0) { Memory_WritePacket(*(U32*)pData, Len); // Process message } OS_INT_DecRI(); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 227 CHAPTER 9 9.2.11 API functions OS_QUEUE_Purge() Description Deletes the last retrieved message in a queue. Prototype void OS_QUEUE_Purge(OS_QUEUE* pQ); Parameters Parameter Description Pointer to the queue. pQ 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_QUEUE_GetPtrBlocked(), OS_QUEUE_GetPtr() or OS_QUEUE_GetPtrTimed(), the message must be removed from the queue by a call of OS_QUEUE_Purge() before a following message can be retrieved from the queue. Consecutive calls of OS_QUEUE_Purge() or calling OS_QUEUE_Purge() without having retrieved a message from the queue will call the embOS error handler OS_Error() in embOS debug builds. Example static OS_QUEUE _MemoryQ; static void _MemoryTask(void) { int Len; char* pData; while (1) { Len = OS_QUEUE_GetPtrBlocked(&_MemoryQ, &pData); Memory_WritePacket(*(U32*)pData, Len); OS_QUEUE_Purge(&_MemoryQ); } // Get message // Process message // Delete message } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 228 CHAPTER 9 9.2.12 API functions OS_QUEUE_Put() Description Stors a new message of given size in a queue. Prototype int OS_QUEUE_Put(OS_QUEUE* pQ, OS_CONST_PTR void *pSrc, OS_UINT Size); Parameters Parameter Description pQ Pointer to a data structure of type OS_QUEUE. pSrc Pointer to the message to store. Size Size of the 1 Size 1 Size message to store. Valid values are: 215 - 1 = 0x7FFF for 8/16 bit CPUs. 231 - 1 = 0x7FFFFFFF for 32 bit CPUs. Return value 0 1 Success, message stored. 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 static OS_QUEUE _MemoryQ; int MEMORY_Write(const char* pData, OS_UINT Len) { return OS_QUEUE_Put(&_MemoryQ, pData, Len); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 229 CHAPTER 9 9.2.13 API functions OS_QUEUE_PutEx() Description Stores a new message, of which the distinct parts are distributed in memory as indicated by a OS_QUEUE_SRCLIST structure, in a queue. Prototype int OS_QUEUE_PutEx(OS_QUEUE* pQ, OS_CONST_PTR OS_QUEUE_SRCLIST *pSrcList, OS_UINT NumSrc); Parameters Parameter Description pQ Pointer to the queue. pSrcList Pointer to an array of OS_QUEUE_SRCLIST structures which contain pointers to the data to store. NumSrc Number of OS_QUEUE_SRCLIST structures at pSrcList. Return value 0 1 Success, message stored. Message could not be stored (queue is full). Additional information This routine never suspends the calling task and may therefore be called from main(), an interrupt routine or a software timer. When the message is deposited into the queue, the entire message is copied into the queue buffer, not only the pointer(s) 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 OS_CONST_PTR OS_QUEUE_SRCLIST aDataList[] = { {"Hello ", 6}, {"World!", 6} }; OS_QUEUE_PutEx(&_MemoryQ, aDataList, 2); 9.2.13.1 The OS_QUEUE_SRCLIST structure The OS_QUEUE_SRCLIST structure consists of two elements: Parameter Description pSrc Pointer to a part of the message to store. Size Size of the part of the message. Valid values are: 1 Size 215 - 1 = 0x7FFF for 8/16 bit CPUs. 1 Size 231 - 1 = 0x7FFFFFFF for 32 bit CPUs. Note The total size of all parts of the message must not exceed 0x7FFF on 8/16 bit CPUs, or 0x7FFFFFFF on 32 bit CPUs, respectively. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 230 CHAPTER 9 9.2.14 API functions OS_QUEUE_PutBlocked() Description Stores a new message of given size in a queue. Prototype void OS_QUEUE_PutBlocked(OS_QUEUE* pQ, OS_CONST_PTR void *pSrc, OS_UINT Size); Parameters Parameter Description pQ Pointer to the queue. pSrc Pointer to the message to store. Size Size of the 1 Size 1 Size message to store. Valid values are: 215 - 1 = 0x7FFF for 8/16 bit CPUs. 231 - 1 = 0x7FFFFFFF for 32 bit CPUs. Additional information If the queue is full, the calling task is suspended. When the message is deposited into the queue, the entire message is copied into the queue buffer, not only the pointer(s) 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 static OS_QUEUE _MemoryQ; void StoreMessage(const char* pData, OS_UINT Len) OS_QUEUE_PutBlocked(&_MemoryQ, pData, Len); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 231 CHAPTER 9 9.2.15 API functions OS_QUEUE_PutBlockedEx() Description Stores a new message, of which the distinct parts are distributed in memory as indicated by a OS_QUEUE_SRCLIST structure, in a queue. Blocks the calling task when queue is full. Prototype void OS_QUEUE_PutBlockedEx(OS_QUEUE* pQ, OS_CONST_PTR OS_QUEUE_SRCLIST *pSrcList, OS_UINT NumSrc); Parameters Parameter Description pQ Pointer to the queue. pSrcList Pointer to an array of OS_QUEUE_SRCLIST structures which contain pointers to the data to store. NumSrc Number of OS_QUEUE_SRCLIST structures at pSrcList. Additional information If the queue is full, the calling task is suspended. When the message is deposited into the queue, the entire message is copied into the queue buffer, not only the pointer(s) to the data. Therefore the message content is protected and remains valid until it is retrieved and accessed by a task reading the message. For more information on the OS_QUEUE_SRCLIST structure, refer to The OS_QUEUE_SRCLIST structure in the chapter The OS_QUEUE_SRCLIST structure on page 229. Example OS_CONST_PTR OS_QUEUE_SRCLIST aDataList[] = { {"Hello ", 6}, {"World!", 6} }; OS_QUEUE_PutEx(&_MemoryQ, aDataList, 2); UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 232 CHAPTER 9 9.2.16 API functions OS_QUEUE_PutTimed() Description Stores a new message of given size in a queue if space is available within a given time. Prototype char OS_QUEUE_PutTimed(OS_QUEUE* OS_CONST_PTR OS_UINT OS_TIME pQ, void *pSrc, Size, Timeout); Parameters Parameter Description pQ Pointer to the queue. pSrc Pointer to the message to store. Size Size of the 1 Size 1 Size Timeout Maximum time until the given message must be stored. Timer period in embOS system ticks. The data type OS_TIME is defined as an integer, therefore valid values are: 1 TimeOut 215 - 1 = 0x7FFF for 8/16 bit CPUs. 1 TimeOut 231 - 1 = 0x7FFFFFFF for 32 bit CPUs. message to store. Valid values are: 215 - 1 = 0x7FFF for 8/16 bit CPUs. 231 - 1 = 0x7FFFFFFF for 32 bit CPUs. Return value 0 1 Success, message stored. 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. When the message is deposited into the queue, the entire message is copied into the queue buffer, not only the pointer(s) 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 static OS_QUEUE _MemoryQ; int MEMORY_WriteTimed(const char* pData, OS_UINT Len, OS_TIME Timeout) { return OS_QUEUE_PutTimed(&_MemoryQ, pData, Len, Timeout); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 233 CHAPTER 9 9.2.17 API functions OS_QUEUE_PutTimedEx() Description Stores a new message, of which the distinct parts are distributed in memory as indicated by a OS_QUEUE_SRCLIST structure, in a queue. Suspends the calling task for a given timeout when the queue is full. Prototype char OS_QUEUE_PutTimedEx(OS_QUEUE* OS_CONST_PTR OS_UINT OS_TIME pQ, OS_QUEUE_SRCLIST *pSrcList, NumSrc, Timeout); Parameters Parameter Description pQ Pointer to the queue. pSrcList Pointer to an array of OS_QUEUE_SRCLIST structures which contain pointers to the data to store. NumSrc Number of OS_QUEUE_SRCLIST structures at pSrcList. Timeout Maximum time until the given message must be stored. Timer period in embOS system ticks. The data type OS_TIME is defined as an integer, therefore valid values are: 1 TimeOut 215 - 1 = 0x7FFF for 8/16 bit CPUs. 1 TimeOut 231 - 1 = 0x7FFFFFFF for 32 bit CPUs. Return value =0 0 Success, message stored. 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. When the message is deposited into the queue, the entire message is copied into the queue buffer, not only the pointer(s) to the data. Therefore the message content is protected and remains valid until it is retrieved and accessed by a task reading the message. For more information on the OS_QUEUE_SRCLIST structure, refer to The OS_QUEUE_SRCLIST structure in the chapter The OS_QUEUE_SRCLIST structure on page 229. Example OS_CONST_PTR OS_QUEUE_SRCLIST aDataList[] = { {"Hello ", 6}, {"World!", 6} }; OS_QUEUE_PutEx(&MemoryQ, aDataList, 2, 100); UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 10 Watchdog UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 235 CHAPTER 10 10.1 Introduction Introduction A watchdog timer is a hardware timer that is used to reset a microcontroller after a specified amount of time. During normal operation, the microcontroller application periodically restarts ("triggers") the watchdog timer to prevent it from timing out. In case of malfunction, however, the watchdog timer will eventually time out and subsequently reset the microcontroller. This allows to detect and recover from microcontroller malfunctions. For example, in a system without an RTOS, the watchdog timer would be triggered periodically from a single point in the application. When the application does not run properly, the watchdog timer will not be triggered and thus the watchdog will cause a reset of the microcontroller. In a system that includes an RTOS, on the other hand, multiple tasks run at the same time. It may happen that one or more of these tasks runs properly, while other tasks fail to run as intended. Hence it may be insufficient to trigger the watchdog from one of these tasks only. Therefore, embOS offers a watchdog support module that allows to automatically check if all tasks, software timers, or even interrupt routines are executing properly. Example #include "RTOS.h" static static static static OS_STACKPTR int OS_TASK OS_WD OS_TICK_HOOK StackHP[128], StackLP[128]; TCBHP, TCBLP; WatchdogHP, WatchdogLP; Hook; static void _TriggerWatchDog(void) { WD_REG = TRIGGER_WD; // Trigger the hardware watchdog. } static void _Reset(OS_CONST_PTR OS_WD* pWD) { OS_USEPARA(pWD); // Applications can use pWD to detect WD expiration cause. SYSTEM_CTRL_REG = PERFORM_RESET; // Reboot microcontroller. } static void HPTask(void) { OS_WD_Add(&WatchdogHP, 50); while (1) { OS_TASK_Delay(50); OS_WD_Trigger(&WatchdogHP); } } static void LPTask(void) { OS_WD_Add(&WatchdogLP, 200); while (1) { OS_TASK_Delay(200); OS_WD_Trigger(&WatchdogLP); } } int main(void) { OS_Init(); // Initialize embOS OS_InitHW(); // Initialize required hardware OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP); OS_TASK_CREATE(&TCBLP, "LP Task", 50, LPTask, StackLP); OS_WD_Config(&_TriggerWatchDog, &_Reset); OS_TICK_AddHook(&Hook, OS_WD_Check); OS_Start(); // Start embOS return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 236 CHAPTER 10 10.2 API functions API functions Timer ISR Task Description main Routine OS_WD_Add() Adds a software watchdog timer to the watchdog list. OS_WD_Check() Checks if a watchdog timer expired. OS_WD_Config() Sets the watchdog callback functions. OS_WD_Remove() Removes a watchdog timer from the watchdog list. OS_WD_Trigger() Triggers a watchdog timer. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 237 CHAPTER 10 10.2.1 API functions OS_WD_Add() Description Adds a software watchdog timer to the watchdog list. Prototype void OS_WD_Add(OS_WD* pWD, OS_TIME Timeout); Parameters Parameter Description pWD Pointer to a watchdog timer object. Timeout Watchdog timer timeout. Must be within the following range: 0 t 215 - 1 = 0x7FFF for 8/16 bit CPUs 0 t 231 - 1 = 0x7FFFFFFF for 32 bit CPUs Please note that these are signed values. Example static OS_WD _myWD; void HPTask(void) { OS_WD_Add(&_myWD, 50); while (1) { OS_WD_Trigger(&_myWD); OS_TASK_Delay(50); } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 238 CHAPTER 10 10.2.2 API functions OS_WD_Check() Description Checks if a watchdog timer expired. If no watchdog timer expired the hardware watchdog is triggered. If a watchdog timer expired, the callback function is called. Prototype void OS_WD_Check(void); Additional information OS_WD_Check() must be called periodically. It is good practice to call it from the system tick handler. Example void SysTick_Handler(void) { OS_INT_Enter(); OS_Tick_Handle(); OS_WD_Check(); OS_INT_Leave(); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 239 CHAPTER 10 10.2.3 API functions OS_WD_Config() Description Sets the watchdog callback functions. Prototype void OS_WD_Config(voidRoutine* pfTriggerFunc, OS_WD_RESET_CALLBACK* pfResetFunc); Parameters Parameter Description pfTriggerFunc Function pointer to hardware watchdog trigger callback function. pfResetFunc Function pointer to callback function which is called in case of an expired watchdog timer. pfResetFunc is optional and may be NULL. Additional information pfResetFunc may be used to perform additional operations inside a callback function prior to the reset of the microcontroller. For example, a message may be written to a log file. If pfResetFunc is NULL, no callback function gets executed, but the hardware watchdog will still cause a reset of the microcontroller. Example static void _TriggerWatchDog(void) { WD_REG = TRIGGER_WD; // Trigger the hardware watchdog } static void _Reset(OS_CONST_PTR OS_WD* pWD) { _WriteLogMessage(pWD); // Store information about expired watchdog prior to reset. SYSTEM_CTRL_REG = PERFORM_RESET; // Reboot microcontroller } int main(void) { ... OS_WD_Config(&_TriggerWatchDog, &_Reset); OS_Start(); } Note In previous versions of embOS, OS_WD_Config() expected the parameter pfResetFunc to be of a different type. Since embOS V4.40, instead of a callback of the type voidRoutine*, OS_WD_Config() expects a callback of type OS_WD_RESET_CALLBACK*. This allows for passing the relevant OS_WD structure to the routine, e.g. for further examination by the application. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 240 CHAPTER 10 10.2.4 API functions OS_WD_Remove() Description Removes a watchdog timer from the watchdog list. Prototype void OS_WD_Remove(OS_CONST_PTR OS_WD *pWD); Parameters Parameter pWD Description Pointer to a watchdog timer object. Example int main(void) { OS_WD_Add(&_myWD); OS_WD_Remove(&_myWD); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 241 CHAPTER 10 10.2.5 API functions OS_WD_Trigger() Description Triggers a watchdog timer. Prototype void OS_WD_Trigger(OS_WD* pWD); Parameters Parameter pWD Description Pointer to a watchdog timer object. Additional information Each software watchdog timer must be triggered periodically. If not, the timeout expires and OS_WD_Check() will no longer trigger the hardware watchdog timer, but will call the reset callback function (if any). Example static OS_WD _myWD; static void HPTask(void) { OS_WD_Add(&_myWD, 50); while (1) { OS_TASK_Delay(50); OS_WD_Trigger(&_myWD); } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 11 Multi-core Support UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 243 CHAPTER 11 11.1 Introduction Introduction embOS can be utilized on multi-core processors by running separate embOS instances on each individual core. For synchronization purposes and in order to exchange data between the cores, embOS includes a comprehensive spinlock API which can be used to control access to shared memory, peripherals, etc. Spinlocks Spinlocks constitute a general purpose locking mechanism in which any process trying to acquire the lock is caused to actively wait until the lock becomes available. To do so, the process trying to acquire the lock remains active and repeatedly checks the availability of the lock in a loop. Effectively, the process will "spin" until it acquires the lock. Once acquired by a process, spinlocks are usually held by that process until they are explicitly released. If held by one process for longer duration, spinlocks may severely impact the runtime behavior of other processes trying to acquire the same spinlock. Therefore, spinlocks should be held by one process for short periods of time only. Usage of spinlocks with embOS embOS spinlocks are intended for inter-core synchronization and communication. They are not intended for synchronization of individual tasks running on the same core, on which semaphores, queues and mailboxes should be used instead. However, multitasking still has to be taken into consideration when using embOS spinlocks. Specifically, an embOS task holding a spinlock should not be preempted, for this would prevent that task from releasing the spinlock as fast as possible, which may in return impact the runtime behavior of other cores attempting to acquire the spinlock. Declaration of critical regions therefore is explicitly recommended while holding spinlocks. embOS spinlocks are usually implemented using hardware instructions specific to one architecture, but a portable software implementation is provided in addition. If appropriate hardware instructions are unavailable for the specific architecture in use, the software implementation is provided exclusively. Note It is important to use matching implementations on each core of the multicore processor that shall access the same spinlock. For example, a core supporting a hardware implementation may use that implementation to access a spinlock that is shared with another core that supports the same hardware implementation. At the same time, that core may use the software implementation to access a different spinlock that is shared with a different core that does not support the same hardware implementation. However, in case all three cores in this example should share the same spinlock, each of them has to use the software implementation. To know the spinlock's location in memory, each core's application must declare the appropriate OS_SPINLOCK variable (or OS_SPINLOCK_SW, respectively) at an identical memory address. Initialization of the spinlock, however, must be performed by one core only. This API is not available in embOS library mode OS_LIBMODE_SAFE. Example of using spinlocks Two cores of a multi-core processor shall access an hardware peripheral, e.g. a LC display. To avoid situations in which both cores access the LCD simultaneously, access must be restricted through usage of a spinlock: Every time the LCD is used by one core, it must first claim the spinlock through the respective embOS API call. After the LCD has been written to, the spinlock is released by another embOS API call. Data exchange between cores can be implemented analogously, e.g. through declaration of a buffer in shared memory: Here, every time a core shall write data to the buffer, it must acquire the spinlock first. After the data has been written to the buffer, the spinlock UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 244 CHAPTER 11 Introduction is released. This ensures that neither core can interfere with the writing of data by the other core. Core 0: #include "RTOS.h" static OS_STACKPTR int Stack[128]; // Task stack static OS_TASK TCB; // Task-control-block static OS_SPINLOCK MySpinlock @ ".shared_mem"; static void Task(void) { while (1) { OS_TASK_EnterRegion(); OS_SPINLOCK_Lock(&MySpinlock); // // Perform critical operation // OS_SPINLOCK_Unlock(&MySpinlock); OS_TASK_LeaveRegion(); } } // Inhibit preemptive task switches // Acquire spinlock // Release spinlock // Re-allow preemptive task switches int main(void) { OS_Init(); // Initialize embOS OS_InitHW(); // Initialize Hardware for OS OS_SPINLOCK_Create(&MySpinlock); // Initialize Spinlock OS_TASK_CREATE(&TCB, "Task", 100, Task, Stack); OS_Start(); // Start multitasking return 0; } Core 1: #include "RTOS.h" static OS_STACKPTR int Stack[128]; // Task stack static OS_TASK TCB; // Task-control-block static OS_SPINLOCK MySpinlock @ ".shared_mem"; static void Task(void) { while (1) { OS_TASK_EnterRegion(); OS_SPINLOCK_Lock(&MySpinlock); // // Perform critical operation // OS_SPINLOCK_Unlock(&MySpinlock); OS_TASK_LeaveRegion(); } } // Inhibit preemptive task switches // Acquire spinlock // Release spinlock // Re-allow preemptive task switches int main(void) { OS_Init(); // Initialize embOS OS_InitHW(); // Initialize Hardware for OS OS_TASK_CREATE(&TCB, "Task", 100, Task, Stack); OS_Start(); // Start multitasking return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 245 CHAPTER 11 11.2 API functions API functions Creates a hardware-specific spinlock. OS_SPINLOCK_Lock() Acquires a hardware-specific spinlock. Busy waiting until the spinlock becomes available. This function is unavailable for some architectures. OS_SPINLOCK_Unlock() Releases a hardware-specific spinlock. OS_SPINLOCK_SW_Create() Creates a software-implementation spinlock. OS_SPINLOCK_SW_Lock() Acquires a software-implementation spinlock. OS_SPINLOCK_SW_Unlock() Releases a software-implementation spinlock. UM01001 User Guide & Reference Manual for embOS Timer OS_SPINLOCK_Create() ISR Task Description main Routine (c) 1995-2018 SEGGER Microcontroller GmbH 246 CHAPTER 11 11.2.0.1 API functions OS_SPINLOCK_Create() Description Creates a hardware-specific spinlock. This function is unavailable for architectures that do not support an appropriate instruction set. Prototype void OS_SPINLOCK_Create(OS_SPINLOCK* pSpinlock); Parameters Parameter pSpinlock Description Pointer to a variable of type OS_SPINLOCK reserved for the management of the spinlock. The variable must reside in shared memory. Additional information After creation, the spinlock is not locked. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 247 CHAPTER 11 11.2.0.2 API functions OS_SPINLOCK_Lock() Description OS_SPINLOCK_Lock() acquires a hardware-specific spinlock. If the spinlock is unavailable, the calling task will not be blocked, but will actively wait until the spinlock becomes available. This function is unavailable for architectures that do not support an appropriate instruction set. Prototype void OS_SPINLOCK_Lock (OS_SPINLOCK* pSpinlock); Parameters Parameter pSpinlock Description Pointer to a variable of type OS_SPINLOCK reserved for the management of the spinlock. Additional information A task that has acquired a spinlock must not call OS_SPINLOCK_Lock() for that spinlock again. The spinlock must first be released by a call to OS_SPINLOCK_Unlock(). The following diagram illustrates how OS_SPINLOCK_Lock() works: UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 248 CHAPTER 11 11.2.0.3 API functions OS_SPINLOCK_Unlock() Description Releases a hardware-specific spinlock. This function is unavailable for architectures that do not support an appropriate instruction set. Prototype void OS_SPINLOCK_Unlock(OS_SPINLOCK* pSpinlock); Parameters Parameter pSpinlock Description Pointer to a variable of type OS_SPINLOCK reserved for the management of the spinlock. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 249 CHAPTER 11 11.2.0.4 API functions OS_SPINLOCK_SW_Create() Description Creates a software-implementation spinlock. Prototype void OS_SPINLOCK_SW_Create(OS_SPINLOCK_SW* pSpinlock); Parameters Parameter pSpinlock Description Pointer to a data structure of type OS_SPINLOCK_SW reserved for the management of the spinlock. The variable must reside in shared memory. Additional information After creation, the spinlock is not locked. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 250 CHAPTER 11 11.2.0.5 API functions OS_SPINLOCK_SW_Lock() Description Acquires a software-implementation spinlock. If the spinlock is unavailable, the calling task will not be blocked, but will actively wait until the spinlock becomes available. Prototype void OS_SPINLOCK_SW_Lock(OS_SPINLOCK_SW* pSpinlock, OS_UINT Id); Parameters Parameter Description pSpinlock Pointer to a data structure of type OS_SPINLOCK_SW reserved for the management of the spinlock. Id Unique identifier to specify the core accessing the spinlock. Valid values are 0 Id < OS_SPINLOCK_MAX_CORES. By default, OS_SPINLOCK_MAX_CORES is defined to 4 and may be changed when using source code. An embOS debug build calls OS_Error() in case invalid values are used. Additional information A task that has acquired a spinlock must not call OS_SPINLOCK_SW_Lock() for that spinlock again. The spinlock must first be released by a call to OS_SPINLOCK_SW_Unlock(). OS_SPINLOCK_SW_Lock() implements Lamport's bakery algorithm, published by Leslie Lamport in "Communications of the Association for Computing Machinery", 1974, Volume 17, Number 8. An excerpt is publicly available at research.microsoft.com. The following diagram illustrates how OS_SPINLOCK_SW_Lock() works: UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 251 CHAPTER 11 11.2.0.6 API functions OS_SPINLOCK_SW_Unlock() Description Releases a software-implementation spinlock. Prototype void OS_SPINLOCK_SW_Unlock(OS_SPINLOCK_SW* pSpinlock, OS_UINT Id); Parameters Parameter Description pSpinlock Pointer to a data structure of type OS_SPINLOCK_SW reserved for the management of the spinlock. Id Unique identifier to specify the core accessing the spinlock. Valid values are 0 Id < OS_SPINLOCK_MAX_CORES. By default, OS_SPINLOCK_MAX_CORES is defined to 4 and may be changed when using source code. An embOS debug build calls OS_Error() in case invalid values are used. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 12 Interrupts UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 253 CHAPTER 12 12.1 What are interrupts? What are 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. 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. Maskable interrupts can occur at any time unless they are disabled. ISRs are also nestable - they can be recognized and executed within other ISRs. There are several good reasons for using interrupt routines. They can respond very quickly to external events such as the status change on an input, the expiration of a hardware timer, reception or completion of transmission of a character via serial interface, or other types of events. Interrupts effectively allow events to be processed as they occur. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 254 CHAPTER 12 12.2 Interrupt latency 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 number of individual smaller delays explained below. Note Interrupt latency caused by embOS can be avoided entirely when using zero latency interrupts, which are explained in chapter Zero interrupt latency on page 256. 12.2.1 * * * * * 12.2.2 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 three CPU cycles can be lost before the interrupt request reaches the CPU core. The CPU will typically complete the current instruction. This instruction can take multiple cycles to complete; 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}; typically is the worst case instruction. It stores thirteen 32 bit registers to the stack, which, in an ARM7 system, takes 15 clock cycles to complete. 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) to the stack. In general, modern CPUs (such as ARM) perform a mode switch, which requires fewer 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 flushes the pipeline, a few extra cycles are required to refill the pipeline. 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 additional 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 additional latency. Real-time Operating system (RTOS). An RTOS also needs to temporarily disable the interrupts which can call API-functions of the RTOS. Some RTOSes disable all interrupts, UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 255 CHAPTER 12 Interrupt latency effectively increasing interrupt latency for all interrupts, some (like embOS) disable only low-priority interrupts and do thereby not affect the latency of high priority interrupts. 12.2.3 How to measure latency and detect its cause It is sometimes desirable to detect the cause for high interrupt latency. High interrupt latency may occur if interrupts are disabled for extended periods of time, or if a low level interrupt handler is executed before the actual interrupt handler. In these regards, embOS related functions like OS_INT_Enter() add to interrupt latency as well. To measure interrupt latency and detect its cause, a timer interrupt may be used. For example, if the hardware timer counts upwards starting from zero after each compare-matchinterrupt, its current counter value may be read from within the interrupt service routine to evaluate how many timer cycles (and thus how much time) have lapsed between the interrupt's occurance and the actual execution of the interrupt handler: static int Latency = 0; void TimerIntHandler(void) { OS_INT_Enter(); Latency = TIMER_CNT_VALUE; OS_INT_Leave(); } // Get current timer value If this measurement is repeated several times, different results will occur. This is for the reason that the interrupt will sometimes be asserted while interrupts have been disabled by the application, while at other times interrupts are enabled when this interrupt request occurs. Thus, an application may keep track of minimum and maximum latency as shown below: static int Latency = 0; static int MaxLatency = 0; static int MinLatency = 0xFFFFFFFF; void TimerIntHandler(void) { OS_INT_Enter(); Latency = TIMER_CNT_VALUE; // Get current timer value MinLatency = (Latency < MinLatency) ? Latency : MinLatency; MaxLatency = (Latency > MaxLatency) ? Latency : MaxLatency; OS_INT_Leave(); } Using this method, MinLatency will hold the latency that was caused by hardware (and any low-level interrupt handler, if applicable). On the other hand, MaxLatency will hold the latency caused both by hardware and interrupt-masking in software. Therefore, by substracting MaxLatency - MinLatency, it is possible to calculate the exact latency that was caused by interrupt-masking (typcially performed by the operating system). Based on this information, a threshold may be defined to detect the cause of high interrupt latency. E.g., a breakpoint may be set for when the current timer value exceeds a predefined threshold as shown below: static int Latency = 0; void TimerIntHandler(void) { OS_INT_Enter(); Latency = TIMER_CNT_VALUE; // Get current timer value if (Latency > LATENCY_THRESHOLD) { while (1); // Set a breakpoint here } OS_INT_Leave(); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 256 CHAPTER 12 Interrupt latency If code trace information is available upon hitting the breakpoint, the exact cause for the latency may be checked through a trace log. Note If the hardware timer interrupt is the only interrupt in the system, its priority may be chosen arbitrarily. Otherwise, in case other interrupts occur during measurement as well, the timer interrupt should be configured to match the specific priority for which to measure latency. This is important, for other (possibly non-nestable) interrupts will influence the results depending on their priority relative to the timer interrupt's priority, which may or may not be desired on a case-to-case basis. Also, in order to provide meaningful results, the interrupt should occur quite frequently. Hence, the timer reload value typically is configured for small periods of time, but must ensure that interrupt execution will not consume the entire CPU time. 12.2.4 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 worst case 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 maximum latency can arise from requirements such as maximum reaction time for a protocol or a software UART implementation that requires very precise timing. For example a UART receiving at up to 800 kHz in software using ARM FIQ on a 48 MHz ARM7. This would be impossible to do if FIQ were disabled even for short periods of time. In many embedded systems, the quality of the product depends on event reaction time and therefore 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 periodical read from an ADC and the result is stored in a global variable. Another way is to assert an interrupt request for a low priority interrupt from within the high priority ISR, which may then communicate or wake up one or more tasks. This is helpful if you want to receive high amounts of data in your high priority ISR. The low priority ISR may then store the data bytes e.g. in a message queue or in a mailbox. 12.2.5 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 priority. The number of interrupt levels depends 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 and low priority interrupts. The embOS port-specific documentations explain which interrupts are considered UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 257 CHAPTER 12 Interrupt latency high and which are considered low priority for that specific port. In general, the differences between those two are as follows: Low priority interrupts * * * May call embOS API functions Latencies caused by embOS Also called "embOS interrupts" High priority interrupts * * * May not call embOS API functions No latencies caused by embOS (Zero latency) Also called "Zero latency interrupts" Example of different interrupt priority levels Let's assume we have a CPU which supports eight interrupt priority levels. With embOS, the interrupt levels are divided per default equal in low priority and high priority interrupt levels. The four highest priority levels are considered "High priority interrupts" and the four lowest priority interrupts are considered as "Low priority interrupts". For ARM CPUs, which support regular interrupts (IRQ) and fast interrupt (FIQ), FIQ is considered as "High priority interrupt" when using embOS. For most implementations the high-priority threshold is adjustable. For details, refer to the processor specific embOS manual. 12.2.5.1 Using embOS API from zero latency interrupts High priority interrupts are prohibited from using embOS functions. This is a consequence of embOS's zero-latency design, according to which embOS never disables high priority interrupts. This means that high priority interrupts can interrupt the operating system at any time, even in critical sections such as the modification of RTOS-maintained linked lists. This design decision has been made because zero interrupt latencies for high priority interrupts usually are more important than the ability to call OS functions. However, high priority interrupts may use OS functions in an indirect manner: The high priority interrupt triggers a low priority interrupt by setting the appropiate interrupt request flag. Subsequently, that low priority interrupt may call the OS functions that the high priority interrupt was not allowed to use. 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 Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 258 CHAPTER 12 12.3 12.3.1 Rules for interrupt handlers Rules for interrupt handlers 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. * * 12.3.2 ISR preserves 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 finish 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. Additional rules for preemptive multitasking A preemptive multitasking system like embOS needs to know if the code that is executing is part of the current task or an interrupt handler. This is necessary because embOS cannot perform a task switch during the execution but only at the end of an ISR. If a task switch was 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: * ISRs that re-enable interrupts or use any embOS function need to call OS_INT_Enter() at the beginning, before executing anything else, and call OS_INT_Leave() immediately before returning. If a higher priority task is made ready by the ISR, the task switch will be performed in the routine OS_INT_Leave(). The end of the ISR is executed later on, when the interrupted task has been made ready again. Please consider this behaviour if you debug an interrupt routine, this has proven to be the most efficient way of initiating a task switch from within an interrupt service routine. 12.3.3 Nesting interrupt routines By default, interrupts are disabled in an ISR because most 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: UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 259 CHAPTER 12 Rules for interrupt handlers For applications requiring short interrupt latency, you may re-enable interrupts inside an ISR by using OS_INT_EnterNestable() and OS_INT_LeaveNestable() within the interrupt handler. Nested interrupts can lead to problems that are difficult to debug; therefore it is not 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, enabling and disabling of interrupts from within an ISR must be done using the functions that embOS offers for this purpose. The routine OS_INT_EnterNestable() enables interrupts within an ISR and prevents further task switches; OS_INT_LeaveNestable() disables interrupts immediately before ending the interrupt routine, thus restoring the default condition. Re-enabling interrupts will make it possible for an embOS scheduler interrupt to interrupt this ISR. In this case, embOS needs to know that another ISR is still active and that it may not perform a task switch. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 260 CHAPTER 12 12.3.4 Rules for interrupt handlers API functions OS_INT_Call() Entry function for use in an embOS interrupt handler. OS_INT_CallNestable() Entry function for use in an embOS interrupt handler. OS_INT_Enter() Informs embOS that interrupt code is executing. OS_INT_EnterNestable() Informs embOS that interrupt code is executing and reenables interrupts. OS_INT_InInterrupt() Checks if the calling function runs in an interrupt context. OS_INT_Leave() Informs embOS that the end of the interrupt routine has been reached; executes task switching within ISR. OS_INT_LeaveNestable() Informs embOS that the end of the interrupt routine has been reached; executes task switching within ISR. UM01001 User Guide & Reference Manual for embOS Timer ISR Task Description main Routine (c) 1995-2018 SEGGER Microcontroller GmbH 261 CHAPTER 12 12.3.4.1 Rules for interrupt handlers OS_INT_Call() Description Entry function for use in an embOS interrupt handler. Nestable interrupts are disabled. Prototype void OS_INT_Call(void ( *pRoutine)()); Parameters Parameter pRoutine Description Pointer to a routine that should run on interrupt. Additional information OS_INT_Call() can be used as an entry function in an embOS interrupt handler, when the corresponding interrupt should not be interrupted by another embOS interrupt. OS_INT_Call() 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_INT_Call() must be used to call an interrupt handler because OS_INT_Enter()/OS_INT_Leave() may not be available. OS_INT_Call() must not be used when OS_INT_Enter()/OS_INT_Leave() is available Please refer to the CPU/compiler specific embOS manual. Example #pragma interrupt void SysTick_Handler(void) { OS_INT_Call(_IsrTickHandler); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 262 CHAPTER 12 12.3.4.2 Rules for interrupt handlers OS_INT_CallNestable() Description Entry function for use in an embOS interrupt handler. Nestable interrupts are enabled. Prototype void OS_INT_CallNestable(void ( *pRoutine)()); Parameters Parameter pRoutine Description Pointer to a routine that should run on interrupt. Additional information OS_INT_CallNestable() can be used as an entry function in an embOS interrupt handler, when interruption by higher prioritized embOS interrupts should be allowed. OS_INT_CallNestable() does not alter the interrupt priority of the CPU, thus keeping all interrupts with higher priority enabled. Note For some specific CPUs OS_INT_CallNestable() must be used to call an interrupt handler because OS_INT_EnterNestable()/OS_INT_LeaveNestable() may not be available. OS_INT_CallNestable() must not be used when OS_INT_EnterNestable()/OS_INT_LeaveNestable() is available Please refer to the CPU/compiler specific embOS manual. Example #pragma interrupt void SysTick_Handler(void) { OS_INT_CallNestable(_IsrTickHandler); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 263 CHAPTER 12 12.3.4.3 Rules for interrupt handlers OS_INT_Enter() Description Informs embOS that interrupt code is executing. Prototype void OS_INT_Enter(void); Additional information Note This function is not available in all ports. If OS_INT_Enter() is used, it should be the first function to be called in the interrupt handler. It must be paired with OS_INT_Leave() as the last function called. The use of this function has the following effects: * * disables task switches keeps interrupts in internal routines disabled. Example Refer to the example of OS_INT_Leave(). UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 264 CHAPTER 12 12.3.4.4 Rules for interrupt handlers OS_INT_EnterNestable() Description Re-enables interrupts and increments the embOS internal critical region counter, thus disabling further task switches. Prototype void OS_INT_EnterNestable(void); Additional information Note This function is not available in all ports. This function should be the first call inside an interrupt handler when nested interrupts are required. The function OS_INT_EnterNestable() is implemented as a macro and offers the same functionality as OS_INT_Enter() in combination with OS_INT_DecRI(), but is more efficient, resulting in smaller and faster code. Example Refer to the example of OS_INT_LeaveNestable(). UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 265 CHAPTER 12 12.3.4.5 Rules for interrupt handlers OS_INT_InInterrupt() Description This function can be called to examine if the calling function is running in an interrupt context. 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. Prototype OS_BOOL OS_INT_InInterrupt(void); Return value =0 0 Code is not executed in an interrupt handler. Code is executed in an interrupt handler. Additional information Note This function is not available in all ports. The function delivers the interrupt state by checking the according CPU registers. It is only implemented for those CPUs where it is possible to read the interrupt state from CPU registers. In case of doubt please contact the embOS support. Example void foo() { if (OS_INT_InInterrupt() == 1) { // Do something within the ISR } else { printf("No interrupt context.\n") } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 266 CHAPTER 12 12.3.4.6 Rules for interrupt handlers OS_INT_Leave() Description Informs embOS that the end of the interrupt routine has been reached; executes task switching within ISR. Prototype void OS_INT_Leave(void); Additional information Note This function is not available in all ports. If OS_INT_Leave() is used, it should be the last function to be called in the interrupt handler. If the interrupt has caused a task switch, that switch is performed immediately (unless the program which was interrupted was in a critical region). Example void ISR_Timer(void) { OS_INT_Enter(); OS_TASKEVENT_Set(1, &Task); OS_INT_Leave(); } // Any functionality could be here UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 267 CHAPTER 12 12.3.4.7 Rules for interrupt handlers OS_INT_LeaveNestable() Description Disables further interrupts, then decrements the embOS internal critical region count, thus re-enabling task switches if the counter has reached zero. Prototype void OS_INT_LeaveNestable(void); Additional information Note This function is not available in all ports. This function is the counterpart of OS_INT_EnterNestable(), and must be the last function call inside an interrupt handler when nested interrupts have been enabled by OS_INT_EnterNestable(). The function OS_INT_LeaveNestable() is implemented as a macro and offers the same functionality as OS_INT_Leave() in combination with OS_INT_IncDI(), but is more efficient, resulting in smaller and faster code. Example _interrupt void ISR_Timer(void) { OS_INT_EnterNestable(); OS_TASKEVENT_Set(1,&Task); // Any functionality could be here OS_INT_LeaveNestable(); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 268 CHAPTER 12 12.4 12.4.1 Interrupt control Interrupt control Enabling / disabling interrupts 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 IntHandler(void) { lvar++; } void routine (void) { lvar++; } Good example: volatile long lvar; void IntHandler(voi lvar++; } void routine (void) { OS_INT_Disable(); lvar++; OS_INT_Enable(); } 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 functions when interrupts are disabled, because this could lead to long interrupt latency times (the longer interrupts are disabled, the higher the interrupt latency). You may also safely use the compiler-provided intrinsics to disable interrupts but you must ensure to not call embOS functions with disabled interrupts. 12.4.2 Global interrupt enable / disable The embOS interrupt enable and disable functions enable and disable embOS interrupts only. If a system is set up to support high and low priority interrupts and embOS is configured to support "zero latency" interrupts, 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 embOS functions. In an application it may be required to disable and enable all interrupts. Since version 3.90, embOS has API functions which allow enabling and disabling all interrupts. These functions UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 269 CHAPTER 12 Interrupt control have the suffix All and allow a "global" handling of the interrupt enable state of the CPU. These functions affect the state of the CPU unconditionally and should be used with care. 12.4.3 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 are prohibited from calling any embOS routines. 12.4.4 API functions Timer ISR Task Description main Routine OS_INT_DecRI() Decrements the counter and enables interrupts if the counter reaches 0. OS_INT_Disable() Disables interrupts. Does not change the interrupt disable counter. OS_INT_Enable() Unconditionally enables interrupts. OS_INT_EnableConditional() Restores the state of the interrupt flag, based on the interrupt disable counter. OS_INT_IncDI() Increments the interrupt disable counter (OS_Global.Counters.DI) and disables interrupts. OS_INT_Preserve() Preserves the embOS interrupt state. OS_INT_Restore() Restores the embOS interrupt state. OS_INT_DisableAll() Disable all interrupts (high and low priority) unconditionally. OS_INT_PreserveAndDisableAll() Preserves the current interrupt enable state and then disables all interrupts. OS_INT_PreserveAll() Preserves the current interrupt enable state. OS_INT_RestoreAll() Restores the interrupt enable state which was preserved before. OS_INT_EnableAll() Enable all interrupts (high and low priority) unconditionally. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 270 CHAPTER 12 12.4.4.1 Interrupt control OS_INT_IncDI() / OS_INT_DecRI() Description 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_INT_IncDI(), then OS_INT_DecRI(). 12.4.4.1.1 OS_INT_IncDI() Short for Increment and Disable Interrupts. Increments the interrupt disable counter (OS_Global.Counters.DI) and disables interrupts. 12.4.4.1.2 OS_INT_DecRI() Short for Decrement and Restore Interrupts. Decrements the counter and enables interrupts if the disable counter reaches zero. Additional information OS_INT_IncDI() increments the interrupt disable counter, interrupts will not be switched on within the running task before the matching OS_INT_DecRI() is executed. The counter is task specific, a task switch may change the value, so if interrupts are disabled they could be enabled in the next task and vice versa. If you need to disable interrupts for a instant only where no routine is called, as in the example above, you could also use the pair OS_INT_Disable() and OS_INT_EnableConditional(). These are slightly 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 functions 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_INT_IncDI() and OS_INT_DecRI(). You can safely call embOS API between OS_INT_IncDI() and OS_INT_DecRI(). The embOS API will not enable interrupts. Example volatile long lvar; void routine (void) { OS_INT_IncDI(); lvar ++; OS_INT_DecRI(); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 271 CHAPTER 12 12.4.4.2 Interrupt control OS_INT_Disable() OS_INT_Disable() disables embOS interrupts but does not change the interrupt disable counter OS_Global.Counters.Cnt.DI. 12.4.4.3 OS_INT_Enable() OS_INT_Enable() enables embOS interrupts but does not check the interrupt disable counter OS_Global.Counters.Cnt.DI. Refrain from using this function directly unless you are sure that the interrupt disable count has the value zero, because it does not take the interrupt disable counter into account. OS_INT_Disable() / OS_INT_Enable() can be used when no embOS API functions are called between which could enable interrupts before the actual call to OS_INT_Enable() and the interrupt disable count is zero. 12.4.4.4 OS_INT_EnableConditional() Restores the interrupt status, based on the interrupt disable counter. interrupts are only enabled if the interrupt disable counter OS_Global.Counters.Cnt.DI is zero. Example volatile long lvar; void routine (void) { OS_INT_Disable(); lvar++; OS_INT_EnableConditional(); } You cannot safely call embOS API between OS_INT_Disable() and OS_INT_Enable()/ OS_INT_EnableConditional(). The embOS API might already enable interrupts because OS_INT_Disable() does not change the interrupt disable counter. In that case please use OS_INT_IncDI() and OS_INT_DecRI() instead. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 272 CHAPTER 12 12.4.4.5 Interrupt control OS_INT_Preserve() Description This function can be called to preserve the current embOS interrupt enable state of the CPU. Prototype void OS_INT_Preserve(OS_U32* pState); Parameters Parameter pState Description Pointer to an OS_U32 variable that receives the interrupt state. Additional information If the interrupt enable state is not known and interrupts should be disabled by a call of OS_INT_Disable(), the current embOS interrupt enable state can be preserved and restored later by a call of OS_INT_Restore(). Example void Sample(void) { OS_U32 IntState; OS_INT_Preserve(&IntState); // OS_INT_Disable(); // // // Execute any code that should // ... OS_INT_Restore(&IntState); // Remember the interrupt enable state. Disable embOS interrupts be executed with embOS interrupts disabled Restore the interrupt enable state } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 273 CHAPTER 12 12.4.4.6 Interrupt control OS_INT_Restore() Description This function must be called to restore the embOS interrupt enable state of the CPU which was preserved before. Prototype void OS_INT_Restore (OS_U32* pState); Parameters Parameter pState Description Pointer to an OS_U32 variable that holds the interrupt enable state. Additional information Restores the embOS interrupt enable state which was saved before by a call of OS_INT_Preserve(). If embOS interrupts were enabled before they were disabled, the function reenables them. Example void Sample(void) { OS_U32 IntState; OS_INT_Preserve(&IntState); // OS_INT_Disable(); // // // Execute any code that should // ... OS_INT_Restore(&IntState); // Remember the interrupt enable state. Disable embOS interrupts be executed with embOS interrupts disabled Restore the interrupt enable state } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 274 CHAPTER 12 12.4.4.7 Interrupt control OS_INT_DisableAll() Description This function disables embOS and zero latency interrupts unconditionally. Prototype void OS_INT_DisableAll(void); Additional information OS_INT_DisableAll() disables all interrupts (including zero latency 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_INT_EnableAll(). After calling OS_INT_DisableAll(), no embOS function except the interrupt enable function OS_INT_EnableAll() should be called, because the interrupt state is not saved by the function. An embOS API function may re-enable interrupts. The exact interrupt enable behaviour depends on the CPU. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 275 CHAPTER 12 12.4.4.8 Interrupt control OS_INT_PreserveAndDisableAll() Description This function preserves the current interrupt enable state of the CPU and then disables embOS and zero latency interrupts. Prototype void OS_INT_PreserveAndDisableAll (OS_U32* pState); Parameters Parameter pState Description Pointer to an OS_U32 variable that receives the interrupt state. Additional information The function store the current interrupt enable state into the variable pointed to by pState and then disables embOS and zero latency interrupts. The interrupt state can be restored later by a corresponding call of OS_INT_RestoreAll(). The pair of function calls OS_INT_PreserveAndDisableAll() and OS_INT_RestoreAll() can be nested, as long as the interrupt enable state is stored into an individual variable on each call of OS_INT_PreserveAndDisableAll(). This function pair should be used when the interrupt enable state is not known when interrupts shall be enabled. Example void Sample(void) { OS_U32 IntState; // Remember the interrupt enable state and disables interrupts. OS_INT_PreserveAndDisableAll(&IntState); // // Execute any code that should be executed with interrupts disabled // No embOS function should be called // ... OS_INT_RestoreAll(&IntState); // Restore the interrupt enable state } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 276 CHAPTER 12 12.4.4.9 Interrupt control OS_INT_PreserveAll() Description This function can be called to preserve the current interrupt enable state of the CPU. Prototype void OS_INT_PreserveAll (OS_U32* pState); Parameters Parameter pState Description Pointer to an OS_U32 variable that receives the interrupt state. Additional information If the interrupt enable state is not known and interrupts should be disabled by a call of OS_INT_DisableAll(), the current interrupt enable state can be preserved and restored later by a call of OS_INT_RestoreAll(). Note that the interrupt state is not stored by embOS. After disabling the interrupts using a call of OS_INT_DisableAll(), no embOS API function should be called because embOS functions might re-enable interrupts. Example void Sample(void) { OS_U32 IntState; // Remember the interrupt enable state. OS_INT_PreserveAll(&IntState); OS_INT_DisableAll(); // Disable interrupts // // Execute any code that should be executed with interrupts disabled // No embOS function should be called // ... OS_INT_RestoreAll(&IntState); // Restore the interrupt enable state } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 277 CHAPTER 12 12.4.4.10 Interrupt control OS_INT_RestoreAll() Description This function must be called to restore the interrupt enable state of the CPU which was preserved before. Prototype void OS_INT_RestoreAll (OS_U32* pState); Parameters Parameter pState Description Pointer to an OS_U32 variable that holds the interrupt enable state. Additional information Restores the interrupt enable state which was saved before by a call of OS_INT_PreserveAll() or OS_INT_PreserveAndDisableAll(). If interrupts were enabled before they were disabled globally, the function reenables them. Example void Sample(void) { OS_U32 IntState; // Remember the interrupt enable state. OS_INT_PreserveAll(&IntState); OS_INT_DisableAll(); // Disable interrupts // // Execute any code that should be executed with interrupts disabled // No embOS function should be called // ... OS_INT_RestoreAll(&IntState); // Restore the interrupt enable state } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 278 CHAPTER 12 12.4.4.11 Interrupt control OS_INT_EnableAll() Description This function enables high and low priority interrupts unconditionally. Prototype void OS_INT_EnableAll(void); Additional information This function re-enables interrupts which were disabled before by a call of OS_INT_DisableAll(). The function re-enables embOS and zero latency interrupts unconditionally. OS_INT_DisableAll() and OS_INT_EnableAll() 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_INT_DisableAll() and OS_INT_EnableAll(), 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_INT_PreserveAll() or OS_INT_PreserveAndDisableAll() and OS_INT_RestoreAll() shall be used as decribed later on. Example void Sample(void) { OS_INT_DisableAll(); // Disable interrupts // // Execute any code that should be executed with interrupts disabled // No embOS function should be called // ... OS_INT_EnableAll(); // Re-enable interrupts unconditionally } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 13 Critical Regions UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 280 CHAPTER 13 13.1 Introduction Introduction Critical regions are program sections during which preemptive task switches are disabled, meaning that no task switch and no execution of software timers are allowed except in situations where the running task must wait. Cooperative task switches are not affected and will be executed in critical regions. 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 region 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 immediately after the region is left. Example void HPTask(void) { OS_TASK_EnterRegion(); DoSomething(); // This code will not be interrupted by other tasks OS_TASK_LeaveRegion(); } Note Cooperative task switches will still be executed although preemptive task switches are disabled in a critical section. void HPTask(void) { OS_TASK_EnterRegion(); OS_TASK_Delay(100); // OS_TASK_Delay() will cause a cooperative task switch OS_TASK_LeaveRegion(); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 281 CHAPTER 13 13.2 API functions API functions Timer ISR Task Description main Routine OS_TASK_EnterRegion() Indicates to embOS the beginning of a critical region. OS_TASK_LeaveRegion() Indicates to embOS the end of a critical region. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 282 CHAPTER 13 13.2.1 API functions OS_TASK_EnterRegion() Description Indicates to embOS the beginning of a critical region. Prototype void OS_TASK_EnterRegion(void); Additional information A critical region counter (OS_Global.Counters.Cnt.Region), which is zero by default, is incremented so that critical regions can be nested. The counter will be decremented by a call to the routine OS_TASK_LeaveRegion(). When this counter reaches zero again, the critical region ends. Interrupts are not disabled using OS_TASK_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_TASK_LeaveRegion(). When the counter reaches zero, any pending task switch is executed. Cooperative task switches are not affected and will be executed in critical regions. When a task is running in a critical region and calls any blocking embOS function, the task will be suspended. When the task is resumed, the task-specific critical region counter is restored, the task continues to run in a critical region until OS_TASK_LeaveRegion() is called. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 283 CHAPTER 13 13.2.2 API functions OS_TASK_LeaveRegion() Description Indicates to embOS the end of a critical region. Decrements the critical region counter and checks if a task switch is pending if the counter reaches 0. Prototype void OS_TASK_LeaveRegion(void); Additional information A critical region counter (OS_Global.Counters.Cnt.Region), which is zero by default, is decremented. If this counter reaches zero, the critical region ends. A task switch which became pending during a critical region will be executed in OS_TASK_EnterRegion() when the counter reaches zero. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 14 Time Measurement UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 285 CHAPTER 14 14.1 Introduction 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 are based on system ticks, while high-resolution measurements are based on a time unit called cycle. The length of a cycle depends on the timer clock frequency. Example OS_TIME BenchmarkLoRes(void) { OS_TIME t; t = OS_TIME_GetTicks(); DoSomething(); // Code to be benchmarked t = OS_TIME_GetTicks() - t; return t; } OS_U32 BenchmarkHiRes(void) { OS_TIMING t; OS_TIME_StartMeasurement(&t); DoSomething(); // Code to be benchmarked OS_TIME_StopMeasurement(&t); return OS_TIME_GetResultus(&t); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 286 CHAPTER 14 14.2 Low-resolution measurement Low-resolution measurement The global system time variable OS_Global.Time is measured in system ticks, which typically equal milliseconds. The low-resolution functions OS_TIME_GetTicks() and OS_TIME_GetTicks32() are used for returning the current contents of this variable. The basic concept 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 system ticks. Consider the following: The global variable OS_Global.Time is incremented with every system tick interrupt, with a default tick of one msec that means once each msec. This means that the actual system time can potentially be later than the lowresolution function returns (for example, if an interrupt actually occurs at system 1.4 ticks, the system will assume only one tick having elapsed). The problem even gets worse when concerning runtime measurement, because the system time must be measured twice. Since each measurement can, potentially, be up to one tick less than the actual time, 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 begins at 0.5 msec and ends at 5.2 msec, which means that its exact execution time is 5.2 msec - 0.5 mesec = 4.7 msec. However, assuming one system tick per msec, the first call to OS_TIME_GetTicks() will return 0, while the second call will return 5. The measured execution time would therefore be returned as 5 system ticks - 0 system ticks = 5 system ticks. For many applications, low-resolution measurement is sufficient for most of all cases. In those cases, its ease of use as well as its faster computation time are clear benefits when compared to high-resolution measurement. Still, high-resolution measurement may be necessary when highly accurate measurements are mandatory. 14.2.1 API functions Timer ISR Task Description main Routine OS_TIME_GetTicks() Returns the current system time in sytem ticks as a native integer value. OS_TIME_GetTicks32() Returns the current system time in system ticks as a 32 bit integer value. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 287 CHAPTER 14 14.2.1.1 Low-resolution measurement OS_TIME_GetTicks() Description Returns the current system time in ticks as a native integer value. Prototype int OS_TIME_GetTicks(void); Return value The system variable OS_Global.Time as a 16 bit integer value on 8/16 bit CPUs, and as a 32 bit integer value on 32 bit CPUs. Additional information The OS_Global.Time variable is a 32 bit integer value. Therefore, if the return value is 32 bit, it holds the entire contents of the OS_Global.Time variable. If the return value is 16 bit, it holds the lower 16 bits of the OS_Global.Time variable. Example void PrintTask(void) { int Time; Time = OS_TIME_GetTicks(); printf("System Time: %d\n", Time); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 288 CHAPTER 14 14.2.1.2 Low-resolution measurement OS_TIME_GetTicks32() Description Returns the current system time in system ticks as a 32 bit integer value. Prototype OS_I32 OS_TIME_GetTicks32(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. Example void PrintTask(void) { OS_I32 Time; Time = OS_TIME_GetTicks32(); printf("System Time: %d\n", Time); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 289 CHAPTER 14 14.3 High-resolution measurement High-resolution measurement High-resolution measurement uses the same routines as those used in profiling builds of embOS, allowing fine-tuning of time measurement. While system resolution depends on the CPU used, it is typically about one microsecond, making high-resolution measurement 1000 times more accurate than low-resolution calculations. Instead of measuring the number of completed system ticks at a given time, an internal count is kept of the number of cycles that have been completed at a given time. Please refer to the illustration below, which measures the execution time of the same code that was used during the low-resolution calculation. For this example, we assume that the CPU has a timer running at 10 MHz and counts upwards. The number of cycles per tick therefore equals (10 MHz / 1 kHz) = 10,000. This means that with each tick-interrupt, the timer restarts at zero and counts up to 10,000. The call to OS_TIME_StartMeasurement() calculates the starting value at 5,000 cycles, while the call to OS_TIME_StopMeasurement() 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 cycles - 5,000 cycles) = 47,000 cycles, which equals 4.7 msec. Although the function OS_TIME_GetResult() may be used for returning the execution time in cycles as above, it is typically more common to use the function OS_TIME_GetResultus(), which returns the value in microseconds. In the above example, the return value would be 4,700 usec. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 290 CHAPTER 14 14.3.1 High-resolution measurement API functions Timer ISR Task Description main Routine OS_TIME_StartMeasurement() Marks the beginning of a code section to be timed. OS_TIME_StopMeasurement() Marks the end of a code section to be timed. OS_TIME_GetResult() Returns the execution time of the code between OS_TIME_StartMeasurement() and OS_TIME_StopMeasurement() in timer cycles. OS_TIME_GetResultus() Returns the execution time of the code between OS_TIME_StartMeasurement() and OS_TIME_StopMeasurement() in microseconds. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 291 CHAPTER 14 14.3.1.1 High-resolution measurement OS_TIME_StartMeasurement() Description Marks the beginning of a code section to be timed. Prototype void OS_TIME_StartMeasurement(OS_TIMING* pCycle); Parameters Parameter pCycle Description Pointer to a data structure of type OS_TIMING. Additional information This function must be used with OS_TIME_StopMeasurement(). Example Please refer to the Example on page 295. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 292 CHAPTER 14 14.3.1.2 High-resolution measurement OS_TIME_StopMeasurement() Description Marks the end of a code section to be timed. Prototype void OS_TIME_StopMeasurement(OS_TIMING* pCycle); Parameters Parameter pCycle Description Pointer to a data structure of type OS_TIMING. Additional information This function must be used with OS_TIME_StartMeasurement(). Example Please refer to the Example on page 295. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 293 CHAPTER 14 14.3.1.3 High-resolution measurement OS_TIME_GetResult() Description Returns the execution time of the code between OS_TIME_StartMeasurement() and OS_TIME_StopMeasurement() in timer cycles. Prototype OS_U32 OS_TIME_GetResult(OS_TIMING* pCycle); Parameters Parameter pCycle Description Pointer to a data structure of type OS_TIMING. Return value The execution time in timer cycles as a 32 bit integer value. Additional information Cycle length depends on the timer clock frequency. Example Please refer to the Example of OS_TIME_GetResultus(), with the only difference that this function returns cycles instead of microseconds. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 294 CHAPTER 14 14.3.1.4 High-resolution measurement OS_TIME_GetResultus() Description Returns the execution time of the code between OS_TIME_StartMeasurement() and OS_TIME_StopMeasurement() in microseconds. Prototype OS_U32 OS_TIME_GetResultus(OS_CONST_PTR OS_TIMING *pCycle); Parameters Parameter pCycle Description Pointer to a data structure of type OS_TIMING. Return value The execution time in microseconds (usec) as a 32-bit integer value. Example Please refer to the Example on page 295. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 295 CHAPTER 14 14.4 Example Example The following sample demonstrates the use of low-resolution and high-resolution measurement to return the execution time of a section of code: #include "RTOS.h" #include static OS_STACKPTR int Stack[1000]; // Task stacks static OS_TASK TCB; // Task-control-blocks static volatile int Dummy; void UserCode(void) { for (Dummy=0; Dummy < 11000; Dummy++); // Burn some time } // // Measure the execution time with low resolution // int BenchmarkLoRes(void) { OS_TIME t; t = OS_TIME_GetTicks(); UserCode(); /* Execute the user code to be benchmarked */ t = OS_TIME_GetTicks() - t; return (int)t; } // // Measure the execution time with high resolution // OS_U32 BenchmarkHiRes(void) { OS_TIMING t; OS_TIME_StartMeasurement(&t); UserCode(); // Execute the user code to be benchmarked OS_TIME_StopMeasurement(&t); return OS_TIME_GetResultus(&t); } void Task(void) { int tLo; OS_U32 tHi; char ac[80]; while (1) { tLo = BenchmarkLoRes(); tHi = BenchmarkHiRes(); sprintf(ac, "LoRes: %d system ticks\n", tLo); OS_COM_SendString(ac); sprintf(ac, "HiRes: %d usec\n", tHi); OS_COM_SendString(ac); } } int main(void) { OS_Init(); // Initialize embOS OS_InitHW(); // Initialize hardware for embOS OS_TASK_CREATE(&TCB, "HP Task", 100, Task, Stack); OS_Start(); // Start multitasking return 0; } The output of the sample is as follows: LoRes: 7 system ticks HiRes: 6641 usec UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 296 CHAPTER 14 14.5 Microsecond precise system time Microsecond precise system time The following functions return the current system time in microsecond resolution. The function OS_TIME_ConfigSysTimer() sets up the necessary parameters. 14.5.1 API functions Timer ISR Task Description main Routine OS_TIME_ConfigSysTimer() Configures the system time parameters for the functions OS_TIME_Getus() and OS_TIME_Getus64(). OS_TIME_Getus() Returns the current system time in microseconds as a 32 bit value. OS_TIME_Getus64() Returns the current system time in microseconds as a 64 bit value. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 297 CHAPTER 14 14.5.1.1 Microsecond precise system time OS_TIME_ConfigSysTimer() Description Configures the system time parameters for the functions OS_TIME_Getus() and OS_TIME_Getus64(). This function usually is called once from OS_InitHW() (implemented in RTOSInit.c). Prototype void OS_TIME_ConfigSysTimer(OS_CONST_PTR OS_SYSTIMER_CONFIG *pConfig); Parameters Parameter Pointer to a data structure of type OS_SYSTIMER_CONFIG. pConfig 14.5.1.1.1 Description The OS_SYSTIMER_CONFIG struct OS_TIME_ConfigSysTimer() uses the struct OS_SYSTIMER_CONFIG: Member Description TimerFreq Timer frequency in Hz TickFreq Tick frequency in Hz IsUpCounter 0: for hardware timer which counts down 1: for hardware timer which counts up pfGetTimerCycles Pointer to a function which returns the current hardware timer count value pfGetTimerIntPending Pointer to a function which indicates whether the hardware timer interrupt pending flag is set 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. 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 =0 Hardware timer interrupt pending flag is not set. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 298 CHAPTER 14 0 Microsecond precise system time The pending flag is set. 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_GetHWTimer_Cycles(void) { return HW_TIMER_VALUE_REG; } static unsigned int _OS_GetHWTimer_IntPending(void) { return HW_TIMER_INT_REG & (1uL << PENDING_BIT); } const OS_SYSTIMER_CONFIG Tick_Config = { OS_PCLK_TIMER, OS_TICK_FREQ, 0, _OS_GetHWTimer_Cycles _OS_GetHWTimer_IntPending }; void OS_InitHW(void) { OS_TIME_ConfigSysTimer(&Tick_Config); ... } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 299 CHAPTER 14 14.5.1.2 Microsecond precise system time OS_TIME_Getus() Description Returns the current system time in microseconds as a 32 bit value. Prototype OS_U32 OS_TIME_Getus(void); Return value The current system time in microseconds (usec) as a 32-bit integer value. Additional information OS_TIME_Getus() returns correct values only if OS_TIME_ConfigSysTimer() was called during initialization. All embOS board support packages already call OS_TIME_ConfigSysTimer(). With this 32 bit value OS_TIME_Getus() can return up to 4249 seconds or ~71 minutes. Example void PrintTime(void) { OS_U32 Time; Time = OS_TIME_Getus(); printf("System Time: %u usec\n", Time); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 300 CHAPTER 14 14.5.1.3 Microsecond precise system time OS_TIME_Getus64() Description Returns the current system time in microseconds as a 64 bit value. Prototype OS_U64 OS_TIME_Getus64(void); Return value The current system time in microseconds (usec) as a 64-bit integer value. Additional information This function is unavailable for compilers that do not support a 64 bit data type (long long). This is the case only for very rare older 8/16 bit compiler. All 32 bit compiler support a 64 bit data type. OS_TIME_Getus64() returns correct values only if OS_TIME_ConfigSysTimer() was called during initialization. All embOS board support packages already call OS_TIME_ConfigSysTimer(). With this 64 bit value OS_TIME_Getus64() can return up to 18446744073709 seconds or ~584942 years. Example void MeasureTime(void) { OS_U64 t0, t1; OS_U32 delta; t0 = OS_TIME_Getus64(); DoSomething(); t1 = OS_TIME_Getus64(); delta = (OS_U32)(t1 - t0); printf("Delta: %u usec\n", delta); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 15 Low Power Support UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 302 CHAPTER 15 15.1 Introduction Introduction embOS provides several means to control the power consumption of your target hardware. These include * * * The possibility to enter power save modes with the embOS function OS_Idle(). The embOS tickless support, allowing the microcontroller to remain in a power save mode for extended periods of time. The embOS peripheral power control module, which allows control of the power consumption of specific peripherals. The following chapter explains each of these in more detail. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 303 CHAPTER 15 15.2 Starting power save modes in OS_Idle() Starting power save modes in OS_Idle() In case your controller supports some kind of power save mode, it is possible to use it with embOS. To enter that mode, you would usually implement the respective functionality in the function OS_Idle(), which is located inside the embOS source file RTOSInit.c. OS_Idle() is executed whenever no task is ready for execution. With many embOS start projects it is preconfigured to activate a power save mode of the target CPU. Please note that the available power save modes are hardware-dependant. For example with Cortex-M CPUs, the wfi instruction is executed per default in OS_Idle() to put the CPU into a power save mode: void OS_Idle(void) { while (1) { __asm(" wfi"); } } // Idle loop: No task is ready to execute // Enter sleep mode For further information on OS_Idle(), please also refer to OS_Idle() on page 304. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 304 CHAPTER 15 15.3 Tickless support 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 and no software timer ready for execution and no interrupt request is pending. Stopping the system tick allows the microcontroller to remain in a power save mode until an interrupt occurs. The embOS tickless support comes with the functions OS_TICKLESS_GetNumIdleTicks(), OS_TICKLESS_AdjustTime(), OS_TICKLESS_Start() and OS_TICKLESS_Stop(). These can be used to add tickless support to any embOS start project. 15.3.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 power save mode: void OS_Idle(void) { while (1) { _EnterLowPowerMode(); } } The tickless OS_Idle() function depends on the hardware: void OS_Idle(void) { OS_TIME IdleTicks; OS_INT_Disable(); IdleTicks = OS_TICKLESS_GetNumIdleTicks(); if (IdleTicks > 1) { if ((OS_U32)IdleTicks > TIMER1_MAX_TICKS) { IdleTicks = TIMER1_MAX_TICKS; } OS_TICKLESS_Start(IdleTicks, &_EndTicklessMode); _SetHWTimer(IdleTicks); } OS_INT_Enable(); while (1) { _EnterLowPowerMode(); } } The following description explains the tickless OS_Idle() function step by step: void OS_Idle(void) { OS_TIME IdleTicks; OS_INT_Disable(); Interrupts are disabled to avoid a timer interrupt. IdleTicks = OS_TICKLESS_GetNumIdleTicks(); if (IdleTicks > 1) { The OS_Idle() function evaluates the number of idle system ticks by calling OS_TICKLESS_GetNumIdleTicks(). The tickless mode is only used when there is more than one idle system tick: If there is one (or none) idle system tick only, the scheduler will be executed with the next system tick, hence it makes no sense to enter the tickless mode in that case. if ((OS_U32)IdleTicks > TIMER_MAX_TICKS) { IdleTicks = TIMER_MAX_TICKS; } If it is not possible to generate the timer interrupt at the specified time, e.g. due to hardware timer limitations, the idle system ticks can be reduced to any lower value. For example, if UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 305 CHAPTER 15 Tickless support OS_TICKLESS_GetNumIdleTicks() returns 200 idle system ticks, but the hardware timer's duration is limited to 100 ticks maximum, the variable IdleTicks will initially be set to 100 system ticks. The system will then wake up after 100 system ticks, OS_Idle() will be executed once more and OS_TICKLESS_GetNumIdleTicks() now returns the remaining 100 idle systems ticks, for which tickless mode is entered once again. This means that the system wakes up two times for the entire 200 idle system ticks. if (IdleTicks > 1) { ... OS_TICKLESS_Start(IdleTicks, &_EndTicklessMode); _SetHWTimer(IdleTicks); } OS_TICKLESS_Start() sets the idle system ticks and the callback function. IdleTicks is later used in the callback function, which is described in more detail below. _SetHWTimer() is a hardware-dependent function that reprograms the hardware timer to generate a system tick interrupt at the time defined by IdleTicks. OS_INT_Enable(); while (1) { _EnterLowPowerMode(); } } Interrupts are reenabled and the CPU continually enters power save mode. _EnterLowPowerMode() is a hardware-dependent function that activates the power save mode. 15.3.2 Callback Function The callback function calculates how long the processor slept in power save mode and corrects the system time accordingly. static void _EndTicklessMode(void) { OS_U32 NumTicks; if (OS_Global.TicklessExpired) { OS_TICKLESS_AdjustTime(OS_Global.TicklessFactor); } else { NumTicks = _GetLowPowerTicks(); OS_TICKLESS_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_TICKLESS_AdjustTime(OS_Global.TicklessFactor); If the hardware timer expired and the system tick interrupt was executed the flag OS_Global.TicklessExpired is set. This can be used to determine if the system slept in power save mode for the entire 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_TICKLESS_AdjustTime(NumTicks); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 306 CHAPTER 15 Tickless support _GetLowPowerTicks() is a hardware-dependent function which returns the expired idle ticks if the power save 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-dependent function which reprograms the hardware timer to its default value for one system tick. 15.3.3 API functions Start the tickless mode. OS_TICKLESS_Stop() Prematurely stops the tickless mode. UM01001 User Guide & Reference Manual for embOS Idle Retrieves the number of embOS embOS system ticks until the next OS_TICKLESS_GetNumIdleTicks() time-scheduled action will be started. OS_TICKLESS_Start() Timer ISR Adjusts the embOS internal time variable by the specified amount of system ticks. Task OS_TICKLESS_AdjustTime() Description main Routine (c) 1995-2018 SEGGER Microcontroller GmbH 307 CHAPTER 15 15.3.3.1 Tickless support OS_TICKLESS_AdjustTime() Description Adjusts the embOS internal time variable by the specified amount of system ticks. Prototype void OS_TICKLESS_AdjustTime(OS_TIME Time); Parameters Parameter Time Description The amount of time which should be added to the embOS internal time variable. Additional information The function may be useful when the embOS system timer was halted for any interval of time with a well-known duration. When the embOS timer is subsequently re-started, the internal time variable must be adjusted to that duration in order to guarantee timescheduled actions are performed accuratetely. Example Please refer to the example described in OS_Idle() on page 304. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 308 CHAPTER 15 15.3.3.2 Tickless support OS_TICKLESS_GetNumIdleTicks() Description Retrieves the number of embOS embOS system ticks until the next time-scheduled action will be started. Prototype OS_TIME OS_TICKLESS_GetNumIdleTicks(void); Return value >0 =0 Number of system ticks until next time scheduled action. A time scheduled action is pending. 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_TICKLESS_AdjustTime(). Example Please refer to the example described in OS_Idle() on page 304. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 309 CHAPTER 15 15.3.3.3 Tickless support OS_TICKLESS_Start() Description Start the tickless mode. It sets the sleep time and the user callback function which is called from the scheduler after wakeup from power save mode. Prototype void OS_TICKLESS_Start(OS_TIME Time, voidRoutine* Callback); Parameters Parameter Description Time Time in ticks which will be spent in power save mode. Callback Callback function to stop the tickless mode. Additional information It must be called before the CPU enters a power save 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_TICKLESS_AdjustTime(). It also must reset the system tick timer to it's default tick period. Example Please refer to the example described in OS_Idle() on page 304. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 310 CHAPTER 15 15.3.3.4 Tickless support OS_TICKLESS_Stop() Description Prematurely stops the tickless mode. Prototype void OS_TICKLESS_Stop(void); Additional information The tickless mode is stopped immediately even when no time-scheduled action is due. OS_TICKLESS_Stop() calls the callback function registered when tickless mode was enabled. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 311 CHAPTER 15 15.3.4 Tickless support Frequently Asked Questions Q: Can I use embOS without tickless support? A: Yes, you can use embOS without tickless support. No changes to your project are required. Q: What hardware-dependent 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 suggest to implement the callback function in the same file. 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 Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 312 CHAPTER 15 15.4 Peripheral power control Peripheral power control The embOS peripheral power control is used to determine if a peripheral's clock or its power supply can be switched off to save power. It includes three functions: OS_POWER_GetMask(), OS_POWER_UsageInc() and OS_POWER_UsageDec(). These functions can be used to add peripheral power control to any embOS start project. If a peripheral gets initialized a call to OS_POWER_UsageInc() increments a specific entry in the power management counter to signal that it is in use. When a peripheral is no longer in use, a call to OS_POWER_UsageDec() decrements this counter. Within OS_Idle() a call of OS_POWER_GetMask() generates a bit mask which describes which clock or power supply is in use, and which is not and may therefore be switched off. 15.4.1 API functions Idle Timer ISR Task Description main Routine OS_POWER_GetMask() Retrieves the power management counter. OS_POWER_UsageDec() Decrements the power management counter(s). OS_POWER_UsageInc() Increments the power management counter(s). UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 313 CHAPTER 15 15.4.1.1 Peripheral power control OS_POWER_GetMask() Description Retrieves the power management counter. Prototype OS_UINT OS_POWER_GetMask(void); Return value A bit mask which describes whether a peripheral is in use or not. Additional information This function generates a bit mask from the power management counter it retrieves. The bit mask describes which peripheral is in use and which one can be turned off. Switching off a peripheral can be done by writing this mask into the specific register. Please refer to the Example for additional information. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 314 CHAPTER 15 15.4.1.2 Peripheral power control OS_POWER_UsageDec() Description Decrements the power management counter(s). Prototype void OS_POWER_UsageDec(OS_UINT Index); Parameters Parameter Index Description Contains a mask with bits set for those counters which should be updated. (Bit 0 => Counter 0) The debug version checks for underflow, overflow and undefined counter number. Additional information When a peripheral is no longer in use this function is called to mark the peripheral as unused and signal that it can be switched off. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 315 CHAPTER 15 15.4.1.3 Peripheral power control OS_POWER_UsageInc() Description Increments the power management counter(s). Prototype void OS_POWER_UsageInc(OS_UINT Index); Parameters Parameter Index Description Contains a mask with bits set for those counters which should be updated. (Bit 0 => Counter 0) The debug version checks for underflow, overflow and undefined counter number. Additional information When a peripheral is in use this function is called to mark the peripheral as in use. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 316 CHAPTER 15 15.4.2 Peripheral power control Example This is an example for the peripheral power control. As it depends on the used hardware, its implementation is fictional: A, B and C are used to represent arbitrary peripherals. #define #define #define #define OS_POWER_USE_A OS_POWER_USE_B OS_POWER_USE_C OS_POWER_USE_ALL (1 << 0) // peripheral "A" (1 << 1) // peripheral "B" (1 << 2) // peripheral "C" (OS_POWER_USE_A | OS_POWER_USE_B | OS_POWER_USE_C) In the following function the peripherals A and C have been initialized and were marked inuse by a call to OS_POWER_UsageInc(): void _InitAC(void) { ... OS_POWER_UsageInc(OS_POWER_USE_A); // Mark "A" as used OS_POWER_UsageInc(OS_POWER_USE_C); // Mark "C" as used ... } After some time, C will not be used any more and can therefore be marked as unused by a call to OS_POWER_UsageDec(): void _WorkDone(void) { ... OS_POWER_UsageDec(OS_POWER_USE_C); // Mark "C" as unused ... } While in OS_Idle(), a call to OS_POWER_GetMask() retrieves a bit mask from the power management counter. That bitmask subsequently is used to modify the corresponding bits of a control register, leaving only those bits set that represent a peripheral which is in-use. void OS_Idle(void) { // Idle loop: No task is ready to execute OS_UINT PowerMask; OS_U16 ClkControl; // // Initially disable interrupts // OS_INT_IncDI(); // // Examine which peripherals may be switched off // PowerMask = OS_POWER_GetMask(); // // Store the content of CTRLREG and clear all OS_POWER_USE related bits // ClkControl = CTRLREG & ~OS_POWER_USE_ALL; // // Set only bits for used peripherals and write them to the specific register // In this case only "A" is marked as used, so "C" gets switched off // CTRLREG = ClkControl | PowerMask; // // Re-enable interrupts // OS_INT_DecRI(); for (;;) { _do_nothing(); }; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 16 Heap Type Memory Management UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 318 CHAPTER 16 16.1 Introduction 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 runtime libraries; they can only be used from one task or by multiple tasks if they are called sequentially. Therefore, embOS offer thread safe variants of these routines. These variants have the same names as their ANSI counterparts, but are prefixed OS_HEAP_; they are called OS_HEAP_malloc(), OS_HEAP_free(), OS_HEAP_realloc(). The thread-safe variants that embOS offers use the standard ANSI routines, but they guarantee that the calls are serialized using a mutex. If heap memory management is not supported by the standard C libraries, 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. This API is not available in embOS library mode OS_LIBMODE_SAFE. Example void HPTask(void) { OS_U32* p; while (1) { p = (OS_U32*)OS_HEAP_malloc(4); *p = 42; OS_HEAP_free(p); } } void LPTask(void) { OS_U16* p; while (1) { p = (OS_U16*)OS_HEAP_malloc(2); *p = 0; OS_HEAP_free(p); } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 319 CHAPTER 16 16.2 API functions API functions Frees a block of memory previously allocated. OS_HEAP_malloc() Allocates a block of memory on the heap. OS_HEAP_realloc() Changes the allocation size. UM01001 User Guide & Reference Manual for embOS Timer OS_HEAP_free() ISR Task Description main Routine (c) 1995-2018 SEGGER Microcontroller GmbH 320 CHAPTER 16 16.2.1 API functions OS_HEAP_free() Description Frees a block of memory previously allocated. This is the thread safe free() variant. Prototype void OS_HEAP_free(void* pMemBlock); Parameters Parameter pMemBlock Description Pointer to a memory block previously allocated with OS_HEAP_malloc(). Example void UseHeapMem(void) { char* sText; sText = (char*)OS_HEAP_malloc(20); strcpy(sText, "Hello World"); printf(sText); OS_HEAP_free(p); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 321 CHAPTER 16 16.2.2 API functions OS_HEAP_malloc() Description Allocates a block of memory on the heap. This is the thread safe malloc() variant. Prototype void *OS_HEAP_malloc(unsigned int Size); Parameters Parameter Size Description Size of the requested memory block in bytes. Return value Upon successful completion with size not equal zero, OS_HEAP_malloc() returns a pointer to the allocated space. Otherwise, it returns a NULL pointer. Example void UseHeapMem(void) { char* sText; sText = (char*)OS_HEAP_malloc(20); strcpy(sText, "Hello World"); printf(sText); OS_HEAP_free(p); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 322 CHAPTER 16 16.2.3 API functions OS_HEAP_realloc() Description Changes the allocation size. This is the thread safe realloc() variant. Prototype void *OS_HEAP_realloc(void* pMemBlock, unsigned int NewSize); Parameters Parameter Description pMemBlock Pointer to a memory block previously allocated with OS_HEAP_malloc(). NewSize New size for the memory block in bytes. Return value Upon successful completion, OS_HEAP_realloc() returns a pointer to the reallocated memory block. Otherwise, it returns a NULL pointer. Example void UseHeapMem(void) { char* sText; sText = (char*)OS_HEAP_malloc(10); strcpy(sText, "Hello"); printf(sText); sText = (char*)OS_HEAP_realloc(sText, 20); strcpy(sText, "Hello World"); printf(sText); OS_HEAP_free(p); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 17 Fixed Block Size Memory Pool UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 324 CHAPTER 17 17.1 Introduction 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_MEMPOOL_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. Example #include "RTOS.h" #include #include #define BLOCK_SIZE #define NUM_BLOCKS #define POOL_SIZE static static static static (16) (16) (NUM_BLOCKS* BLOCK_SIZE) OS_STACKPTR int StackHP[128], StackLP[128]; OS_TASK TCBHP, TCBLP; OS_MEMPOOL MEMF; OS_U8 aPool[POOL_SIZE]; // Task stacks // Task-control-blocks static void HPTask(void) { char* a; while (1) { // // Request one memory block // a = OS_MEMPOOL_AllocBlocked(&MEMF); // // Work with memory block // strcpy(a, "Hello World\n"); printf(a); OS_MEMPOOL_FreeEx(&MEMF, a); // Release memory block OS_TASK_Delay (10); } } static void LPTask(void) { char* b; while (1) { // // Request one memory block when available in max. next 10 system ticks // b = OS_MEMPOOL_AllocTimed(&MEMF, 10); if (b != 0) { // // Work with memory block // b[0] = 0x12; b[1] = 0x34; // // Releae memory block // OS_MEMPOOL_FreeEx(&MEMF, b); } OS_TASK_Delay (50); } } int main(void) { OS_Init(); UM01001 User Guide & Reference Manual for embOS // Initialize embOS (c) 1995-2018 SEGGER Microcontroller GmbH 325 CHAPTER 17 Introduction OS_InitHW(); // Initialize hardware for embOS OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP); OS_TASK_CREATE(&TCBLP, "LP Task", 50, LPTask, StackLP); // // Create [NUM_BLOCKS] blocks with a size of [BLOCK_SIZE] each // OS_MEMPOOL_Create(&MEMF, aPool, NUM_BLOCKS, BLOCK_SIZE); OS_Start(); // Start multitasking return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 326 CHAPTER 17 17.2 API functions API functions Timer ISR Task Description main Routine OS_MEMPOOL_Alloc() Requests allocation of a memory block. OS_MEMPOOL_AllocBlocked() Allocates a memory block from pool. OS_MEMPOOL_AllocTimed() Allocates a memory block from pool with a timeout. OS_MEMPOOL_Create() Creates and initializes a fixed block size memory pool. OS_MEMPOOL_Delete() Deletes a fixed block size memory pool. OS_MEMPOOL_Free() Releases a memory block that was previously allocated. OS_MEMPOOL_FreeEx() Releases a memory block that was previously allocated. OS_MEMPOOL_GetBlockSize() Returns the size of a single memory block in the pool. OS_MEMPOOL_GetMaxUsed() Returns maximum number of blocks in a pool that have been used simultane- ously since creation of the pool. OS_MEMPOOL_GetNumBlocks() Returns the total number of memory blocks in the pool. OS_MEMPOOL_GetNumFreeBlocks() Returns the number of free memory blocks in the pool. OS_MEMPOOL_IsInPool() Information routine to examine whether a memory block reference pointer belongs to the specified memory pool. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 327 CHAPTER 17 17.2.1 API functions OS_MEMPOOL_Alloc() Description Requests allocation of a memory block. Continues execution without blocking. Prototype void *OS_MEMPOOL_Alloc(OS_MEMPOOL* pMEMF); Parameters Parameter Description Pointer to the control data structure of the memory pool. pMEMF Return value NULL = NULL Pointer to the allocated block. If no block has been allocated. Additional information The calling task is never suspended by calling OS_MEMPOOL_Alloc(). The returned pointer must be delivered to OS_MEMPOOL_FreeEx() as parameter to free the memory block. The pointer must not be modified. Example static OS_MEMPOOL _MemPool; void Task(void) { void* pData; pData = OS_MEMPOOL_Alloc(&_MemPool, 0); if (pData != NULL) { // Success: Work with the allocated memory. } else { // Failed: Do something else. } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 328 CHAPTER 17 17.2.2 API functions OS_MEMPOOL_AllocBlocked() Description Allocates a memory block from pool. Suspends until memory is available. Prototype void *OS_MEMPOOL_AllocBlocked(OS_MEMPOOL* pMEMF); Parameters Parameter pMEMF Description Pointer to the control data structure of the memory pool. Return value Pointer to the allocated memory 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_MEMPOOL_FreeEx() as a parameter to free the memory block. The pointer must not be modified. Example Please refer to the example in the Introduction on page 324. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 329 CHAPTER 17 17.2.3 API functions OS_MEMPOOL_AllocTimed() Description Allocates a memory block from pool with a timeout. Suspends until memory is available or a timeout occurs. Prototype void *OS_MEMPOOL_AllocTimed(OS_MEMPOOL* pMEMF, OS_TIME Timeout); Parameters Parameter Description pMEMF Pointer to the control data structure of the memory pool. Timeout Time limit before timeout, given in system ticks. The data type OS_TIME is defined as an integer, therefore valid values are: 0 TimeOut 215 - 1 = 0x7FFF for 8/16 bit CPUs. 0 TimeOut 231 - 1 = 0x7FFFFFFF for 32 bit CPUs. Return value = NULL NULL No memory block could be allocated within the specified time. Pointer to the allocated memory block. 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 returned pointer must be delivered to OS_MEMPOOL_FreeEx() 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 period longer than the timeout value, it may happen that the memory block becomes available after the timeout expired, but before the calling task is resumed. Anyhow, the function returns with timeout, because the memory block was not available within the requested time. Example static OS_MEMPOOL _MemPool; void Task(void) { void* pData; pData = OS_MEMPOOL_AllocTimed(&_MemPool, 20, 0); if (pData != NULL) { // Success: Work with the allocated memory. } else { // Failed: Do something else. } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 330 CHAPTER 17 17.2.4 API functions OS_MEMPOOL_Create() Description Creates and initializes a fixed block size memory pool. Prototype void OS_MEMPOOL_Create(OS_MEMPOOL* void* OS_UINT OS_UINT pMEMF, pPool, NumBlocks, BlockSize); Parameters Parameter Description pMEMF Pointer to the control data structure of the memory pool. pPool Pointer to memory to be used for the memory pool. Required size is: NumBlocks * BlockSize. NumBlocks Number of blocks in the pool. BlockSize Size in bytes of one block. Additional information 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 0x7FFF and for 32Bit CPUs 0x7FFFFFFF. Example #define NUM_BLOCKS (16) #define BLOCK_SIZE (16) #define POOL_SIZE (NUM_BLOCKS * BLOCK_SIZE) OS_U8 aPool[POOL_SIZE]; OS_MEMPOOL MyMEMF; void Init(void) { // Create 16 Blocks with size of 16 Bytes OS_MEMPOOL_Create(&MyMEMF, aPool, NUM_BLOCKS, BLOCK_SIZE); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 331 CHAPTER 17 17.2.5 API functions OS_MEMPOOL_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_MEMPOOL_Delete(OS_MEMPOOL* pMEMF); Parameters Parameter pMEMF Description Pointer to the control data structure of the memory pool. Additional information This routine is provided for completeness. It is not used in the majority of applications since there is no need to dynamically create/delete memory pools. For most applications, it is suggested to have a static memory pool design: memory pools are created at startup (before calling OS_Start()) and never get deleted. A debug build of embOS will explicitly mark a memory pool as deleted. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 332 CHAPTER 17 17.2.6 API functions OS_MEMPOOL_Free() Description Releases a memory block that was previously allocated. The memory pool does not need to be denoted. Prototype void OS_MEMPOOL_Free(void* pMemBlock); Parameters Parameter pMemBlock Description Pointer to the control data structure of the memory pool. Additional information This function may be used instead of OS_MEMPOOL_FreeEx(). It has the advantage that only one parameter is needed since embOS will automatically determine the associated memory pool. The memory block becomes available for other tasks waiting for a memory block from the associated pool, which may cause a subsequent task switch. Example void Task(void) { void* pMem; ... OS_MEMPOOL_Free(pMem); ... } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 333 CHAPTER 17 17.2.7 API functions OS_MEMPOOL_FreeEx() Description Releases a memory block that was previously allocated. Prototype void OS_MEMPOOL_FreeEx(OS_MEMPOOL* pMEMF, void* pMemBlock); Parameters Parameter Description pMEMF Pointer to the control data structure of the memory pool. pMemBlock Pointer to memory block to free. Additional information The memory block becomes available for other tasks waiting for a memory block from the associated pool, which may cause a subsequent task switch. Example Please refer to the example in the Introduction on page 324. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 334 CHAPTER 17 17.2.8 API functions OS_MEMPOOL_GetBlockSize() Description Returns the size of a single memory block in the pool. Prototype int OS_MEMPOOL_GetBlockSize(OS_CONST_PTR OS_MEMPOOL *pMEMF); Parameters Parameter pMEMF Description Pointer to the control data structure of the memory pool. Return value Size in bytes of a single memory block in the specified memory pool. This is the value of the parameter when the memory pool was created. Example static OS_MEMPOOL _MemPool; void PrintBlockSize(void) { int Size; Size = OS_MEMPOOL_GetBlockSize(&_MemPool); printf("Block Size: %d\n", Size); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 335 CHAPTER 17 17.2.9 API functions OS_MEMPOOL_GetMaxUsed() Description Returns maximum number of blocks in a pool that have been used simultaneously since creation of the pool. Prototype int OS_MEMPOOL_GetMaxUsed(OS_CONST_PTR OS_MEMPOOL *pMEMF); Parameters Parameter pMEMF Description Pointer to the control data structure of the memory pool. Return value Maximum number of blocks in the specified memory pool that were used simultaneously since the pool was created. Example static OS_MEMPOOL _MemPool; void PrintMemoryUsagePeak(void) { int BlockCnt, UsedBlocks, ; void* pData; pData = OS_MEMPOOL_AllocBlocked(&_MemPool, 0); BlockCnt = OS_MEMPOOL_GetNumBlocks(&_MemPool); UsedBlocks = OS_MEMPOOL_GetMaxUsed(&_MemPool); if (UsedBlocks != 0) { printf("Max used Memory: %d%%\n", (int) (((float)UsedBlocks / BlockCnt) * 100)); } else { printf("Max used Memory: 0%%"); } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 336 CHAPTER 17 17.2.10 API functions OS_MEMPOOL_GetNumBlocks() Description Returns the total number of memory blocks in the pool. Prototype int OS_MEMPOOL_GetNumBlocks(OS_CONST_PTR OS_MEMPOOL *pMEMF); Parameters Parameter pMEMF Description Pointer to the control data structure of memory pool. 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. Please refer to the example of OS_MEMPOOL_GetMaxUsed() or OS_MEMPOOL_GetNumFreeBlocks(). UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 337 CHAPTER 17 17.2.11 API functions OS_MEMPOOL_GetNumFreeBlocks() Description Returns the number of free memory blocks in the pool. Prototype int OS_MEMPOOL_GetNumFreeBlocks(OS_CONST_PTR OS_MEMPOOL *pMEMF); Parameters Parameter pMEMF Description Pointer to the control data structure of the memory pool. Return value The number of free blocks currently available in the specified memory pool. Example static OS_MEMPOOL _MemPool; void PrintMemoryUsage(void) { int BlockCnt; int UnusedBlocks; void* pData; pData = OS_MEMPOOL_AllocBlocked(&_MemPool, 0); BlockCnt = OS_MEMPOOL_GetNumBlocks(&_MemPool); UnusedBlocks = OS_MEMPOOL_GetNumFreeBlocks(&_MemPool); if (UnusedBlocks != 0) { printf("Used Memory: %d%%\n", 100 - (int) (((float)UnusedBlocks / BlockCnt) * 100)); } else { printf("Used Memory: 0%%"); } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 338 CHAPTER 17 17.2.12 API functions OS_MEMPOOL_IsInPool() Description Information routine to examine whether a memory block reference pointer belongs to the specified memory pool. Prototype OS_BOOL OS_MEMPOOL_IsInPool(OS_CONST_PTR OS_MEMPOOL *pMEMF, OS_CONST_PTR void *pMemBlock); Parameters Parameter Description pMEMF Pointer to the control data structure of the memory pool. pMemBlock Pointer to a memory block that should be checked. Return value 0 1 Pointer does not belong to the specified memory pool. Pointer belongs to the specified memory pool. Example static OS_MEMPOOL _MemPool; void CheckPointerLocation(OS_MEMPOOL* pMEMF, void* Pointer) { if (OS_MEMPOOL_IsInPool(pMEMF, Pointer) == 0) { printf("Pointer doesn't belong to the specified memory pool.\n"); } else { printf("Pointer belongs to the specified memory pool.\n"); } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 18 System Tick UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 340 CHAPTER 18 18.1 Introduction Introduction This chapter explains the concept of the system tick, which is used as a time base for embOS. Typically, a hardware timer is used to generate periodic interrupts which are then utilized as a time base for embOS. To do so, the timer's according interrupt service routine must call one of the embOS tick handlers. embOS offers different tick handlers with different functionality, and also provides the means to optionally call a user-defined hook function from within these tick handlers. The used hardware timer usually is initialized within OS_InitHW(), which is delivered with the respective embOS start project's RTOSInit.c. This also includes the interupt handler that is called by the hardware timer interrupt. Modifications to this initialization and the respective interrupt handler are required when a different hardware timer should be used (see Using a different timer to generate tick interrupts for embOS on page 461). Tick handler The interrupt service routine used as a time base must call one of the embOS tick handlers. The reason why there are different tick handlers is simple: They differ in capabilities, code size and execution speed. Most applications use the standard tick handler OS_TICK_Handle(), which increments the tick count by one each time it is called. This tick handler is small and efficient, but it cannot handle situations in which the interrupt rate differs from the tick rate. OS_TICK_HandleEx() is capable of handling even fractional interrupt rates, such as 1.6 interrupts per tick. 18.2 API functions OS_TICK_Config() Configures the tick to interrupt ratio. OS_TICK_Handle() Default embOS timer tick handler. OS_TICK_HandleEx() Alternate tick handler that may be used instead of the default tick handler. OS_TICK_HandleNoHook() Speed-optimized embOS timer tick handler without hook functionality. UM01001 User Guide & Reference Manual for embOS Timer ISR Task Description main Routine (c) 1995-2018 SEGGER Microcontroller GmbH 341 CHAPTER 18 18.2.1 API functions OS_TICK_Config() Description Configures the tick to interrupt ratio. The default tick handler, OS_TICK_Handle(), assumes a 1:1 ratio, meaning one interrupt increments the tick count (OS_Global.Time) by one. For other ratios, OS_TICK_HandleEx() must to be used instead of the default handler and the tick to interrupt ratio must be configured through a call to OS_TICK_Config(). Since this must be done before the embOS timer is started, it is suggested to call OS_TICK_Config() during OS_InitHW(). Prototype void OS_TICK_Config(unsigned FractPerInt, unsigned FractPerTick); Parameters Parameter Description FractPerInt Number of fractions per interrupt. FractPerTick Number of fractions per tick. Additional information FractPerInt/FractPerTick = Time between two tick interrupts/Time for one tick. Fractional values are supported. For example, a 1 msec tick can be used even when an interrupt is generated every 1.6 msec only. In that case, FractPerInt and FractPerTick must be: FractPerInt = 16; FractPerTick = 10; or FractPerInt = 8; FractPerTick = 5; Example 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 (2 msec), 1 Interrupts once per 1.6 msec, 10 kHz interrupts (0.1 msec), 10 kHz interrupts (0.1 msec), 10 kHz interrupts (0.1 msec), UM01001 User Guide & Reference Manual for embOS msec tick 1 msec tick 1 msec tick 0.1 msec tick 1 usec tick (c) 1995-2018 SEGGER Microcontroller GmbH 342 CHAPTER 18 18.2.2 API functions OS_TICK_Handle() Description Default embOS timer tick handler. It assumes a 1:1 tick to interrupt ratio, i.e. one interrupt increments the tick count by one. Prototype void OS_TICK_Handle(void); Additional information The embOS tick handler must not be called by the application, but must be called from the hardware timer interrupt handler. OS_INT_Enter() or OS_INT_EnterNestable() must be called before calling the embOS tick handler. If any tick hook functions have been added by the application (see Hooking into the system tick on page 345), these will be called by OS_TICK_Handle(). Example __interrupt void SysTick_Handler(void) { OS_INT_EnterNestable(); OS_TICK_Handle(); OS_INT_LeaveNestable(); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 343 CHAPTER 18 18.2.3 API functions OS_TICK_HandleEx() Description Alternate tick handler that may be used instead of the default tick handler. It may be used in situations in which the interrupt rate differs from the tick rate. Prototype void OS_TICK_HandleEx(void); Additional information The embOS tick handler must not be called by the application, but must be called from the hardware timer interrupt handler. OS_INT_Enter() or OS_INT_EnterNestable() must be called before calling the embOS tick handler. If any tick hook functions have been added by the application (see Hooking into the system tick on page 345), these will be called by OS_TICK_HandleEx(). Refer to OS_TICK_Config() for information on how to configure the tick to interrupt ratio for OS_TICK_HandleEx(). Example __interrupt void SysTick_Handler(void) { OS_INT_EnterNestable(); OS_TICK_HandleEx(); OS_INT_LeaveNestable(); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 344 CHAPTER 18 18.2.4 API functions OS_TICK_HandleNoHook() Description Speed-optimized embOS timer tick handler without hook functionality. Prototype void OS_TICK_HandleNoHook(void); Additional information The embOS tick handler must not be called by the application, it is only called from the system tick interrupt handler. OS_INT_Enter() or OS_INT_EnterNestable() must be called before calling the embOS tick handler. OS_TICK_HandleNoHook() will not call any tick hook functions that may have been added by the application (see Hooking into the system tick on page 345). Example __interrupt void SysTick_Handler(void) { OS_INT_EnterNestable(); OS_TICK_HandleNoHook(); OS_INT_LeaveNestable(); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 345 CHAPTER 18 18.3 Hooking into the system tick 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. 18.4 API functions Adds a tick hook handler. OS_TICK_RemoveHook() Removes a tick hook handler. UM01001 User Guide & Reference Manual for embOS Timer OS_TICK_AddHook() ISR Task Description main Routine (c) 1995-2018 SEGGER Microcontroller GmbH 346 CHAPTER 18 18.4.1 API functions OS_TICK_AddHook() Description Adds a tick hook handler. Prototype void OS_TICK_AddHook(OS_TICK_HOOK* pHook, OS_TICK_HOOK_ROUTINE* pfUser); Parameters Parameter Description pHook Pointer to a structure of OS_TICK_HOOK. pfUser Pointer to an OS_TICK_HOOK_ROUTINE function. Additional information The hook function is called directly from the interrupt handler. The function therefore should execute as quickly as possible. The function called by the tick hook must not re-enable interrupts. Example static OS_TICK_HOOK _Hook; void HookRoutine(void) { // Do something... } int main(void) { ... OS_TICK_AddHook(&_Hook, HookRoutine); ... } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 347 CHAPTER 18 18.4.2 API functions OS_TICK_RemoveHook() Description Removes a tick hook handler. Prototype void OS_TICK_RemoveHook(OS_CONST_PTR OS_TICK_HOOK *pHook); Parameters Parameter pHook Description Pointer to a structure of OS_TICK_HOOK. Additional information The function may be called to dynamically remove a tick hook function installed by a call to OS_TICK_AddHook(). Example static OS_TICK_HOOK _Hook; void Task(void) { ... OS_TICK_RemoveHook(&_Hook); ... } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 348 CHAPTER 18 18.5 Disabling the system tick Disabling the system tick With many MCUs, power consumption may be reduced by using the embOS tickless support. Please refer to Tickless support on page 304 for further information. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 19 Debugging UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 350 CHAPTER 19 19.1 Runtime application errors Runtime application errors Many application errors can be detected during runtime. These are for example: * * * * Invalid usage of embOS API Usage of uninitialized embOS data structures Invalid pointers Stack overflow Which runtime errors can be detected depends on how many checks are performed. Unfortunately, additional checks cost memory and performance (it is not that significant, but there is a difference). Not all embOS library modes include the debug and stack check code. For example OS_LIBMODE_DP includes the debug and stack check, whereas OS_LIBMODE_R does not contain any debug or stack check code. Note If an application error is detected and OS_Error() is called, do not switch to another embOS library mode which does not contain the debug checks. While doing so avoids calls to OS_Error(), it does not fix the original application error. When embOS detects a runtime error, it calls the following routine: void OS_Error(OS_STATUS ErrCode); This routine is shipped as source code as part of the module OS_Error.c. Although this function is named OS_Error(), it does not show embOS erros but application errors. It simply disables further task switches and then, after re-enabling interrupts, loops forever as follows: Example // // Run time error reaction // void OS_Error(OS_STATUS ErrCode) { OS_TASK_EnterRegion(); // Avoid further task switches OS_Global.Counters.DI = 0u; // Allow interrupts so we can communicate OS_INT_Enable(); OS_Status = ErrCode; while (OS_Status) { // Endless loop may be left by setting OS_Status to 0 } } If you are using embOSView, you can see the value and meaning of OS_Status in the system variable window. When using a debugger, 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 a parameter. You should add OS_Status to your watch window. You can modify the routine to accommodate to your own hardware; this could mean that your target hardware sets an error-indicating LED or shows a small message on the display. Note When modifying the OS_Error() routine, the first statement needs to be the disabling of the scheduler via OS_TASK_EnterRegion(); the last statement needs to be the infinite loop. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 351 CHAPTER 19 Runtime application errors 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 debugger, 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. OS_DEBUG_LEVEL The preprocessor symbol OS_DEBUG_LEVEL defines the embOS debug level. The default value is 1. With higher debug levels more debug code is included. This define can be changed with the embOS source code only. 19.1.1 List of error codes Value Define Explanation 0 OS_OK No error, everything ok. 100 OS_ERR_ISR_INDEX Index value out of bounds during interrupt controller initialization or interrupt installation. 101 OS_ERR_ISR_VECTOR Default interrupt handler called, but interrupt vector not initialized. 102 OS_ERR_ISR_PRIO Wrong interrupt priority. 103 OS_ERR_WRONG_STACK Wrong stack used before main(). 104 OS_ERR_ISR_NO_HANDLER No interrupt handler was defined for this interrupt. 105 OS_ERR_TLS_INIT OS_TLS_Init() called multiple times from one task. 106 OS_ERR_MB_BUFFER_SIZE For 16bit CPUs, the maximum buffer size for a mailbox (64KB) exceeded. 116 OS_ERR_EXTEND_CONTEXT OS_ExtendTaskContext() called multiple times from one task. 118 OS_ERR_INTERNAL OS_ChangeTask() called without Region Counter set (or other internal error). 119 OS_ERR_IDLE_RETURNS OS_Idle() must not return. 120 OS_ERR_STACK Task stack overflow or invalid task stack. 121 OS_ERR_SEMAPHORE_OVERFLOW Semaphore value overflow. 122 OS_ERR_POWER_OVER Counter overflows when calling OS_POWER_UsageInc(). 123 OS_ERR_POWER_UNDER Counter underflows when calling OS_POWER_UsageDec(). 124 OS_ERR_POWER_INDEX Index to high, exceeds (OS_POWER_NUM_COUNTERS - 1). 125 OS_ERR_SYS_STACK System stack overflow. 126 OS_ERR_INT_STACK Interrupt stack overflow. 128 OS_ERR_INV_TASK Task control block invalid, not initialized or overwritten. 129 OS_ERR_INV_TIMER Timer control block invalid, not initialized or overwritten. 130 OS_ERR_INV_MAILBOX Mailbox control block invalid, not initialized or overwritten. 132 OS_ERR_INV_SEMAPHORE Control block for semaphore invalid, not initialized or overwritten. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 352 CHAPTER 19 Value Runtime application errors Define Explanation OS_ERR_INV_MUTEX Control block for mutex invalid, not initialized or overwritten. 135 OS_ERR_MAILBOX_NOT1 One of the following 1-byte mailbox functions has been used on a multibyte mailbox: OS_MAILBOX_Get1(), OS_MAILBOX_GetBlocked1(), OS_MAILBOX_GetTimed1(), OS_MAILBOX_Put1(), OS_MAILBOX_PutBlocked1(), OS_MAILBOX_PutFront1(), OS_MAILBOX_PutFrontBlocked1() or OS_MAILBOX_PutTimed1(). * OS_MAILBOX_Get1() * OS_MAILBOX_GetBlocked1() * OS_MAILBOX_GetTimed1() * OS_MAILBOX_Put1() * OS_MAILBOX_PutBlocked1() * OS_MAILBOX_PutFront1() * OS_MAILBOX_PutFrontBlocked1() * OS_MAILBOX_PutTimed1() 136 OS_ERR_MAILBOX_DELETE OS_MAILBOX_Delete() was called on a mailbox with waiting tasks. 137 OS_ERR_SEMAPHORE_DELETE OS_SEMAPHORE_Delete() was called on a semaphore with waiting tasks. 138 OS_ERR_MUTEX_DELETE OS_MUTEX_Delete() was called on a mutex which is claimed by a task. 140 OS_ERR_MAILBOX_NOT_IN_LIST The mailbox is not in the list of mail-boxes as expected. Possible reasons may be that one mailbox data structure was overwritten. 142 OS_ERR_TASKLIST_CORRUPT The OS internal task list is destroyed. 143 OS_ERR_QUEUE_INUSE Queue in use. 144 OS_ERR_QUEUE_NOT_INUSE Queue not in use. 145 OS_ERR_QUEUE_INVALID Queue invalid. 146 OS_ERR_QUEUE_DELETE A queue was deleted by a call of OS_QUEUE_Delete() while tasks are waiting at the queue. 147 OS_ERR_MB_INUSE Mailbox in use. 148 OS_ERR_MB_NOT_INUSE Mailbox not in use. 149 OS_ERR_MESSAGE_SIZE_ZERO Attempt to store a message with size of zero. 150 OS_ERR_UNUSE_BEFORE_USE OS_MUTEX_Unlock() has been called on a mutex hasn't been locked before. 151 OS_ERR_LEAVEREGION_BEFORE_ENTERREGION OS_TASK_LeaveRegion() has been called before OS_TASK_EnterRegion(). 152 OS_ERR_LEAVEINT Error in OS_INT_Leave(). OS_ERR_DICNT The interrupt disable counter ( OS_Global.Counters.Cnt.DI ) is out of range (0-15). The counter is affected by the following API calls: * OS_INT_IncDI() * OS_INT_DecRI() * OS_INT_Enter() * OS_INT_Leave() 133 153 UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 353 CHAPTER 19 Value Define Runtime application errors Explanation 154 OS_TASK_Delay() or OS_TASK_DelayUnOS_ERR_INTERRUPT_DISABLED til() called from inside a critical region with interrupts disabled. 155 OS_ERR_TASK_ENDS_WITHOUT_TERMINATE Task routine returns without 0S_TASK_Terminate(). 156 OS_ERR_RESOURCE_OWNER OS_MUTEX_Unlock() has been called from a task which does not own the mutex. 157 OS_ERR_REGIONCNT The Region counter overflows (>255). 158 OS_ERR_DELAYUS_INTERRUPT_DISABLED OS_TASK_Delayus() called with interrupts disabled. OS_ERR_ILLEGAL_IN_ISR 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. 161 OS_ERR_ILLEGAL_IN_TIMER Illegal function call in a software timer: A routine that must not be called from within a software timer has been called from within a timer. 162 OS_ERR_ILLEGAL_OUT_ISR Not a legal API outside interrupt. 163 OS_ERR_NOT_IN_ISR OS_INT_Enter() has been called, but CPU is not in ISR state. 164 OS_ERR_IN_ISR OS_INT_Enter() has not been called, but CPU is in ISR state. 165 OS_ERR_INIT_NOT_CALLED OS_Init() was not called. 166 OS_ERR_CPU_STATE_ISR_ILLEGAL embOS API called from ISR with high priority. 167 OS_ERR_CPU_STATE_ILLEGAL CPU runs in illegal mode. 168 OS_ERR_CPU_STATE_UNKNOWN CPU runs in unknown mode or mode could not be read. 170 OS_ERR_2USE_TASK Task control block has been initialized by calling a create function twice. 171 OS_ERR_2USE_TIMER Timer control block has been initialized by calling a create function twice. 172 OS_ERR_2USE_MAILBOX Mailbox control block has been initialized by calling a create function twice. 174 OS_ERR_2USE_SEMAPHORE Semaphore has been initialized by calling a create function twice. 175 OS_ERR_2USE_MUTEX Mutex has been initialized by calling a create function twice. 176 OS_ERR_2USE_MEMF Fixed size memory pool has been initialized by calling a create function twice. 177 OS_ERR_2USE_QUEUE Queue has been initialized by calling a create function twice. 178 OS_ERR_2USE_EVENT Event object has been initialized by calling a create function twice. 179 OS_ERR_2USE_WATCHDOG Watchdog has been initialized by calling a create function twice. 180 OS_ERR_NESTED_RX_INT OS_Rx interrupt handler for embOSView is nested. Disable nestable interrupts. 160 UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 354 CHAPTER 19 Value Define Runtime application errors Explanation 185 OS_ERR_SPINLOCK_INV_CORE Invalid core ID specified for accessing a OS_SPINLOCK_SW struct. 190 OS_ERR_MEMF_INV Fixed size memory block control structure not created before use. 191 OS_ERR_MEMF_INV_PTR Pointer to memory block does not belong to memory pool on Release. 192 OS_ERR_MEMF_PTR_FREE Pointer to memory block is already free when calling OS_MEMPOOL_Release(). Possibly, same pointer was released twice. 193 OS_ERR_MEMF_RELEASE OS_MEMPOOL_Release() was called for a memory pool, that had no memory block allocated (all available blocks were already free before). 194 OS_ERR_MEMF_POOLADDR OS_MEMPOOL_Create() was called with a memory pool base address which is not located at a word aligned base address. 195 OS_ERR_MEMF_BLOCKSIZE OS_MEMPOOL_Create() was called with a data block size which is not a multiple of processors word size. 200 OS_ERR_SUSPEND_TOO_OFTEN Nested call of OS_TASK_Suspend() exceeded OS_MAX_SUSPEND_CNT. 201 OS_ERR_RESUME_BEFORE_SUSPEND OS_TASK_Resume() called on a task that was not suspended. 202 OS_ERR_TASK_PRIORITY OS_TASK_Create() 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. 203 OS_ERR_TASK_PRIORITY_INVALID The value 0 was used as task priority. 205 OS_ERR_TIMER_PERIOD_INVALID The value 0 was used as timer period. 210 OS_ERR_EVENT_INVALID An OS_EVENT object was used before it was created. 212 OS_ERR_EVENT_DELETE An OS_EVENT object was deleted with waiting tasks. 220 OS_ERR_WAITLIST_RING This error should not occur. Please contact the support. 221 OS_ERR_WAITLIST_PREV This error should not occur. Please contact the support. 222 OS_ERR_WAITLIST_NEXT This error should not occur. Please contact the support. 223 OS_ERR_TICKHOOK_INVALID Invalid tick hook. 224 OS_ERR_TICKHOOK_FUNC_INVALID Invalid tick hook function. 225 OS_ERR_NOT_IN_REGION A function was called without declaring the necessary critical region. 226 OS_ERR_ILLEGAL_IN_MAIN Not a legal API call from main(). 227 OS_ERR_ILLEGAL_IN_TASK Not a legal API after OS_Start(). 228 OS_ERR_ILLEGAL_AFTER_OSSNot a legal API after OS_Start(). TART UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 355 CHAPTER 19 Value Runtime application errors Define Explanation 230 OS_ERR_NON_ALIGNED_INVALIDATE Cache invalidation needs to be cache line aligned. 234 OS_ERR_HW_NOT_AVAILABLE Hardware unit is not implemented or enabled. 235 OS_ERR_NON_TIMERCYCLES_FUNC Callback function for timer counter value has not been set. Required by OS_TIME_Getus(). 236 OS_ERR_NON_TIMERINTPENDING_FUNC Callback function for timer interrupt pending flag has not been set. Required by OS_TIME_Getus(). 240 OS_ERR_MPU_NOT_PRESENT MPU unit not present in the device. 241 OS_ERR_MPU_INVALID_REGION Invalid MPU region index number. 242 OS_ERR_MPU_INVALID_SIZE Invalid MPU region size. 243 OS_ERR_MPU_INVALID_PERMISSION Invalid MPU region permission. 244 OS_ERR_MPU_INVALID_ALIGNInvalid MPU region alignment. MENT 245 OS_ERR_MPU_INVALID_OBJECT OS object is directly accessible from the task which is not allowed. 250 OS_ERR_CONFIG_OSSTOP OS_Stop() is called without using OS_ConfigStop() before. 251 OS_ERR_OSSTOP_BUFFER Buffer is too small to hold a copy of the main() stack. 253 OS_ERR_VERSION_MISMATCH OS library and RTOS have different version numbers. Please ensure both are from the same embOS shipment. 19.1.2 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 your own defined error code from your application. Example #define OS_ERR_APPL (0x02u) void UserAppFunc(void) { int r; r = DoSomething() if (r == 0) { OS_Error(OS_ERR_APPL) } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 356 CHAPTER 19 19.2 Human readable object identifiers Human readable object identifiers embOS objects like mailbox or semaphore are handled via separate control structures. Each OS object is identified by the address of the according control structure. For debugging purpose this address is displayed in external tools like embOSView or IDE RTOS plugins. Tasks always have a human readable task name (except in OS_LIBMODE_XR) which is set at task creation. It can be helpful to have human readable identifiers for other OS objects, as well. Example static OS_MAILBOX static OS_OBJNAME static char Mailbox; MailboxName; Buffer[100]; OS_MAILBOX_Create(&Mailbox, 10, 10, &Buffer); OS_DEBUG_SetObjName(&MailboxName, &Mailbox, "My Mailbox"); With the following API you can easily add human readable identifiers to an unlimited amount of OS objects. Human readable object identifiers are not supported in embOS library mode OS_LIBMODE_XR. 19.2.1 API functions Sets an OS object name. OS_DEBUG_GetObjName() Returns the name of an OS object. UM01001 User Guide & Reference Manual for embOS Timer OS_DEBUG_SetObjName() ISR Task Description main Routine (c) 1995-2018 SEGGER Microcontroller GmbH 357 CHAPTER 19 19.2.2 Human readable object identifiers OS_DEBUG_SetObjName() Description Sets an OS object name. Prototype void OS_DEBUG_SetObjName(OS_OBJNAME* pObjName, OS_CONST_PTR void *pOSObjID, OS_CONST_PTR char *sName); Parameters Parameter Description pObjName Pointer to a OS_OBJNAME control structure. pOSObjID ID of the OS object. sName Name of the OS object. Additional information With OS_DEBUG_SetObjName() every OS object like mailbox can have a name. This name can be shown in debug tools like IDE RTOS plug-ins. Every object name needs a control structure of type OS_OBJNAME. This function is not available in OS_LIBMODE_XR. Example #include "RTOS.h" #include static static static static static OS_STACKPTR int StackHP[128]; OS_TASK TCBHP; OS_MAILBOX Mailbox; OS_OBJNAME MailboxName; char Buffer[100]; static void HPTask(void) { const char* s; s = OS_DEBUG_GetObjName(&Mailbox); printf(s); while (1) { OS_TASK_Delay(50); } } int main(void) { OS_Init(); // Initialize embOS OS_InitHW(); // Initialize required hardware OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP); OS_MAILBOX_Create(&Mailbox, 10, 10, &Buffer); OS_DEBUG_SetObjName(&MailboxName, &Mailbox, "My Mailbox"); OS_Start(); // Start embOS return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 358 CHAPTER 19 19.2.3 Human readable object identifiers OS_DEBUG_GetObjName() Description Returns the name of an OS object. Prototype char *OS_DEBUG_GetObjName(OS_CONST_PTR void *pOSObjID); Parameters Parameter pOSObjID Description Pointer to the OS object. Return value = NULL NULL Name was not set for this object. Pointer to the OS object name. Additional information OS_DEBUG_GetObjName() returns the object name which was set before with OS_DEBUG_SetObjName(). This function is not available in OS_LIBMODE_XR. Example For an example, see OS_DEBUG_SetObjName(). UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 20 Profiling UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 360 CHAPTER 20 20.1 Introduction Introduction This chapter explains the profiling functions that can be used by an application. In software engineering, profiling ("program profiling", "software profiling") is a form of dynamic program analysis that measures, for example, the time complexity of a program and duration of function calls. Example #include "RTOS.h" #include static OS_STACKPTR int StackHP[128], StackLP[128], StackSample[128]; static OS_TASK TCBHP, TCBLP, TCBSample; static void HPTask(void) { while (1) { OS_TASK_Delayus(500); OS_TASK_Delay(1); } } // Do something. // Give other tasks a chance to run. static void LPTask(void) { while (1) { OS_TASK_Delayus(250); OS_TASK_Delay(1); } } // Do something. // Give other tasks a chance to run. static void SampleTask(void) { while (1) { OS_STAT_Sample(); // Calculate CPU load. printf("CPU usage of HP Task: %d\n", OS_STAT_GetLoad(&TCBHP)); printf("CPU usage of LP Task: %d\n\n", OS_STAT_GetLoad(&TCBLP)); OS_TASK_Delay(1000); // Wait for at least 1 second before next sampling. } } int main(void) { OS_Init(); // Initialize embOS OS_InitHW(); // Initialize the hardware OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP); OS_TASK_CREATE(&TCBLP, "LP Task", 50, LPTask, StackLP); OS_TASK_CREATE(&TCBSample, "Sample Task", 1, SampleTask, StackSample); OS_Start(); // Start multitasking return 0; } Output CPU usage of HP Task: 520 CPU usage of LP Task: 268 UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 361 CHAPTER 20 20.2 API functions API functions Timer ISR Task Description main Routine OS_STAT_AddLoadMeasurement() Initializes the periodic CPU load measurement. OS_STAT_AddLoadMeasurementEx() Initializes the periodic CPU load measurement. OS_STAT_Disable() Disables the kernel profiling. OS_STAT_Enable() Enables the kernel profiling (for an indefinite time). OS_STAT_GetExecTime() Returns the total task execution time. OS_STAT_GetLoadMeasurement() Retrieves the result of the CPU load measurement. OS_STAT_GetLoad() Calculates the current task's CPU load in permille. OS_STAT_Sample() Starts the kernel profiling and calculates the absolute task run time since the last call to OS_STAT_Sample(). UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 362 CHAPTER 20 20.2.1 API functions OS_STAT_AddLoadMeasurement() Description Initializes the periodic CPU load measurement. May be used to start the calculation of the total CPU load of an application. Note OS_STAT_AddLoadMeasurement() starts a CPU load task with a predefined task stack size of 48 integers. The stack size is sufficient for most applications. However, in some situations more task stack may be required. In that case please use OS_STAT_AddLoadMeasurementEx() which allows to use an application defined stack size. Prototype void OS_STAT_AddLoadMeasurement(int Period, OS_U8 AutoAdjust, OS_I32 DefaultMaxValue); Parameters Parameter Description Period Measurement period in embOS system ticks. AutoAdjust If not zero, the measurement is autoadjusted once initially. DefaultMaxValue May be used to set a default counter value when AutoAdjust is not used. (See additional information) The CPU load is the percentage of CPU time that was not spent in OS_Idle(). To measure it, OS_STAT_AddLoadMeasurement() creates a task running at highest priority. This task periodically suspends itself by calling OS_TASK_Delay(Period). Each time it is resumed, it calculates the CPU load through comparison of two counter values. For this calculation, it is required that OS_Idle() gets executed and increments a counter by calling OS_INC_IDLE_CNT(). Furthermore, the calculation will fail if OS_Idle() starts a power save mode of the CPU. OS_Idle() must therefore be similar to: void OS_Idle(void) { while (1) { OS_INC_IDLE_CNT(); } } The maximum value of the idle counter is stored once at the beginning and is subsequently used for comparison with the current value of the counter each time the measurement task gets activated. For this comparison, it is assumed that the maximum value of the counter represents a CPU load of 0%, whereas a value of zero represents a CPU load of 100%. The maximum value of the counter can either be examined automatically, or may else be set manually. When AutoAdjust is non-zero, the task will examine the maximum value of the counter automatically. To do so, it will initially suspend all other tasks for the Period-time and will subsequently call OS_TASK_Delay(Period). This way, the entire period is spent in OS_Idle() and the counter incremented in OS_Idle() reaches its maximum value, which is then saved and used for comparisons. Especially when the initial suspension of all tasks for the Period-time is not desired, the maximum counter value may also be configured manually via the parameter DefaultMaxValue when AutoAdjust is zero. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 363 CHAPTER 20 20.2.1.1 API functions OS_IdleCnt Description This global variable holds the counter value used for CPU load measurement. It may be helpful when examining the appropiate DefaultMaxValue for the manual configuration of OS_STAT_AddLoadMeasurement(). Declaration volatile OS_I32 OS_IdleCnt; Additional information The appropiate DefaultMaxValue may, for example, be examined prior to creating any other task, similar to the given sample below: void MainTask(void) { OS_I32 DefaultMax; OS_TASK_Delay(100); DefaultMax = OS_IdleCnt; /* This value can be used as DefaultMaxValue. */ /* Now other tasks can be created and started. */ } This function is not available in OS_LIBMODE_SAFE. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 364 CHAPTER 20 20.2.2 API functions OS_STAT_AddLoadMeasurementEx() Description Initializes the periodic CPU load measurement. May be used to start the calculation of the total CPU load of an application. OS_STAT_AddLoadMeasurementEx() allows to define the stack location and size for the CPU load task which is started automatically by OS_STAT_AddLoadMeasurementEx() Prototype void OS_STAT_AddLoadMeasurementEx(int OS_U8 OS_I32 void OS_UINT Period, AutoAdjust, DefaultMaxValue, OS_STACKPTR *pStack, StackSize); Parameters Parameter Description Period Measurement period in embOS system ticks. AutoAdjust If not zero, the measurement is autoadjusted once initially. DefaultMaxValue May be used to set a default counter value when AutoAdjust is not used. (See additional information) pStack Pointer to the stack. StackSize Size of the stack. Additional information Please refer to the description of OS_STAT_AddLoadMeasurement() for more details. This function is not available in OS_LIBMODE_SAFE. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 365 CHAPTER 20 20.2.3 API functions OS_STAT_Disable() Description Disables the kernel profiling. Prototype void OS_STAT_Disable(void); Additional information The function OS_STAT_Enable() may be used to start profiling. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 366 CHAPTER 20 20.2.4 API functions OS_STAT_Enable() Description Enables the kernel profiling (for an indefinite time). Prototype void OS_STAT_Enable(void); Additional information The function OS_STAT_Disable() may be used to stop profiling. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 367 CHAPTER 20 20.2.5 API functions OS_STAT_GetExecTime() Description Returns the total task execution time. Prototype OS_U32 OS_STAT_GetExecTime(OS_CONST_PTR OS_TASK *pTask); Parameters Parameter pTask Description Pointer to a task control block. Return value The total task execution time in timer cycles. Additional information This function only returns valid values when profiling was enabled before by a call to OS_STAT_Enable(). If pTask is a 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(). Example OS_U32 ExecTime; void MyTask(void) { OS_STAT_Enable(); while (1) { ExecTime = OS_STAT_GetExecTime(NULL); OS_TASK_Delay(100); } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 368 CHAPTER 20 20.2.6 API functions OS_STAT_GetLoadMeasurement() Description Retrieves the result of the CPU load measurement. Prototype int OS_STAT_GetLoadMeasurement(void); Return value The total CPU load in percent. Additional information OS_STAT_GetLoadMeasurement() delivers correct results if * * the CPU load measurement was started before by calling OS_STAT_AddLoadMeasurement() with auto-adjustment or else with a correct default value, and OS_Idle() updates the measurement by calling OS_INC_IDLE_CNT(). 20.2.6.1 OS_CPU_Load Description The global variable OS_CPU_Load holds the total CPU load as a percentage. It may prove helpful to monitor the variable in a debugger with live-watch capability during development. Declaration volatile OS_INT OS_CPU_Load; Additional information This variable will not contain correct results unless the CPU load measurement was started by a call to OS_STAT_AddLoadMeasurement(). This function is not available in OS_LIBMODE_SAFE. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 369 CHAPTER 20 20.2.7 API functions OS_STAT_GetLoad() Description Calculates the current task's CPU load in permille. Prototype int OS_STAT_GetLoad(OS_CONST_PTR OS_TASK *pTask); Parameters Parameter pTask Description Pointer to a task control block. Return value The current task's CPU load in permille. Additional information OS_STAT_GetLoad() requires OS_STAT_Sample() to be periodically called by the task for which to measure the CPU load. OS_STAT_GetLoad() cannot be used from multiple tasks simultaneously for it uses a global variable. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 370 CHAPTER 20 20.2.8 API functions OS_STAT_Sample() Description Starts the kernel 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() enables profiling for five consecutive seconds. The next call to OS_STAT_Sample() must be performed within these five seconds. To retrieve the calculated CPU load in permille, use the embOS function OS_STAT_GetLoad(). OS_STAT_Sample() cannot be used from multiple tasks simultaneously because it uses a global variable. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 21 embOSView UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 372 CHAPTER 21 21.1 Overview Overview The embOSView utility is a helpful tool for the analysis of the running target application. It is shipped as embOSView.exe with embOS and runs on Windows. Most often, a serial interface (UART) is used for the communication with the target hardware. Alternative communication channels include Ethernet, memory read/write for Cortex-M and RX CPUs, and DCC for ARM7/9 and Cortex-A CPUs. The hardware dependent routines and defines available for communication with embOSView are implemented inside the source file RTOSInit.c. Details on how to modify this file are also included in How to change settings on page 461. The communication API is not available in embOS library mode OS_LIBMODE_SAFE. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 373 CHAPTER 21 21.2 Task list window Task list window embOSView shows the state of every task created by 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 Run Count Number of activations since reset. SP, DP, DT Time slice Round-robin time slice All The Task list window is helpful in analysis of stack usage and CPU load for every running task. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 374 CHAPTER 21 21.3 System variables window System variables window embOSView shows the state of major system variables in the System variables window. The information shown also depends on the library used by your application: Item Description 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 system ticks. All OS_NumTasks 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 UM01001 User Guide & Reference Manual for embOS Builds (c) 1995-2018 SEGGER Microcontroller GmbH 375 CHAPTER 21 21.4 Sharing the SIO for terminal I/O 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. 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_COM_SendString() for sending a string to the Terminal window and the function OS_COM_SetRxCallback() to hook a reception-routine that receives one byte. 21.4.1 API functions Sends a string to the embOSView terminal window. OS_COM_SetRxCallback() Sets a callback hook to a routine for receiving one character from embOSView. UM01001 User Guide & Reference Manual for embOS Timer OS_COM_SendString() ISR Task Description main Routine (c) 1995-2018 SEGGER Microcontroller GmbH 376 CHAPTER 21 21.4.1.1 Sharing the SIO for terminal I/O OS_COM_SendString() Description Sends a string to the embOSView terminal window. Prototype void OS_COM_SendString(const char* s); Parameters Parameter s Description Pointer to a null-terminated string that should be sent to the terminal window. Additional information This function utilizes the target-specific function OS_COM_Send1() (see OS_COM_Send1()). UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 377 CHAPTER 21 21.4.1.2 Sharing the SIO for terminal I/O OS_COM_SetRxCallback() Description Sets a callback hook to a routine for receiving one character from embOSView. Prototype OS_RX_CALLBACK *OS_COM_SetRxCallback(OS_RX_CALLBACK* cb); Parameters Parameter cb Description Pointer to the application routine that should be called when one character is received over the serial interface. Return value 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. The callback function is defined as: typedef void OS_RX_CALLBACK (OS_U8 Data); Example void GUI_X_OnRx(OS_U8 Data); /* Callback ... called from Rx-interrupt */ void GUI_X_Init(void) { OS_COM_SetRxCallback(&GUI_X_OnRx); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 378 CHAPTER 21 21.5 Enable communication to embOSView Enable communication to embOSView The communication to embOSView can be enabled by setting the compile time switch OS_VIEW_IFSELECT to an interface define which may be defined in the project settings or in the configuration file OS_Config.h. If OS_VIEW_IFSELECT is defined as OS_VIEW_DISABLED, the communication is disabled. In the RTOSInit files the OS_VIEW_IFSELECT switch is set to a specific interface if not defined as project option. The OS_Config.h file sets the compile time switch OS_VIEW_IFSELECT to OS_VIEW_DISABLED when DEBUG=1 is not defined. Therefore, in the embOS start projects, the communication is enabled per default when using the Debug configuration, and is disabled when using the Release configuration. Communication interface OS_VIEW_IFSELECT OS_VIEW_DISABLED Disabled OS_VIEW_IF_UART UART OS_VIEW_IF_JLINK J-Link OS_VIEW_IF_ETHERNET Ethernet UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 379 CHAPTER 21 21.6 Select the communication channel Select the communication channel When the communication to embOSView is enabled by setting the compile time switch OS_VIEW_IFSELECT, the communication can be handled via UART, J-Link or ethernet. 21.6.1 Select a UART for communication Set the compile time switch OS_VIEW_IFSELECT to OS_VIEW_IF_UART by project option/compiler preprocessor or in RTOSInit.c to enable the communication via UART. 21.6.2 Select J-Link for communication Per default, J-Link is selected as communication device in most embOS start projects, if available. The compile time switch OS_VIEW_IFSELECT is predefined to OS_VIEW_IF_JLINK in the CPU specific RTOSInit.c files, thus J-Link communication is selected per default unless overwritten by project / compiler preprocessor options. 21.6.3 Select Ethernet for communication Set the compile time switch OS_VIEW_IFSELECT to OS_VIEW_IF_ETHERNET by project / compiler preprocessor options or in RTOSInit.c to switch the communication to Ethernet. This communication mode is only available when embOS/IP or a different TCP/IP stack is included with the project. Also, the file UDP_Process.c must be added to your project and the file UDPCOM.h to your Start\Inc folder. These files are not shipped with embOS, but are available on request. Using a different TCP/IP stack than embOS/IP requires modifications to UDP_Process.c. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 380 CHAPTER 21 21.7 Setup embOSView for communication Setup embOSView for communication When the communication to embOSView is enabled in the target application, embOSView can be used to analyze the running application. The communication channel of embOSView has to be setup according to the communication channel which was selected in the project. 21.7.1 Select a UART for communication Start embOSView and chose menu Setup: In the Communication tab, choose UART in the Type selection listbox. In the Host interface box, select the baud rate for communication and the COM port of the PC which should be connected to the target board. The default baud rate of all projects is 38,400. The COM port list box lists all currently available COM ports of the PC. The serial communication will work when the target is running stand-alone or during a debug session, when the target is connected to a debugger. The serial connection can be used when the target board has a spare UART port and the UART functions are included in the application. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 381 CHAPTER 21 21.7.2 Setup embOSView for communication Select J-Link for communication embOS supports communication channel to embOSView which uses J-Link to communicate with the running application. embOSView version 3.82g or higher and a J-Link DLL is required to use J-Link for communication. To select this communication channel, start embOSView and open the Setup menu: In the Communication tab, choose J-Link Cortex-M (memory access), J-Link RX (memory access) or J-Link ARM7/9/11 (DCC) in the Type selection listbox. In the Host interface box, select the USB or TCP/IP channel used to communicate with your J-Link. In the Target interface box, select the communication speed of the target interface and the physical target connection, which may be a JTAG, SWD or FINE connection. In the Log File box, choose whether a log file should be created and define its file name and location. The JTAG Chain box allows the selection of a specific device in a JTAG scan chain with multiple devices. Currently, up to eight devices in the scan chain are supported. Two values must be configured: the position of the target device in the scan chain and the total number of bits in the instruction registers of the devices before the target device (IR len). Target position is numbered in descending order, which means the target that is closest to J-Link's TDI is in the highest position (max. 7), while the target closest to J-Link's TDO is in the lowest position (which is always 0). Upon selecting the position, the according IR len is determined automatically, which should succeed for most target devices. IR len can also be written manually, which is mandatory in case automatic detection was not successful. For further information, please refer to the J-Link / J-Trace User Guide (UM08001, Chapter 5.3 "JTAG interface"). UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 382 CHAPTER 21 21.7.3 Setup embOSView for communication Select Ethernet for communication embOS supports communication channel to embOSView which uses Ethernet to communicate with the running application. embOS/IP, or a different TCP/IP stack, is required to use Ethernet for communication. To select this communication channel, start embOSView and open the Setup menu: In the Communication tab, choose Ethernet in the Type selection listbox. In the Host interface box, select the IP address of your target and the port number 50021. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 383 CHAPTER 21 21.7.4 lel Setup embOSView for communication Use J-Link for communication and debugging in paral- J-Link can be used to communicate with embOSView during a running debug session that uses the same J-Link as debug probe. To avoid potential incompatibilites, the target interface settings for J-Link should be the same in the debugger settings and in the embOSView Target interface settings. To use embOSView during a debug session, proceed as follows: * * * * * Examine the target interface settings in the Debugger settings of the project. Before starting the debugger, start embOSView and set the same target interface as found in the debugger settings. Close embOSView. Start the debugger. Restart embOSView. J-Link will now communicate with the debugger and embOSView will simultaneously communicate with embOS via J-Link. 21.7.5 Restrictions for using J-Link with embOSView With the current version of embOSView, J-Link communication with Cortex-M (memory access) can only be used when the Cortex-M vector table of the target application is located at address 0x0. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 384 CHAPTER 21 21.8 Using the API trace Using the API trace embOS contains 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_TRACE_Enable() and OS_TRACE_Disable(). 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_TASK_Delay(10). Once the trace buffer is full, trace is automatically stopped. The Trace list and buffer can be cleared from embOSView. 21.8.1 Settings 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 Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 385 CHAPTER 21 Using the API trace 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_TASK_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 Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 386 CHAPTER 21 21.9 Trace filter setup functions 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 helpful to control recording of trace events directly from the application, using the following functions. 21.9.1 API functions Timer ISR Task Description main Routine OS_TRACE_Enable() Enables tracing of filtered API calls. OS_TRACE_EnableAll() Sets up Filter 0 (any task), enables tracing of all API calls and then enables the trace function. OS_TRACE_EnableId() Sets the specified ID value in Filter 0 (any task), thus enabling trace of the specified function, but does not start trace. OS_TRACE_EnableFilterId() Sets the specified ID value in the specified trace filter, thus enabling trace of the specified function, but does not start trace. OS_TRACE_Disable() Disables tracing of filtered API and user function calls. OS_TRACE_DisableAll() Sets up Filter 0 (any task), disables tracing of all API calls and also disables trace. OS_TRACE_DisableId() Resets the specified ID value in Filter 0 (any task), thus disabling trace of the specified function, but does not stop trace. OS_TRACE_DisableFilterId() Resets the specified ID value in the specified trace filter, thus disabling trace of the specified function, but does not stop trace. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 387 CHAPTER 21 21.9.1.1 Trace filter setup functions OS_TRACE_Enable() Description Enables tracing of filtered API calls. Prototype void OS_TRACE_Enable(void); Additional information The trace filter conditions must be 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 Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 388 CHAPTER 21 21.9.1.2 Trace filter setup functions OS_TRACE_EnableAll() Description Sets up Filter 0 (any task), enables tracing of all API calls and then enables the trace function. Prototype void OS_TRACE_EnableAll(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 Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 389 CHAPTER 21 21.9.1.3 Trace filter setup functions OS_TRACE_EnableId() 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_TRACE_EnableId(OS_U8 id); Parameters Parameter id Description ID value of API call that should be enabled for trace: 0 id 255 Values from 0 to 99 and 128 to 255 are reserved for embOS. 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 Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 390 CHAPTER 21 21.9.1.4 Trace filter setup functions OS_TRACE_EnableFilterId() 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_TRACE_EnableFilterId(OS_U8 FilterIndex, OS_U8 id); Parameters Parameter Description FilterIndex Index of the filter that should be affected: 0 FilterIndex 4 0 affects Filter 0 (any task) and so on. id ID value of API call that should be enabled for trace: 0 id 255 Values from 0 to 99 are reserved for embOS. 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 Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 391 CHAPTER 21 21.9.1.5 Trace filter setup functions OS_TRACE_Disable() Description Disables tracing of filtered API and user function calls. Prototype void OS_TRACE_Disable(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 Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 392 CHAPTER 21 21.9.1.6 Trace filter setup functions OS_TRACE_DisableAll() Description Sets up Filter 0 (any task), disables tracing of all API calls and also disables trace. Prototype void OS_TRACE_DisableAll(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 Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 393 CHAPTER 21 21.9.1.7 Trace filter setup functions OS_TRACE_DisableId() 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_TRACE_DisableId(OS_U8 id); Parameters Parameter id Description ID value of API call that should be enabled for trace: 0 id 255 Values from 0 to 99 and 128 to 255 are reserved for embOS. 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 Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 394 CHAPTER 21 21.9.1.8 Trace filter setup functions OS_TRACE_DisableFilterId() 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_TRACE_DisableFilterId(OS_U8 FilterIndex, OS_U8 id); Parameters Parameter Description FilterIndex Index of the filter that should be affected: 0 FilterIndex 4 0 affects Filter 0 (any task) and so on. id ID value of API call that should be enabled for trace: 0 id 255 Values from 0 to 99 and 128 to 255 are reserved for embOS. 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 Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 395 CHAPTER 21 21.10 Trace record functions Trace record functions The following functions write 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 100 to 127 must be used as the ID parameter. ID values from 0 to 99 and 128 to 255 are internally reserved for embOS. The events specified as ID must be enabled in trace filters. Active system time and the current task are automatically recorded together with the specified event. 21.10.1 API functions Timer ISR Task Description main Routine OS_TRACE_Data() Writes an entry with ID and an integer as parameter into the trace buffer. OS_TRACE_DataPtr() Writes an entry with ID, an integer, and a pointer as parameter into the trace buffer. OS_TRACE_Ptr() Writes an entry with ID and a pointer as parameter into the trace buffer. OS_TRACE_U32Ptr() Writes an entry with ID, a 32 bit unsigned integer, and a pointer as parameter into the trace buffer. OS_TRACE_Void() Writes an entry identified only by its ID into the trace buffer. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 396 CHAPTER 21 21.10.1.1 Trace record functions OS_TRACE_Data() Description Writes an entry with ID and an integer as parameter into the trace buffer. Prototype void OS_TRACE_Data(OS_U8 id, int v); Parameters Parameter Description id ID value of API call that should be enabled for trace: 0 id 255 Values from 0 to 99 and 128 to 255 are reserved for embOS. v Any integer value that should be recorded as parameter. 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 Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 397 CHAPTER 21 21.10.1.2 Trace record functions OS_TRACE_DataPtr() Description Writes an entry with ID, an integer, and a pointer as parameter into the trace buffer. Prototype void OS_TRACE_DataPtr( OS_U8 id, int v, volatile OS_CONST_PTR void *p); Parameters Parameter Description id ID value of API call that should be enabled for trace: 0 id 255 Values from 0 to 99 and 128 to 255 are reserved for embOS. v Any integer value that should be recorded as parameter. p Any void pointer that should be recorded as parameter. 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 Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 398 CHAPTER 21 21.10.1.3 Trace record functions OS_TRACE_Ptr() Description Writes an entry with ID and a pointer as parameter into the trace buffer. Prototype void OS_TRACE_Ptr( OS_U8 id, volatile OS_CONST_PTR void *p); Parameters Parameter Description id ID value of API call that should be enabled for trace: 0 id 255 Values from 0 to 99 and 128 to 255 are reserved for embOS. p Any void pointer that should be recorded as parameter. 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 Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 399 CHAPTER 21 21.10.1.4 Trace record functions OS_TRACE_U32Ptr() Description Writes an entry with ID, a 32 bit unsigned integer, and a pointer as parameter into the trace buffer. Prototype void OS_TRACE_U32Ptr( OS_U8 id, OS_U32 p0, volatile OS_CONST_PTR void *p1); Parameters Parameter Description id ID value of API call that should be enabled for trace: 0 id 255 Values from 0 to 99 and 128 to 255 are reserved for embOS. p0 Any unsigned 32 bit value that should be recorded as parameter. p1 Any void pointer that should be recorded as parameter. 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 Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 400 CHAPTER 21 21.10.1.5 Trace record functions OS_TRACE_Void() Description Writes an entry identified only by its ID into the trace buffer. Prototype void OS_TRACE_Void(OS_U8 id); Parameters Parameter id Description ID value of API call that should be enabled for trace: 0 id 255 Values from 0 to 99 and 128 to 255 are reserved for embOS. Additional information This functionality is available in trace builds only, and the API call is not removed by the preprocessor. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 401 CHAPTER 21 21.11 Application-controlled trace example 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 useful 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_TRACE_EnableID() sets 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_TRACE_EnableFilterId() is called with filter 1, which results in tracing calls from outside running tasks. Example code #include "RTOS.h" #define APP_TRACE_ID_SETSTATE 100 // Application specific trace id char MainState; void SetState(char* pState, char Value) { #if (OS_TRACE != 0) OS_TRACE_DataPtr(APP_TRACE_ID_SETSTATE, Value, pState); #endif *pState = Value; } int main(void) { OS_Init(); OS_InitHW(); #if (OS_TRACE != 0) OS_TRACE_DisableAll(); // Disable all API trace calls OS_TRACE_EnableId(APP_TRACE_ID_SETSTATE); // User trace OS_TRACE_EnableFilterId(0, APP_TRACE_ID_SETSTATE); // User trace OS_TRACE_Enable(); #endif SetState(&MainState, 1); OS_TASK_CREATE(&TCBMain, "MainTask", 100, MainTask, MainStack); OS_Start(); // Start multitasking return 0; } 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_TRACE_DataPtr(). UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 402 CHAPTER 21 21.12 User-defined functions 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 Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 22 MPU - Memory Protection UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 404 CHAPTER 22 22.1 Introduction Introduction This chapter describes embOS-MPU. embOS-MPU is a separate product which adds memory protection to embOS. Memory protection is a way to control memory access rights, and is a part of most modern processor architectures and operating systems. The main purpose of memory protection is to prevent a task from accessing memory that has not been allocated to it. This prevents a bug or malware within a task from affecting other tasks, or the operating system itself. embOS-MPU uses the hardware MPU and additional checks to avoid that a task affects the remaining system. Even if a bug in one task occurs all other tasks and the OS continue execution. The task which caused the issue is terminated automatically and the application is informed via an optional callback function. Since a hardware MPU is required embOS MPU support is unavailable for some embOS ports. The MPU support is included in separate embOS ports and is not part of the general embOS port. 22.1.1 Privilege states Application tasks which may affect other tasks or the OS itself must not have the permission to access the whole memory, special function registers or embOS control structures. Such application code could be e.g. unreliable software from a third party vendor. Therefore, those application tasks do not run on the same privileged state like the OS. The OS runs in privileged state which means that it has full access to all memory, peripherals and CPU features. Application tasks, on the other hand, run in unprivileged state and have restricted access only to the memory. To access peripherals and memory from unprivileged tasks, additional API and specific device drivers may be used. State Description Privileged Full access to memory, peripheral and CPU features Unprivileged Only restricted access to memory, no direct access to peripherals, no access to some CPU features 22.1.2 Code organization embOS-MPU assumes that the application code is divided into two parts. The first part runs in privileged state: it initializes the MPU settings and includes the device driver. It contains critical code and must be verified for full reliability by the responsible developers. Usually, this code consists of only a few simple functions which may be located in one single C file. The second part is the application itself which doesn't need to or in some cases can't be verified for full reliability. As it runs in unprivileged state, it can't affect the remaining system. Usually, this code is organized in several C files. This can e.g. simplify a certification. Part Description 1st part Task and MPU initialization Device drivers 2nd part Application code from e.g. third party vendor UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 405 CHAPTER 22 22.2 Memory Access permissions Memory Access permissions All privileged tasks have full access to the whole memory. An unprivileged task, however, can have access to several memory regions with different access permissions. Access permissions for RAM and ROM can be used combined, e.g. a ROM region could be readable and code execution could be allowed. In that case the permission defines would be used as OS_MPU_READONLY | OS_MPU_EXECUTION_ALLOWED. The following memory access permissions exist: Permission Description OS_MPU_NOACCESS No access to a memory region OS_MPU_READONLY Read only access to a memory region OS_MPU_READWRITE Read and write access to a memory region Permission Description OS_MPU_EXECUTION_ALLOWED Code execution is allowed OS_MPU_EXECUTION_DISALLOWED Code execution is not allowed 22.2.1 Default memory access permissions A newly created unprivileged task has per default only access to the following memory regions: Region Permissions ROM OS_MPU_READONLY, OS_MPU_EXECUTION_ALLOWED RAM OS_MPU_READONLY, OS_MPU_EXECUTION_ALLOWED Task stack OS_MPU_READWRITE, OS_MPU_EXECUTION_ALLOWED An unprivileged task can read and execute the whole RAM and ROM. Write access is restricted to its own task stack. More access rights can be added by embOS API calls. 22.2.2 Interrupts Interrupts are always privileged and can access the whole memory. 22.2.3 Access to additional memory regions An unprivileged task can have access to additional memory regions. This could be necessary e.g when a task needs to write LCD data to a frame buffer in RAM. Using a device driver could be too inefficient. Additional memory regions can be added with the API function OS_MPU_AddRegion(). It is CPU specific if the region has to be aligned. Please refer to the according CPU/ compiler specific embOS manual for more details. 22.2.4 Access to OS objects An unprivileged task has no direct write access to embOS objects. It also has per default no access via embOS API functions. Access to OS objects can be added with OS_MPU_SetAllowedObjects(). The object list must be located in ROM memory. The OS object must be created in the privileged part of the task. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 406 CHAPTER 22 22.3 ROM placement of embOS ROM placement of embOS embOS must be placed in one memory section. embOS-MPU needs this information to e.g. check that supervisor calls are made from embOS API functions only. The address and the size of this section must be passed to embOS with OS_MPU_ConfigMem(). __os_start__ and __os_size__ are linker symbols which are defined in the linker file. Example This example is for the GCC compiler and linker. Linker file: __os_load_start__ = ALIGN(__text_end__ , 4); .os ALIGN(__text_end__ , 4) : AT(ALIGN(__text_end__ , 4)) { __os_start__ = .; *(.os .os.*) } __os_end__ = __os_start__ + SIZEOF(.os); __os_size__ = SIZEOF(.os); __os_load_end__ = __os_end__; C Code: void OS_InitHW() { OS_MPU_ConfigMem(0x08000000u, 0x00100000u, 0x20000000u, 0x00020000u, __os_start__, __os_size__); } UM01001 User Guide & Reference Manual for embOS // ROM base address and size // RAM base address and size // OS base address and size (c) 1995-2018 SEGGER Microcontroller GmbH 407 CHAPTER 22 22.4 Allowed embOS API in unprivileged tasks Allowed embOS API in unprivileged tasks Not all embOS API functions are allowed to be called from an unprivileged task. Only the following API is allowed in unprivileged task: Allowed embOS API General API OS_IsRunning() Task API OS_TASK_Delay() OS_TASK_DelayUntil() OS_TASK_Delayus() OS_TASK_GetID() OS_TASK_GetName() OS_TASK_GetNumTasks() OS_TASK_GetPriority() OS_TASK_GetSuspendCnt() OS_TASK_GetTimeSliceRem() OS_TASK_IsTask() OS_TASK_Index2Ptr() OS_TASK_Resume() OS_TASK_Suspend() OS_TASK_Wake() OS_TASK_Yield() Software timer API OS_TIMER_GetPeriod() OS_TIMER_GetRemainingPeriod() OS_TIMER_GetStatus() OS_TIMER_GetCurrent() OS_TIMER_Restart() OS_TIMER_SetPeriod() OS_TIMER_Start() OS_TIMER_Stop() OS_TIMER_Trigger() OS_TIMER_GetPeriodEx() OS_TIMER_GetRemainingPeriodEx() OS_TIMER_GetStatusEx() OS_TIMER_GetCurrentEx() OS_TIMER_RestartEx() OS_TIMER_SetPeriodEx() OS_TIMER_StartEx() OS_TIMER_StopEx() OS_TIMER_TriggerEx() Task events API OS_TASKEVENT_Clear() OS_TASKEVENT_ClearEx() UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 408 CHAPTER 22 Allowed embOS API in unprivileged tasks Allowed embOS API OS_TASKEVENT_Get() OS_TASKEVENT_Set() OS_TASKEVENT_GetBlocked() OS_TASKEVENT_GetSingleBlocked() OS_TASKEVENT_GetTimed() OS_TASKEVENT_GetSingleTimed() Event objects API OS_EVENT_Get() OS_EVENT_GetBlocked() OS_EVENT_GetTimed() OS_EVENT_GetMask() OS_EVENT_GetMaskBlocked() OS_EVENT_GetMaskTimed() OS_EVENT_GetMaskMode() OS_EVENT_GetResetMode() OS_EVENT_Pulse() OS_EVENT_Reset() OS_EVENT_Set() OS_EVENT_SetMask() OS_EVENT_SetMaskMode() OS_EVENT_SetResetMode() Mutex API OS_MUTEX_GetValue() OS_MUTEX_GetOwner() OS_MUTEX_Lock() OS_MUTEX_LockBlocked() OS_MUTEX_LockTimed() OS_MUTEX_Unlock() Semaphore API OS_SEMAPHORE_GetValue() OS_SEMAPHORE_Give() OS_SEMAPHORE_GiveMax() OS_SEMAPHORE_SetValue() OS_SEMAPHORE_Take() OS_SEMAPHORE_TakeBlocked() OS_SEMAPHORE_TakeTimed() Mailbox API OS_MAILBOX_Clear() OS_MAILBOX_Get() OS_MAILBOX_Get1() OS_MAILBOX_GetBlocked() OS_MAILBOX_GetBlocked1() OS_MAILBOX_GetMessageCnt() UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 409 CHAPTER 22 Allowed embOS API in unprivileged tasks Allowed embOS API OS_MAILBOX_GetTimed() OS_MAILBOX_GetTimed1() OS_MAILBOX_GetPtr() OS_MAILBOX_GetPtrBlocked() OS_MAILBOX_Peek() OS_MAILBOX_Purge() OS_MAILBOX_Put() OS_MAILBOX_Put1() OS_MAILBOX_PutBlocked() OS_MAILBOX_PutBlocked1() OS_MAILBOX_PutFront() OS_MAILBOX_PutFront1() OS_MAILBOX_PutFrontBlocked() OS_MAILBOX_PutFrontBlocked1() OS_MAILBOX_PutTimed() OS_MAILBOX_PutTimed1() OS_MAILBOX_WaitBlocked() OS_MAILBOX_WaitTimed() Queue API OS_QUEUE_Clear() OS_QUEUE_IsInUse() OS_QUEUE_GetMessageCnt() OS_QUEUE_GetMessageSize() OS_QUEUE_GetPtr() OS_QUEUE_GetPtrBlocked() OS_QUEUE_GetPtrTimed() OS_QUEUE_PeekPtr() OS_QUEUE_Purge() OS_QUEUE_Put() OS_QUEUE_PutEx() OS_QUEUE_PutBlocked() OS_QUEUE_PutBlockedEx() OS_QUEUE_PutTimed() OS_QUEUE_PutTimedEx() Watchdog OS_WD_Trigger() Interrupt API OS_INT_InInterrupt() Timing API OS_TIME_GetTicks() OS_TIME_GetTicks32() OS_TIME_StartMeasurement() OS_TIME_StopMeasurement() UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 410 CHAPTER 22 Allowed embOS API in unprivileged tasks Allowed embOS API OS_TIME_GetResult() OS_TIME_GetResultus() OS_TIME_Getus() OS_TIME_Getus64() OS_ConvertCycles2us() Low power API OS_POWER_GetMask() OS_POWER_UsageInc() OS_POWER_UsageDec() Fixed block size memory pool API OS_MEMPOOL_Alloc() OS_MEMPOOL_AllocBlocked() OS_MEMPOOL_AllocTimed() OS_MEMPOOL_IsInPool() OS_MEMPOOL_FreeEx() OS_MEMPOOL_Free() OS_MEMPOOL_GetBlockSize() OS_MEMPOOL_GetMaxUsed() OS_MEMPOOL_GetNumBlocks() OS_MEMPOOL_GetNumFreeBlocks() Debug API OS_DEBUG_GetObjName() OS_COM_SendString() Info routines API OS_INFO_GetCPU() OS_INFO_GetLibMode() OS_INFO_GetLibName() OS_INFO_GetModel() OS_INFO_GetVersion() Stack info API OS_STACK_GetTaskStackBase() OS_STACK_GetTaskStackSize() OS_STACK_GetTaskStackSpace() OS_STACK_GetTaskStackUsed() OS_STACK_GetSysStackBase() OS_STACK_GetSysStackSize() OS_STACK_GetSysStackSpace() OS_STACK_GetSysStackUsed() OS_STACK_GetIntStackBase() OS_STACK_GetIntStackSize() OS_STACK_GetIntStackSpace() OS_STACK_GetIntStackUsed() OS_STACK_GetCheckLimit() UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 411 CHAPTER 22 Allowed embOS API in unprivileged tasks Allowed embOS API MPU API OS_MPU_CallDeviceDriver() OS_MPU_GetThreadState() OS_MPU_SanityCheck() UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 412 CHAPTER 22 22.5 Device driver Device driver 22.5.1 Concept An unprivileged task has no access to any peripheral. Thus a device driver is necessary to use peripherals like UART, SPI or port pins. A device driver consists of two parts, an unprivileged part and a privileged part. embOS ensures there is only one explicit and safe way to switch from the unprivileged part to the privileged part. The application must call driver functions only in the unprivileged part. The actual peripheral access is performed in the privileged part only. OS_MPU_CallDeviceDriver() is used to call the device driver. The first parameter is the index of the device driver function. Optional parameters can be passed to the device driver. Note You must not call any embOS API from a device driver. Example A device driver for a LED should be developed. The LED driver can toggle a LED with a given index number. The function BSP_Toggle_LED() is the unprivileged part of the driver. It can be called by the unprivileged application. typedef struct BSP_LED_PARAM_STRUCT { BSP_LED_DRIVER_API Action; OS_U32 Index; } BSP_LED_PARAM; void BSP_ToggleLED(int Index) { BSP_LED_PARAM p; p.Action = BSP_LED_TOGGLE; p.Index = Index; OS_MPU_CallDeviceDriver(0u, &p); } The device driver itself runs in privileged state and accesses the LED port pin. void BSP_LED_DeviceDriver(void* Param) { BSP_LED_PARAM* p; p = (BSP_LED_PARAM*)Param; switch (p->Action) { case BSP_LED_SET: BSP_SetLED_SVC(p->Index); break; case BSP_LED_CLR: BSP_ClrLED_SVC(p->Index); break; case BSP_LED_TOGGLE: BSP_ToggleLED_SVC(p->Index); break; default: break; } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 413 CHAPTER 22 Device driver All device driver addresses are stored in one const list which is passed to embOS-MPU with OS_MPU_SetDeviceDriverList(). static const OS_MPU_DEVICE_DRIVER_FUNC _DeviceDriverList[] = { BSP_LED_DeviceDriver, NULL }; // Last item must be NULL void BSP_Init(void) { OS_MPU_SetDeviceDriverList(_DeviceDriverList); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 414 CHAPTER 22 22.6 API functions API functions TIMER ISR Unpriv Task main Description Priv Task Routine OS_MPU_AddRegion() Adds an additional memory region to which the task has access. OS_MPU_CallDeviceDriver() Calls a device driver. OS_MPU_ConfigMem() Configures basic memory information. OS_MPU_Enable() Initializes the MPU hardware with the default MPU API list and enables it. OS_MPU_EnableEx() Initializes the MPU hardware with the specified MPU API list and enables it. OS_MPU_ExtendTaskContext() Extends the task context for the MPU registers. OS_MPU_GetThreadState() Returns the current privileged task state. OS_MPU_SetAllowedObjects() Sets a task specific list of objects to which the task has access via embOS API functions. OS_MPU_SetDeviceDriverList() Sets the device driver list. OS_MPU_SetErrorCallback() Sets the MPU error callback function. OS_MPU_SwitchToUnprivState() Switches a task to unprivileged state. OS_MPU_SwitchToUnprivStateEx() Switches a task to unprivileged state and calls a task function which runs on a separate task stack. OS_MPU_SetSanityCheckBuffer() Sets the pointer in the task control block to a buffer which holds a copy of the MPU register for sanity check. OS_MPU_SanityCheck() Performs an MPU sanity check which checks if the MPU register still have the correct value. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 415 CHAPTER 22 22.6.1 API functions OS_MPU_AddRegion() Description Adds an additional memory region to which the task has access. Prototype void OS_MPU_AddRegion(OS_TASK* OS_U32 OS_U32 OS_U32 OS_U32 pTask, BaseAddr, Size, Permissions, Attributes); Parameters Parameter Description pTask Pointer to a task control block. BaseAddr Region base address. Size Region size. Permissions Access permissions. Attributes Additional core specific memory attributes. Additional information This function can be used if a task needs access to additional RAM regions. This RAM region can be e.g. a LCD frame buffer or a queue data buffer. It is CPU specific if the region has to be aligned. Please refer to the according CPU/compiler specific embOS manual for more details. A memory region can have the following access permissions: Permission Description OS_MPU_NOACCESS No access to memory region OS_MPU_READONLY Read only access to memory region OS_MPU_READWRITE Read and write access to memory region OS_MPU_EXECUTION_ALLOWED Code execution is allowed OS_MPU_EXECUTION_DISALLOWED Code execution is not allowed Access permissions for data and code execution can be jointly set for one region. A region can for example be set to read only and code execution can be disabled (OS_MPU_READONLY | OS_MPU_EXECUTION_DISALLOWED). Per default an unprivileged task has only access to the following memory regions: Region Permission ROM Read and execution access for complete ROM RAM Read only and and execution access for complete RAM Task stack Read and write and execution access to the task stack Example static void HPTask(void) { OS_MPU_AddRegion(&TCBHP, (OS_U32)MyQBuffer, 512, OS_MPU_READWRITE, 0u); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 416 CHAPTER 22 22.6.2 API functions OS_MPU_CallDeviceDriver() Description Calls a device driver. Prototype void OS_MPU_CallDeviceDriver(OS_U32 Index, void* Param); Parameters Parameter Description Index Index of device driver function. Param Parameter to device driver. Additional information Unprivileged tasks have no direct access to any peripherals. A device driver is instead necessary. OS_MPU_CallDeviceDriver() is used to let embOS call the device driver which then runs in privileged state. Optional parameter can be passed to the driver function. The device driver is called e.g. for Cortex-M via SVC call. Example typedef struct BSP_LED_PARAM_STRUCT { BSP_LED_DRIVER_API Action; OS_U32 Index; } BSP_LED_PARAM; static const OS_MPU_DEVICE_DRIVER_FUNC _DeviceDriverList[] = { BSP_LED_DeviceDriver, NULL }; // Last item must be NULL void BSP_LED_DeviceDriver(void* Param) { BSP_LED_PARAM* p; p = (BSP_LED_PARAM*)Param; switch (p->Action) { case BSP_LED_SET: BSP_SetLED_SVC(p->Index); break; case BSP_LED_CLR: BSP_ClrLED_SVC(p->Index); break; case BSP_LED_TOGGLE: BSP_ToggleLED_SVC(p->Index); break; default: break; } } void BSP_ToggleLED(int Index) { BSP_LED_PARAM p; p.Action = BSP_LED_TOGGLE; p.Index = Index; OS_MPU_CallDeviceDriver(0u, &p); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 417 CHAPTER 22 22.6.3 API functions OS_MPU_ConfigMem() Description Configures basic memory information. OS_MPU_ConfigMem() tells embOS where ROM, RAM and the embOS code is located in memory. This information is used to setup the default task regions at task creation. Prototype void OS_MPU_ConfigMem(OS_U32 OS_U32 OS_U32 OS_U32 OS_U32 OS_U32 ROM_BaseAddr, ROM_Size, RAM_BaseAddr, RAM_Size, OS_BaseAddr, OS_Size); Parameters Parameter Description ROM_BaseAddr ROM base addr. ROM_Size ROM size. RAM_BaseAddr RAM base addr. RAM_Size RAM size. OS_BaseAddr embOS ROM region base address. OS_Size embOS ROM region size. Additional information This function must be called before any unprivileged task is created. Example void main(void) { OS_MPU_ConfigMem(0x08000000u, 0x00100000u, 0x20000000u, 0x00020000u, __os_start__, __os_size__); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 418 CHAPTER 22 22.6.4 API functions OS_MPU_Enable() Description Initializes the MPU hardware with the default MPU API list and enables it. Prototype void OS_MPU_Enable(void); Additional information This function must be called before any embOS-MPU related function is used or any task is created. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 419 CHAPTER 22 22.6.5 API functions OS_MPU_EnableEx() Description Initializes the MPU hardware with the specified MPU API list and enables it. Prototype void OS_MPU_EnableEx(OS_CONST_PTR OS_MPU_API_LIST *pAPIList); Parameters Parameter pAPIList Description Pointer to core specific MPU API list. Additional information This function must be called before any embOS-MPU related function is used or any task is created. Example void main(void) { OS_MPU_EnableEx(&OS_ARMv7M_MPU_API); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 420 CHAPTER 22 22.6.6 API functions OS_MPU_ExtendTaskContext() Description Extends the task context for the MPU registers. Prototype void OS_MPU_ExtendTaskContext(void); Additional information It is device dependent how many MPU regions are available. This function makes it possible to use all MPU regions for every single task. Otherwise the tasks would have to share the MPU regions. To do so the MPU register must be saved and restored with every context switch. This function allows the user to extend the task context for the MPU registers. A major advantage is that the task extension is task-specific. This means that the additional MPU register 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 MPU registers. The task context can be extended only once per task. The function must not be called multiple times for one task. OS_MPU_ExtendTaskContext() is not available in OS_LIBMODE_XR. OS_SetDefaultContextExtension() can be used to automatically add MPU register to the task context of every newly created task. Example static void HPTask(void) { OS_MPU_ExtendTaskContext(); OS_MPU_SwitchToUnprivState(); while (1) { OS_TASK_Delay(50); } } static void HPTask(void) { OS_MPU_ExtendTaskContext(); OS_MPU_SwitchToUnprivState(); while (1) { OS_TASK_Delay(200); } } Note If you run more than one unprivileged task you must use OS_MPU_ExtendTaskContext() in order to save and restore the MPU register for each unprivileged task. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 421 CHAPTER 22 22.6.7 API functions OS_MPU_GetThreadState() Description Returns the current privileged task state. Prototype OS_MPU_THREAD_STATE OS_MPU_GetThreadState(void); Return value 0 1 Privileged state (OS_MPU_THREAD_STATE_PRIVILEGED). Unprivileged state (OS_MPU_THREAD_STATE_UNPRIVILEGED). Additional information A new created task has the task state OS_MPU_THREAD_STATE_PRIVILEGED. It can be set to OS_MPU_THREAD_STATE_UNPRIVILEGED with the API function OS_MPU_SwitchToUnprivState(). A task can never set itself back to the privileged state OS_MPU_THREAD_STATE_PRIVILEGED. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 422 CHAPTER 22 22.6.8 API functions OS_MPU_SetAllowedObjects() Description Sets a task specific list of objects to which the task has access via embOS API functions. Prototype void OS_MPU_SetAllowedObjects(OS_TASK* pTask, OS_CONST_PTR OS_MPU_OBJ *pObjList); Parameters Parameter Description pTask Pointer to a task control block. pObjList Pointer to a list of allowed objects. Additional information Per default a task has neither direct nor indirect write access via embOS API functions to any embOS object like a task control block. Even if the object is in the list of allowed objects a direct write access to a control structure is not possible. But if an object is in the list the task can access the object via embOS API functions. This can be e.g. the own task control block, a mailbox control structure which is mutual used by different task or even the task control block of another task. It is the developer responsibility to only add objects which are necessary for the unprivileged task. The list is null-terminated which means the last entry must always be: {NULL, OS_MPU_OBJTYPE_INVALID}. The following object types exist: OS_MPU_OBJTYPE_TASK OS_MPU_OBJTYPE_MUTEX OS_MPU_OBJTYPE_SEMA OS_MPU_OBJTYPE_EVENT OS_MPU_OBJTYPE_QUEUE OS_MPU_OBJTYPE_MAILBOX OS_MPU_OBJTYPE_SWTIMER OS_MPU_OBJTYPE_MEMPOOL OS_MPU_OBJTYPE_WATCHDOG Example static const OS_MPU_OBJ _ObjList[] = {{(OS_U32)&TCBHP, OS_MPU_OBJTYPE_TASK}, {(OS_U32)NULL, OS_MPU_OBJTYPE_INVALID}}; static void _Unpriv(void) { OS_TASK_SetName(&TCBHP, "Segger"); while (1) { OS_TASK_Delay(10); } } static void HPTask(void) { OS_MPU_ExtendTaskContext(); OS_MPU_SetAllowedObjects(&TCBHP, _ObjList); OS_MPU_SwitchToUnprivState(); _Unpriv(); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 423 CHAPTER 22 22.6.9 API functions OS_MPU_SetDeviceDriverList() Description Sets the device driver list. Prototype void OS_MPU_SetDeviceDriverList(OS_CONST_PTR OS_MPU_DEVICE_DRIVER_FUNC *pList); Parameters Parameter pList Description Pointer to device driver function address list. Additional information All device driver function addresses are stored in one list. The last item must be NULL. A device driver is called with the according index to this list. Example static const OS_MPU_DEVICE_DRIVER_FUNC _DeviceDriverList[] = { BSP_LED_DeviceDriver, NULL }; // Last item must be NULL void BSP_Init(void) { OS_MPU_SetDeviceDriverList(_DeviceDriverList); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 424 CHAPTER 22 22.6.10 API functions OS_MPU_SetErrorCallback() Description Sets the MPU error callback function. This function is called when a task is suspended due to an MPU fault. Prototype void OS_MPU_SetErrorCallback(OS_MPU_ERROR_CALLBACK pFunc); Parameters Parameter Description Pointer to callback function. pFunc Additional information embOS suspends a task when it detects an invalid access. The internal error function OS_MPU_Error() calls the user callback function in order to inform the application. The application can e.g. turn on an error LED or write the fault into a log file. The callback function is called with the following parameter: Parameter type Description OS_TASK* Pointer to task control block of the unprivileged task which caused the MPU error. OS_MPU_ERRORCODE Error code which describes the cause for the MPU error. Example static void _ErrorCallback(OS_TASK* pTask, OS_MPU_ERRORCODE ErrorCode) { printf("%s has been stopped due to error %d\n", pTask->Name, ErrorCode); } int main(void) { OS_MPU_SetErrorCallback(&_ErrorCallback); } embOS-MPU error codes Define Explanation OS_MPU_ERROR_INVALID_REGION The OS object address is within an allowed task region. This is not allowed. This can for example happen when the object was placed on the task stack. OS_MPU_ERROR_INVALID_OBJECT The unprivileged task is not allowed to access this OS object. OS_MPU_ERROR_INVALID_API The unprivileged task tried to call an embOS API function which is not valid for an unprivileged task. For example unprivileged tasks must not call OS_TASK_EnterRegion(). OS_MPU_ERROR_HARDFAULT Indicates that the task caused a hardfault. OS_MPU_ERROR_MEMFAULT An illegal memory access was performed. A unprivileged task tried to write memory without having the access permission. OS_MPU_ERROR_BUSFAULT Indicates that the task caused a bus fault. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 425 CHAPTER 22 Define API functions Explanation OS_MPU_ERROR_USAGEFAULT Indicates that the task caused an usage fault. OS_MPU_ERROR_SVC The supervisor call was not made within an embOS API function. This is not allowed. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 426 CHAPTER 22 22.6.11 API functions OS_MPU_SwitchToUnprivState() Description Switches a task to unprivileged state. Prototype void OS_MPU_SwitchToUnprivState(void); Additional information The task code must be split into two parts. The first part runs in privileged state and initializes the embOS MPU settings. The second part runs in unprivileged state and is called after the privileged part switched to the unprivileged state with OS_MPU_SwitchToUnprivState(). Example static void _Unsecure(void) { while (1) { OS_TASK_Delay(10); } } static void HPTask(void) { // // Initialization, e.g. add memory regions // OS_MPU_ExtendTaskContext(); OS_MPU_SwitchToUnprivState(); _Unsecure(); } Note If you run more than one unprivileged task you must use OS_MPU_ExtendTaskContext() in order to save and restore the MPU register for each unprivileged task. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 427 CHAPTER 22 22.6.12 API functions OS_MPU_SwitchToUnprivStateEx() Description Switches a task to unprivileged state and calls a task function which runs on a separate task stack. This is an extended handling which is used with ARMv8M only. Prototype void OS_MPU_SwitchToUnprivStateEx(voidRoutine* pRoutine, void OS_STACKPTR *pStack, OS_UINT StackSize); Parameters Parameter Description pRoutine Pointer to a function that should run in unprivileged state. pStack Pointer to the task stack which should be used in unprivileged state. StackSize Size of the task stack. Additional information The task code must be split into two parts. The first part runs in privileged state and initializes the embOS MPU settings. The second part runs in unprivileged state and is called after the privileged part switched to the unprivileged state with OS_MPU_SwitchToUnprivStateEx(). You must use OS_MPU_SwitchToUnprivStateEx() with ARMv8M only. Example static unsigned char _Stack[512]; static void _Unsecure(void) { while (1) { OS_TASK_Delay(10); } } // Runs on the stack _Stack static void HPTask(void) { // // Initialization, e.g. add memory regions // OS_MPU_ExtendTaskContext(); OS_MPU_SwitchToUnprivStateEx(_Unsecure, _Stack, 512); } Note If you run more than one unprivileged task you must use OS_MPU_ExtendTaskContext() in order to save and restore the MPU register for each unprivileged task. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 428 CHAPTER 22 22.6.13 API functions OS_MPU_SetSanityCheckBuffer() Description Sets the pointer in the task control block to a buffer which holds a copy of the MPU register for sanity check. The buffer size needs to be the size of all MPU register. Prototype void OS_MPU_SetSanityCheckBuffer(OS_TASK* pTask, void* p); Parameters Parameter Description pTask Pointer to the task control block. p Pointer to the MPU register buffer. Additional information OS_MPU_SetSanityCheckBuffer() is only available in OS_LIBMODE_SAFE which is used in the certified embOS-MPU. Due to e.g. a hardware failure, a MPU register content could change. A copy of all relevant MPU register is held in the buffer. OS_MPU_SanityCheck() compares this copy to the actual MPU register and returns whether the register still have the same value. OS_MPU_SetSanityCheckBuffer() must be used prior to calling OS_MPU_SwitchToUnprivState() only. It must be called before OS_MPU_SanityCheck() is used for the first time. The size of the buffer depends on the used hardware MPU. Appropiate defines are provided, e.g. OS_ARM_V7M_MPU_REGS_SIZE. Example static OS_U8 HPBuffer[OS_ARM_V7M_MPU_REGS_SIZE]; static void HPTask(void) { OS_BOOL r; OS_MPU_SetSanityCheckBuffer(&TCBHP, HPBuffer); OS_MPU_ExtendTaskContext(); OS_MPU_SwitchToUnprivState(); while (1) { r = OS_MPU_SanityCheck(); if (r == 0) { while (1) { // MPU register value invalid } } } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 429 CHAPTER 22 22.6.14 API functions OS_MPU_SanityCheck() Description Performs an MPU sanity check which checks if the MPU register still have the correct value. Prototype OS_BOOL OS_MPU_SanityCheck(void); Return value 0 1 Failure, at least one register has not the correct value. Success, all registers have the correct value. Additional information OS_MPU_SanityCheck() is only available in OS_LIBMODE_SAFE which is used in the certified embOS-MPU. Due to e.g. a hardware failure, an MPU register content could change. A copy of all relevant MPU register is held in a buffer and a pointer to this buffer is stored in the according task control block. OS_MPU_SanityCheck() compares this copy to the actual MPU register and returns whether the register still have the same value. OS_MPU_SanityCheck() must be used in unprivileged tasks after the call to OS_MPU_SwitchToUnprivState() only. OS_MPU_SetSanityCheckBuffer() must be called before OS_MPU_SanityCheck() is used for the first time. If the buffer is not set, OS_MPU_SanityCheck() will return 0. Example static OS_U8 HPBuffer[OS_ARM_V7M_MPU_REGS_SIZE]; static void HPTask(void) { OS_BOOL r; OS_MPU_SetSanityCheckBuffer(&TCBHP, HPBuffer); OS_MPU_ExtendTaskContext(); OS_MPU_SwitchToUnprivState(); while (1) { r = OS_MPU_SanityCheck(); if (r == 0) { while (1) { // MPU register value invalid } } } } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 23 Stacks UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 431 CHAPTER 23 23.1 Introduction 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. Therefore, the debug and stack-check builds of embOS monitor the stack size (and, if available, also interrupt stack size) and call OS_Error() if they detect stack overflows. To detect a stack overflow, the stack is filled with control characters upon its creation, thereby allowing for a check on these characters every time a task is deactivated. However, embOS does not guarantee to reliably detect all stack overflows. A stack that has been defined larger than necessary, on the other hand, does no harm; even though it is a waste of memory. 23.1.1 System stack Before embOS takes control (before the call to OS_Start()), a program uses the socalled 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 for the following (when no task is executing): * * 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. 23.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 depends on the CPU and the compiler. For details, see the CPU & Compiler Specifics manual of embOS documentation. 23.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_INT_EnterIntStack() at beginning of an interrupt service routine and OS_INT_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_INT_EnterIntStack() and OS_INT_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 Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 432 CHAPTER 23 23.1.4 Introduction Stack size calculation embOS includes stack size calculation routines. embOS fills the task stacks and 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. 23.1.5 Stack-check embOS includes stack-check routines. embOS fills the task stacks and also the system stack and the interrupt stack with a pattern byte. embOS periodically checks whether the last pattern byte at the end of the stack was overwritten and calls OS_Error() when it was. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 433 CHAPTER 23 23.2 API functions API functions Timer ISR Task Description main Routine OS_STACK_GetIntStackBase() Returns the base address of the interrupt stack. OS_STACK_GetIntStackSize() Returns the size of the interrupt stack. OS_STACK_GetIntStackSpace() Returns the amount of interrupt stack which was never used (Free interrupt stack space). OS_STACK_GetIntStackUsed() Returns the amount of interrupt stack which is actually used. OS_STACK_GetTaskStackBase() Returns a pointer to the base of a task stack. OS_STACK_GetTaskStackSize() Returns the total size of a task stack. Returns the amount of task stack which OS_STACK_GetTaskStackSpace() was never used by the task (Free stack space). OS_STACK_GetTaskStackUsed() Returns the amount of task stack which is actually used by the task. OS_STACK_GetSysStackBase() Returns the base address of the system stack. OS_STACK_GetSysStackSize() Returns the size of the system stack. OS_STACK_GetSysStackSpace() Returns the amount of system stack which was never used (Free system stack space). OS_STACK_GetSysStackUsed() Returns the amount of system stack which is actually used. OS_STACK_SetCheckLimit() Sets the stack check limit to a percentaged value of the stack size. OS_STACK_GetCheckLimit() Returns the stack check limit in percent. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 434 CHAPTER 23 23.2.1 API functions OS_STACK_GetIntStackBase() Description Returns a pointer to the base of the interrupt stack. Prototype void* OS_STACK_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 %p", OS_STACK_GetIntStackBase()); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 435 CHAPTER 23 23.2.2 API functions OS_STACK_GetIntStackSize() Description Returns the size of the interrupt stack. Prototype unsigned int OS_STACK_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 %u", OS_STACK_GetIntStackSize()); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 436 CHAPTER 23 23.2.3 API functions OS_STACK_GetIntStackSpace() Description Returns the amount of interrupt stack which was never used (Free interrupt stack space). Prototype unsigned int OS_STACK_GetIntStackSpace(void); Return value Amount of interrupt stack which was never used in bytes. Additional information This function is only available in the debug and stack-check builds and when an interrupt stack exists. Note 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 %u", OS_STACK_GetIntStackSpace()); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 437 CHAPTER 23 23.2.4 API functions OS_STACK_GetIntStackUsed() Description Returns the amount of interrupt stack which is actually used. Prototype unsigned int OS_STACK_GetIntStackUsed(void); Return value Amount of interrupt stack which is actually used in bytes. Additional information This function is only available in the debug and stack-check builds and when an interrupt stack exists. Note 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 %u", OS_STACK_GetIntStackUsed()); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 438 CHAPTER 23 23.2.5 API functions OS_STACK_GetTaskStackBase() Description Returns a pointer to the base of a task stack. If pTask is NULL, the currently executed task is checked. Prototype void OS_STACKPTR *OS_STACK_GetTaskStackBase(OS_CONST_PTR OS_TASK *pTask); Parameters Parameter pTask Description The task whose stack base should be returned. NULL denotes the current task. Return value Pointer to the base address of the task stack. Additional information If NULL is passed for pTask, the currently running task is used. However, NULL must not be passed for pTask from main(), a timer callback or from an interrupt handler. A debug build of embOS will call OS_Error() in case pTask does not indicate a valid task. 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] %p", OS_STACK_GetTaskStackBase(&TCB[0]); OS_TASK_Delay(1000); printf("Addr Stack[1] %p", OS_STACK_GetTaskStackBase(&TCB[1]); OS_TASK_Delay(1000); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 439 CHAPTER 23 23.2.6 API functions OS_STACK_GetTaskStackSize() Description Returns the total size of a task stack. Prototype unsigned int OS_STACK_GetTaskStackSize(OS_CONST_PTR OS_TASK *pTask); Parameters Parameter pTask Description The task whose stack size should be checked. NULL means current task. Return value Total size of the task stack in bytes. Additional information If NULL is passed for pTask, the currently running task is used. However, NULL must not be passed for pTask from main(), a timer callback or from an interrupt handler. A debug build of embOS will call OS_Error() in case pTask does not indicate a valid task. 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] %u", OS_STACK_GetTaskStackSize(&TCB[0]); OS_TASK_Delay(1000); printf("Size Stack[1] %u", OS_STACK_GetTaskStackSize(&TCB[1]); OS_TASK_Delay(1000); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 440 CHAPTER 23 23.2.7 API functions OS_STACK_GetTaskStackSpace() Description Returns the amount of task stack which was never used by the task (Free stack space). If no specific task is addressed, the current task is checked. Prototype unsigned int OS_STACK_GetTaskStackSpace(OS_CONST_PTR OS_TASK *pTask); Parameters Parameter pTask Description The task whose stack space should be checked. NULL denotes the current task. Return value Amount of task stack which was never used by the task in bytes. Additional information If NULL is passed for pTask, the currently running task is used. However, NULL must not be passed for pTask from main(), a timer callback or from an interrupt handler. A debug build of embOS will call OS_Error() in case pTask does not indicate a valid task. 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_STACK_GetTaskStackSpace(), 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. This function is only available in the debug and stack-check builds of embOS. Note 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] %u", OS_STACK_GetTaskStackSpace(&TCB[0]); OS_TASK_Delay(1000); printf("Unused Stack[1] %u", OS_STACK_GetTaskStackSpace(&TCB[1]); OS_TASK_Delay(1000); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 441 CHAPTER 23 23.2.8 API functions OS_STACK_GetTaskStackUsed() Description Returns the amount of task stack which is actually used by the task. If no specific task is addressed, the current task is checked. Prototype unsigned int OS_STACK_GetTaskStackUsed(OS_CONST_PTR OS_TASK *pTask); Parameters Parameter pTask Description The task whose stack usage should be checked. NULL denotes the current task. Return value Amount of task stack which is actually used by the task in bytes. Additional information If NULL is passed for pTask, the currently running task is used. However, NULL must not be passed for pTask from main(), a timer callback or from an interrupt handler. A debug build of embOS will call OS_Error() in case pTask does not indicate a valid task. 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_STACK_GetTaskStackUsed(), 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. This function is only available in the debug and stack-check builds of embOS. Note 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] %u", OS_STACK_GetTaskStackUsed(&TCB[0]); OS_TASK_Delay(1000); printf("Used Stack[1] %u", OS_STACK_GetTaskStackUsed(&TCB[1]); OS_TASK_Delay(1000); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 442 CHAPTER 23 23.2.9 API functions OS_STACK_GetSysStackBase() Description Returns a pointer to the base of the system stack. Prototype void* OS_STACK_GetSysStackBase(void); Return value The pointer to the base address of the system stack. Example void CheckSysStackBase(void) { printf("Addr System Stack %p", OS_STACK_GetSysStackBase()); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 443 CHAPTER 23 23.2.10 API functions OS_STACK_GetSysStackSize() Description Returns the size of the system stack. Prototype unsigned int OS_STACK_GetSysStackSize(void); Return value The size of the system stack in bytes. Example void CheckSysStackSize(void) { printf("Size System Stack %u", OS_STACK_GetSysStackSize()); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 444 CHAPTER 23 23.2.11 API functions OS_STACK_GetSysStackSpace() Description Returns the amount of system stack which was never used (Free system stack space). Prototype unsigned int OS_STACK_GetSysStackSpace(void); Return value Amount of unused system stack, in bytes. Additional information This function is only available in the debug and stack-check builds of embOS. Note 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 %u", OS_STACK_GetSysStackSpace()); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 445 CHAPTER 23 23.2.12 API functions OS_STACK_GetSysStackUsed() Description Returns the amount of system stack which is actually used. Prototype unsigned int OS_STACK_GetSysStackUsed(void); Return value Amount of used system stack, in bytes. Additional information This function is only available in the debug and stack-check builds of embOS. Note 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 %u", OS_STACK_GetSysStackUsed()); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 446 CHAPTER 23 23.2.13 API functions OS_STACK_SetCheckLimit() Description Sets the stack check limit to a percentaged value of the stack size. Prototype void OS_STACK_SetCheckLimit(OS_U8 Limit); Parameters Parameter Limit Description Stack check limit in percent. Valid values are 0..100%. Values above 100% are trimmed to 100%. Additional information This function is only available in safety builds of embOS (OS_LIBMODE_SAFE). In all other embOS builds the stack check limit is fixed to 100%. It can be used to set the stack check limit to a value which triggers the error condidition before the stack is filled completely. With the safety build of embOS the application can react before the stack actually overflows. Note This routine must only be called from main() or privileged tasks. This setting is jointly used for the system stack, the interrupt stack and all task stacks. The best practice is to call it in main() before OS_Start(). Example int main(void) { OS_Init(); OS_InitHW(); OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP); OS_TASK_CREATE(&TCBLP, "LP Task", 50, LPTask, StackLP); OS_STACK_SetCheckLimit(70); // Set the stack check limit to 70% OS_Start(); } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 447 CHAPTER 23 23.2.14 API functions OS_STACK_GetCheckLimit() Description Returns the stack check limit in percent. Prototype OS_U8 OS_STACK_GetCheckLimit(void); Return value The stack check limit as a percentaged value of the stack size. Additional information This function is only available in safety builds of embOS (OS_LIBMODE_SAFE). In all other embOS builds the stack check limit is fixed to 100%. Note This routine must only be called from main() or privileged tasks. This setting is jointly used for the system stack, the interrupt stack and all task stacks. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 24 Board Support Packages UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 449 CHAPTER 24 24.1 Introduction Introduction This chapter explains the target system specific parts of embOS, called BSP (board support package). If the software is up and running on your target system, there is no need to read this chapter. In general, no configuration is required to get started with embOS: The start projects supplied with your embOS shipment will execute on your system. Small modifications to the configuration might be necessary at a later point, for example to configure a different system frequency or in order to enable a UART for the optional communication with embOSView. All hardware-specific routines that may require modifications are located in one of two source files delivered with embOS. The file RTOSInit.c is provided in source code and contains most of the functions that may require modifications to match your target hardware. Furthermore, the file BSP.c is provided in source code as well and may contain routines to initialize and control LEDs, which may require further modifications to match your target hardware. The sole exception to this rule is that some ports of embOS require an additional interrupt vector table file. Further details on these are available with the CPU & Compiler Specifics manual of the embOS documentation. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 450 CHAPTER 24 24.2 Hardware-specific routines Hardware-specific routines The following routines are not exposed as user API, but are instead required by embOS for internal usage. They are shipped as source code to allow for modifications to match your actual target hardware. However, unless explicitly stated otherwise, these functions must not be called from your application. Timer ISR Task Description main Routine Required for embOS OS_ConvertCycles2us() Converts cycles into microseconds. OS_GetTime_Cycles() Reads the timestamp in cycles. OS_Idle() The idle loop is executed whenever no task is ready for execution. OS_InitHW() Initializes the hardware required for embOS to run. SysTick_Handler() The embOS timer interrupt handler. Optional for run-time embOSView OS_COM_Init() Initializes communication with embOSView. OS_COM_Send1() Sends one character towards embOSView. OS_ISR_Rx() Receive interrupt handler for UART communication with embOSView. OS_ISR_Tx() Transmit interrupt handler for UART communication with embOSView. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 451 CHAPTER 24 24.2.1 Hardware-specific routines OS_ConvertCycles2us() Description Converts clock cycles into microseconds. Prototype OS_U32 OS_ConvertCycles2us(OS_U32 Cycles); Parameters Parameter Cycles Description Number of CPU cycles to convert. Return value The period of time in microseconds that is equivalent to the given number of clock cycles as a 32 bit unsigned integer value. Additional information This function is required for profiling and high resolution time measurement. You must modify it when using different clock settings (see Setting the system frequency OS_FSYS on page 461). UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 452 CHAPTER 24 24.2.2 Hardware-specific routines OS_GetTime_Cycles() Description Returns the system time in timer clock cycles. Cycle length depends on the system. Prototype OS_U32 OS_GetTime_Cycles(void); Return value The number of clock cycles that have passed since the last reset as a 32 bit unsigned integer value. Additional information Interrupts must be disabled prior to calling this function. This function is required for profiling and high resolution time measurement. You must modify it when using different clock settings (see Setting the system frequency OS_FSYS on page 461). UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 453 CHAPTER 24 24.2.3 Hardware-specific routines OS_Idle() Description The function OS_Idle() is called when no task, timer routine or ISR is ready for execution. Usually, OS_Idle() is programmed as an endless loop without any content. With many embOS start projects, however, it activates a power save mode of the target CPU (see Starting power save modes in OS_Idle() on page 303). Prototype void OS_Idle(void); Additional information OS_Idle() is not a task, it neither has a task context nor a dedicated stack. Instead, it runs on the system's C stack, which is also used by the kernel. Exceptions and interrupts occurring during OS_Idle() will return to OS_Idle() unless they trigger a task switch. When returning to OS_Idle(), execution is continued from where it was interrupted. However, in case a task switch did occur during execution of OS_Idle(), the function is abandoned and execution will start from the beginning when it is activated again. Hence, no functionality should be implemented that relies on the stack to be preserved. If this is required, please consider implementing a custom idle task (Creating a custom Idle task on page 454). Calling OS_TASK_EnterRegion() and OS_TASK_LeaveRegion() from OS_Idle() allows to inhibit task switches during the execution of OS_Idle(). Running in a critical region does not block interrupts, but disables task switches until OS_TASK_LeaveRegion() is called. Using a critical region during OS_Idle() will therefore affect task activation time, but will not affect interrupt latency. Example void OS_Idle(void) { while (1) { } } // Idle loop: No task is ready to execute UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 454 CHAPTER 24 24.2.3.1 Hardware-specific routines Creating a custom Idle task As an alternative to OS_Idle(), it is also possible to create a custom "idle task". This task must run as an endless loop at the lowest task priority within the system. If no blocking function is called from that task, the system will effectively never enter OS_Idle(), but will execute this task instead whenever no other task is ready for execution. Example #include "RTOS.h" #include "BSP.h" static OS_STACKPTR int StackHP[128], StackLP[128], StackIdle[128]; static OS_TASK TCBHP, TCBLP, TCBIdle; static void HPTask(void) { while (1) { BSP_ToggleLED(0); OS_TASK_Delay(50); } } static void LPTask(void) { while (1) { BSP_ToggleLED(1); OS_TASK_Delay(200); } } static void IdleTask(void) { while (1) { // // Perform idle duty, e.g. // - Switch off clocks for unused peripherals. // - Free resources that are no longer used by any task. // - Enter power save mode. // } } int main(void) { OS_Init(); // Initialize embOS OS_InitHW(); // Initialize hardware for embOS BSP_Init(); // Initialize LED ports OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP); OS_TASK_CREATE(&TCBLP, "LP Task", 50, LPTask, StackLP); OS_TASK_CREATE(&TCBIdle, "Idle Task", 1, IdleTask, StackIdle); OS_Start(); // Start multitasking return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 455 CHAPTER 24 24.2.4 Hardware-specific routines OS_InitHW() Description Initializes the hardware required for embOS to run. embOS needs a timer interrupt to determine when to activate tasks that wait for the expiration of a delay, when to call a software timer, and to keep the time variable up-to-date. This function must be called once during main(). Prototype void OS_InitHW(void); Additional information You must modify this routine when a different hardware timer should be used (see Using a different timer to generate tick interrupts for embOS on page 461). With most embOS start projects, this routine may also call further, optional configuration functions, e.g. for * * configuration of the embOS microsecond precise system time parameters (see OS_TIME_ConfigSysTimer()), and initialization of the communication interface to be used with embOSView (see OS_COM_Init()). UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 456 CHAPTER 24 24.2.5 Hardware-specific routines SysTick_Handler() Description The embOS system timer tick interrupt handler. Prototype void SysTick_Handler(void); Additional information With specific embOS start projects, this handler may be implemented using a device specific interrupt name. When using a different timer, always check the specified interrupt vector. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 457 CHAPTER 24 24.2.6 Hardware-specific routines OS_COM_Init() Description Initializes the communication channel for embOSView. This function usually is called once during OS_InitHW(). Prototype void OS_COM_Init(void); Additional information You must modify this routine according to your communication interface. For example when a different UART or baudrate should be used for communication with embOSView. (see Using a different UART or baudrate for embOSView on page 461). To select a communications interface other than UART, refer to Select the communication channel on page 379. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 458 CHAPTER 24 24.2.7 Hardware-specific routines OS_COM_Send1() Description Sends one character towards embOSView via the configured interface. Prototype void OS_COM_Send1(OS_U8 c); Parameters Parameter c Description The character to send towards embOSView. Additional information This function is required for OS_COM_SendString() (see OS_COM_SendString()). You must modify this routine according to your communication interface. Using a different UART or baudrate for embOSView on page 461). To select a communications interface other than UART, refer to Select the communication channel on page 379. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 459 CHAPTER 24 24.2.8 Hardware-specific routines OS_ISR_Rx() Description Receive interrupt handler for UART communication with embOSView. Prototype void OS_ISR_Rx(void); Additional information You must modify this routine when UART is selected as communications interface but a different UART should be used for communication with embOSView. With specific embOS start projects, this handler may be implemented using a device specific interrupt name. Furthermore, with specific devices UART interrupts may share a common interrupt source. In that case, OS_ISR_Rx() and OS_ISR_Tx() are implemented as a single interrupt handler that may utilize a device specific interrupt name. When using a different communications interface, this routine is not used. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 460 CHAPTER 24 24.2.9 Hardware-specific routines OS_ISR_Tx() Description Transmit interrupt handler for UART communication with embOSView. Prototype void OS_ISR_Tx(void); Additional information You must modify this routine when UART is selected as communications interface but a different UART should be used for communication with embOSView. With specific embOS start projects, this handler may be implemented using a device specific interrupt name. Furthermore, with specific devices the UART interrupts may share a common interrupt source. In that case, OS_ISR_Rx() and OS_ISR_Tx() are implemented as a single interrupt handler that may utilize a device specific interrupt name. When using a different communications interface, this routine is not used. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 461 CHAPTER 24 24.3 24.3.1 How to change settings How to change settings Setting the system frequency OS_FSYS Relevant defines * OS_FSYS (System frequency in Hz) Relevant routines * * * OS_ConvertCycles2us() OS_GetTime_Cycles() OS_InitHW() OS_FSYS defines the clock frequency of your system in Hz (times per second). The value of OS_FSYS is used to calculate the desired reload counter value for the system timer for 1000 interrupts / sec. The interrupt frequency therefore typically is 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_Global.Time will no longer be equivalent to multiples of 1 msec (see OS_Global.Time on page 464). However, if you use a multiple of 1 msec as tick time, the basic time unit can be made 1 msec by using the function OS_TICK_Config() (see OS_TICK_Config()). The basic time unit does not need to be 1 msec; it might just as well be 100 usec or 10 msec or any other value. For most applications, however, 1 msec is an appropriate value. 24.3.2 Using a different timer to generate tick interrupts for embOS Relevant routines * OS_InitHW() embOS usually generates one interrupt per msec, making the timer interrupt, or tick, normally equal to 1 msec. 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. 24.3.3 Using a different UART or baudrate for embOSView Relevant defines * * OS_UART (Selection of UART to be used with embOSView, -1 to disable) OS_BAUDRATE (Selection of baudrate for communication with embOSView) Relevant routines: * * * * OS_COM_Init() OS_COM_Send1() OS_ISR_Rx() OS_ISR_Tx() In some cases, this may be done by simply changing the define OS_UART. Refer to the contents of the RTOSInit.c file for more information about which UARTS have been preconfigured for your target hardware. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 25 System Variables UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 463 CHAPTER 25 25.1 Introduction Introduction The system variables are described here for a deeper understanding of how the OS works and to make debugging easier. Not all embOS internal variables are explained here as they are not 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. These variables are accessible, but they should only be altered by functions of embOS. However, some of these variables can be very useful, especially the time variables. Note Do not alter any system variables! UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 464 CHAPTER 25 25.2 25.2.1 Time variables Time variables 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. 25.2.2 OS_Global.Time Description This is the time variable which contains the current system time in embOS system ticks (typically equivalent to msec). Additional information The time variable has a resolution of one time unit, which is normally 1/1000 sec (1 msec) and is normally the time between two successive calls to the embOS timer interrupt handler. Instead of accessing this variable directly, use OS_TIME_GetTicks() or OS_TIME_GetTicks32() as explained in the Chapter Time Measurement on page 284. 25.2.3 OS_Global.TimeDex 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 contains 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_TICKLESS_GetNumIdleTicks() can be used to get the number of system ticks spent idle. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 465 CHAPTER 25 25.3 OS information routines OS information routines Timer ISR Task Description main Routine OS_INFO_GetCPU() Returns the CPU name. OS_INFO_GetLibMode() Returns the library mode. OS_INFO_GetLibName() Returns the library name. OS_INFO_GetModel() Returns the memory model name. OS_INFO_GetVersion() Returns the embOS version number. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 466 CHAPTER 25 25.3.1 OS information routines OS_INFO_GetCPU() Description Returns the CPU name. Prototype char *OS_INFO_GetCPU(void); Return value Char pointer to a null-terminated string containing the CPU name. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 467 CHAPTER 25 25.3.2 OS information routines OS_INFO_GetLibMode() Description Returns the library mode. Prototype char *OS_INFO_GetLibMode(void); Return value Char pointer to a null-terminated string containing the embOS library mode, e.g. "DP", "R" or "SP". UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 468 CHAPTER 25 25.3.3 OS information routines OS_INFO_GetLibName() Description Returns the library name. Prototype char *OS_INFO_GetLibName(void); Return value Char pointer to a null-terminated string containing the complete embOS library name, memory model and library mode, e.g. "v7vLDP". UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 469 CHAPTER 25 25.3.4 OS information routines OS_INFO_GetModel() Description Returns the memory model name. Prototype char *OS_INFO_GetModel(void); Return value Char pointer to a null-terminated string containing the embOS memory model string, e.g. "v7vL". UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 470 CHAPTER 25 25.3.5 OS information routines OS_INFO_GetVersion() Description Returns the embOS version number. Prototype OS_UINT OS_INFO_GetVersion(void); Return value Returns the embOS version number, e.g. "41203" for embOS version 4.12c. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 26 Supported Development Tools UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 472 CHAPTER 26 26.1 Overview 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 mutex 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 in 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 Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 27 Source Code UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 474 CHAPTER 27 27.1 Introduction Introduction embOS is available in two versions: 1. Object version: Object code + hardware initialization source. 2. 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 complete flexibility: 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. Generally, you should not modify any of the files in the CPU folder. The GenOSSrc folder contains all generic embOS sources. The embOS libraries can be rebuild with the additional batch files in the root folder. All of them are described in the following section. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 475 CHAPTER 27 27.2 Building embOS libraries Building embOS libraries The embOS libraries can only be built if you have licensed 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 and RTOS.h for your CPU. 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 small number of batch files which are located in the root directory of your source code distribution: * * * * * * * * * * ASM.bat: This batch file calls the assembler and is used for assembling the assembly part of embOS which contains the task switch functionality. This file is called from the embOS internal batch file CC_OS.bat and cannot be called directly. ASM_CPU.bat: This batch file is used to compile additional assembler files in the CPU/ OSSrcCPU folder. ASM_CPU.bat cannot be called directly. 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 generally should 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. This file is called from the embOS internal batch file CC_OS.bat and cannot be called directly. CC_CPU.bat: This batch file is used to compile additional C files in the CPU/OSSrcCPU folder. CC_CPU.bat 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 identical to those used in CC.bat, except debug output is activated to enable debugging of global variables when using embOS libraries. This file is called from the embOS internal batch file CC_OS.bat and cannot be called directly. Clean.bat: Deletes the entire output of the embOS library build process. It is called during the build process, before new libraries are generated. It deletes the Start folder. Therefore, be careful not to call this batch file accidentally. This file is called initially by M.bat during the build process of all libraries. M.bat: This batch file must be called to rebuild all embOS libraries and RTOS.h. It initially calls Clean.bat and therefore deletes the previous libraries and RTOS.h. M1.bat: This batch file is called from M.bat and is used for building one specific embOS library, it 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. RTOS.h is output in the subfolder Start\Inc. 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. This batch file is the only one which might require modifications to build the embOS libraries. This file is called from M.bat during the build process of all libraries. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 476 CHAPTER 27 27.3 Compile time switches Compile time switches Many features of embOS may be modified using compile-time switches. With each embOS distribution, these switches are preconfigured to appropriate values for each embOS library mode. In case a configuration set is desired that was not covered by the shipped embOS libraries, the compile-time switches may be modified accordingly to create customized configurations on your own authority. The embOS source code is necessary in order to do so. According modifications must not be done to OS_RAW.h or RTOS.h, instead compile-time switches must be added to OS_Config.h or configured as preprocessor definitions. Subsequently, the embOS sources must be recompiled to reflect the modified switches. In case of doubt, please contact the embOS support for assistance. The default values depend on the used library mode and are given in the following table for library mode OS_LIBMODE_DP. Compile time switch Description Permitted values Default Enables runtime debug checks 0: Disabled 1: Enabled 1 Enables additional debug checks 1: Standard debug code 2: Extended debug code 1 OS_CHECKSTACK Performs stack checks 0: Disabled 1: Enabled 2: Stack check with 1 configurable stack check limit OS_STACKCHECK_LIMIT Percentage of stack usage that will be detected as a stack overflow error 1-100 100 OS_PROFILE Profiling support 0: Disabled 1: Enabled 1 OS_SUPPORT_TICKSTEP embOSView tick step support 0: Disabled 1: Enabled 1 OS_TRACE embOSView trace support 0: Disabled 1: Enabled 0 OS_TRACE_RECORD_API_END Generates additional SystemView API-End events 0: Disabled 1: Enabled 1 OS_RR_SUPPORTED Round-Robin supported 0: Disabled 1: Enabled 1 OS_TRACKNAME Allows task and OS object names 0: Disabled 1: Enabled 1 OS_SUPPORT_SAVE_RESTORE_HOOK Support task context extensions 0: Disabled 1: Enabled 1 OS_SUPPORT_STAT Generate task statistic information 0: Disabled 1: Enabled 1 OS_SUPPORT_PTLS Support for thread local storage 0: Disabled 1: Enabled 1 OS_INIT_EXPLICITLY Initialization of internal embOS variables 0: Disabled 1: Enabled 0 OS_DEBUG OS_DEBUG_LEVEL UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 477 CHAPTER 27 Compile time switches Description Permitted values OS_SUPPORT_TIMER Support for embOS software timers 0: Disabled 1: Enabled 1 OS_SUPPORT_TICKLESS Support for embOS tickless mode 0: Disabled 1: Enabled 1 OS_SUPPORT_PERIPHERAL_POWER_CTRL Enables peripheral power 0: Disabled control 1: Enabled 1 OS_POWER_NUM_COUNTERS Number of peripherals which can be used >0 5 OS_SPINLOCK_MAX_CORES Number of cores that should access a spinlock >0 4 OS_SUPPORT_OS_ALLOC Support for embOS thread safe heap allocation 0: Disabled 1: Enabled 1 Compile time switch UM01001 User Guide & Reference Manual for embOS Default (c) 1995-2018 SEGGER Microcontroller GmbH 478 CHAPTER 27 27.4 Source code project Source code project All embOS start projects use the embOS libraries instead of the embOS source code. Even the embOS source shipment does not include a project which uses embOS sources. It can be useful to have the embOS sources instead of the embOS library in a project, e.g. for easier debugging. To do so you just have to exclude or delete the embOS library from your project and add the embOS sources as described below. The embOS sources consists of the files in the folder GenOSSrc, CPU and CPU\OSSrcCPU. These files can be found in the embOS source shipment. Folder Description GenOSSrc embOS generic sources CPU RTOS assembler file CPU\OSSrcCPU CPU and compiler-specific files Please add all C and assembler files from these folders to your project and add include paths to these folders to your project settings. For some embOS ports it might be necessary to add additional defines to your preprocessor settings. If necessary you will find more information about it in the CPU and compiler-specific embOS manual. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 28 Shipment This chapter describes the different embOS shipment variants. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 480 CHAPTER 28 28.1 General information General information embOS is available in three different variants: Free, Library, and Source code. The fully functional free variant can easily be downloaded for each embOS port and has no technical limitation. The following table lists the included features with each of these variants: Features embOS libraries Free Library Source code embOS source code embOSView - Profiling PC tool embOS manual CPU/Compiler specific manual Release notes embOS IDE plug-ins Board support packages Feature & maintenance updates Technical support Free for any non-commercial use UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 481 CHAPTER 28 28.2 Library variant Library variant Directory File Board support packages in vendor specific subfolders Start\BoardSupport Start\Inc Description RTOS.h, BSP.h, OS_Config.h Including files for embOS embOS libraries Start\Lib embOSView.exe PC utility for runtime analysis JLinkARM.dll J-Link DLL used with embOSView Release_embOS.html embOS release history Release_embOS_CPU_Compil- embOS CPU and compiler-specifer.html ic release history SYSVIEW_embOS.txt SytemView ID descripton file UM010xx_embOS_CPU_Compil- embOS CPU and compiler-specifer.pdf ic manual UM01001_embOS.pdf UM01001 User Guide & Reference Manual for embOS embOS manual (c) 1995-2018 SEGGER Microcontroller GmbH 482 CHAPTER 28 28.3 Free variant Free variant The Free variant is identical to the library variant, exept for additional license information governing the use of this variant. Directory File Board support packages in vendor specific subfolders Start\BoardSupport Start\Inc Description RTOS.h, BSP.h, OS_Config.h Including files for embOS embOS libraries Start\Lib embOSView.exe PC utility for runtime analysis JLinkARM.dll J-Link DLL used with embOSView License.txt License information Release_embOS.html embOS release history Release_embOS_CPU_Compil- embOS CPU and compiler-specifer.html ic release history SYSVIEW_embOS.txt SytemView ID descripton file UM010xx_embOS_CPU_Compil- embOS CPU and compiler-specifer.pdf ic manual UM01001_embOS.pdf UM01001 User Guide & Reference Manual for embOS embOS manual (c) 1995-2018 SEGGER Microcontroller GmbH 483 CHAPTER 28 28.4 Source code variant Source code variant The source code variant is identical to the library variant, but in addition also contains the embOS source files and a set of batch files that can be used to rebuild the embOS libraries. Directory CPU File OSCHIP.h, OS_Priv.h, RTOS.asm Description CPU- and compiler-specific files CPU\OSSrcCPU Additional CPU- and compiler-specific source files GenOSSrc Generic source files Start\BoardSupport Board support packages in vendor specific subfolders Start\Inc RTOS.h, BSP.h, OS_Config.h Including files for embOS embOS libraries Start\Lib embOSView.exe PC utility for runtime analysis JLinkARM.dll J-Link DLL used with embOSView Release_embOS.html embOS release history Release_embOS_CPU_Compil- embOS CPU and compiler-specifer.html ic release history SYSVIEW_embOS.txt SytemView ID descripton file UM010xx_embOS_CPU_Compil- embOS CPU and compiler-specifer.pdf ic manual UM01001_embOS.pdf embOS manual *.bat Batch files to rebuild the embOS libraries UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 29 Update UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 485 CHAPTER 29 29.1 Introduction Introduction This chapter describes how to update an existing project with a newer embOS version. embOS ports are available for different CPUs and compiler. Each embOS port has its own version number. SEGGER updates embOS ports to a newer software version for different reasons. This is done to fix problems or to include the newest embOS features. Customers which have a valid support and update agreement will be automatically informed about a new software version via email and may subsequently download the updated software from www.myaccount.segger.com. The version information and release history is also available at www.segger.com. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 486 CHAPTER 29 29.2 How to update an existing project How to update an existing project If an existing project should be updated to a later embOS version, only files have to be replaced. Note Do not use embOS files from different embOS versions in your project! You should have received the embOS update as a zip file. Unzip this file to the location of your choice and replace all embOS files in your project with the newer files from the embOS update shipment. For an easier update procedure, we recommend to not modify the files shipped with embOS. In case these need to be updated, you will have to merge your modifications into the most recent shipment version of that file, or else your modifications will be lost. In general, the following files have to be updated: File Location Description embOS libraries Start\Lib embOS object code libraries RTOS.h Start\Inc embOS header file OS_Config.h Start\Inc embOS config header file BSP.h Start\Inc Board support header file RTOSInit.c Start\BoardSupport\...\Setup Hardware related routines OS_Error.c Start\BoardSupport\...\Setup embOS error routines Additional files Start\BoardSupport\...\Setup CPU and compiler-specific files 29.2.1 My project does not work anymore. What did I do wrong? One common mistake is to only update the embOS library but not RTOS.h. You should always ensure the embOS library and RTOS.h belong to the same embOS port version. Also, please ensure further embOS files like OS_Error.c and RTOSInit.c have been updated to the same version. If you are still experiencing problems, please do not hesitate to contact the embOS support (see Contacting support on page 496). UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 487 CHAPTER 29 29.3 embOS API Migration guide embOS API Migration guide Most embOS API names and some object type names have changed between embOS V4 and V5. The legacy embOS API names can still be used and there is no need to update the user application. embOS is still 100% compatible. However, for new projects the V5 API should be used. If you want to replace the V4 with the V5 API in an existing application you can easily replace all API calls. SEGGER provides a CSV file on request which can be used to automatically replace all API calls. Please be aware with some API the parameter order has changed. This needs to be adapted manually. OS_TASK_CREATE()/ OS_TASK_CREATEEX(): The order of the parameters Priority and pRoutine has changed. OS_TASKEVENT_Set(): The order of the parameters pTask and Event has changed. OS_MEMPOOL_Alloc()/ OS_MEMPOOL_AllocBlocked()/ OS_MEMPOOL_AllocTimed(): The parameter Purpose does not longer exist. V4 V5 OS_IsRunning() OS_IsRunning() OS_Config_Stop() OS_ConfigStop() OS_InitKern() OS_Init() OS_IsRunning() OS_IsRunning() OS_Start() OS_Start() OS_Stop() OS_Stop() OS_AddExtendTaskContext() OS_TASK_AddContextExtension() OS_AddTerminateHook() OS_TASK_AddTerminateHook() OS_CREATETASK() OS_TASK_CREATE() OS_CreateTask() OS_TASK_Create() OS_CREATETASK_EX() OS_TASK_CREATEEX() OS_CreateTaskEx() OS_TASK_CreateEx() OS_Delay() OS_TASK_Delay() OS_DelayUntil() OS_TASK_DelayUntil() OS_Delayus() OS_TASK_Delayus() OS_ExtendTaskContext() OS_TASK_SetContextExtension() OS_GetNumTasks() OS_TASK_GetNumTasks() OS_GetPriority() OS_TASK_GetPriority() OS_GetSuspendCnt() OS_TASK_GetSuspendCnt() OS_GetTaskID() OS_TASK_GetID() OS_GetTaskName() OS_TASK_GetName() OS_GetTimeSliceRem() OS_TASK_GetTimeSliceRem() OS_IsTask() OS_TASK_IsTask() OS_RemoveTerminateHook() OS_TASK_RemoveTerminateHook() OS_RemoveAllTerminateHooks() OS_TASK_RemoveAllTerminateHooks() OS_Resume() OS_TASK_Resume() OS_ResumeAllTasks() OS_TASK_ResumeAll() OS_SetDefaultTaskContextExtension() OS_TASK_SetDefaultContextExtension() OS_SetDefaultTaskStartHook() OS_TASK_SetDefaultStartHook() OS_SetInitialSuspendCnt() OS_TASK_SetInitialSuspendCnt() UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 488 CHAPTER 29 embOS API Migration guide V4 V5 OS_SetPriority() OS_TASK_SetPriority() OS_SetTaskName() OS_TASK_SetName() OS_SetTimeSlice() OS_TASK_SetTimeSlice() OS_Suspend() OS_TASK_Suspend() OS_SuspendAllTasks() OS_TASK_SuspendAll() OS_TaskIndex2Ptr() OS_TASK_Index2Ptr() OS_TerminateTask() OS_TASK_Terminate() OS_WakeTask() OS_TASK_Wake() OS_Yield() OS_TASK_Yield() OS_CREATETIMER() OS_TIMER_CREATE() OS_CreateTimer() OS_TIMER_Create() OS_CREATETIMER_EX() OS_TIMER_CREATEEX() OS_CreateTimerEx() OS_TIMER_CreateEx() OS_DeleteTimer() OS_TIMER_Delete() OS_DeleteTimerEx() OS_TIMER_DeleteEx() OS_GetpCurrentTimer() OS_TIMER_GetCurrent() OS_GetpCurrentTimerEx() OS_TIMER_GetCurrentEx() OS_GetTimerPeriod() OS_TIMER_GetPeriod() OS_GetTimerPeriodEx() OS_TIMER_GetPeriodEx() OS_GetTimerStatus() OS_TIMER_GetStatus() OS_GetTimerStatusEx() OS_TIMER_GetStatusEx() OS_GetTimerValue() OS_TIMER_GetRemainingPeriod() OS_GetTimerValueEx() OS_TIMER_GetRemainingPeriodEx() OS_RetriggerTimer() OS_TIMER_Restart() OS_RetriggerTimerEx() OS_TIMER_RestartEx() OS_SetTimerPeriod() OS_TIMER_SetPeriod() OS_SetTimerPeriodEx() OS_TIMER_SetPeriodEx() OS_StartTimer() OS_TIMER_Start() OS_StartTimerEx() OS_TIMER_StartEx() OS_StopTimer() OS_TIMER_Stop() OS_StopTimerEx() OS_TIMER_StopEx() OS_TriggerTimer() OS_TIMER_Trigger() OS_TriggerTimerEx() OS_TIMER_TriggerEx() OS_ClearEvents() OS_TASKEVENT_Clear() OS_ClearEventsEx() OS_TASKEVENT_ClearEx() OS_GetEventsOccurred() OS_TASKEVENT_Get() OS_SignalEvent() OS_TASKEVENT_Set() OS_WaitEvent() OS_TASKEVENT_GetBlocked() OS_WaitEventTimed() OS_TASKEVENT_GetTimed() OS_WaitSingleEvent() OS_TASKEVENT_GetSingleBlocked() OS_WaitSingleEventTimed() OS_TASKEVENT_GetSingleTimed() OS_EVENT_Create() OS_EVENT_Create() OS_EVENT_CreateEx() OS_EVENT_CreateEx() UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 489 CHAPTER 29 embOS API Migration guide V4 V5 OS_EVENT_Delete() OS_EVENT_Delete() OS_EVENT_Get() OS_EVENT_Get() OS_EVENT_GetMask() OS_EVENT_GetMask() OS_EVENT_GetMaskMode() OS_EVENT_GetMaskMode() OS_EVENT_GetResetMode() OS_EVENT_GetResetMode() OS_EVENT_Pulse() OS_EVENT_Pulse() OS_EVENT_Reset() OS_EVENT_Reset() OS_EVENT_Set() OS_EVENT_Set() OS_EVENT_SetMask() OS_EVENT_SetMask() OS_EVENT_SetMaskMode() OS_EVENT_SetMaskMode() OS_EVENT_SetResetMode() OS_EVENT_SetResetMode() OS_EVENT_Wait() OS_EVENT_GetBlocked() OS_EVENT_WaitMask() OS_EVENT_GetMaskBlocked() OS_EVENT_WaitMaskTimed() OS_EVENT_GetMaskTimed() OS_EVENT_WaitTimed() OS_EVENT_GetTimed() OS_CreateRSema() OS_MUTEX_Create() OS_CREATERSEMA() OS_MUTEX_CREATE() OS_DeleteRSema() OS_MUTEX_Delete() OS_GetResourceOwner() OS_MUTEX_GetOwner() OS_GetSemaValue() OS_MUTEX_GetValue() OS_Request() OS_MUTEX_Lock() OS_Unuse() OS_MUTEX_Unlock() OS_Use() OS_MUTEX_LockBlocked() OS_UseTimed() OS_MUTEX_LockTimed() OS_CREATECSEMA() OS_SEMAPHORE_CREATE() OS_CreateCSema() OS_SEMAPHORE_Create() OS_CSemaRequest() OS_SEMAPHORE_Take() OS_DeleteCSema() OS_SEMAPHORE_Delete() OS_GetCSemaValue() OS_SEMAPHORE_GetValue() OS_SetCSemaValue() OS_SEMAPHORE_SetValue() OS_SignalCSema() OS_SEMAPHORE_Give() OS_SignalCSemaMax() OS_SEMAPHORE_GiveMax() OS_WaitCSema() OS_SEMAPHORE_TakeBlocked() OS_WaitCSemaTimed() OS_SEMAPHORE_TakeTimed() OS_ClearMB() OS_MAILBOX_Clear() OS_CreateMB() OS_MAILBOX_Create() OS_DeleteMB() OS_MAILBOX_Delete() OS_GetMail() OS_MAILBOX_GetBlocked() OS_GetMail1() OS_MAILBOX_GetBlocked1() OS_GetMailCond() OS_MAILBOX_Get() OS_GetMailCond1() OS_MAILBOX_Get1() OS_GetMailTimed() OS_MAILBOX_GetTimed() OS_GetMailTimed1() OS_MAILBOX_GetTimed1() UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 490 CHAPTER 29 embOS API Migration guide V4 V5 OS_GetMessageCnt() OS_MAILBOX_GetMessageCnt() OS_Mail_GetPtr() OS_MAILBOX_GetPtrBlocked() OS_Mail_GetPtrCond() OS_MAILBOX_GetPtr() OS_Mail_Purge() OS_MAILBOX_Purge() OS_PeekMail() OS_MAILBOX_Peek() OS_PutMail() OS_MAILBOX_PutBlocked() OS_PutMail1() OS_MAILBOX_PutBlocked1() OS_PutMailCond() OS_MAILBOX_Put() OS_PutMailCond1() OS_MAILBOX_Put1() OS_PutMailFront() OS_MAILBOX_PutFrontBlocked() OS_PutMailFront1() OS_MAILBOX_PutFrontBlocked1() OS_PutMailFrontCond() OS_MAILBOX_PutFront() OS_PutMailFrontCond1() OS_MAILBOX_PutFront1() OS_PutMailTimed() OS_MAILBOX_PutTimed() OS_PutMailTimed1() OS_MAILBOX_PutTimed1() OS_WaitMail() OS_MAILBOX_WaitBlocked() OS_WaitMailTimed() OS_MAILBOX_WaitTimed() OS_Q_Clear() OS_QUEUE_Clear() OS_Q_Create() OS_QUEUE_Create() OS_Q_Delete() OS_QUEUE_Delete() OS_Q_GetMessageCnt() OS_QUEUE_GetMessageCnt() OS_Q_GetMessageSize() OS_QUEUE_GetMessageSize() OS_Q_GetPtr() OS_QUEUE_GetPtrBlocked() OS_Q_GetPtrCond() OS_QUEUE_GetPtr() OS_Q_GetPtrTimed() OS_QUEUE_GetPtrTimed() OS_Q_IsInUse() OS_QUEUE_IsInUse() OS_Q_PeekPtr() OS_QUEUE_PeekPtr() OS_Q_Purge() OS_QUEUE_Purge() OS_Q_Put() OS_QUEUE_Put() OS_Q_PutEx() OS_QUEUE_PutEx() OS_Q_PutBlocked() OS_QUEUE_PutBlocked() OS_Q_PutBlockedEx() OS_QUEUE_PutBlockedEx() OS_Q_PutTimed() OS_QUEUE_PutTimed() OS_Q_PutTimedEx() OS_QUEUE_PutTimedEx() OS_WD_Add() OS_WD_Add() OS_WD_Check() OS_WD_Check() OS_WD_Config() OS_WD_Config() OS_WD_Remove() OS_WD_Remove() OS_WD_Trigger() OS_WD_Trigger() OS_SPINLOCK_Create() OS_SPINLOCK_Create() OS_SPINLOCK_Lock() OS_SPINLOCK_Lock() OS_SPINLOCK_Unlock() OS_SPINLOCK_Unlock() OS_SPINLOCK_SW_Create() OS_SPINLOCK_SW_Create() UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 491 CHAPTER 29 embOS API Migration guide V4 V5 OS_SPINLOCK_SW_Lock() OS_SPINLOCK_SW_Lock() OS_SPINLOCK_SW_Unlock() OS_SPINLOCK_SW_Unlock() OS_DecRI() OS_INT_DecRI() OS_DI() OS_INT_Disable() OS_EI() OS_INT_Enable() OS_IncDI() OS_INT_IncDI() OS_INT_PRIO_PRESERVE() OS_INT_Preserve() OS_INT_PRIO_RESTORE() OS_INT_Restore() OS_INTERRUPT_MaskGlobal() OS_INT_DisableAll() OS_INTERRUPT_PreserveAndMaskGlobal() OS_INT_PreserveAndDisableAll() OS_INTERRUPT_PreserveGlobal() OS_INT_PreserveAll() OS_INTERRUPT_RestoreGlobal() OS_INT_RestoreAll() OS_INTERRUPT_UnmaskGlobal() OS_INT_EnableAll() OS_RestoreI() OS_INT_EnableConditional() OS_CallISR() OS_INT_Call() OS_CallNestableISR() OS_INT_CallNestable() OS_EnterInterrupt() OS_INT_Enter() OS_EnterNestableInterrupt() OS_INT_EnterNestable() OS_InInterrupt() OS_INT_InInterrupt() OS_LeaveInterrupt() OS_INT_Leave() OS_LeaveNestableInterrupt() OS_INT_LeaveNestable() OS_EnterIntStack() OS_INT_EnterIntStack() OS_LeaveIntStack() OS_INT_LeaveIntStack() OS_SetFastIntPriorityLimit() OS_INT_SetPriorityThreshold() OS_EnterRegion() OS_TASK_EnterRegion() OS_LeaveRegion() OS_TASK_LeaveRegion() OS_GetTime() OS_TIME_GetTicks() OS_GetTime32() OS_TIME_GetTicks32() OS_Timing_End() OS_TIME_StopMeasurement() OS_Timing_GetCycles() OS_TIME_GetResult() OS_Timing_Start() OS_TIME_StartMeasurement() OS_Timing_Getus() OS_TIME_GetResultus() OS_Config_SysTimer() OS_TIME_ConfigSysTimer() OS_GetTime_us() OS_TIME_Getus() OS_GetTime_us64() OS_TIME_Getus64() OS_AdjustTime() OS_TICKLESS_AdjustTime() OS_GetNumIdleTicks() OS_TICKLESS_GetNumIdleTicks() OS_StartTicklessMode() OS_TICKLESS_Start() OS_StopTicklessMode() OS_TICKLESS_Stop() OS_POWER_GetMask() OS_POWER_GetMask() OS_POWER_UsageDec() OS_POWER_UsageDec() OS_POWER_UsageInc() OS_POWER_UsageInc() OS_free() OS_HEAP_free() UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 492 CHAPTER 29 embOS API Migration guide V4 V5 OS_malloc() OS_HEAP_malloc() OS_realloc() OS_HEAP_realloc() OS_MEMF_Alloc() OS_MEMPOOL_AllocBlocked() OS_MEMF_AllocTimed() OS_MEMPOOL_AllocTimed() OS_MEMF_Create() OS_MEMPOOL_Create() OS_MEMF_Delete() OS_MEMPOOL_Delete() OS_MEMF_FreeBlock() OS_MEMPOOL_Free() OS_MEMF_GetBlockSize() OS_MEMPOOL_GetBlockSize() OS_MEMF_GetMaxUsed() OS_MEMPOOL_GetMaxUsed() OS_MEMF_GetNumBlocks() OS_MEMPOOL_GetNumBlocks() OS_MEMF_GetNumFreeBlocks() OS_MEMPOOL_GetNumFreeBlocks() OS_MEMF_IsInPool() OS_MEMPOOL_IsInPool() OS_MEMF_Release() OS_MEMPOOL_FreeEx() OS_MEMF_Request() OS_MEMPOOL_Alloc() OS_TICK_Config() OS_TICK_Config() OS_TICK_Handle() OS_TICK_Handle() OS_TICK_HandleEx() OS_TICK_HandleEx() OS_TICK_HandleNoHook() OS_TICK_HandleNoHook() OS_TICK_AddHook() OS_TICK_AddHook() OS_TICK_RemoveHook() OS_TICK_RemoveHook() OS_SetObjName() OS_DEBUG_SetObjName() OS_GetObjName() OS_DEBUG_GetObjName() OS_AddLoadMeasurement() OS_STAT_AddLoadMeasurement() OS_GetLoadMeasurement() OS_STAT_GetLoadMeasurement() OS_STAT_Disable() OS_STAT_Disable() OS_STAT_Enable() OS_STAT_Enable() OS_STAT_GetLoad() OS_STAT_GetLoad() OS_STAT_GetTaskExecTime() OS_STAT_GetExecTime() OS_STAT_Sample() OS_STAT_Sample() OS_SendString() OS_COM_SendString() OS_SetRxCallback() OS_COM_SetRxCallback() OS_TraceDisable() OS_TRACE_Disable() OS_TraceDisableAll() OS_TRACE_DisableAll() OS_TraceDisableFilterId() OS_TRACE_DisableFilterId() OS_TraceDisableId() OS_TRACE_DisableId() OS_TraceEnable() OS_TRACE_Enable() OS_TraceEnableAll() OS_TRACE_EnableAll() OS_TraceEnableFilterId() OS_TRACE_EnableFilterId() OS_TraceEnableId() OS_TRACE_EnableId() OS_TraceData() OS_TRACE_Data() OS_TraceDataPtr() OS_TRACE_DataPtr() OS_TracePtr() OS_TRACE_Ptr() OS_TraceU32Ptr() OS_TRACE_U32Ptr() UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 493 CHAPTER 29 embOS API Migration guide V4 V5 OS_TraceVoid() OS_TRACE_Void() OS_SetTraceAPI() OS_TRACE_SetAPI() OS_MPU_AddRegion() OS_MPU_AddRegion() OS_MPU_CallDeviceDriver() OS_MPU_CallDeviceDriver() OS_MPU_ConfigMem() OS_MPU_ConfigMem() OS_MPU_Enable() OS_MPU_Enable() OS_MPU_EnableEx() OS_MPU_EnableEx() OS_MPU_ExtendTaskContext() OS_MPU_ExtendTaskContext() OS_MPU_GetThreadState() OS_MPU_GetThreadState() OS_MPU_SetAllowedObjects() OS_MPU_SetAllowedObjects() OS_MPU_SetDeviceDriverList() OS_MPU_SetDeviceDriverList() OS_MPU_SetErrorCallback() OS_MPU_SetErrorCallback() OS_MPU_SwitchToUnprivState() OS_MPU_SwitchToUnprivState() OS_MPU_SwitchToUnprivStateEx() OS_MPU_SwitchToUnprivStateEx() OS_MPU_AddSanityCheckBuffer() OS_MPU_SetSanityCheckBuffer() OS_MPU_SanityCheck() OS_MPU_SanityCheck() OS_GetIntStackBase() OS_STACK_GetIntStackBase() OS_GetIntStackSize() OS_STACK_GetIntStackSize() OS_GetIntStackSpace() OS_STACK_GetIntStackSpace() OS_GetIntStackUsed() OS_STACK_GetIntStackUsed() OS_GetStackBase() OS_STACK_GetTaskStackBase() OS_GetStackSize() OS_STACK_GetTaskStackSize() OS_GetStackSpace() OS_STACK_GetTaskStackSpace() OS_GetStackUsed() OS_STACK_GetTaskStackUsed() OS_GetSysStackBase() OS_STACK_GetSysStackBase() OS_GetSysStackSize() OS_STACK_GetSysStackSize() OS_GetSysStackSpace() OS_STACK_GetSysStackSpace() OS_GetSysStackUsed() OS_STACK_GetSysStackUsed() OS_SetStackCheckLimit() OS_STACK_SetCheckLimit() OS_GetStackCheckLimit() OS_STACK_GetCheckLimit() OS_OnRx() OS_COM_OnRx() OS_OnTx() OS_COM_OnTx() OS_EvaPacketEx() OS_COM_EvaPacketEx() OS_GetCPU() OS_INFO_GetCPU() OS_GetLibMode() OS_INFO_GetLibMode() OS_GetLibName() OS_INFO_GetLibName() OS_GetModel() OS_INFO_GetModel() OS_GetVersion() OS_INFO_GetVersion() Changed object types: V4 V5 OS_RSEMA OS_MUTEX OS_CSEMA OS_SEMAPHORE UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 494 CHAPTER 29 embOS API Migration guide V4 V5 OS_Q OS_QUEUE OS_Q_SRCLIST OS_QUEUE_SRCLIST OS_MEMF OS_MEMPOOL OS_TASK_EVENT OS_TASKEVENT UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 30 Support UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 496 CHAPTER 30 30.1 Contacting support Contacting support This chapter should help if any problem occurs and describes how to contact the embOS 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. Note Even without a valid license, feel free to contact our support e.g. in case of questions during your evaluation of embOS or for hobbyist purposes. Please also take a few moments to help us improve our services by providing a short feedback once your support case has been solved. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 31 Performance and Resource Usage UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 498 CHAPTER 31 31.1 Introduction Introduction 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. 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 Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 499 CHAPTER 31 31.2 Memory requirements 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. These values are typical values for a 32 bit CPU and depend on CPU, compiler, and library model used. Module Memory type Memory requirements embOS kernel ROM 1700 bytes embOS kernel RAM 71 bytes Mailbox RAM 24 bytes Semaphore RAM 8 bytes Mutex RAM 16 bytes Software timer RAM 20 bytes Task event RAM 0 bytes UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 500 CHAPTER 31 31.3 Performance Performance The following section shows how to benchmark embOS with the supplied example programs. 31.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 \Application directory of your embOS shipment. SEGGER uses these programs to benchmark 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 number of cycles are not equal to the number of instructions. Many instructions on ARM need two or three cycles even at zero wait-states, 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 Time / Cycles ST STM32F756 @ 200 MHz RAM 1.5us / 260 Renesas RZ @ 400 MHz RAM 720ns / 287 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 6.40.5, OS_LIBMODE_XR and high optimization level. embOS version 4.14 has been used; values may differ for different builds. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 501 CHAPTER 31 31.4.1 Benchmarking Measurement with port pins and oscilloscope The example file OS_MeasureCST_Scope.c uses the BSP.c module to set and clear a port pin. This allows measuring the context switch time with an oscilloscope. The following source code is an excerpt from OS_MeasureCST_Scope.c: #include "RTOS.h" #include "BSP.h" static OS_STACKPTR int StackHP[128], StackLP[128]; /* Task stacks */ static OS_TASK TCBHP, TCBLP; /* Task-control-blocks */ /********************************************************************* * * HPTask */ static void HPTask(void) { while (1) { OS_TASK_Suspend(NULL); // Suspend high priority task BSP_ClrLED(0); // Stop measurement } } /********************************************************************* * * LPTask */ static void LPTask(void) { while (1) { OS_TASK_Delay(100); // Synchronize to tick to avoid jitter // // Display measurement overhead // BSP_SetLED(0); BSP_ClrLED(0); // // Perform measurement // BSP_SetLED(0); // Start measurement OS_TASK_Resume(&TCBHP); // Resume high priority task to force task switch } } /********************************************************************* * * main */ int main(void) { OS_Init(); // Initialize embOS OS_InitHW(); // Initialize hardware for embOS BSP_Init(); // Initialize LED ports OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP); OS_TASK_CREATE(&TCBLP, "LP Task", 50, LPTask, StackLP); OS_Start(); // Start multitasking return 0; } UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 502 CHAPTER 31 31.4.1.1 Benchmarking 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 = LED is switched on for overhead measurement B = LED is switched off for overhead measurement C = LED is switched on right before context switch in low-prio task D = LED is switched 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 tCS is calculated as follows: tCS = tCD - tAB UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 503 CHAPTER 31 31.4.1.2 Benchmarking Example measurements Renesas RZ, Thumb2 code in RAM Task switching time has been measured with the parameters listed below: embOS Version V4.14 Application program: OS_MeasureCST_Scope.c Hardware: Renesas RZ processor with 399MHz Program is executing in RAM Thumb2 mode is used Compiler used: SEGGER Embedded Studio V2.10B (GCC) CPU frequency (fCPU): 399.0MHz CPU clock cycle (tCycle): tCycle = 1 / fCPU = 1 / 399.0MHz = 2.506ns Measuring tAB and tCD tAB is measured as 480ns. The number of cycles calculates as follows: CyclesAB = tAB / tCycle = 480ns / 2.506ns = 191.54 Cycles => 192 Cycles tCD is measured as 12000ns. The number of cycles calculates as follows: CyclesCD = tCD / tCycle = 1200ns / 2.506ns = 478.85 Cycles => 479 Cycles Resulting context switching time and number of cycles The time which is required for the pure context switch is: tCS = tCD - tAB = 479 Cycles - 192 Cycles = 287 Cycles => 287 Cycles (0.72us @399 MHz). UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 504 CHAPTER 31 31.4.1.3 Benchmarking 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 289 for detailed information about the embOS highresolution measurement. The example OS_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 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_TASK_Suspend(NULL); // Suspend high priority task OS_TIME_StopMeasurement(&_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_TIME_StartMeasurement(&MeasureOverhead); OS_TIME_StopMeasurement(&MeasureOverhead); // // Perform measurements in endless loop // while (1) { OS_TASK_Delay(100); // Sync. to tick to avoid jitter OS_TIME_StartMeasurement(&_Time); // Start measurement OS_TASK_Resume(&TCBHP); // Resume high priority task to force task switch v = OS_TIME_GetResult(&_Time); v -= OS_TIME_GetResult(&MeasureOverhead); v = OS_ConvertCycles2us(1000 * v); // Convert cycles to nano-seconds sprintf(acBuffer, "Context switch time: %1u.%.31u usec\r", v / 1000uL, v % 1000uL); OS_COM_SendString(acBuffer); } } The example program calculates and subtracts the measurement overhead. The results will be transmitted to embOSView, so the example runs on every target that supports UART communication to embOSView. The example program OS_MeasureCST_HRTimer_Printf.c is identical to the example program OS_MeasureCST_HRTimer_embOSView.c but displays the results with the printf() function for those debuggers which support terminal output emulation. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Chapter 32 Glossary UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 506 CHAPTER 32 Term Definition 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 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 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 an 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. Mutex A data structure used for managing resources by ensuring that only one task has access to a resource at a time. 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. Two 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. Priority The relative importance of one task to another. Every task in an RTOS has a priority. Priority inversion 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. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH 507 CHAPTER 32 Term Definition 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. 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. Two threads can access the same memory locations. If virtual memory is used, the same virtual to physical translation and access rights are used(c.f. Thread, Process) Tick The OS timer interrupt. Typically equals 1 msec. Time slice The time (number of system ticks) for which a task will be executed until a round-robin task change may occur. UM01001 User Guide & Reference Manual for embOS (c) 1995-2018 SEGGER Microcontroller GmbH Mouser Electronics Authorized Distributor Click to View Pricing, Inventory, Delivery & Lifecycle Information: Segger Microcontroller: 1.xx.01 1.xx.04 1.xx.02 7.50.02