From: rtel Date: Mon, 15 Dec 2014 14:13:03 +0000 (+0000) Subject: + New feature added: Task notifications. X-Git-Tag: V8.2.0rc1~6 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=b473fddd0a6a35390132c46400b32af8c7ef36e9;p=freertos + New feature added: Task notifications. + Optimise Cortex-M4F ports by inlining some critical section macros. + Original ports used a #define to set the path to portmacro.h - that method has been obsolete for years and now all the old definitions have been moved into a separate header files called deprecated_definitions.h. + Cortex-M port now check the active vector bits against 0xff when determining if a function is called from an interrupt - previously only a subset of the bits (0x1f) were checked. + Add in new standard demo/test files TaskNotify.c/h and include the files in the simulator demos. + Update trace recorder code, and some demos to use the new version (more to do). + Introduce uxTaskPriorityGetFromISR(). + Minor typo corrections. + Update MingW simulator demo to match the MSVC simulator demo. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2314 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/ConfigurationTemplate/trcConfig.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/ConfigurationTemplate/trcConfig.h index e2d22e053..4f3c2e924 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/ConfigurationTemplate/trcConfig.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/ConfigurationTemplate/trcConfig.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Tracealyzer v2.6.0 Recorder Library + * Tracealyzer v2.7.0 Recorder Library * Percepio AB, www.percepio.com * * trcConfig.h @@ -36,237 +36,162 @@ * damages, or the exclusion of implied warranties or limitations on how long an * implied warranty may last, so the above limitations may not apply to you. * - * Copyright Percepio AB, 2013. + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2014. * www.percepio.com ******************************************************************************/ #ifndef TRCCONFIG_H #define TRCCONFIG_H -/******************************************************************************* - * CONFIGURATION RELATED TO CAPACITY AND ALLOCATION - ******************************************************************************/ - -/******************************************************************************* - * EVENT_BUFFER_SIZE - * - * Macro which should be defined as an integer value. - * - * This defines the capacity of the event buffer, i.e., the number of records - * it may store. Each registered event typically use one record (4 byte), but - * vTracePrintF may use multiple records depending on the number of data args. - ******************************************************************************/ +/****************************************************************************** + * SELECTED_PORT + * + * Macro that specifies what hardware port that should be used. + * Available ports are: + * + * Port Name Code Official OS supported + * PORT_APPLICATION_DEFINED -2 - - + * PORT_NOT_SET -1 - - + * PORT_HWIndependent 0 Yes Any + * PORT_Win32 1 Yes FreeRTOS on Win32 + * PORT_Atmel_AT91SAM7 2 No Any + * PORT_Atmel_UC3A0 3 No Any + * PORT_ARM_CortexM 4 Yes Any + * PORT_Renesas_RX600 5 Yes Any + * PORT_Microchip_dsPIC_AND_PIC24 6 Yes Any + * PORT_TEXAS_INSTRUMENTS_TMS570 7 No Any + * PORT_TEXAS_INSTRUMENTS_MSP430 8 No Any + * PORT_MICROCHIP_PIC32MX 9 Yes Any + * PORT_XILINX_PPC405 10 No FreeRTOS + * PORT_XILINX_PPC440 11 No FreeRTOS + * PORT_XILINX_MICROBLAZE 12 No Any + * PORT_NXP_LPC210X 13 No Any + * PORT_MICROCHIP_PIC32MZ 14 Yes Any + * PORT_ARM_CORTEX_A9 15 No Any + *****************************************************************************/ -#define EVENT_BUFFER_SIZE 4000 /* Adjust wrt. to available RAM */ +#ifndef WIN32 + // Set the port setting here! + #define SELECTED_PORT PORT_NOT_SET + #if (SELECTED_PORT == PORT_NOT_SET) + #error "You need to define SELECTED_PORT here!" + #endif +#else + // For Win32 demo projects this is set automatically + #define SELECTED_PORT PORT_Win32 +#endif -/******************************************************************************* - * USE_LINKER_PRAGMA - * - * Macro which should be defined as an integer value, default is 0. - * - * If this is 1, the header file "recorderdata_linker_pragma.h" is included just - * before the declaration of RecorderData (in trcBase.c), i.e., the trace data - * structure. This allows the user to specify a pragma with linker options. - * - * Example (for IAR Embedded Workbench and NXP LPC17xx): - * #pragma location="AHB_RAM_MEMORY" +/****************************************************************************** + * FREERTOS_VERSION * - * This example instructs the IAR linker to place RecorderData in another RAM - * bank, the AHB RAM. This can also be used for other compilers with a similar - * pragmas for linker options. + * Specify what version of FreeRTOS that is used. This is necessary compensate + * for renamed symbols in the FreeRTOS kernel (does not build if incorrect). * - * Note that this only applies if using static allocation, see below. - ******************************************************************************/ - -#define USE_LINKER_PRAGMA 0 - + * FREERTOS_VERSION_7_3_OR_7_4 (= 1) If using FreeRTOS v7.3.0 - v7.4.2 + * FREERTOS_VERSION_7_5_OR_7_6 (= 2) If using FreeRTOS v7.5.0 - v7.6.0 + * FREERTOS_VERSION_8_0_OR_LATER (= 3) If using FreeRTOS v8.0.0 or later + *****************************************************************************/ +#define FREERTOS_VERSION FREERTOS_VERSION_8_0_OR_LATER -/******************************************************************************* - * SYMBOL_TABLE_SIZE +/****************************************************************************** + * TRACE_RECORDER_STORE_MODE * - * Macro which should be defined as an integer value. + * Macro which should be defined as one of: + * - TRACE_STORE_MODE_RING_BUFFER + * - TRACE_STORE_MODE_STOP_WHEN_FULL + * Default is TRACE_STORE_MODE_RING_BUFFER. * - * This defines the capacity of the symbol table, in bytes. This symbol table - * stores User Events labels and names of deleted tasks, queues, or other kernel - * objects. Note that the names of active objects not stored here but in the - * Object Table. Thus, if you don't use User Events or delete any kernel - * objects you set this to a very low value, e.g. 4, but not zero (0) since - * this causes a declaration of a zero-sized array, for which the C compiler - * behavior is not standardized and may cause misaligned data. - ******************************************************************************/ -#define SYMBOL_TABLE_SIZE 800 - -#if (SYMBOL_TABLE_SIZE == 0) -#error "SYMBOL_TABLE_SIZE may not be zero!" -#endif + * With TRACE_RECORDER_STORE_MODE set to TRACE_STORE_MODE_RING_BUFFER, the + * events are stored in a ring buffer, i.e., where the oldest events are + * overwritten when the buffer becomes full. This allows you to get the last + * events leading up to an interesting state, e.g., an error, without having + * to store the whole run since startup. + * + * When TRACE_RECORDER_STORE_MODE is TRACE_STORE_MODE_STOP_WHEN_FULL, the + * recording is stopped when the buffer becomes full. This is useful for + * recording events following a specific state, e.g., the startup sequence. + *****************************************************************************/ +#define TRACE_RECORDER_STORE_MODE TRACE_STORE_MODE_STOP_WHEN_FULL /******************************************************************************* - * USE_SEPARATE_USER_EVENT_BUFFER + * TRACE_SCHEDULING_ONLY * * Macro which should be defined as an integer value. - * Default is zero (0). * - * This enables and disables the use of the separate user event buffer. + * If this setting is enabled (= 1), only scheduling events are recorded. + * If disabled (= 0), all events are recorded. * - * Note: When using the separate user event buffer, you may get an artificial - * task instance named "Unknown actor". This is added as a placeholder when the - * user event history is longer than the task scheduling history. - ******************************************************************************/ -#define USE_SEPARATE_USER_EVENT_BUFFER 0 - -/******************************************************************************* - * USER_EVENT_BUFFER_SIZE + * Users of FreeRTOS+Trace Free Edition only displays scheduling events, so this + * option can be used to avoid storing unsupported events. * - * Macro which should be defined as an integer value. + * Default value is 0 (store all enabled events). * - * This defines the capacity of the user event buffer, in number of slots. - * A single user event can use between 1 and X slots, depending on the data. - * - * Only in use if USE_SEPARATE_USER_EVENT_BUFFER is set to 1. ******************************************************************************/ -#define USER_EVENT_BUFFER_SIZE 10 +#define TRACE_SCHEDULING_ONLY 0 /******************************************************************************* - * USER_EVENT_CHANNELS + * EVENT_BUFFER_SIZE * * Macro which should be defined as an integer value. * - * This defines the number of allowed user event channels. - * - * Only in use if USE_SEPARATE_USER_EVENT_BUFFER is set to 1. + * This defines the capacity of the event buffer, i.e., the number of records + * it may store. Most events use one record (4 byte), although some events + * require multiple 4-byte records. You should adjust this to the amount of RAM + * available in the target system. + * + * Default value is 1000, which means that 4000 bytes is allocated for the + * event buffer. ******************************************************************************/ -#define CHANNEL_FORMAT_PAIRS 32 +#define EVENT_BUFFER_SIZE 1000 /******************************************************************************* * NTask, NISR, NQueue, NSemaphore, NMutex * - * A group of Macros which should be defined as an integer value of zero (0) - * or larger. + * A group of macros which should be defined as integer values, zero or larger. * - * This defines the capacity of the Object Property Table - the maximum number - * of objects active at any given point within each object class. + * These define the capacity of the Object Property Table, i.e., the maximum + * number of objects active at any given point, within each object class (e.g., + * task, queue, semaphore, ...). * - * NOTE: In case objects are deleted and created during runtime, this setting - * does not limit the total amount of objects, only the number of concurrently - * active objects. + * If tasks or other other objects are deleted in your system, this + * setting does not limit the total amount of objects created, only the number + * of objects that have been successfully created but not yet deleted. * - * Using too small values will give an error message through the vTraceError - * routine, which makes the error message appear when opening the trace data - * in Tracealyzer. If you are using the recorder status monitor task, - * any error messages are displayed in console prints, assuming that the - * print macro has been defined properly (vConsolePrintMessage). + * Using too small values will cause vTraceError to be called, which stores an + * error message in the trace that is shown when opening the trace file. * - * It can be wise to start with very large values for these constants, + * It can be wise to start with large values for these constants, * unless you are very confident on these numbers. Then do a recording and - * check the actual usage in Tracealyzer. This is shown by selecting - * View -> Trace Details -> Resource Usage -> Object Table - * - * NOTE 2: Remember to account for all tasks and other objects created by - * the kernel, such as the IDLE task, any timer tasks, and any tasks created - * by other 3rd party software components, such as communication stacks. - * Moreover, one task slot is used to indicate "(startup)", i.e., a fictive - * task that represent the time before the scheduler starts. - * NTask should thus be at least 2-3 slots larger than your application task count. - * + * check the actual usage by selecting View menu -> Trace Details -> + * Resource Usage -> Object Table. ******************************************************************************/ -#define NTask 15 -#define NISR 5 -#define NQueue 10 -#define NSemaphore 10 -#define NMutex 10 -#define NTimer 2 -#define NEventGroup 2 - -/* Maximum object name length for each class (includes zero termination) */ -#define NameLenTask 15 -#define NameLenISR 15 -#define NameLenQueue 15 -#define NameLenSemaphore 15 -#define NameLenMutex 15 -#define NameLenTimer 15 -#define NameLenEventGroup 15 - -/****************************************************************************** - * TRACE_DESCRIPTION - * - * Macro which should be defined as a string. - * - * This string is stored in the trace and displayed in Tracealyzer. Can be - * used to store, e.g., system version or build date. This is also used to store - * internal error messages from the recorder, which if occurs overwrites the - * value defined here. This may be maximum 256 chars. - *****************************************************************************/ -#define TRACE_DESCRIPTION "Tracealyzer Recorder Test Program" - -/****************************************************************************** - * TRACE_DESCRIPTION_MAX_LENGTH - * - * The maximum length (including zero termination) for the TRACE_DESCRIPTION - * string. Since this string also is used for internal error messages from the - * recorder do not make it too short, as this may truncate the error messages. - * Default is 80. - * Maximum allowed length is 256 - the trace will fail to load if longer. - *****************************************************************************/ -#define TRACE_DESCRIPTION_MAX_LENGTH 80 - +#define NTask 15 +#define NISR 5 +#define NQueue 10 +#define NSemaphore 10 +#define NMutex 10 +#define NTimer 2 +#define NEventGroup 2 /****************************************************************************** - * TRACE_DATA_ALLOCATION - * - * This defines how to allocate the recorder data structure, i.e., using a - * static declaration or using a dynamic allocation in runtime (malloc). - * - * Should be one of these two options: - * - TRACE_DATA_ALLOCATION_STATIC (default) - * - TRACE_DATA_ALLOCATION_DYNAMIC - * - * Using static allocation has the benefits of compile-time errors if the buffer - * is too large (too large constants in trcConfig.h) and no need to call the - * initialization routine (xTraceInitTraceData). - * - * Using dynamic allocation may give more flexibility in some cases. - *****************************************************************************/ - -#define TRACE_DATA_ALLOCATION TRACE_DATA_ALLOCATION_STATIC - - -/****************************************************************************** - * CONFIGURATION REGARDING WHAT CODE/FEATURES TO INCLUDE - *****************************************************************************/ - -/****************************************************************************** - * USE_TRACE_ASSERT - * - * Macro which should be defined as either zero (0) or one (1). - * Default is 0. - * - * If this is one (1), the TRACE_ASSERT macro will verify that a condition is - * true. If the condition is false, vTraceError() will be called. - *****************************************************************************/ -#define USE_TRACE_ASSERT 1 - -/****************************************************************************** - * INCLUDE_FLOAT_SUPPORT - * + * INCLUDE_MEMMANG_EVENTS + * * Macro which should be defined as either zero (0) or one (1). - * Default is 1. * - * If this is zero (0), all references to floating point values are removed, - * in case floating point values are not supported by the platform used. - * Floating point values are only used in vTracePrintF and its subroutines, to - * store float (%f) or double (%lf) argments. + * This controls if malloc and free calls should be traced. Set this to zero to + * exclude malloc/free calls, or one (1) to include such events in the trace. * - * Note: vTracePrintF can still be used with integer and string arguments in - * either case. + * Default value is 1. *****************************************************************************/ -#define INCLUDE_FLOAT_SUPPORT 1 +#define INCLUDE_MEMMANG_EVENTS 1 /****************************************************************************** * INCLUDE_USER_EVENTS * * Macro which should be defined as either zero (0) or one (1). - * Default is 1. * * If this is zero (0) the code for creating User Events is excluded to * reduce code size. User Events are application-generated events, like @@ -274,19 +199,40 @@ * much faster than a printf and can therefore be used in timing critical code. * See vTraceUserEvent() and vTracePrintF() in trcUser.h * - * Note that User Events are not displayed in FreeRTOS+Trace Free Edition. + * Default value is 1. + * + * Note that User Events are only displayed in Professional Edition. *****************************************************************************/ #define INCLUDE_USER_EVENTS 1 +/***************************************************************************** + * INCLUDE_ISR_TRACING + * + * Macro which should be defined as either zero (0) or one (1). + * + * If this is zero (0), the code for recording Interrupt Service Routines is + * excluded to reduce code size. + * + * Default value is 1. + * + * Note, if the kernel has no central interrupt dispatcher, recording ISRs + * require that you insert calls to vTraceStoreISRBegin and vTraceStoreISREnd + * in your interrupt handlers. + *****************************************************************************/ +#define INCLUDE_ISR_TRACING 1 + /***************************************************************************** * INCLUDE_READY_EVENTS * * Macro which should be defined as either zero (0) or one (1). - * Default is 1. * - * If this is zero (0), the code for recording Ready events is - * excluded. Note, this will make it impossible to calculate the correct - * response times. + * If one (1), events are recorded when tasks enter scheduling state "ready". + * This uses a lot of space in the event buffer, so excluding "ready events" + * will allow for longer traces. Including ready events however allows for + * showing the initial pending time before tasks enter the execution state, and + * for presenting accurate response times. + * + * Default value is 1. *****************************************************************************/ #define INCLUDE_READY_EVENTS 1 @@ -294,106 +240,137 @@ * INCLUDE_NEW_TIME_EVENTS * * Macro which should be defined as either zero (0) or one (1). - * Default is 0. * - * If this is zero (1), events will be generated whenever the os clock is + * If this is zero (1), events will be generated whenever the OS clock is * increased. + * + * Default value is 0. *****************************************************************************/ #define INCLUDE_NEW_TIME_EVENTS 0 -/***************************************************************************** - * INCLUDE_ISR_TRACING +/****************************************************************************** + * INCLUDE_FLOAT_SUPPORT * * Macro which should be defined as either zero (0) or one (1). - * Default is 1. * - * If this is zero (0), the code for recording Interrupt Service Routines is - * excluded to reduce code size. - * - * Note, if the kernel has no central interrupt dispatcher, recording ISRs - * require that you insert calls to vTraceStoreISRBegin and vTraceStoreISREnd - * in your interrupt handlers. + * If this is zero (0), all references to floating point values are removed, + * in case floating point values are not supported by the platform used. + * Floating point values are only used in vTracePrintF and its subroutines, to + * store float (%f) or double (%lf) arguments. + * + * vTracePrintF can be used with integer and string arguments in either case. + * + * Default value is 1. *****************************************************************************/ -#define INCLUDE_ISR_TRACING 1 +#define INCLUDE_FLOAT_SUPPORT 1 /****************************************************************************** * INCLUDE_OBJECT_DELETE * * Macro which should be defined as either zero (0) or one (1). - * Default is 1. * * This must be enabled (1) if tasks, queues or other * traced kernel objects are deleted at runtime. If no deletes are made, this * can be set to 0 in order to exclude the delete-handling code. + * + * Default value is 1. *****************************************************************************/ #define INCLUDE_OBJECT_DELETE 1 -/****************************************************************************** - * INCLUDE_MEMMANG_EVENTS - * - * Macro which should be defined as either zero (0) or one (1). - * Default is 1. +/******************************************************************************* + * SYMBOL_TABLE_SIZE * - * This controls if malloc and free calls should be traced. Set this to zero to - * exclude malloc/free calls from the tracing. - *****************************************************************************/ -#define INCLUDE_MEMMANG_EVENTS 1 + * Macro which should be defined as an integer value. + * + * This defines the capacity of the symbol table, in bytes. This symbol table + * stores User Events labels and names of deleted tasks, queues, or other kernel + * objects. If you don't use User Events or delete any kernel + * objects you set this to a very low value. The minimum recommended value is 4. + * A size of zero (0) is not allowed since a zero-sized array may result in a + * 32-bit pointer, i.e., using 4 bytes rather than 0. + * + * Default value is 800. + ******************************************************************************/ +#define SYMBOL_TABLE_SIZE 800 + +#if (SYMBOL_TABLE_SIZE == 0) +#error "SYMBOL_TABLE_SIZE may not be zero!" +#endif /****************************************************************************** - * CONFIGURATION RELATED TO BEHAVIOR + * NameLenTask, NameLenQueue, ... + * + * Macros that specify the maximum lengths (number of characters) for names of + * kernel objects, such as tasks and queues. If longer names are used, they will + * be truncated when stored in the recorder. *****************************************************************************/ +#define NameLenTask 15 +#define NameLenISR 15 +#define NameLenQueue 15 +#define NameLenSemaphore 15 +#define NameLenMutex 15 +#define NameLenTimer 15 +#define NameLenEventGroup 15 /****************************************************************************** - * TRACE_RECORDER_STORE_MODE + * TRACE_DATA_ALLOCATION * - * Macro which should be defined as one of: - * - TRACE_STORE_MODE_RING_BUFFER - * - TRACE_STORE_MODE_STOP_WHEN_FULL - * Default is TRACE_STORE_MODE_RING_BUFFER. + * This defines how to allocate the recorder data structure, i.e., using a + * static declaration or using a dynamic allocation in runtime (malloc). + * + * Should be one of these two options: + * - TRACE_DATA_ALLOCATION_STATIC (default) + * - TRACE_DATA_ALLOCATION_DYNAMIC + * + * Using static allocation has the benefits of compile-time errors if the buffer + * is too large (too large constants in trcConfig.h) and no need to call the + * initialization routine (xTraceInitTraceData). * - * With TRACE_RECORDER_STORE_MODE set to TRACE_STORE_MODE_RING_BUFFER, the events are - * stored in a ring buffer, i.e., where the oldest events are overwritten when - * the buffer becomes full. This allows you to get the last events leading up - * to an interesting state, e.g., an error, without having a large trace buffer - * for string the whole run since startup. In this mode, the recorder can run - * "forever" as the buffer never gets full, i.e., in the sense that it always - * has room for more events. - * - * To fetch the trace in mode TRACE_STORE_MODE_RING_BUFFER, you need to first halt the - * system using your debugger and then do a RAM dump, or to explicitly stop the - * recorder using vTraceStop() and then store/upload the trace data using a - * task that you need to provide yourself. The trace data is found in the struct - * RecorderData, initialized in trcBase.c. - * - * Note that, if you upload the trace using a RAM dump, i.e., when the system is - * halted on a breakpoint or by a debugger command, there is no need to stop the - * recorder first. - * - * When TRACE_RECORDER_STORE_MODE is TRACE_STORE_MODE_STOP_WHEN_FULL, the recording is - * stopped when the buffer becomes full. When the recorder stops itself this way - * vTracePortEnd() is called which allows for custom actions, such as triggering - * a task that stores the trace buffer, i.e., in case taking a RAM dump - * using an on-chip debugger is not possible. In the Windows port, vTracePortEnd - * saves the trace to file directly, but this is not recommended in a real-time - * system since the scheduler is blocked during the processing of vTracePortEnd. + * Using dynamic allocation may give more flexibility in some cases. *****************************************************************************/ +#define TRACE_DATA_ALLOCATION TRACE_DATA_ALLOCATION_STATIC + -#define TRACE_RECORDER_STORE_MODE TRACE_STORE_MODE_RING_BUFFER /****************************************************************************** - * STOP_AFTER_N_EVENTS + *** ADVANCED SETTINGS ******************************************************** + ****************************************************************************** + * The remaining settings are not necessary to modify but allows for optimizing + * the recorder setup for your specific needs, e.g., to exclude events that you + * are not interested in, in order to get longer traces. + *****************************************************************************/ + +/****************************************************************************** +* HEAP_SIZE_BELOW_16M +* +* An integer constant that can be used to reduce the buffer usage of memory +* allocation events (malloc/free). This value should be 1 if the heap size is +* below 16 MB (2^24 byte), and you can live with reported addresses showing the +* lower 24 bits only. If 0, you get the full 32-bit addresses. +* +* Default value is 0. +******************************************************************************/ +#define HEAP_SIZE_BELOW_16M 0 + +/****************************************************************************** + * USE_LINKER_PRAGMA * - * Macro which should be defined as an integer value, or not defined. - * Default is -1 + * Macro which should be defined as an integer value, default is 0. * - * STOP_AFTER_N_EVENTS is intended for tests of the ring buffer mode (when - * RECORDER_STORE_MODE is STORE_MODE_RING_BUFFER). It stops the recording when - * the specified number of events has been observed. This value can be larger - * than the buffer size, to allow for test of the "wrapping around" that occurs - * in ring buffer mode . A negative value (or no definition of this macro) - * disables this feature. - *****************************************************************************/ -#define STOP_AFTER_N_EVENTS -1 + * If this is 1, the header file "recorderdata_linker_pragma.h" is included just + * before the declaration of RecorderData (in trcBase.c), i.e., the trace data + * structure. This allows the user to specify a pragma with linker options. + * + * Example (for IAR Embedded Workbench and NXP LPC17xx): + * #pragma location="AHB_RAM_MEMORY" + * + * This example instructs the IAR linker to place RecorderData in another RAM + * bank, the AHB RAM. This can also be used for other compilers with a similar + * pragmas for linker options. + * + * Note that this only applies if using static allocation, see below. + ******************************************************************************/ +#define USE_LINKER_PRAGMA 0 /****************************************************************************** * USE_IMPLICIT_IFE_RULES @@ -401,57 +378,27 @@ * Macro which should be defined as either zero (0) or one (1). * Default is 1. * - * ### Instance Finish Events (IFE) ### - * - * For tasks with "infinite" main loops (non-terminating tasks), the concept - * of a task instance has no clear definition, it is an application-specific - * thing. Tracealyzer allows you to define Instance Finish Events (IFEs), - * which marks the point in a cyclic task when the "task instance" ends. - * The IFE is a blocking kernel call, typically in the main loop of a task - * which typically reads a message queue, waits for a semaphore or performs - * an explicit delay. - * - * If USE_IMPLICIT_IFE_RULES is one (1), the kernel macros (trcKernelPort.h) - * will define what kernel calls are considered by default to be IFEs. - * - * However, Implicit IFEs only applies to blocking kernel calls. If a - * service reads a message without blocking, it does not create a new - * instance since no blocking occurred. + * Tracealyzer groups the events into actor instances, based on context-switches + * and a definition of "Instance Finish Events", or IFEs. These are kernel calls + * considered to be the last event in a task instance. Some kernel calls are + * considered IFEs by default (e.g., delay functions), but it is also possible + * to specify this individually for each task (see vTraceTaskInstanceFinish). * - * Moreover, the actual IFE might sometimes be another blocking call. We - * therefore allow for user-defined Explicit IFEs by calling + * If USE_IMPLICIT_IFE_RULES is one (1), the default IFEs will be enabled, which + * gives a "typical" grouping of events into instances. You can combine this + * with calls to vTraceTaskInstanceFinish for specific tasks. * - * vTraceTaskInstanceIsFinished() - * - * right before the kernel call considered as IFE. This does not create an - * additional event but instead stores the service code and object handle - * of the IFE call as properties of the task. - * - * If using Explicit IFEs and the task also calls an Implicit IFE, this may - * result in additional incorrect task instances. - * This is solved by disabling the Implicit IFEs for the task, by adding - * a call to - * - * vTraceTaskSkipDefaultInstanceFinishedEvents() - * - * in the very beginning of that task. This allows you to combine Explicit IFEs - * for some tasks with Implicit IFEs for the rest of the tasks, if - * USE_IMPLICIT_IFE_RULES is 1. - * - * By setting USE_IMPLICIT_IFE_RULES to zero (0), the implicit IFEs are disabled - * for all tasks. Tasks will then be considered to have a single instance only, - * covering all execution fragments, unless you define an explicit IFE in each - * task by calling vTraceTaskInstanceIsFinished before the blocking call. + * If USE_IMPLICIT_IFE_RULES is zero (0), the implicit IFEs are disabled and all + * events withing each task is then shown as a single instance, unless you call + * vTraceTaskInstanceFinish() at suitable locations to mark the IFEs. *****************************************************************************/ #define USE_IMPLICIT_IFE_RULES 1 - /****************************************************************************** * USE_16BIT_OBJECT_HANDLES * * Macro which should be defined as either zero (0) or one (1). - * Default is 0. - * + * * If set to 0 (zero), the recorder uses 8-bit handles to identify kernel * objects such as tasks and queues. This limits the supported number of * concurrently active objects to 255 of each type (object class). @@ -462,69 +409,67 @@ * object property table is limited to 64 KB, the practical limit is about * 3000 objects in total. * - * NOTE: An object with a high ID (> 255) will generate an extra event - * (= 4 byte) in the event buffer. - * - * NOTE: Some internal tables in the recorder gets larger when using 16-bit - * handles. The additional RAM usage is 5-10 byte plus 1 byte per kernel object - *, i.e., task, queue, semaphore, mutex, etc. + * Default is 0. + * + * NOTE: An object with handle above 255 will use an extra 4-byte record in + * the event buffer whenever referenced. Moreover, some internal tables in the + * recorder gets larger when using 16-bit handles. The additional RAM usage is + * 5-10 byte plus 1 byte per kernel object i.e., task, queue, mutex, etc. *****************************************************************************/ #define USE_16BIT_OBJECT_HANDLES 0 -/****** Port Name ******************** Code ** Official ** OS Platform ****** -* PORT_APPLICATION_DEFINED -2 - - -* PORT_NOT_SET -1 - - -* PORT_HWIndependent 0 Yes Any -* PORT_Win32 1 Yes FreeRTOS Win32 -* PORT_Atmel_AT91SAM7 2 No Any -* PORT_Atmel_UC3A0 3 No Any -* PORT_ARM_CortexM 4 Yes Any -* PORT_Renesas_RX600 5 Yes Any -* PORT_Microchip_dsPIC_AND_PIC24 6 Yes Any -* PORT_TEXAS_INSTRUMENTS_TMS570 7 No Any -* PORT_TEXAS_INSTRUMENTS_MSP430 8 No Any -* PORT_MICROCHIP_PIC32 9 No Any -* PORT_XILINX_PPC405 10 No FreeRTOS -* PORT_XILINX_PPC440 11 No FreeRTOS -* PORT_XILINX_MICROBLAZE 12 No Any -* PORT_NXP_LPC210X 13 No Any -*****************************************************************************/ -#define SELECTED_PORT PORT_ARM_CortexM - -#if (SELECTED_PORT == PORT_NOT_SET) -#error "You need to define SELECTED_PORT here!" -#endif - /****************************************************************************** -* USE_PRIMASK_CS (for Cortex M devices only) -* -* An integer constant that selects between two options for the critical -* sections of the recorder library. + * USE_TRACE_ASSERT * -* 0: The default FreeRTOS critical section (BASEPRI) - default setting -* 1: Always disable ALL interrupts (using PRIMASK) + * Macro which should be defined as either zero (0) or one (1). + * Default is 1. * -* Option 0 uses the standard FreeRTOS macros for critical sections. -* However, on Cortex-M devices they only disable interrupts with priorities -* below a certain configurable level, while higher priority ISRs remain active. -* Such high-priority ISRs may not use the recorder functions in this mode. -* -* Option 1 allows you to safely call the recorder from any ISR, independent of -* the interrupt priority. This mode may however cause higher IRQ latencies -* (some microseconds) since ALL configurable interrupts are disabled during -* the recorder's critical sections in this mode, using the PRIMASK register. + * If this is one (1), the TRACE_ASSERT macro will verify that a condition is + * true. If the condition is false, vTraceError() will be called. + * This is used on several places in the recorder code for sanity checks on + * parameters. Can be switched off to reduce CPU usage of the tracing. + *****************************************************************************/ +#define USE_TRACE_ASSERT 1 + +/******************************************************************************* + * USE_SEPARATE_USER_EVENT_BUFFER + * + * Macro which should be defined as an integer value. + * Default is zero (0). + * + * This enables and disables the use of the separate user event buffer. Using + * this separate buffer has the benefit of not overwriting the user events with + * kernel events (usually generated at a much higher rate), i.e., when using + * ring-buffer mode. + * + * Note: When using the separate user event buffer, you may get an artificial + * task instance named "Unknown actor". This is added as a placeholder when the + * user event history is longer than the task scheduling history. ******************************************************************************/ -#define USE_PRIMASK_CS 0 +#define USE_SEPARATE_USER_EVENT_BUFFER 0 -/****************************************************************************** -* HEAP_SIZE_BELOW_16M -* -* An integer constant that can be used to reduce the buffer usage of memory -* allocation events (malloc/free). This value should be 1 if the heap size is -* below 16 MB (2^24 byte), and you can live with addresses truncated to the -* lower 24 bit. Otherwise set it to 0 to get the full 32-bit addresses. -******************************************************************************/ -#define HEAP_SIZE_BELOW_16M 0 +/******************************************************************************* + * USER_EVENT_BUFFER_SIZE + * + * Macro which should be defined as an integer value. + * + * This defines the capacity of the user event buffer, in number of slots. + * A single user event can use between 1 and X slots, depending on the data. + * + * Only in use if USE_SEPARATE_USER_EVENT_BUFFER is set to 1. + ******************************************************************************/ +#define USER_EVENT_BUFFER_SIZE 10 + +/******************************************************************************* + * USER_EVENT_CHANNELS + * + * Macro which should be defined as an integer value. + * + * This defines the number of allowed user event channels. + * + * Only in use if USE_SEPARATE_USER_EVENT_BUFFER is set to 1. + ******************************************************************************/ +#define CHANNEL_FORMAT_PAIRS 32 #endif diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcBase.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcBase.h index b3e522d51..889299688 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcBase.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcBase.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Tracealyzer v2.6.0 Recorder Library + * Tracealyzer v2.7.0 Recorder Library * Percepio AB, www.percepio.com * * trcBase.h @@ -31,7 +31,9 @@ * damages, or the exclusion of implied warranties or limitations on how long an * implied warranty may last, so the above limitations may not apply to you. * - * Copyright Percepio AB, 2013. + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2014. * www.percepio.com ******************************************************************************/ @@ -99,20 +101,20 @@ extern uint8_t excludedEventCodes[NEventCodes / 8 + 1]; *****************************************************************************/ typedef struct { - /* For each object class, the index of the next handle to allocate */ - uint16_t indexOfNextAvailableHandle[ TRACE_NCLASSES ]; + /* For each object class, the index of the next handle to allocate */ + uint16_t indexOfNextAvailableHandle[ TRACE_NCLASSES ]; - /* The lowest index of this class (constant) */ - uint16_t lowestIndexOfClass[ TRACE_NCLASSES ]; + /* The lowest index of this class (constant) */ + uint16_t lowestIndexOfClass[ TRACE_NCLASSES ]; - /* The highest index of this class (constant) */ - uint16_t highestIndexOfClass[ TRACE_NCLASSES ]; + /* The highest index of this class (constant) */ + uint16_t highestIndexOfClass[ TRACE_NCLASSES ]; - /* The highest use count for this class (for statistics) */ - uint16_t handleCountWaterMarksOfClass[ TRACE_NCLASSES ]; + /* The highest use count for this class (for statistics) */ + uint16_t handleCountWaterMarksOfClass[ TRACE_NCLASSES ]; - /* The free object handles - a set of stacks within this array */ - objectHandleType objectHandles[ TRACE_KERNEL_OBJECT_COUNT ]; + /* The free object handles - a set of stacks within this array */ + objectHandleType objectHandles[ TRACE_KERNEL_OBJECT_COUNT ]; } objectHandleStackType; @@ -136,47 +138,47 @@ extern objectHandleStackType objectHandleStacks; typedef struct { - /* = NCLASSES */ - uint32_t NumberOfObjectClasses; + /* = NCLASSES */ + uint32_t NumberOfObjectClasses; - uint32_t ObjectPropertyTableSizeInBytes; + uint32_t ObjectPropertyTableSizeInBytes; - /* This is used to calculate the index in the dynamic object table - (handle - 1 - nofStaticObjects = index)*/ + /* This is used to calculate the index in the dynamic object table + (handle - 1 - nofStaticObjects = index)*/ #if (USE_16BIT_OBJECT_HANDLES == 1) - objectHandleType NumberOfObjectsPerClass[2*((TRACE_NCLASSES+1)/2)]; + objectHandleType NumberOfObjectsPerClass[2*((TRACE_NCLASSES+1)/2)]; #else objectHandleType NumberOfObjectsPerClass[4*((TRACE_NCLASSES+3)/4)]; #endif - /* Allocation size rounded up to the closest multiple of 4 */ - uint8_t NameLengthPerClass[ 4*((TRACE_NCLASSES+3)/4) ]; + /* Allocation size rounded up to the closest multiple of 4 */ + uint8_t NameLengthPerClass[ 4*((TRACE_NCLASSES+3)/4) ]; - uint8_t TotalPropertyBytesPerClass[ 4*((TRACE_NCLASSES+3)/4) ]; + uint8_t TotalPropertyBytesPerClass[ 4*((TRACE_NCLASSES+3)/4) ]; - /* Allocation size rounded up to the closest multiple of 2 */ - uint16_t StartIndexOfClass[ 2*((TRACE_NCLASSES+1)/2) ]; + /* Allocation size rounded up to the closest multiple of 2 */ + uint16_t StartIndexOfClass[ 2*((TRACE_NCLASSES+1)/2) ]; - /* The actual handles issued, should be Initiated to all zeros */ - uint8_t objbytes[ 4*((TRACE_OBJECT_TABLE_SIZE+3)/4) ]; + /* The actual handles issued, should be Initiated to all zeros */ + uint8_t objbytes[ 4*((TRACE_OBJECT_TABLE_SIZE+3)/4) ]; } ObjectPropertyTableType; /* Symbol table data structure */ typedef struct { - /* = SYMBOL_HISTORY_TABLE_SIZE_IN_BYTES */ - uint32_t symTableSize; + /* = SYMBOL_HISTORY_TABLE_SIZE_IN_BYTES */ + uint32_t symTableSize; - /* Entry 0 is reserved. Any reference to entry 0 implies NULL*/ - uint32_t nextFreeSymbolIndex; + /* Entry 0 is reserved. Any reference to entry 0 implies NULL*/ + uint32_t nextFreeSymbolIndex; - /* Size rounded up to closest multiple of 4, to avoid alignment issues*/ - uint8_t symbytes[4*((SYMBOL_TABLE_SIZE+3)/4)]; + /* Size rounded up to closest multiple of 4, to avoid alignment issues*/ + uint8_t symbytes[4*((SYMBOL_TABLE_SIZE+3)/4)]; - /* Used for lookups - Up to 64 linked lists within the symbol table - connecting all entries with the same 6 bit checksum. - This field holds the current list heads. Should be initiated to zeros */ - uint16_t latestEntryOfChecksum[64]; + /* Used for lookups - Up to 64 linked lists within the symbol table + connecting all entries with the same 6 bit checksum. + This field holds the current list heads. Should be initiated to zeros */ + uint16_t latestEntryOfChecksum[64]; } symbolTableType; @@ -186,72 +188,80 @@ typedef struct typedef struct { - uint8_t type; - uint8_t objHandle; - uint16_t dts; /* differential timestamp - time since last event */ + uint8_t type; + uint8_t objHandle; + uint16_t dts; /* differential timestamp - time since last event */ } TSEvent, TREvent; typedef struct { uint8_t type; uint8_t dummy; - uint16_t dts; /* differential timestamp - time since last event */ + uint16_t dts; /* differential timestamp - time since last event */ } LPEvent; typedef struct { - uint8_t type; - uint8_t objHandle; - uint16_t dts; /* differential timestamp - time since last event */ + uint8_t type; + uint8_t objHandle; + uint16_t dts; /* differential timestamp - time since last event */ } KernelCall; typedef struct { - uint8_t type; - uint8_t objHandle; - uint8_t param; - uint8_t dts; /* differential timestamp - time since last event */ + uint8_t type; + uint8_t objHandle; + uint8_t param; + uint8_t dts; /* differential timestamp - time since last event */ } KernelCallWithParamAndHandle; typedef struct { - uint8_t type; - uint8_t dts; /* differential timestamp - time since last event */ - uint16_t param; + uint8_t type; + uint8_t dts; /* differential timestamp - time since last event */ + uint16_t param; } KernelCallWithParam16; typedef struct { - uint8_t type; - uint8_t objHandle; /* the handle of the closed object */ - uint16_t symbolIndex; /* the name of the closed object */ + uint8_t type; + uint8_t objHandle; /* the handle of the closed object */ + uint16_t symbolIndex; /* the name of the closed object */ } ObjCloseNameEvent; typedef struct { - uint8_t type; - uint8_t arg1; - uint8_t arg2; - uint8_t arg3; + uint8_t type; + uint8_t arg1; + uint8_t arg2; + uint8_t arg3; } ObjClosePropEvent; typedef struct { - uint8_t type; - uint8_t dts; - uint16_t payload; /* the name of the user event */ + uint8_t type; + uint8_t unused1; + uint8_t unused2; + uint8_t dts; +} TaskInstanceStatusEvent; + +typedef struct +{ + uint8_t type; + uint8_t dts; + uint16_t payload; /* the name of the user event */ } UserEvent; typedef struct { - uint8_t type; + uint8_t type; - /* 8 bits extra for storing DTS, if it does not fit in ordinary event - (this one is always MSB if used) */ - uint8_t xts_8; + /* 8 bits extra for storing DTS, if it does not fit in ordinary event + (this one is always MSB if used) */ + uint8_t xts_8; - /* 16 bits extra for storing DTS, if it does not fit in ordinary event. */ - uint16_t xts_16; + /* 16 bits extra for storing DTS, if it does not fit in ordinary event. */ + uint16_t xts_16; } XTSEvent; typedef struct @@ -309,110 +319,108 @@ typedef struct typedef struct { - uint8_t startmarker0; - uint8_t startmarker1; - uint8_t startmarker2; - uint8_t startmarker3; - uint8_t startmarker4; - uint8_t startmarker5; - uint8_t startmarker6; - uint8_t startmarker7; - uint8_t startmarker8; - uint8_t startmarker9; - uint8_t startmarker10; - uint8_t startmarker11; - - /* Used to determine Kernel and Endianess */ - uint16_t version; - - /* Currently 3, since v2.6.0 */ - uint8_t minor_version; + uint8_t startmarker0; + uint8_t startmarker1; + uint8_t startmarker2; + uint8_t startmarker3; + uint8_t startmarker4; + uint8_t startmarker5; + uint8_t startmarker6; + uint8_t startmarker7; + uint8_t startmarker8; + uint8_t startmarker9; + uint8_t startmarker10; + uint8_t startmarker11; + + /* Used to determine Kernel and Endianess */ + uint16_t version; - /* This should be 0 if lower IRQ priority values implies higher priority - levels, such as on ARM Cortex M. If the opposite scheme is used, i.e., - if higher IRQ priority values means higher priority, this should be 1. */ - uint8_t irq_priority_order; + /* Currently 3, since v2.6.0 */ + uint8_t minor_version; - /* sizeof(RecorderDataType) - just for control */ - uint32_t filesize; + /* This should be 0 if lower IRQ priority values implies higher priority + levels, such as on ARM Cortex M. If the opposite scheme is used, i.e., + if higher IRQ priority values means higher priority, this should be 1. */ + uint8_t irq_priority_order; - /* Current number of events recorded */ - uint32_t numEvents; + /* sizeof(RecorderDataType) - just for control */ + uint32_t filesize; - /* The buffer size, in number of event records */ - uint32_t maxEvents; + /* Current number of events recorded */ + uint32_t numEvents; - /* The event buffer index, where to write the next event */ - uint32_t nextFreeIndex; + /* The buffer size, in number of event records */ + uint32_t maxEvents; - /* 1 if the buffer is full, 0 otherwise */ - uint32_t bufferIsFull; + /* The event buffer index, where to write the next event */ + uint32_t nextFreeIndex; - /* The frequency of the clock/timer/counter used as time base */ - uint32_t frequency; + /* 1 if the buffer is full, 0 otherwise */ + uint32_t bufferIsFull; - /* The absolute timestamp of the last stored event, in the native - timebase, modulo frequency! */ - uint32_t absTimeLastEvent; + /* The frequency of the clock/timer/counter used as time base */ + uint32_t frequency; - /* The number of seconds in total - lasts for 136 years */ - uint32_t absTimeLastEventSecond; + /* The absolute timestamp of the last stored event, in the native + timebase, modulo frequency! */ + uint32_t absTimeLastEvent; - /* 1 if the recorder has been started, 0 if not yet started or stopped. - This is a 32 bit variable due to alignment issues. */ - uint32_t recorderActive; + /* The number of seconds in total - lasts for 136 years */ + uint32_t absTimeLastEventSecond; - /* Not used, remains for compatibility and future use */ - uint8_t notused[28]; + /* 1 if the recorder has been started, 0 if not yet started or stopped. + This is a 32 bit variable due to alignment issues. */ + uint32_t recorderActive; - /* The amount of heap memory remaining at the last malloc or free event */ + /* Not used, remains for compatibility and future use */ + uint8_t notused[28]; + + /* The amount of heap memory remaining at the last malloc or free event */ uint32_t heapMemUsage; - /* 0xF0F0F0F0 - for control only */ - int32_t debugMarker0; + /* 0xF0F0F0F0 - for control only */ + int32_t debugMarker0; /* Set to value of USE_16BIT_OBJECT_HANDLES */ uint32_t isUsing16bitHandles; - /* The Object Property Table holds information about currently active - tasks, queues, and other recorded objects. This is updated on each - create call and includes object name and other properties. */ - ObjectPropertyTableType ObjectPropertyTable; + /* The Object Property Table holds information about currently active + tasks, queues, and other recorded objects. This is updated on each + create call and includes object name and other properties. */ + ObjectPropertyTableType ObjectPropertyTable; - /* 0xF1F1F1F1 - for control only */ - int32_t debugMarker1; + /* 0xF1F1F1F1 - for control only */ + int32_t debugMarker1; - /* The Symbol Table stores strings for User Events and is also used to - store names of deleted objects, which still may be in the trace but no - longer are available. */ - symbolTableType SymbolTable; + /* The Symbol Table stores strings for User Events and is also used to + store names of deleted objects, which still may be in the trace but no + longer are available. */ + symbolTableType SymbolTable; - /* For inclusion of float support, and for endian detection of floats. - The value should be (float)1 or (uint32_t)0 */ + /* For inclusion of float support, and for endian detection of floats. + The value should be (float)1 or (uint32_t)0 */ #if (INCLUDE_FLOAT_SUPPORT == 1) - float exampleFloatEncoding; + float exampleFloatEncoding; #else - uint32_t exampleFloatEncoding; + uint32_t exampleFloatEncoding; #endif - /* This is non-zero if an internal error occurred in the recorder, e.g., if - one of the Nxxx constants was too small. The systemInfo string will then - contain an error message that is displayed when attempting to view the - trace file. */ - uint32_t internalErrorOccured; + /* This is non-zero if an internal error occurred in the recorder, e.g., if + one of the Nxxx constants was too small. The systemInfo string will then + contain an error message that is displayed when attempting to view the + trace file. */ + uint32_t internalErrorOccured; - /* 0xF2F2F2F2 - for control only */ - int32_t debugMarker2; + /* 0xF2F2F2F2 - for control only */ + int32_t debugMarker2; - /* Generic system information string, presented in the tool. Note that this - is also used for storing any internal error messages from the recorder, so - do not make TRACE_DESCRIPTION_MAX_LENGTH too small. 80 is recommended. */ - char systemInfo[TRACE_DESCRIPTION_MAX_LENGTH]; + /* Error messages from the recorder. */ + char systemInfo[80]; - /* 0xF3F3F3F3 - for control only */ - int32_t debugMarker3; + /* 0xF3F3F3F3 - for control only */ + int32_t debugMarker3; - /* The event data, in 4-byte records */ - uint8_t eventData[ EVENT_BUFFER_SIZE * 4 ]; + /* The event data, in 4-byte records */ + uint8_t eventData[ EVENT_BUFFER_SIZE * 4 ]; #if (USE_SEPARATE_USER_EVENT_BUFFER == 1) UserEventBuffer userEventBuffer; @@ -421,18 +429,18 @@ typedef struct /* This should always be 0 */ uint32_t endOfSecondaryBlocks; - uint8_t endmarker0; - uint8_t endmarker1; - uint8_t endmarker2; - uint8_t endmarker3; - uint8_t endmarker4; - uint8_t endmarker5; - uint8_t endmarker6; - uint8_t endmarker7; - uint8_t endmarker8; - uint8_t endmarker9; - uint8_t endmarker10; - uint8_t endmarker11; + uint8_t endmarker0; + uint8_t endmarker1; + uint8_t endmarker2; + uint8_t endmarker3; + uint8_t endmarker4; + uint8_t endmarker5; + uint8_t endmarker6; + uint8_t endmarker7; + uint8_t endmarker8; + uint8_t endmarker9; + uint8_t endmarker10; + uint8_t endmarker11; } RecorderDataType; extern RecorderDataType* RecorderDataPtr; @@ -444,14 +452,14 @@ uint16_t prvTraceGetDTS(uint16_t param_maxDTS); void prvTraceGetChecksum(const char *pname, uint8_t* pcrc, uint8_t* plength); traceLabel prvTraceCreateSymbolTableEntry(const char* name, - uint8_t crc6, - uint8_t len, - traceLabel channel); + uint8_t crc6, + uint8_t len, + traceLabel channel); traceLabel prvTraceLookupSymbolTableEntry(const char* name, - uint8_t crc6, - uint8_t len, - traceLabel channel); + uint8_t crc6, + uint8_t len, + traceLabel channel); traceLabel prvTraceOpenSymbol(const char* name, traceLabel userEventChannel); @@ -462,11 +470,11 @@ void prvCheckDataToBeOverwrittenForMultiEntryEvents(uint8_t nEntries); objectHandleType xTraceGetObjectHandle(traceObjectClass objectclass); void vTraceFreeObjectHandle(traceObjectClass objectclass, - objectHandleType handle); + objectHandleType handle); void vTraceSetObjectName(traceObjectClass objectclass, - objectHandleType handle, - const char* name); + objectHandleType handle, + const char* name); void* xTraceNextFreeEventBufferSlot(void); @@ -478,7 +486,7 @@ unsigned char prvTraceGet8BitHandle(objectHandleType handle); uint16_t uiIndexOfObject(objectHandleType objecthandle, - uint8_t objectclass); + uint8_t objectclass); /******************************************************************************* * vTraceError @@ -519,9 +527,6 @@ RecorderDataPtr->ObjectPropertyTable.objbytes[uiIndexOfObject(handle, objectclas #define TRACE_CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(eventCode) TRACE_CLEAR_FLAG_ISEXCLUDED(excludedEventCodes, eventCode) #define TRACE_GET_EVENT_CODE_FLAG_ISEXCLUDED(eventCode) TRACE_GET_FLAG_ISEXCLUDED(excludedEventCodes, eventCode) -#define TRACE_INCR_HEAP_USAGE(change) {if (RecorderDataPtr != NULL) RecorderDataPtr->heapMemUsage += change;} -#define TRACE_DECR_HEAP_USAGE(change) {if (RecorderDataPtr != NULL) RecorderDataPtr->heapMemUsage -= change;} - /* DEBUG ASSERTS */ #if defined USE_TRACE_ASSERT && USE_TRACE_ASSERT != 0 #define TRACE_ASSERT(eval, msg, defRetVal) \ @@ -536,4 +541,8 @@ if (!(eval)) \ #endif -#endif \ No newline at end of file +#endif + + + + diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcHardwarePort.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcHardwarePort.h index c66654e67..01ce3a590 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcHardwarePort.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcHardwarePort.h @@ -1,10 +1,10 @@ -/******************************************************************************* - * Tracealyzer v2.6.0 Recorder Library +/******************************************************************************* + * Tracealyzer v2.7.0 Recorder Library * Percepio AB, www.percepio.com * * trcHardwarePort.h * - * Contains together with trcHardwarePort.c all hardware portability issues of + * Contains together with trcHardwarePort.c all hardware portability issues of * the trace recorder library. * * Terms of Use @@ -12,27 +12,29 @@ * use together with Percepio products. You may distribute the recorder library * in its original form, including modifications in trcPort.c and trcPort.h * given that these modification are clearly marked as your own modifications - * and documented in the initial comment section of these source files. - * This software is the intellectual property of Percepio AB and may not be - * sold or in other ways commercially redistributed without explicit written + * and documented in the initial comment section of these source files. + * This software is the intellectual property of Percepio AB and may not be + * sold or in other ways commercially redistributed without explicit written * permission by Percepio AB. * - * Disclaimer - * The trace tool and recorder library is being delivered to you AS IS and - * Percepio AB makes no warranty as to its use or performance. Percepio AB does - * not and cannot warrant the performance or results you may obtain by using the - * software or documentation. Percepio AB make no warranties, express or - * implied, as to noninfringement of third party rights, merchantability, or - * fitness for any particular purpose. In no event will Percepio AB, its - * technology partners, or distributors be liable to you for any consequential, - * incidental or special damages, including any lost profits or lost savings, - * even if a representative of Percepio AB has been advised of the possibility - * of such damages, or for any claim by any third party. Some jurisdictions do - * not allow the exclusion or limitation of incidental, consequential or special - * damages, or the exclusion of implied warranties or limitations on how long an + * Disclaimer + * The trace tool and recorder library is being delivered to you AS IS and + * Percepio AB makes no warranty as to its use or performance. Percepio AB does + * not and cannot warrant the performance or results you may obtain by using the + * software or documentation. Percepio AB make no warranties, express or + * implied, as to noninfringement of third party rights, merchantability, or + * fitness for any particular purpose. In no event will Percepio AB, its + * technology partners, or distributors be liable to you for any consequential, + * incidental or special damages, including any lost profits or lost savings, + * even if a representative of Percepio AB has been advised of the possibility + * of such damages, or for any claim by any third party. Some jurisdictions do + * not allow the exclusion or limitation of incidental, consequential or special + * damages, or the exclusion of implied warranties or limitations on how long an * implied warranty may last, so the above limitations may not apply to you. * - * Copyright Percepio AB, 2013. + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2014. * www.percepio.com ******************************************************************************/ @@ -43,21 +45,21 @@ /* If Win32 port */ #ifdef WIN32 - #undef _WIN32_WINNT - #define _WIN32_WINNT 0x0600 + #undef _WIN32_WINNT + #define _WIN32_WINNT 0x0600 - /* Standard includes. */ - #include - #include - #include + /* Standard includes. */ + #include + #include + #include /******************************************************************************* * The Win32 port by default saves the trace to file and then kills the * program when the recorder is stopped, to facilitate quick, simple tests * of the recorder. ******************************************************************************/ - #define WIN32_PORT_SAVE_WHEN_STOPPED 1 - #define WIN32_PORT_EXIT_WHEN_STOPPED 1 + #define WIN32_PORT_SAVE_WHEN_STOPPED 1 + #define WIN32_PORT_EXIT_WHEN_STOPPED 1 #endif @@ -66,104 +68,106 @@ /****************************************************************************** * Supported ports - * + * * PORT_HWIndependent - * A hardware independent fallback option for event timestamping. Provides low + * A hardware independent fallback option for event timestamping. Provides low * resolution timestamps based on the OS tick. - * This may be used on the Win32 port, but may also be used on embedded hardware - * platforms. All time durations will be truncated to the OS tick frequency, - * typically 1 KHz. This means that a task or ISR that executes in less than + * This may be used on the Win32 port, but may also be used on embedded hardware + * platforms. All time durations will be truncated to the OS tick frequency, + * typically 1 KHz. This means that a task or ISR that executes in less than * 1 ms get an execution time of zero. * * PORT_APPLICATION_DEFINED * Allows for defining the port macros in other source code files. * * PORT_Win32 - * "Accurate" timestamping based on the Windows performance counter for Win32 + * "Accurate" timestamping based on the Windows performance counter for Win32 * builds. Note that this gives the host machine time, not the kernel time. * * Hardware specific ports - * To get accurate timestamping, a hardware timer is necessary. Below are the - * available ports. Some of these are "unofficial", meaning that - * they have not yet been verified by Percepio but have been contributed by - * external developers. They should work, otherwise let us know by emailing - * support@percepio.com. Some work on any OS platform, while other are specific + * To get accurate timestamping, a hardware timer is necessary. Below are the + * available ports. Some of these are "unofficial", meaning that + * they have not yet been verified by Percepio but have been contributed by + * external developers. They should work, otherwise let us know by emailing + * support@percepio.com. Some work on any OS platform, while other are specific * to a certain operating system. *****************************************************************************/ -/****** Port Name ******************** Code ** Official ** OS Platform *******/ -#define PORT_APPLICATION_DEFINED -2 /* - - */ -#define PORT_NOT_SET -1 /* - - */ -#define PORT_HWIndependent 0 /* Yes Any */ -#define PORT_Win32 1 /* Yes Windows (FreeRTOS)*/ -#define PORT_Atmel_AT91SAM7 2 /* No Any */ -#define PORT_Atmel_UC3A0 3 /* No Any */ -#define PORT_ARM_CortexM 4 /* Yes Any */ -#define PORT_Renesas_RX600 5 /* Yes Any */ -#define PORT_Microchip_dsPIC_AND_PIC24 6 /* Yes Any */ -#define PORT_TEXAS_INSTRUMENTS_TMS570 7 /* No Any */ -#define PORT_TEXAS_INSTRUMENTS_MSP430 8 /* No Any */ -#define PORT_MICROCHIP_PIC32 9 /* No Any */ -#define PORT_XILINX_PPC405 10 /* No FreeRTOS */ -#define PORT_XILINX_PPC440 11 /* No FreeRTOS */ -#define PORT_XILINX_MICROBLAZE 12 /* No Any */ -#define PORT_NXP_LPC210X 13 /* No Any */ - -#include "trcConfig.h" // Where SELECTED_PORT is defined +/****** Port Name ********************** Code ***** Official ** OS Platform *********/ +#define PORT_APPLICATION_DEFINED -2 /* - - */ +#define PORT_NOT_SET -1 /* - - */ +#define PORT_HWIndependent 0 /* Yes Any */ +#define PORT_Win32 1 /* Yes FreeRTOS on Win32 */ +#define PORT_Atmel_AT91SAM7 2 /* No Any */ +#define PORT_Atmel_UC3A0 3 /* No Any */ +#define PORT_ARM_CortexM 4 /* Yes Any */ +#define PORT_Renesas_RX600 5 /* Yes Any */ +#define PORT_Microchip_dsPIC_AND_PIC24 6 /* Yes Any */ +#define PORT_TEXAS_INSTRUMENTS_TMS570 7 /* No Any */ +#define PORT_TEXAS_INSTRUMENTS_MSP430 8 /* No Any */ +#define PORT_MICROCHIP_PIC32MX 9 /* Yes Any */ +#define PORT_XILINX_PPC405 10 /* No FreeRTOS */ +#define PORT_XILINX_PPC440 11 /* No FreeRTOS */ +#define PORT_XILINX_MICROBLAZE 12 /* No Any */ +#define PORT_NXP_LPC210X 13 /* No Any */ +#define PORT_MICROCHIP_PIC32MZ 14 /* Yes Any */ +#define PORT_ARM_CORTEX_A9 15 /* No Any */ + +#include "trcConfig.h" /******************************************************************************* * IRQ_PRIORITY_ORDER * * Macro which should be defined as an integer of 0 or 1. * - * This should be 0 if lower IRQ priority values implies higher priority - * levels, such as on ARM Cortex M. If the opposite scheme is used, i.e., + * This should be 0 if lower IRQ priority values implies higher priority + * levels, such as on ARM Cortex M. If the opposite scheme is used, i.e., * if higher IRQ priority values means higher priority, this should be 1. * - * This setting is not critical. It is used only to sort and colorize the + * This setting is not critical. It is used only to sort and colorize the * interrupts in priority order, in case you record interrupts using * the vTraceStoreISRBegin and vTraceStoreISREnd routines. * ****************************************************************************** * - * HWTC Macros + * HWTC Macros * - * These four HWTC macros provides a hardware isolation layer representing a - * generic hardware timer/counter used for driving the operating system tick, - * such as the SysTick feature of ARM Cortex M3/M4, or the PIT of the Atmel + * These four HWTC macros provides a hardware isolation layer representing a + * generic hardware timer/counter used for driving the operating system tick, + * such as the SysTick feature of ARM Cortex M3/M4, or the PIT of the Atmel * AT91SAM7X. * - * HWTC_COUNT: The current value of the counter. This is expected to be reset - * a each tick interrupt. Thus, when the tick handler starts, the counter has + * HWTC_COUNT: The current value of the counter. This is expected to be reset + * a each tick interrupt. Thus, when the tick handler starts, the counter has * already wrapped. * * HWTC_COUNT_DIRECTION: Should be one of: * - DIRECTION_INCREMENTING - for hardware timer/counters of incrementing type - * such as the PIT on Atmel AT91SAM7X. - * When the counter value reach HWTC_PERIOD, it is reset to zero and the - * interrupt is signaled. + * such as the PIT on Atmel AT91SAM7X. + * When the counter value reach HWTC_PERIOD, it is reset to zero and the + * interrupt is signaled. * - DIRECTION_DECREMENTING - for hardware timer/counters of decrementing type - * such as the SysTick on ARM Cortex M3/M4 chips. - * When the counter value reach 0, it is reset to HWTC_PERIOD and the - * interrupt is signaled. + * such as the SysTick on ARM Cortex M3/M4 chips. + * When the counter value reach 0, it is reset to HWTC_PERIOD and the + * interrupt is signaled. * * HWTC_PERIOD: The number of increments or decrements of HWTC_COUNT between * two OS tick interrupts. This should preferably be mapped to the reload - * register of the hardware timer, to make it more portable between chips in the + * register of the hardware timer, to make it more portable between chips in the * same family. The macro should in most cases be (reload register + 1). - * For FreeRTOS, this can in most cases be defined as + * For FreeRTOS, this can in most cases be defined as * #define HWTC_PERIOD (configCPU_CLOCK_HZ / configTICK_RATE_HZ) * * HWTC_DIVISOR: If the timer frequency is very high, like on the Cortex M chips - * (where the SysTick runs at the core clock frequency), the "differential - * timestamping" used in the recorder will more frequently insert extra XTS - * events to store the timestamps, which increases the event buffer usage. - * In such cases, to reduce the number of XTS events and thereby get longer + * (where the SysTick runs at the core clock frequency), the "differential + * timestamping" used in the recorder will more frequently insert extra XTS + * events to store the timestamps, which increases the event buffer usage. + * In such cases, to reduce the number of XTS events and thereby get longer * traces, you use HWTC_DIVISOR to scale down the timestamps and frequency. * Assuming a OS tick rate of 1 KHz, it is suggested to keep the effective timer * frequency below 65 MHz to avoid an excessive amount of XTS events. Thus, a - * Cortex M chip running at 72 MHZ should use a HWTC_DIVISOR of 2, while a - * faster chip require a higher HWTC_DIVISOR value. + * Cortex M chip running at 72 MHZ should use a HWTC_DIVISOR of 2, while a + * faster chip require a higher HWTC_DIVISOR value. * * The HWTC macros and vTracePortGetTimeStamp is the main porting issue * or the trace recorder library. Typically you should not need to change @@ -172,164 +176,172 @@ ******************************************************************************/ #if (SELECTED_PORT == PORT_Win32) - // This can be used as a template for any free-running 32-bit counter - #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING - #define HWTC_COUNT (ulGetRunTimeCounterValue()) - #define HWTC_PERIOD 0 - #define HWTC_DIVISOR 1 + // This can be used as a template for any free-running 32-bit counter + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT (ulGetRunTimeCounterValue()) + #define HWTC_PERIOD 0 + #define HWTC_DIVISOR 1 - // Please update according to your system... - #define IRQ_PRIORITY_ORDER 1 - -#elif (SELECTED_PORT == PORT_HWIndependent) - // OS Tick only (typically 1 ms resolution) - #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING - #define HWTC_COUNT 0 - #define HWTC_PERIOD 1 - #define HWTC_DIVISOR 1 - // Please update according to your system... - #define IRQ_PRIORITY_ORDER NOT_SET + #define IRQ_PRIORITY_ORDER 1 + +#elif (SELECTED_PORT == PORT_HWIndependent) + // OS Tick only (typically 1 ms resolution) + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT 0 + #define HWTC_PERIOD 1 + #define HWTC_DIVISOR 1 + + // Please update according to your system... + #define IRQ_PRIORITY_ORDER NOT_SET #elif (SELECTED_PORT == PORT_ARM_CortexM) - void prvTraceSetIRQMask(uint32_t priMask); - uint32_t prvTraceGetIRQMask(void); - - void prvTraceEnableIRQ(void); - void prvTraceDisableIRQ(void); - void prvTraceInitCortexM(void); - - #define PORT_SPECIFIC_INIT() prvTraceInitCortexM() - - extern uint32_t DWT_CYCLES_ADDED; - #define DWT_CTRL_REG (*((uint32_t*)0xE0001000)) - #define DWT_CYCLE_COUNTER (*((uint32_t*)0xE0001004)) - #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING - #define HWTC_COUNT (DWT_CYCLE_COUNTER + DWT_CYCLES_ADDED) - #define HWTC_PERIOD 0 - #define HWTC_DIVISOR 4 + #define REG_DEMCR (*(volatile unsigned int*)0xE000EDFC) + #define REG_DWT_CTRL (*(volatile unsigned int*)0xE0001000) + #define REG_DWT_CYCCNT (*(volatile unsigned int*)0xE0001004) + #define REG_DWT_EXCCNT (*(volatile unsigned int*)0xE000100C) + + /* Bit mask for TRCENA bit in DEMCR - Global enable for DWT and ITM */ + #define DEMCR_TRCENA (1 << 24) - #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant + /* Bit mask for NOPRFCNT bit in DWT_CTRL. If 1, DWT_EXCCNT is not supported */ + #define DWT_CTRL_NOPRFCNT (1 << 24) -#elif (SELECTED_PORT == PORT_Renesas_RX600) + /* Bit mask for NOCYCCNT bit in DWT_CTRL. If 1, DWT_CYCCNT is not supported */ + #define DWT_CTRL_NOCYCCNT (1 << 25) - #include "iodefine.h" + /* Bit mask for EXCEVTENA_ bit in DWT_CTRL. Set to 1 to enable DWT_EXCCNT */ + #define DWT_CTRL_EXCEVTENA (1 << 18) - #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING - #define HWTC_COUNT (CMT0.CMCNT) - #define HWTC_PERIOD (CMT0.CMCOR + 1) - #define HWTC_DIVISOR 1 - #define IRQ_PRIORITY_ORDER 1 // higher IRQ priority values are more significant + /* Bit mask for EXCEVTENA_ bit in DWT_CTRL. Set to 1 to enable DWT_CYCCNT */ + #define DWT_CTRL_CYCCNTENA (1) + + #define PORT_SPECIFIC_INIT() prvTraceInitCortexM() + + extern uint32_t DWT_CYCLES_ADDED; + + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT (REG_DWT_CYCCNT + DWT_CYCLES_ADDED) + #define HWTC_PERIOD 0 + #define HWTC_DIVISOR 4 + + #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant + +#elif (SELECTED_PORT == PORT_Renesas_RX600) + + #include "iodefine.h" + + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT (CMT0.CMCNT) + #define HWTC_PERIOD (CMT0.CMCOR + 1) + #define HWTC_DIVISOR 1 + #define IRQ_PRIORITY_ORDER 1 // higher IRQ priority values are more significant + +#elif (SELECTED_PORT == PORT_MICROCHIP_PIC32MX || PORT_MICROCHIP_PIC32MZ) + + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT (TMR1) + #define HWTC_PERIOD (PR1 + 1) + #define HWTC_DIVISOR 1 + #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant #elif (SELECTED_PORT == PORT_Microchip_dsPIC_AND_PIC24) - /* For Microchip PIC24 and dsPIC (16 bit) */ + /* For Microchip PIC24 and dsPIC (16 bit) */ - /* Note: The trace library is designed for 32-bit MCUs and is slower than - intended on 16-bit MCUs. Storing an event on a PIC24 takes about 70 usec. - In comparison, 32-bit MCUs are often 10-20 times faster. If recording overhead - becomes a problem on PIC24, use the filters to exclude less interesting tasks - or system calls. */ + /* Note: The trace library is designed for 32-bit MCUs and is slower than + intended on 16-bit MCUs. Storing an event on a PIC24 takes about 70 usec. + In comparison, this is 10-20 times faster on a 32-bit MCU... */ - #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING - #define HWTC_COUNT (TMR1) - #define HWTC_PERIOD (PR1+1) - #define HWTC_DIVISOR 1 - #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT (TMR1) + #define HWTC_PERIOD (PR1+1) + #define HWTC_DIVISOR 1 + #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant #elif (SELECTED_PORT == PORT_Atmel_AT91SAM7) - /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ - - #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING - #define HWTC_COUNT ((uint32_t)(AT91C_BASE_PITC->PITC_PIIR & 0xFFFFF)) - #define HWTC_PERIOD ((uint32_t)(AT91C_BASE_PITC->PITC_PIMR + 1)) - #define HWTC_DIVISOR 1 - #define IRQ_PRIORITY_ORDER 1 // higher IRQ priority values are more significant + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ + + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT ((uint32_t)(AT91C_BASE_PITC->PITC_PIIR & 0xFFFFF)) + #define HWTC_PERIOD ((uint32_t)(AT91C_BASE_PITC->PITC_PIMR + 1)) + #define HWTC_DIVISOR 1 + #define IRQ_PRIORITY_ORDER 1 // higher IRQ priority values are more significant #elif (SELECTED_PORT == PORT_Atmel_UC3A0) - /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ - /* For Atmel AVR32 (AT32UC3A).*/ - - #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING - #define HWTC_COUNT ((uint32_t)sysreg_read(AVR32_COUNT)) - #define HWTC_PERIOD ((uint32_t)(sysreg_read(AVR32_COMPARE) + 1)) - #define HWTC_DIVISOR 1 - #define IRQ_PRIORITY_ORDER 1 // higher IRQ priority values are more significant + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ + /* For Atmel AVR32 (AT32UC3A).*/ + + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT ((uint32_t)sysreg_read(AVR32_COUNT)) + #define HWTC_PERIOD ((uint32_t)(sysreg_read(AVR32_COMPARE) + 1)) + #define HWTC_DIVISOR 1 + #define IRQ_PRIORITY_ORDER 1 // higher IRQ priority values are more significant #elif (SELECTED_PORT == PORT_NXP_LPC210X) - /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ - /* Tested with LPC2106, but should work with most LPC21XX chips. */ - - #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING - #define HWTC_COUNT *((uint32_t *)0xE0004008 ) - #define HWTC_PERIOD *((uint32_t *)0xE0004018 ) - #define HWTC_DIVISOR 1 - #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ + /* Tested with LPC2106, but should work with most LPC21XX chips. */ -#elif (SELECTED_PORT == PORT_TEXAS_INSTRUMENTS_TMS570) - - /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ - - #define RTIFRC0 *((uint32_t *)0xFFFFFC10) - #define RTICOMP0 *((uint32_t *)0xFFFFFC50) - #define RTIUDCP0 *((uint32_t *)0xFFFFFC54) - #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING - #define HWTC_COUNT (RTIFRC0 - (RTICOMP0 - RTIUDCP0)) - #define HWTC_PERIOD (RTIUDCP0) - #define HWTC_DIVISOR 1 + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT *((uint32_t *)0xE0004008 ) + #define HWTC_PERIOD *((uint32_t *)0xE0004018 ) + #define HWTC_DIVISOR 1 + #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant - #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant +#elif (SELECTED_PORT == PORT_TEXAS_INSTRUMENTS_TMS570) -#elif (SELECTED_PORT == PORT_TEXAS_INSTRUMENTS_MSP430) + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ - /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ + #define RTIFRC0 *((uint32_t *)0xFFFFFC10) + #define RTICOMP0 *((uint32_t *)0xFFFFFC50) + #define RTIUDCP0 *((uint32_t *)0xFFFFFC54) + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT (RTIFRC0 - (RTICOMP0 - RTIUDCP0)) + #define HWTC_PERIOD (RTIUDCP0) + #define HWTC_DIVISOR 1 - #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING - #define HWTC_COUNT (TA0R) - #define HWTC_PERIOD (((uint16_t)TACCR0)+1) - #define HWTC_DIVISOR 1 - #define IRQ_PRIORITY_ORDER 1 // higher IRQ priority values are more significant + #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant -#elif (SELECTED_PORT == PORT_MICROCHIP_PIC32) +#elif (SELECTED_PORT == PORT_TEXAS_INSTRUMENTS_MSP430) - /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ - #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING - #define HWTC_COUNT (ReadTimer1()) /* Should be available in BSP */ - #define HWTC_PERIOD (ReadPeriod1()+1) /* Should be available in BSP */ - #define HWTC_DIVISOR 1 - #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT (TA0R) + #define HWTC_PERIOD (((uint16_t)TACCR0)+1) + #define HWTC_DIVISOR 1 + #define IRQ_PRIORITY_ORDER 1 // higher IRQ priority values are more significant #elif (SELECTED_PORT == PORT_XILINX_PPC405) - - /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ - #define HWTC_COUNT_DIRECTION DIRECTION_DECREMENTING - #define HWTC_COUNT mfspr(0x3db) + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ + + #define HWTC_COUNT_DIRECTION DIRECTION_DECREMENTING + #define HWTC_COUNT mfspr(0x3db) #if (defined configCPU_CLOCK_HZ && defined configTICK_RATE_HZ) // Check if FreeRTOS - /* For FreeRTOS only - found no generic OS independent solution for the PPC405 architecture. */ - #define HWTC_PERIOD ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) // Same as in port.c for PPC405 + /* For FreeRTOS only - found no generic OS independent solution for the PPC405 architecture. */ + #define HWTC_PERIOD ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) // Same as in port.c for PPC405 #else - /* Not defined for other operating systems yet */ - #error HWTC_PERIOD must be defined to give the number of hardware timer ticks per OS tick. - #endif - #define HWTC_DIVISOR 1 - #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant + /* Not defined for other operating systems yet */ + #error HWTC_PERIOD must be defined to give the number of hardware timer ticks per OS tick. + #endif + #define HWTC_DIVISOR 1 + #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant #elif (SELECTED_PORT == PORT_XILINX_PPC440) - + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ - /* This should work with most PowerPC chips */ - + /* This should work with most PowerPC chips */ + #define HWTC_COUNT_DIRECTION DIRECTION_DECREMENTING - #define HWTC_COUNT mfspr(0x016) + #define HWTC_COUNT mfspr(0x016) #if (defined configCPU_CLOCK_HZ && defined configTICK_RATE_HZ) // Check if FreeRTOS /* For FreeRTOS only - found no generic OS independent solution for the PPC440 architecture. */ #define HWTC_PERIOD ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) // Same as in port.c for PPC440 @@ -337,23 +349,49 @@ /* Not defined for other operating systems yet */ #error HWTC_PERIOD must be defined to give the number of hardware timer ticks per OS tick. #endif - #define HWTC_DIVISOR 1 - #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant - + #define HWTC_DIVISOR 1 + #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant + #elif (SELECTED_PORT == PORT_XILINX_MICROBLAZE) - /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ + + /* This should work with most Microblaze configurations. + * It uses the AXI Timer 0 - the tick interrupt source. + * If an AXI Timer 0 peripheral is available on your hardware platform, no modifications are required. + */ + #include "xtmrctr_l.h" + + #define HWTC_COUNT_DIRECTION DIRECTION_DECREMENTING + #define HWTC_COUNT XTmrCtr_GetTimerCounterReg( XPAR_TMRCTR_0_BASEADDR, 0 ) + #define HWTC_PERIOD (XTmrCtr_mGetLoadReg( XPAR_TMRCTR_0_BASEADDR, 0) + 1) + #define HWTC_DIVISOR 16 + #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant + +#elif (SELECTED_PORT == PORT_ARM_CORTEX_A9) + + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ + + #define CA9_MPCORE_PRIVCTR_CONTROL_PRESCALER_MASK 0x0000FF00 + #define CA9_MPCORE_PRIVCTR_CONTROL_PRESCALER_SHIFT 8 + + #define CA9_MPCORE_PRIVCTR_PERIOD_REG (*(volatile uint32_t*)(0xF8F00600 + 0)) + #define CA9_MPCORE_PRIVCTR_COUNTER_REG (*(volatile uint32_t*)(0xF8F00600 + 4)) + #define CA9_MPCORE_PRIVCTR_CONTROL_REG (*(volatile uint32_t*)(0xF8F00600 + 8)) + + #define CA9_MPCORE_PRIVCTR_PRESCALER (((CA9_MPCORE_PRIVCTR_CONTROL_REG & CA9_MPCORE_PRIVCTR_CONTROL_PRESCALER_MASK) >> CA9_MPCORE_PRIVCTR_CONTROL_PRESCALER_SHIFT) + 1) - /* This should work with most Microblaze configurations. - * It uses the AXI Timer 0 - the tick interrupt source. - * If an AXI Timer 0 peripheral is available on your hardware platform, no modifications are required. - */ - #include "xtmrctr_l.h" - #define HWTC_COUNT_DIRECTION DIRECTION_DECREMENTING - #define HWTC_COUNT XTmrCtr_GetTimerCounterReg( XPAR_TMRCTR_0_BASEADDR, 0 ) - #define HWTC_PERIOD (XTmrCtr_mGetLoadReg( XPAR_TMRCTR_0_BASEADDR, 0) + 1) - #define HWTC_DIVISOR 16 + #define HWTC_COUNT_DIRECTION DIRECTION_DECREMENTING + #define HWTC_COUNT CA9_MPCORE_PRIVCTR_COUNTER_REG + #define HWTC_PERIOD ((CA9_MPCORE_PRIVCTR_PERIOD_REG * CA9_MPCORE_PRIVCTR_PRESCALER) + 1) + + //NOTE: The private timer ticks with a very high frequency (half the core-clock usually), + //but offers the possibility to apply a prescaler. Depending on the prescaler you set the + //HWTC_DIVISOR may need to be raised. Refer to the notes at the beginning of this file + //for more information. + #define HWTC_DIVISOR 1 + #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant #elif (SELECTED_PORT == PORT_APPLICATION_DEFINED) @@ -364,47 +402,47 @@ #elif (SELECTED_PORT != PORT_NOT_SET) - #error "SELECTED_PORT had unsupported value!" - #define SELECTED_PORT PORT_NOT_SET + #error "SELECTED_PORT had unsupported value!" + #define SELECTED_PORT PORT_NOT_SET #endif #if (SELECTED_PORT != PORT_NOT_SET) - - #ifndef HWTC_COUNT_DIRECTION - #error "HWTC_COUNT_DIRECTION is not set!" - #endif - - #ifndef HWTC_COUNT - #error "HWTC_COUNT is not set!" - #endif - - #ifndef HWTC_PERIOD - #error "HWTC_PERIOD is not set!" - #endif - - #ifndef HWTC_DIVISOR - #error "HWTC_DIVISOR is not set!" - #endif - - #ifndef IRQ_PRIORITY_ORDER - #error "IRQ_PRIORITY_ORDER is not set!" - #elif (IRQ_PRIORITY_ORDER != 0) && (IRQ_PRIORITY_ORDER != 1) - #error "IRQ_PRIORITY_ORDER has bad value!" - #endif - - #if (HWTC_DIVISOR < 1) - #error "HWTC_DIVISOR must be a non-zero positive value!" - #endif - + + #ifndef HWTC_COUNT_DIRECTION + #error "HWTC_COUNT_DIRECTION is not set!" + #endif + + #ifndef HWTC_COUNT + #error "HWTC_COUNT is not set!" + #endif + + #ifndef HWTC_PERIOD + #error "HWTC_PERIOD is not set!" + #endif + + #ifndef HWTC_DIVISOR + #error "HWTC_DIVISOR is not set!" + #endif + + #ifndef IRQ_PRIORITY_ORDER + #error "IRQ_PRIORITY_ORDER is not set!" + #elif (IRQ_PRIORITY_ORDER != 0) && (IRQ_PRIORITY_ORDER != 1) + #error "IRQ_PRIORITY_ORDER has bad value!" + #endif + + #if (HWTC_DIVISOR < 1) + #error "HWTC_DIVISOR must be a non-zero positive value!" + #endif + #endif /******************************************************************************* * vTraceConsoleMessage * * A wrapper for your system-specific console "printf" console output function. - * This needs to be correctly defined to see status reports from the trace + * This needs to be correctly defined to see status reports from the trace * status monitor task (this is defined in trcUser.c). - ******************************************************************************/ + ******************************************************************************/ #define vTraceConsoleMessage(x) /******************************************************************************* @@ -420,14 +458,4 @@ ******************************************************************************/ void vTracePortGetTimeStamp(uint32_t *puiTimestamp); -/******************************************************************************* - * vTracePortEnd - * - * This function is called when the recorder is stopped due to full buffer. - * Mainly intended to show a message in the console. - * This is used by the Win32 port to store the trace to a file. The file path is - * set using vTracePortSetFileName. - ******************************************************************************/ -void vTracePortEnd(void); - #endif diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernel.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernel.h index b92afa827..1ee5e4bf1 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernel.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernel.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Tracealyzer v2.6.0 Recorder Library + * Tracealyzer v2.7.0 Recorder Library * Percepio AB, www.percepio.com * * trcKernel.h @@ -55,10 +55,10 @@ void vTraceStoreTaskswitch(objectHandleType task_handle); void vTraceStoreKernelCall(uint32_t eventcode, traceObjectClass objectClass, uint32_t byteParam); void vTraceStoreKernelCallWithNumericParamOnly(uint32_t evtcode, - uint32_t param); + uint32_t param); void vTraceStoreKernelCallWithParam(uint32_t evtcode, traceObjectClass objectClass, - uint32_t objectNumber, uint32_t param); + uint32_t objectNumber, uint32_t param); void vTraceSetTaskInstanceFinished(objectHandleType handle); @@ -73,18 +73,19 @@ uint8_t uiTraceGetObjectState(uint8_t objectclass, objectHandleType id); #if (INCLUDE_OBJECT_DELETE == 1) void vTraceStoreObjectNameOnCloseEvent(objectHandleType handle, - traceObjectClass objectclass); + traceObjectClass objectclass); void vTraceStoreObjectPropertiesOnCloseEvent(objectHandleType handle, - traceObjectClass objectclass); + traceObjectClass objectclass); #endif /* Internal constants for task state */ #define TASK_STATE_INSTANCE_NOT_ACTIVE 0 #define TASK_STATE_INSTANCE_ACTIVE 1 -#define TASK_STATE_INSTANCE_MARKED_FINISHED 2 +#endif #endif -#endif \ No newline at end of file + + diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernelHooks.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernelHooks.h index a029124e4..49dd644ab 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernelHooks.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernelHooks.h @@ -1,5 +1,5 @@ /******************************************************************************* -* Tracealyzer v2.6.0 Recorder Library +* Tracealyzer v2.7.0 Recorder Library * Percepio AB, www.percepio.com * * trcKernelHooks.h @@ -12,7 +12,7 @@ * compile-time errors. * * #ifdef __ICCARM__ -* #include "percepio/Include/trcKernelHooks.h" +* #include "trcKernelPort.h" * #endif * * Terms of Use @@ -207,4 +207,7 @@ vTraceStoreObjectNameOnCloseEvent(TRACE_GET_TIMER_NUMBER(pxTimer), TRACE_CLASS_T vTraceStoreObjectPropertiesOnCloseEvent(TRACE_GET_TIMER_NUMBER(pxTimer), TRACE_CLASS_TIMER); \ vTraceFreeObjectHandle(TRACE_CLASS_TIMER, TRACE_GET_TIMER_NUMBER(pxTimer)); -#endif /* TRCKERNELHOOKS_H */ \ No newline at end of file +#endif /* TRCKERNELHOOKS_H */ + + + diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernelPort.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernelPort.h index 58d73060a..59dc94bc8 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernelPort.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernelPort.h @@ -1,10 +1,10 @@ /******************************************************************************* - * Tracealyzer v2.6.0 Recorder Library + * Tracealyzer v2.7.0 Recorder Library * Percepio AB, www.percepio.com * * trcKernelPort.h * - * Kernel-specific functionality for FreeRTOS, used by the recorder library. + * Wrapper for kernel-specific port (trcKernelPort.h) * * Terms of Use * This software is copyright Percepio AB. The recorder library is free for @@ -31,947 +31,13 @@ * damages, or the exclusion of implied warranties or limitations on how long an * implied warranty may last, so the above limitations may not apply to you. * - * Copyright Percepio AB, 2013. - * www.percepio.com - ******************************************************************************/ - - -#ifndef TRCKERNELPORT_H_ -#define TRCKERNELPORT_H_ - -#include "FreeRTOS.h" // Defines configUSE_TRACE_FACILITY -#include "trcHardwarePort.h" - -extern int uiInEventGroupSetBitsFromISR; - -#define USE_TRACEALYZER_RECORDER configUSE_TRACE_FACILITY - -#if (USE_TRACEALYZER_RECORDER == 1) - -/* Defines that must be set for the recorder to work properly */ -#define TRACE_KERNEL_VERSION 0x1AA1 -#define TRACE_TICK_RATE_HZ configTICK_RATE_HZ /* Defined in "FreeRTOS.h" */ -#define TRACE_CPU_CLOCK_HZ configCPU_CLOCK_HZ /* Defined in "FreeRTOSConfig.h" */ - -#if ((SELECTED_PORT == PORT_ARM_CortexM) && (USE_PRIMASK_CS == 1)) - -#define TRACE_SR_ALLOC_CRITICAL_SECTION() int __irq_status; - -#define TRACE_ENTER_CRITICAL_SECTION() { __irq_status = prvTraceGetIRQMask(); prvTraceDisableIRQ(); } - -#define TRACE_EXIT_CRITICAL_SECTION() { prvTraceSetIRQMask(__irq_status); } - -#define trcCRITICAL_SECTION_BEGIN_ON_CORTEX_M_ONLY trcCRITICAL_SECTION_BEGIN -#define trcCRITICAL_SECTION_END_ON_CORTEX_M_ONLY trcCRITICAL_SECTION_END - -#else - -#define TRACE_ENTER_CRITICAL_SECTION() portENTER_CRITICAL() -#define TRACE_EXIT_CRITICAL_SECTION() portEXIT_CRITICAL() - -#define trcCRITICAL_SECTION_BEGIN_ON_CORTEX_M_ONLY() recorder_busy++; -#define trcCRITICAL_SECTION_END_ON_CORTEX_M_ONLY() recorder_busy--; - -#endif - -/************************************************************************/ -/* KERNEL SPECIFIC OBJECT CONFIGURATION */ -/************************************************************************/ -#define TRACE_NCLASSES 7 -#define TRACE_CLASS_QUEUE ((traceObjectClass)0) -#define TRACE_CLASS_SEMAPHORE ((traceObjectClass)1) -#define TRACE_CLASS_MUTEX ((traceObjectClass)2) -#define TRACE_CLASS_TASK ((traceObjectClass)3) -#define TRACE_CLASS_ISR ((traceObjectClass)4) -#define TRACE_CLASS_TIMER ((traceObjectClass)5) -#define TRACE_CLASS_EVENTGROUP ((traceObjectClass)6) - -#define TRACE_KERNEL_OBJECT_COUNT (NQueue + NSemaphore + NMutex + NTask + NISR + NTimer + NEventGroup) - -/* The size of the Object Property Table entries, in bytes, per object */ - -/* Queue properties (except name): current number of message in queue */ -#define PropertyTableSizeQueue (NameLenQueue + 1) - -/* Semaphore properties (except name): state (signaled = 1, cleared = 0) */ -#define PropertyTableSizeSemaphore (NameLenSemaphore + 1) - -/* Mutex properties (except name): owner (task handle, 0 = free) */ -#define PropertyTableSizeMutex (NameLenMutex + 1) - -/* Task properties (except name): Byte 0: Current priority - Byte 1: state (if already active) - Byte 2: legacy, not used - Byte 3: legacy, not used */ -#define PropertyTableSizeTask (NameLenTask + 4) - -/* ISR properties: Byte 0: priority - Byte 1: state (if already active) */ -#define PropertyTableSizeISR (NameLenISR + 2) - -/* NTimer properties: Byte 0: state (unused for now) */ -#define PropertyTableSizeTimer (NameLenTimer + 1) - -/* NEventGroup properties: Byte 0-3: state (unused for now)*/ -#define PropertyTableSizeEventGroup (NameLenEventGroup + 4) - - -/* The layout of the byte array representing the Object Property Table */ -#define StartIndexQueue 0 -#define StartIndexSemaphore StartIndexQueue + NQueue * PropertyTableSizeQueue -#define StartIndexMutex StartIndexSemaphore + NSemaphore * PropertyTableSizeSemaphore -#define StartIndexTask StartIndexMutex + NMutex * PropertyTableSizeMutex -#define StartIndexISR StartIndexTask + NTask * PropertyTableSizeTask -#define StartIndexTimer StartIndexISR + NISR * PropertyTableSizeISR -#define StartIndexEventGroup StartIndexTimer + NTimer * PropertyTableSizeTimer - -/* Number of bytes used by the object table */ -#define TRACE_OBJECT_TABLE_SIZE StartIndexEventGroup + NEventGroup * PropertyTableSizeEventGroup - -/* Includes */ -#include "trcConfig.h" /* Must be first, even before trcTypes.h */ -#include "trcHardwarePort.h" -#include "trcTypes.h" -#include "trcKernelHooks.h" -#include "trcBase.h" -#include "trcKernel.h" -#include "trcUser.h" - -#if (INCLUDE_NEW_TIME_EVENTS == 1 && configUSE_TICKLESS_IDLE != 0) -#error "NewTime events can not be used in combination with tickless idle!" -#endif - -/* Initialization of the object property table */ -void vTraceInitObjectPropertyTable(void); - -/* Initialization of the handle mechanism, see e.g, xTraceGetObjectHandle */ -void vTraceInitObjectHandleStack(void); - -/* Returns the "Not enough handles" error message for the specified object class */ -const char* pszTraceGetErrorNotEnoughHandles(traceObjectClass objectclass); - -/******************************************************************************* - * The event codes - should match the offline config file. - * - * Some sections below are encoded to allow for constructions like: - * - * vTraceStoreKernelCall(EVENTGROUP_CREATE + objectclass, ... + * Tabs are used for indent in this file (1 tab = 4 spaces) * - * The object class ID is given by the three LSB bits, in such cases. Since each - * object class has a separate object property table, the class ID is needed to - * know what section in the object table to use for getting an object name from - * an object handle. - ******************************************************************************/ - -#define NULL_EVENT (0x00) /* Ignored in the analysis*/ - -/******************************************************************************* - * EVENTGROUP_DIV - * - * Miscellaneous events. - ******************************************************************************/ -#define EVENTGROUP_DIV (NULL_EVENT + 1) /*0x01*/ -#define DIV_XPS (EVENTGROUP_DIV + 0) /*0x01*/ -#define DIV_TASK_READY (EVENTGROUP_DIV + 1) /*0x02*/ -#define DIV_NEW_TIME (EVENTGROUP_DIV + 2) /*0x03*/ - -/******************************************************************************* - * EVENTGROUP_TS - * - * Events for storing task-switches and interrupts. The RESUME events are - * generated if the task/interrupt is already marked active. - ******************************************************************************/ -#define EVENTGROUP_TS (EVENTGROUP_DIV + 3) /*0x04*/ -#define TS_ISR_BEGIN (EVENTGROUP_TS + 0) /*0x04*/ -#define TS_ISR_RESUME (EVENTGROUP_TS + 1) /*0x05*/ -#define TS_TASK_BEGIN (EVENTGROUP_TS + 2) /*0x06*/ -#define TS_TASK_RESUME (EVENTGROUP_TS + 3) /*0x07*/ - -/******************************************************************************* - * EVENTGROUP_OBJCLOSE_NAME - * - * About Close Events - * When an object is evicted from the object property table (object close), two - * internal events are stored (EVENTGROUP_OBJCLOSE_NAME and - * EVENTGROUP_OBJCLOSE_PROP), containing the handle-name mapping and object - * properties valid up to this point. - ******************************************************************************/ -#define EVENTGROUP_OBJCLOSE_NAME (EVENTGROUP_TS + 4) /*0x08*/ - -/******************************************************************************* - * EVENTGROUP_OBJCLOSE_PROP - * - * The internal event carrying properties of deleted objects - * The handle and object class of the closed object is not stored in this event, - * but is assumed to be the same as in the preceding CLOSE event. Thus, these - * two events must be generated from within a critical section. - * When queues are closed, arg1 is the "state" property (i.e., number of - * buffered messages/signals). - * When actors are closed, arg1 is priority, arg2 is handle of the "instance - * finish" event, and arg3 is event code of the "instance finish" event. - * In this case, the lower three bits is the object class of the instance finish - * handle. The lower three bits are not used (always zero) when queues are - * closed since the queue type is given in the previous OBJCLOSE_NAME event. - ******************************************************************************/ -#define EVENTGROUP_OBJCLOSE_PROP (EVENTGROUP_OBJCLOSE_NAME + 8) /*0x10*/ - -/******************************************************************************* - * EVENTGROUP_CREATE - * - * The events in this group are used to log Kernel object creations. - * The lower three bits in the event code gives the object class, i.e., type of - * create operation (task, queue, semaphore, etc). - ******************************************************************************/ -#define EVENTGROUP_CREATE_OBJ_SUCCESS (EVENTGROUP_OBJCLOSE_PROP + 8) /*0x18*/ - -/******************************************************************************* - * EVENTGROUP_SEND - * - * The events in this group are used to log Send/Give events on queues, - * semaphores and mutexes The lower three bits in the event code gives the - * object class, i.e., what type of object that is operated on (queue, semaphore - * or mutex). - ******************************************************************************/ -#define EVENTGROUP_SEND_SUCCESS (EVENTGROUP_CREATE_OBJ_SUCCESS + 8) /*0x20*/ - -/******************************************************************************* - * EVENTGROUP_RECEIVE - * - * The events in this group are used to log Receive/Take events on queues, - * semaphores and mutexes. The lower three bits in the event code gives the - * object class, i.e., what type of object that is operated on (queue, semaphore - * or mutex). - ******************************************************************************/ -#define EVENTGROUP_RECEIVE_SUCCESS (EVENTGROUP_SEND_SUCCESS + 8) /*0x28*/ - -/* Send/Give operations, from ISR */ -#define EVENTGROUP_SEND_FROM_ISR_SUCCESS (EVENTGROUP_RECEIVE_SUCCESS + 8) /*0x30*/ - -/* Receive/Take operations, from ISR */ -#define EVENTGROUP_RECEIVE_FROM_ISR_SUCCESS (EVENTGROUP_SEND_FROM_ISR_SUCCESS + 8) /*0x38*/ - -/* "Failed" event type versions of above (timeout, failed allocation, etc) */ -#define EVENTGROUP_KSE_FAILED (EVENTGROUP_RECEIVE_FROM_ISR_SUCCESS + 8) /*0x40*/ - -/* Failed create calls - memory allocation failed */ -#define EVENTGROUP_CREATE_OBJ_FAILED (EVENTGROUP_KSE_FAILED) /*0x40*/ - -/* Failed send/give - timeout! */ -#define EVENTGROUP_SEND_FAILED (EVENTGROUP_CREATE_OBJ_FAILED + 8) /*0x48*/ - -/* Failed receive/take - timeout! */ -#define EVENTGROUP_RECEIVE_FAILED (EVENTGROUP_SEND_FAILED + 8) /*0x50*/ - -/* Failed non-blocking send/give - queue full */ -#define EVENTGROUP_SEND_FROM_ISR_FAILED (EVENTGROUP_RECEIVE_FAILED + 8) /*0x58*/ - -/* Failed non-blocking receive/take - queue empty */ -#define EVENTGROUP_RECEIVE_FROM_ISR_FAILED \ - (EVENTGROUP_SEND_FROM_ISR_FAILED + 8) /*0x60*/ - -/* Events when blocking on receive/take */ -#define EVENTGROUP_RECEIVE_BLOCK \ - (EVENTGROUP_RECEIVE_FROM_ISR_FAILED + 8) /*0x68*/ - -/* Events when blocking on send/give */ -#define EVENTGROUP_SEND_BLOCK (EVENTGROUP_RECEIVE_BLOCK + 8) /*0x70*/ - -/* Events on queue peek (receive) */ -#define EVENTGROUP_PEEK_SUCCESS (EVENTGROUP_SEND_BLOCK + 8) /*0x78*/ - -/* Events on object delete (vTaskDelete or vQueueDelete) */ -#define EVENTGROUP_DELETE_OBJ_SUCCESS (EVENTGROUP_PEEK_SUCCESS + 8) /*0x80*/ - -/* Other events - object class is implied: TASK */ -#define EVENTGROUP_OTHERS (EVENTGROUP_DELETE_OBJ_SUCCESS + 8) /*0x88*/ -#define TASK_DELAY_UNTIL (EVENTGROUP_OTHERS + 0) /*0x88*/ -#define TASK_DELAY (EVENTGROUP_OTHERS + 1) /*0x89*/ -#define TASK_SUSPEND (EVENTGROUP_OTHERS + 2) /*0x8A*/ -#define TASK_RESUME (EVENTGROUP_OTHERS + 3) /*0x8B*/ -#define TASK_RESUME_FROM_ISR (EVENTGROUP_OTHERS + 4) /*0x8C*/ -#define TASK_PRIORITY_SET (EVENTGROUP_OTHERS + 5) /*0x8D*/ -#define TASK_PRIORITY_INHERIT (EVENTGROUP_OTHERS + 6) /*0x8E*/ -#define TASK_PRIORITY_DISINHERIT (EVENTGROUP_OTHERS + 7) /*0x8F*/ - -#define EVENTGROUP_MISC_PLACEHOLDER (EVENTGROUP_OTHERS + 8) /*0x90*/ -#define PEND_FUNC_CALL (EVENTGROUP_MISC_PLACEHOLDER+0) /*0x90*/ -#define PEND_FUNC_CALL_FROM_ISR (EVENTGROUP_MISC_PLACEHOLDER+1) /*0x91*/ -#define PEND_FUNC_CALL_FAILED (EVENTGROUP_MISC_PLACEHOLDER+2) /*0x92*/ -#define PEND_FUNC_CALL_FROM_ISR_FAILED (EVENTGROUP_MISC_PLACEHOLDER+3) /*0x93*/ -#define MEM_MALLOC_SIZE (EVENTGROUP_MISC_PLACEHOLDER+4) /*0x94*/ -#define MEM_MALLOC_ADDR (EVENTGROUP_MISC_PLACEHOLDER+5) /*0x95*/ -#define MEM_FREE_SIZE (EVENTGROUP_MISC_PLACEHOLDER+6) /*0x96*/ -#define MEM_FREE_ADDR (EVENTGROUP_MISC_PLACEHOLDER+7) /*0x97*/ - -/* User events */ -#define EVENTGROUP_USEREVENT (EVENTGROUP_MISC_PLACEHOLDER + 8) /*0x98*/ -#define USER_EVENT (EVENTGROUP_USEREVENT + 0) - -/* Allow for 0-15 arguments (the number of args is added to event code) */ -#define USER_EVENT_LAST (EVENTGROUP_USEREVENT + 15) /*0xA7*/ - -/******************************************************************************* - * XTS Event - eXtended TimeStamp events - * The timestamps used in the recorder are "differential timestamps" (DTS), i.e. - * the time since the last stored event. The DTS fields are either 1 or 2 bytes - * in the other events, depending on the bytes available in the event struct. - * If the time since the last event (the DTS) is larger than allowed for by - * the DTS field of the current event, an XTS event is inserted immediately - * before the original event. The XTS event contains up to 3 additional bytes - * of the DTS value - the higher bytes of the true DTS value. The lower 1-2 - * bytes are stored in the normal DTS field. - * There are two types of XTS events, XTS8 and XTS16. An XTS8 event is stored - * when there is only room for 1 byte (8 bit) DTS data in the original event, - * which means a limit of 0xFF (255). The XTS16 is used when the original event - * has a 16 bit DTS field and thereby can handle values up to 0xFFFF (65535). - * - * Using a very high frequency time base can result in many XTS events. - * Preferably, the time between two OS ticks should fit in 16 bits, i.e., - * at most 65535. If your time base has a higher frequency, you can define - * the TRACE - ******************************************************************************/ - -#define EVENTGROUP_SYS (EVENTGROUP_USEREVENT + 16) /*0xA8*/ -#define XTS8 (EVENTGROUP_SYS + 0) /*0xA8*/ -#define XTS16 (EVENTGROUP_SYS + 1) /*0xA9*/ - -#define EVENT_BEING_WRITTEN (EVENTGROUP_SYS + 2) /*0xAA*/ - -#define RESERVED_DUMMY_CODE (EVENTGROUP_SYS + 3) /*0xAB*/ - -#define LOW_POWER_BEGIN (EVENTGROUP_SYS + 4) /*0xAC*/ -#define LOW_POWER_END (EVENTGROUP_SYS + 5) /*0xAD*/ - -#define XID (EVENTGROUP_SYS + 6) /*0xAE*/ - -#define XTS16L (EVENTGROUP_SYS + 7) /*0xAF*/ - -#define EVENTGROUP_TIMER (EVENTGROUP_SYS + 8) /*0xB0*/ - -#define TIMER_CREATE (EVENTGROUP_TIMER + 0) /*0xB0*/ -#define TIMER_START (EVENTGROUP_TIMER + 1) /*0xB0*/ -#define TIMER_RESET (EVENTGROUP_TIMER + 2) /*0xB1*/ -#define TIMER_STOP (EVENTGROUP_TIMER + 3) /*0xB2*/ -#define TIMER_CHANGE_PERIOD (EVENTGROUP_TIMER + 4) /*0xB3*/ -#define TIMER_DELETE (EVENTGROUP_TIMER + 5) /*0xB4*/ -#define TIMER_START_FROM_ISR (EVENTGROUP_TIMER + 6) /*0xB6*/ -#define TIMER_RESET_FROM_ISR (EVENTGROUP_TIMER + 7) /*0xB7*/ -#define TIMER_STOP_FROM_ISR (EVENTGROUP_TIMER + 8) /*0xB8*/ - -#define TIMER_CREATE_FAILED (EVENTGROUP_TIMER + 9) /*0xB9*/ -#define TIMER_START_FAILED (EVENTGROUP_TIMER + 10) /*0xBA*/ -#define TIMER_RESET_FAILED (EVENTGROUP_TIMER + 11) /*0xBB*/ -#define TIMER_STOP_FAILED (EVENTGROUP_TIMER + 12) /*0xBC*/ -#define TIMER_CHANGE_PERIOD_FAILED (EVENTGROUP_TIMER + 13) /*0xBD*/ -#define TIMER_DELETE_FAILED (EVENTGROUP_TIMER + 14) /*0xBE*/ -#define TIMER_START_FROM_ISR_FAILED (EVENTGROUP_TIMER + 15) /*0xBF*/ -#define TIMER_RESET_FROM_ISR_FAILED (EVENTGROUP_TIMER + 16) /*0xC0*/ -#define TIMER_STOP_FROM_ISR_FAILED (EVENTGROUP_TIMER + 17) /*0xC1*/ - -#define EVENTGROUP_EG (EVENTGROUP_TIMER + 18) /*0xC2*/ -#define EVENT_GROUP_CREATE (EVENTGROUP_EG + 0) /*0xC2*/ -#define EVENT_GROUP_CREATE_FAILED (EVENTGROUP_EG + 1) /*0xC3*/ -#define EVENT_GROUP_SYNC_BLOCK (EVENTGROUP_EG + 2) /*0xC4*/ -#define EVENT_GROUP_SYNC_END (EVENTGROUP_EG + 3) /*0xC5*/ -#define EVENT_GROUP_WAIT_BITS_BLOCK (EVENTGROUP_EG + 4) /*0xC6*/ -#define EVENT_GROUP_WAIT_BITS_END (EVENTGROUP_EG + 5) /*0xC7*/ -#define EVENT_GROUP_CLEAR_BITS (EVENTGROUP_EG + 6) /*0xC8*/ -#define EVENT_GROUP_CLEAR_BITS_FROM_ISR (EVENTGROUP_EG + 7) /*0xC9*/ -#define EVENT_GROUP_SET_BITS (EVENTGROUP_EG + 8) /*0xCA*/ -#define EVENT_GROUP_DELETE (EVENTGROUP_EG + 9) /*0xCB*/ -#define EVENT_GROUP_SYNC_END_FAILED (EVENTGROUP_EG + 10) /*0xCC*/ -#define EVENT_GROUP_WAIT_BITS_END_FAILED (EVENTGROUP_EG + 11) /*0xCD*/ -#define EVENT_GROUP_SET_BITS_FROM_ISR (EVENTGROUP_EG + 12) /*0xCE*/ -#define EVENT_GROUP_SET_BITS_FROM_ISR_FAILED (EVENTGROUP_EG + 13) /*0xCF*/ - -/************************************************************************/ -/* KERNEL SPECIFIC DATA AND FUNCTIONS NEEDED TO PROVIDE THE */ -/* FUNCTIONALITY REQUESTED BY THE TRACE RECORDER */ -/************************************************************************/ - -/****************************************************************************** - * TraceObjectClassTable - * Translates a FreeRTOS QueueType into trace objects classes (TRACE_CLASS_). - * This was added since we want to map both types of Mutex and both types of - * Semaphores on common classes for all Mutexes and all Semaphores respectively. - * - * FreeRTOS Queue types - * #define queueQUEUE_TYPE_BASE (0U) => TRACE_CLASS_QUEUE - * #define queueQUEUE_TYPE_MUTEX (1U) => TRACE_CLASS_MUTEX - * #define queueQUEUE_TYPE_COUNTING_SEMAPHORE (2U) => TRACE_CLASS_SEMAPHORE - * #define queueQUEUE_TYPE_BINARY_SEMAPHORE (3U) => TRACE_CLASS_SEMAPHORE - * #define queueQUEUE_TYPE_RECURSIVE_MUTEX (4U) => TRACE_CLASS_MUTEX + * Copyright Percepio AB, 2014. + * www.percepio.com ******************************************************************************/ -extern traceObjectClass TraceObjectClassTable[5]; - -/* These functions are implemented in the .c file since certain header files must not be included in this one */ -objectHandleType prvTraceGetObjectNumber(void* handle); -unsigned char prvTraceGetObjectType(void* handle); -objectHandleType prvTraceGetTaskNumber(void* handle); -unsigned char prvTraceIsSchedulerActive(void); -unsigned char prvTraceIsSchedulerSuspended(void); -unsigned char prvTraceIsSchedulerStarted(void); -void* prvTraceGetCurrentTaskHandle(void); - -#if (configUSE_TIMERS == 1) -#undef INCLUDE_xTimerGetTimerDaemonTaskHandle -#define INCLUDE_xTimerGetTimerDaemonTaskHandle 1 -#endif - -/************************************************************************/ -/* KERNEL SPECIFIC MACROS USED BY THE TRACE RECORDER */ -/************************************************************************/ - -#define TRACE_MALLOC(size) pvPortMalloc(size) -#define TRACE_IS_SCHEDULER_ACTIVE() prvTraceIsSchedulerActive() -#define TRACE_IS_SCHEDULER_STARTED() prvTraceIsSchedulerStarted() -#define TRACE_IS_SCHEDULER_SUSPENDED() prvTraceIsSchedulerSuspended() -#define TRACE_GET_CURRENT_TASK() prvTraceGetCurrentTaskHandle() - -#define TRACE_GET_TASK_PRIORITY(pxTCB) ((uint8_t)pxTCB->uxPriority) -#define TRACE_GET_TASK_NAME(pxTCB) ((char*)pxTCB->pcTaskName) -#define TRACE_GET_TASK_NUMBER(pxTCB) (prvTraceGetTaskNumber(pxTCB)) -#define TRACE_SET_TASK_NUMBER(pxTCB) pxTCB->uxTaskNumber = xTraceGetObjectHandle(TRACE_CLASS_TASK); - -#define TRACE_GET_CLASS_TRACE_CLASS(CLASS, kernelClass) TraceObjectClassTable[kernelClass] -#define TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject) TRACE_GET_CLASS_TRACE_CLASS(CLASS, prvTraceGetObjectType(pxObject)) - -#define TRACE_GET_TIMER_NUMBER(tmr) ( ( objectHandleType ) ((Timer_t*)tmr)->uxTimerNumber ) -#define TRACE_SET_TIMER_NUMBER(tmr) ((Timer_t*)tmr)->uxTimerNumber = xTraceGetObjectHandle(TRACE_CLASS_TIMER); -#define TRACE_GET_TIMER_NAME(pxTimer) pxTimer->pcTimerName -#define TRACE_GET_TIMER_PERIOD(pxTimer) pxTimer->xTimerPeriodInTicks - -#define TRACE_GET_EVENTGROUP_NUMBER(eg) ( ( objectHandleType ) uxEventGroupGetNumber(eg) ) -#define TRACE_SET_EVENTGROUP_NUMBER(eg) ((EventGroup_t*)eg)->uxEventGroupNumber = xTraceGetObjectHandle(TRACE_CLASS_EVENTGROUP); - -#define TRACE_GET_OBJECT_NUMBER(CLASS, pxObject) (prvTraceGetObjectNumber(pxObject)) -#define TRACE_SET_OBJECT_NUMBER(CLASS, pxObject) pxObject->uxQueueNumber = xTraceGetObjectHandle(TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject)); - -#define TRACE_GET_CLASS_EVENT_CODE(SERVICE, RESULT, CLASS, kernelClass) (uint8_t)(EVENTGROUP_##SERVICE##_##RESULT + TRACE_GET_CLASS_TRACE_CLASS(CLASS, kernelClass)) -#define TRACE_GET_OBJECT_EVENT_CODE(SERVICE, RESULT, CLASS, pxObject) (uint8_t)(EVENTGROUP_##SERVICE##_##RESULT + TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject)) -#define TRACE_GET_TASK_EVENT_CODE(SERVICE, RESULT, CLASS, pxTCB) (uint8_t)(EVENTGROUP_##SERVICE##_##RESULT + TRACE_CLASS_TASK) - -/************************************************************************/ -/* KERNEL SPECIFIC WRAPPERS THAT SHOULD BE CALLED BY THE KERNEL */ -/************************************************************************/ - -#if (configUSE_TICKLESS_IDLE != 0) - -#undef traceLOW_POWER_IDLE_BEGIN -#define traceLOW_POWER_IDLE_BEGIN() \ - { \ - extern uint32_t trace_disable_timestamp; \ - vTraceStoreLowPower(0); \ - trace_disable_timestamp = 1; \ - } - -#undef traceLOW_POWER_IDLE_END -#define traceLOW_POWER_IDLE_END() \ - { \ - extern uint32_t trace_disable_timestamp; \ - trace_disable_timestamp = 0; \ - vTraceStoreLowPower(1); \ - } - -#endif - -/* A macro that will update the tick count when returning from tickless idle */ -#undef traceINCREASE_TICK_COUNT -/* Note: This can handle time adjustments of max 2^32 ticks, i.e., 35 seconds at 120 MHz. Thus, tick-less idle periods longer than 2^32 ticks will appear "compressed" on the time line.*/ -#define traceINCREASE_TICK_COUNT( xCount ) { DWT_CYCLES_ADDED += (xCount * (TRACE_CPU_CLOCK_HZ / TRACE_TICK_RATE_HZ)); } - -/* Called for each task that becomes ready */ -#undef traceMOVED_TASK_TO_READY_STATE -#define traceMOVED_TASK_TO_READY_STATE( pxTCB ) \ - trcKERNEL_HOOKS_MOVED_TASK_TO_READY_STATE(pxTCB); - -/* Called on each OS tick. Will call uiPortGetTimestamp to make sure it is called at least once every OS tick. */ -#undef traceTASK_INCREMENT_TICK -#define traceTASK_INCREMENT_TICK( xTickCount ) \ - if (uxSchedulerSuspended == ( UBaseType_t ) pdTRUE || uxPendedTicks == 0) { trcKERNEL_HOOKS_INCREMENT_TICK(); } \ - if (uxSchedulerSuspended == ( UBaseType_t ) pdFALSE) { trcKERNEL_HOOKS_NEW_TIME(DIV_NEW_TIME, xTickCount + 1); } - -/* Called on each task-switch */ -#undef traceTASK_SWITCHED_IN -#define traceTASK_SWITCHED_IN() \ - trcKERNEL_HOOKS_TASK_SWITCH(TRACE_GET_CURRENT_TASK()); - -/* Called on vTaskSuspend */ -#undef traceTASK_SUSPEND -#define traceTASK_SUSPEND( pxTaskToSuspend ) \ - trcKERNEL_HOOKS_TASK_SUSPEND(TASK_SUSPEND, pxTaskToSuspend); - -/* Called on vTaskDelay - note the use of FreeRTOS variable xTicksToDelay */ -#undef traceTASK_DELAY -#define traceTASK_DELAY() \ - trcKERNEL_HOOKS_TASK_DELAY(TASK_DELAY, pxCurrentTCB, xTicksToDelay); \ - trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED(); - -/* Called on vTaskDelayUntil - note the use of FreeRTOS variable xTimeToWake */ -#undef traceTASK_DELAY_UNTIL -#define traceTASK_DELAY_UNTIL() \ - trcKERNEL_HOOKS_TASK_DELAY(TASK_DELAY_UNTIL, pxCurrentTCB, xTimeToWake); \ - trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED(); - -#if (INCLUDE_OBJECT_DELETE == 1) -/* Called on vTaskDelete */ -#undef traceTASK_DELETE -#define traceTASK_DELETE( pxTaskToDelete ) \ - { TRACE_SR_ALLOC_CRITICAL_SECTION(); \ - TRACE_ENTER_CRITICAL_SECTION(); \ - trcKERNEL_HOOKS_TASK_DELETE(DELETE_OBJ, pxTaskToDelete); \ - TRACE_EXIT_CRITICAL_SECTION(); } -#endif - -#if (INCLUDE_OBJECT_DELETE == 1) -/* Called on vQueueDelete */ -#undef traceQUEUE_DELETE -#define traceQUEUE_DELETE( pxQueue ) \ - { TRACE_SR_ALLOC_CRITICAL_SECTION(); \ - TRACE_ENTER_CRITICAL_SECTION(); \ - trcKERNEL_HOOKS_OBJECT_DELETE(DELETE_OBJ, UNUSED, pxQueue); \ - TRACE_EXIT_CRITICAL_SECTION(); } -#endif - -/* Called on vTaskCreate */ -#undef traceTASK_CREATE -#define traceTASK_CREATE(pxNewTCB) \ - if (pxNewTCB != NULL) \ - { \ - trcKERNEL_HOOKS_TASK_CREATE(CREATE_OBJ, UNUSED, pxNewTCB); \ - } - -/* Called in vTaskCreate, if it fails (typically if the stack can not be allocated) */ -#undef traceTASK_CREATE_FAILED -#define traceTASK_CREATE_FAILED() \ - trcKERNEL_HOOKS_TASK_CREATE_FAILED(CREATE_OBJ, UNUSED); - -/* Called in xQueueCreate, and thereby for all other object based on queues, such as semaphores. */ -#undef traceQUEUE_CREATE -#define traceQUEUE_CREATE( pxNewQueue )\ - trcKERNEL_HOOKS_OBJECT_CREATE(CREATE_OBJ, UNUSED, pxNewQueue); - -/* Called in xQueueCreate, if the queue creation fails */ -#undef traceQUEUE_CREATE_FAILED -#define traceQUEUE_CREATE_FAILED( queueType ) \ - trcKERNEL_HOOKS_OBJECT_CREATE_FAILED(CREATE_OBJ, UNUSED, queueType); - -/* Called in xQueueCreateMutex, and thereby also from xSemaphoreCreateMutex and xSemaphoreCreateRecursiveMutex */ -#undef traceCREATE_MUTEX -#define traceCREATE_MUTEX( pxNewQueue ) \ - trcKERNEL_HOOKS_OBJECT_CREATE(CREATE_OBJ, UNUSED, pxNewQueue); - -/* Called in xQueueCreateMutex when the operation fails (when memory allocation fails) */ -#undef traceCREATE_MUTEX_FAILED -#define traceCREATE_MUTEX_FAILED() \ - trcKERNEL_HOOKS_OBJECT_CREATE_FAILED(CREATE_OBJ, UNUSED, queueQUEUE_TYPE_MUTEX); - -/* Called when the Mutex can not be given, since not holder */ -#undef traceGIVE_MUTEX_RECURSIVE_FAILED -#define traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex ) \ - trcKERNEL_HOOKS_KERNEL_SERVICE(SEND, FAILED, UNUSED, pxMutex); - -/* Called when a message is sent to a queue */ /* CS IS NEW ! */ -#undef traceQUEUE_SEND -#define traceQUEUE_SEND( pxQueue ) \ - trcKERNEL_HOOKS_KERNEL_SERVICE(SEND, SUCCESS, UNUSED, pxQueue); \ - trcKERNEL_HOOKS_SET_OBJECT_STATE(UNUSED, pxQueue, TRACE_GET_OBJECT_TRACE_CLASS(UNUSED, pxQueue) == TRACE_CLASS_MUTEX ? (uint8_t)0 : (uint8_t)(pxQueue->uxMessagesWaiting + 1)); - -/* Called when a message failed to be sent to a queue (timeout) */ -#undef traceQUEUE_SEND_FAILED -#define traceQUEUE_SEND_FAILED( pxQueue ) \ - trcKERNEL_HOOKS_KERNEL_SERVICE(SEND, FAILED, UNUSED, pxQueue); - -/* Called when the task is blocked due to a send operation on a full queue */ -#undef traceBLOCKING_ON_QUEUE_SEND -#define traceBLOCKING_ON_QUEUE_SEND( pxQueue ) \ - trcKERNEL_HOOKS_KERNEL_SERVICE(SEND, BLOCK, UNUSED, pxQueue); - -/* Called when a message is received from a queue */ -#undef traceQUEUE_RECEIVE -#define traceQUEUE_RECEIVE( pxQueue ) \ - trcKERNEL_HOOKS_KERNEL_SERVICE(RECEIVE, SUCCESS, UNUSED, pxQueue); \ - trcKERNEL_HOOKS_SET_OBJECT_STATE(UNUSED, pxQueue, TRACE_GET_OBJECT_TRACE_CLASS(UNUSED, pxQueue) == TRACE_CLASS_MUTEX ? TRACE_GET_TASK_NUMBER(TRACE_GET_CURRENT_TASK()) : (uint8_t)(pxQueue->uxMessagesWaiting - 1)); - -/* Called when a receive operation on a queue fails (timeout) */ -#undef traceQUEUE_RECEIVE_FAILED -#define traceQUEUE_RECEIVE_FAILED( pxQueue ) \ - trcKERNEL_HOOKS_KERNEL_SERVICE(RECEIVE, FAILED, UNUSED, pxQueue); - -/* Called when the task is blocked due to a receive operation on an empty queue */ -#undef traceBLOCKING_ON_QUEUE_RECEIVE -#define traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ) \ - trcKERNEL_HOOKS_KERNEL_SERVICE(RECEIVE, BLOCK, UNUSED, pxQueue); \ - if (TRACE_GET_OBJECT_TRACE_CLASS(UNUSED, pxQueue) != TRACE_CLASS_MUTEX) \ - {trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED();} - -/* Called on xQueuePeek */ -#undef traceQUEUE_PEEK -#define traceQUEUE_PEEK( pxQueue ) \ - trcKERNEL_HOOKS_KERNEL_SERVICE(PEEK, SUCCESS, UNUSED, pxQueue); - -/* Called when a message is sent from interrupt context, e.g., using xQueueSendFromISR */ -#undef traceQUEUE_SEND_FROM_ISR -#define traceQUEUE_SEND_FROM_ISR( pxQueue ) \ - trcKERNEL_HOOKS_KERNEL_SERVICE(SEND_FROM_ISR, SUCCESS, UNUSED, pxQueue); \ - trcKERNEL_HOOKS_SET_OBJECT_STATE(UNUSED, pxQueue, (uint8_t)(pxQueue->uxMessagesWaiting + 1)); - -/* Called when a message send from interrupt context fails (since the queue was full) */ -#undef traceQUEUE_SEND_FROM_ISR_FAILED -#define traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue ) \ - trcKERNEL_HOOKS_KERNEL_SERVICE(SEND_FROM_ISR, FAILED, UNUSED, pxQueue); - -/* Called when a message is received in interrupt context, e.g., using xQueueReceiveFromISR */ -#undef traceQUEUE_RECEIVE_FROM_ISR -#define traceQUEUE_RECEIVE_FROM_ISR( pxQueue ) \ - trcKERNEL_HOOKS_KERNEL_SERVICE(RECEIVE_FROM_ISR, SUCCESS, UNUSED, pxQueue); \ - trcKERNEL_HOOKS_SET_OBJECT_STATE(UNUSED, pxQueue, (uint8_t)(pxQueue->uxMessagesWaiting - 1)); - -/* Called when a message receive from interrupt context fails (since the queue was empty) */ -#undef traceQUEUE_RECEIVE_FROM_ISR_FAILED -#define traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue ) \ - trcKERNEL_HOOKS_KERNEL_SERVICE(RECEIVE_FROM_ISR, FAILED, UNUSED, pxQueue); - -/* Called in vTaskPrioritySet */ -#undef traceTASK_PRIORITY_SET -#define traceTASK_PRIORITY_SET( pxTask, uxNewPriority ) \ - trcKERNEL_HOOKS_TASK_PRIORITY_CHANGE(TASK_PRIORITY_SET, pxTask, uxNewPriority); - -/* Called in vTaskPriorityInherit, which is called by Mutex operations */ -#undef traceTASK_PRIORITY_INHERIT -#define traceTASK_PRIORITY_INHERIT( pxTask, uxNewPriority ) \ - trcKERNEL_HOOKS_TASK_PRIORITY_CHANGE(TASK_PRIORITY_INHERIT, pxTask, uxNewPriority); - -/* Called in vTaskPriorityDisinherit, which is called by Mutex operations */ -#undef traceTASK_PRIORITY_DISINHERIT -#define traceTASK_PRIORITY_DISINHERIT( pxTask, uxNewPriority ) \ - trcKERNEL_HOOKS_TASK_PRIORITY_CHANGE(TASK_PRIORITY_DISINHERIT, pxTask, uxNewPriority); - -/* Called in vTaskResume */ -#undef traceTASK_RESUME -#define traceTASK_RESUME( pxTaskToResume ) \ - trcKERNEL_HOOKS_TASK_RESUME(TASK_RESUME, pxTaskToResume); - -/* Called in vTaskResumeFromISR */ -#undef traceTASK_RESUME_FROM_ISR -#define traceTASK_RESUME_FROM_ISR( pxTaskToResume ) \ - trcKERNEL_HOOKS_TASK_RESUME(TASK_RESUME_FROM_ISR, pxTaskToResume); - - -/* Called in timer.c - xTimerCreate */ -#undef traceTIMER_CREATE -#define traceTIMER_CREATE(tmr) \ - trcKERNEL_HOOKS_TIMER_CREATE(TIMER_CREATE, tmr); - -#undef traceTIMER_CREATE_FAILED -#define traceTIMER_CREATE_FAILED() \ - trcKERNEL_HOOKS_TIMER_EVENT(TIMER_CREATE_FAILED, 0); - -/* Note that xCommandID can never be tmrCOMMAND_EXECUTE_CALLBACK (-1) since the trace macro is not called in that case */ -#undef traceTIMER_COMMAND_SEND -#define traceTIMER_COMMAND_SEND(tmr, xCommandID, xOptionalValue, xReturn) \ -if (xCommandID > tmrCOMMAND_START_DONT_TRACE){\ - if (xCommandID == tmrCOMMAND_CHANGE_PERIOD) vTraceStoreKernelCallWithParam((xReturn == pdPASS) ? TIMER_CHANGE_PERIOD : TIMER_CHANGE_PERIOD_FAILED, TRACE_CLASS_TIMER, TRACE_GET_TIMER_NUMBER(tmr), xOptionalValue);\ - else if ((xCommandID == tmrCOMMAND_DELETE) && (xReturn == pdPASS)){ trcKERNEL_HOOKS_TIMER_DELETE(TIMER_DELETE, tmr); } \ - else {trcKERNEL_HOOKS_TIMER_EVENT(EVENTGROUP_TIMER + xCommandID + ((xReturn == pdPASS)?0:(TIMER_CREATE_FAILED - TIMER_CREATE)), tmr); }\ -} - -#undef tracePEND_FUNC_CALL -#define tracePEND_FUNC_CALL(func, arg1, arg2, ret) \ -if (ret == pdPASS) \ - vTraceStoreKernelCall(PEND_FUNC_CALL, TRACE_CLASS_TASK, uxTaskGetTaskNumber(xTimerGetTimerDaemonTaskHandle()) ); \ -else \ - vTraceStoreKernelCall(PEND_FUNC_CALL_FAILED, TRACE_CLASS_TASK, uxTaskGetTaskNumber(xTimerGetTimerDaemonTaskHandle()) ); - -#undef tracePEND_FUNC_CALL_FROM_ISR -#define tracePEND_FUNC_CALL_FROM_ISR(func, arg1, arg2, ret) \ - if (! uiInEventGroupSetBitsFromISR) vTraceStoreKernelCall(PEND_FUNC_CALL_FROM_ISR, TRACE_CLASS_TASK, uxTaskGetTaskNumber(xTimerGetTimerDaemonTaskHandle()) ); \ - uiInEventGroupSetBitsFromISR = 0; - -#undef traceEVENT_GROUP_CREATE -#define traceEVENT_GROUP_CREATE(eg) \ - TRACE_SET_EVENTGROUP_NUMBER(eg); \ - vTraceStoreKernelCall(EVENT_GROUP_CREATE, TRACE_CLASS_EVENTGROUP, TRACE_GET_EVENTGROUP_NUMBER(eg)); - -#undef traceEVENT_GROUP_DELETE -#define traceEVENT_GROUP_DELETE(eg) \ - vTraceStoreKernelCall(EVENT_GROUP_DELETE, TRACE_CLASS_EVENTGROUP, TRACE_GET_EVENTGROUP_NUMBER(eg)); \ - vTraceStoreObjectNameOnCloseEvent(TRACE_GET_EVENTGROUP_NUMBER(eg), TRACE_CLASS_EVENTGROUP); \ - vTraceStoreObjectPropertiesOnCloseEvent(TRACE_GET_EVENTGROUP_NUMBER(eg), TRACE_CLASS_EVENTGROUP); \ - vTraceFreeObjectHandle(TRACE_CLASS_EVENTGROUP, TRACE_GET_EVENTGROUP_NUMBER(eg)); - -#undef traceEVENT_GROUP_CREATE_FAILED -#define traceEVENT_GROUP_CREATE_FAILED() \ - vTraceStoreKernelCall(EVENT_GROUP_CREATE_FAILED, TRACE_CLASS_EVENTGROUP, 0); - -#undef traceEVENT_GROUP_SYNC_BLOCK -#define traceEVENT_GROUP_SYNC_BLOCK(eg, bitsToSet, bitsToWaitFor) \ - vTraceStoreKernelCallWithParam(EVENT_GROUP_SYNC_BLOCK, TRACE_CLASS_EVENTGROUP, TRACE_GET_EVENTGROUP_NUMBER(eg), bitsToWaitFor); - -#undef traceEVENT_GROUP_SYNC_END -#define traceEVENT_GROUP_SYNC_END(eg, bitsToSet, bitsToWaitFor, wasTimeout) \ - if (wasTimeout){ vTraceStoreKernelCallWithParam(EVENT_GROUP_SYNC_END_FAILED, TRACE_CLASS_EVENTGROUP, TRACE_GET_EVENTGROUP_NUMBER(eg), bitsToWaitFor);} \ - else{ vTraceStoreKernelCallWithParam(EVENT_GROUP_SYNC_END, TRACE_CLASS_EVENTGROUP, TRACE_GET_EVENTGROUP_NUMBER(eg), bitsToWaitFor); } - -#undef traceEVENT_GROUP_WAIT_BITS_BLOCK -#define traceEVENT_GROUP_WAIT_BITS_BLOCK(eg, bitsToWaitFor) \ - vTraceStoreKernelCallWithParam(EVENT_GROUP_WAIT_BITS_BLOCK, TRACE_CLASS_EVENTGROUP, TRACE_GET_EVENTGROUP_NUMBER(eg), bitsToWaitFor); \ - trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED(); - -#undef traceEVENT_GROUP_WAIT_BITS_END -#define traceEVENT_GROUP_WAIT_BITS_END(eg, bitsToWaitFor, wasTimeout) \ - if (wasTimeout){ vTraceStoreKernelCallWithParam(EVENT_GROUP_WAIT_BITS_END_FAILED, TRACE_CLASS_EVENTGROUP, TRACE_GET_EVENTGROUP_NUMBER(eg), bitsToWaitFor); } \ - else{ vTraceStoreKernelCallWithParam(EVENT_GROUP_WAIT_BITS_END, TRACE_CLASS_EVENTGROUP, TRACE_GET_EVENTGROUP_NUMBER(eg), bitsToWaitFor); } - -#undef traceEVENT_GROUP_CLEAR_BITS -#define traceEVENT_GROUP_CLEAR_BITS(eg, bitsToClear) \ - if (bitsToClear) vTraceStoreKernelCallWithParam(EVENT_GROUP_CLEAR_BITS, TRACE_CLASS_EVENTGROUP, TRACE_GET_EVENTGROUP_NUMBER(eg), bitsToClear); - -#undef traceEVENT_GROUP_CLEAR_BITS_FROM_ISR -#define traceEVENT_GROUP_CLEAR_BITS_FROM_ISR(eg, bitsToClear) \ - if (bitsToClear) vTraceStoreKernelCallWithParam(EVENT_GROUP_CLEAR_BITS_FROM_ISR, TRACE_CLASS_EVENTGROUP, TRACE_GET_EVENTGROUP_NUMBER(eg), bitsToClear); - -#undef traceEVENT_GROUP_SET_BITS -#define traceEVENT_GROUP_SET_BITS(eg, bitsToSet) \ - vTraceStoreKernelCallWithParam(EVENT_GROUP_SET_BITS, TRACE_CLASS_EVENTGROUP, TRACE_GET_EVENTGROUP_NUMBER(eg), bitsToSet); - -#undef traceEVENT_GROUP_SET_BITS_FROM_ISR -#define traceEVENT_GROUP_SET_BITS_FROM_ISR(eg, bitsToSet) \ - vTraceStoreKernelCallWithParam(EVENT_GROUP_SET_BITS_FROM_ISR, TRACE_CLASS_EVENTGROUP, TRACE_GET_EVENTGROUP_NUMBER(eg), bitsToSet); \ - uiInEventGroupSetBitsFromISR = 1; - -#if (INCLUDE_MEMMANG_EVENTS == 1) - -extern void vTraceStoreMemMangEvent(uint32_t ecode, uint32_t address, uint32_t size); - -#undef traceMALLOC -#define traceMALLOC( pvAddress, uiSize ) {vTraceStoreMemMangEvent(MEM_MALLOC_SIZE, ( uint32_t ) pvAddress, uiSize); TRACE_INCR_HEAP_USAGE(uiSize);} - - -#undef traceFREE -#define traceFREE( pvAddress, uiSize ) {vTraceStoreMemMangEvent(MEM_FREE_SIZE, ( uint32_t ) pvAddress, uiSize); TRACE_DECR_HEAP_USAGE(uiSize);} - -#endif - -/************************************************************************/ -/* KERNEL SPECIFIC MACROS TO EXCLUDE OR INCLUDE THINGS IN TRACE */ -/************************************************************************/ - -/* Returns the exclude state of the object */ -uint8_t uiTraceIsObjectExcluded(traceObjectClass objectclass, objectHandleType handle); - -#define TRACE_SET_QUEUE_FLAG_ISEXCLUDED(queueIndex) TRACE_SET_FLAG_ISEXCLUDED(excludedObjects, queueIndex) -#define TRACE_CLEAR_QUEUE_FLAG_ISEXCLUDED(queueIndex) TRACE_CLEAR_FLAG_ISEXCLUDED(excludedObjects, queueIndex) -#define TRACE_GET_QUEUE_FLAG_ISEXCLUDED(queueIndex) TRACE_GET_FLAG_ISEXCLUDED(excludedObjects, queueIndex) - -#define TRACE_SET_SEMAPHORE_FLAG_ISEXCLUDED(semaphoreIndex) TRACE_SET_FLAG_ISEXCLUDED(excludedObjects, NQueue+1+semaphoreIndex) -#define TRACE_CLEAR_SEMAPHORE_FLAG_ISEXCLUDED(semaphoreIndex) TRACE_CLEAR_FLAG_ISEXCLUDED(excludedObjects, NQueue+1+semaphoreIndex) -#define TRACE_GET_SEMAPHORE_FLAG_ISEXCLUDED(semaphoreIndex) TRACE_GET_FLAG_ISEXCLUDED(excludedObjects, NQueue+1+semaphoreIndex) - -#define TRACE_SET_MUTEX_FLAG_ISEXCLUDED(mutexIndex) TRACE_SET_FLAG_ISEXCLUDED(excludedObjects, NQueue+1+NSemaphore+1+mutexIndex) -#define TRACE_CLEAR_MUTEX_FLAG_ISEXCLUDED(mutexIndex) TRACE_CLEAR_FLAG_ISEXCLUDED(excludedObjects, NQueue+1+NSemaphore+1+mutexIndex) -#define TRACE_GET_MUTEX_FLAG_ISEXCLUDED(mutexIndex) TRACE_GET_FLAG_ISEXCLUDED(excludedObjects, NQueue+1+NSemaphore+1+mutexIndex) - -#define TRACE_SET_TASK_FLAG_ISEXCLUDED(taskIndex) TRACE_SET_FLAG_ISEXCLUDED(excludedObjects, NQueue+1+NSemaphore+1+NMutex+1+taskIndex) -#define TRACE_CLEAR_TASK_FLAG_ISEXCLUDED(taskIndex) TRACE_CLEAR_FLAG_ISEXCLUDED(excludedObjects, NQueue+1+NSemaphore+1+NMutex+1+taskIndex) -#define TRACE_GET_TASK_FLAG_ISEXCLUDED(taskIndex) TRACE_GET_FLAG_ISEXCLUDED(excludedObjects, NQueue+1+NSemaphore+1+NMutex+1+taskIndex) - -#define TRACE_SET_TIMER_FLAG_ISEXCLUDED(timerIndex) TRACE_SET_FLAG_ISEXCLUDED(excludedObjects, NQueue+1+NSemaphore+1+NMutex+1+NTask+1+timerIndex) -#define TRACE_CLEAR_TIMER_FLAG_ISEXCLUDED(timerIndex) TRACE_CLEAR_FLAG_ISEXCLUDED(excludedObjects, NQueue+1+NSemaphore+1+NMutex+1+NTask+1+timerIndex) -#define TRACE_GET_TIMER_FLAG_ISEXCLUDED(timerIndex) TRACE_GET_FLAG_ISEXCLUDED(excludedObjects, NQueue+1+NSemaphore+1+NMutex+1+NTask+1+timerIndex) - -#define TRACE_SET_EVENTGROUP_FLAG_ISEXCLUDED(egIndex) TRACE_SET_FLAG_ISEXCLUDED(excludedObjects, NQueue+1+NSemaphore+1+NMutex+1+NTask+1+NTimer+1+egIndex) -#define TRACE_CLEAR_EVENTGROUP_FLAG_ISEXCLUDED(egIndex) TRACE_CLEAR_FLAG_ISEXCLUDED(excludedObjects, NQueue+1+NSemaphore+1+NMutex+1+NTask+1+NTimer+1+egIndex) -#define TRACE_GET_EVENTGROUP_FLAG_ISEXCLUDED(egIndex) TRACE_GET_FLAG_ISEXCLUDED(excludedObjects, NQueue+1+NSemaphore+1+NMutex+1+NTask+1+NTimer+1+egIndex) - - -#define TRACE_CLEAR_OBJECT_FLAG_ISEXCLUDED(objectclass, handle) \ -switch (objectclass) \ -{ \ -case TRACE_CLASS_QUEUE: \ - TRACE_CLEAR_QUEUE_FLAG_ISEXCLUDED(handle); \ - break; \ -case TRACE_CLASS_SEMAPHORE: \ - TRACE_CLEAR_SEMAPHORE_FLAG_ISEXCLUDED(handle); \ - break; \ -case TRACE_CLASS_MUTEX: \ - TRACE_CLEAR_MUTEX_FLAG_ISEXCLUDED(handle); \ - break; \ -case TRACE_CLASS_TASK: \ - TRACE_CLEAR_TASK_FLAG_ISEXCLUDED(handle); \ - break; \ -case TRACE_CLASS_TIMER: \ - TRACE_CLEAR_TIMER_FLAG_ISEXCLUDED(handle); \ - break; \ -case TRACE_CLASS_EVENTGROUP: \ - TRACE_CLEAR_EVENTGROUP_FLAG_ISEXCLUDED(handle); \ - break; \ -} - -#define TRACE_SET_OBJECT_FLAG_ISEXCLUDED(objectclass, handle) \ -switch (objectclass) \ -{ \ -case TRACE_CLASS_QUEUE: \ - TRACE_SET_QUEUE_FLAG_ISEXCLUDED(handle); \ - break; \ -case TRACE_CLASS_SEMAPHORE: \ - TRACE_SET_SEMAPHORE_FLAG_ISEXCLUDED(handle); \ - break; \ -case TRACE_CLASS_MUTEX: \ - TRACE_SET_MUTEX_FLAG_ISEXCLUDED(handle); \ - break; \ -case TRACE_CLASS_TASK: \ - TRACE_SET_TASK_FLAG_ISEXCLUDED(handle); \ - break; \ -case TRACE_CLASS_TIMER: \ - TRACE_SET_TIMER_FLAG_ISEXCLUDED(handle); \ - break; \ -case TRACE_CLASS_EVENTGROUP: \ - TRACE_SET_EVENTGROUP_FLAG_ISEXCLUDED(handle); \ - break; \ -} - -/* Task */ -#define vTraceExcludeTaskFromTrace(handle) \ -TRACE_SET_TASK_FLAG_ISEXCLUDED(TRACE_GET_TASK_NUMBER(handle)); - -#define vTraceIncludeTaskInTrace(handle) \ -TRACE_CLEAR_TASK_FLAG_ISEXCLUDED(TRACE_GET_TASK_NUMBER(handle)); - - -/* Queue */ -#define vTraceExcludeQueueFromTrace(handle) \ -TRACE_SET_QUEUE_FLAG_ISEXCLUDED(TRACE_GET_OBJECT_NUMBER(UNUSED, handle)); - -#define vTraceIncludeQueueInTrace(handle) \ -TRACE_CLEAR_QUEUE_FLAG_ISEXCLUDED(TRACE_GET_OBJECT_NUMBER(UNUSED, handle)); - - -/* Semaphore */ -#define vTraceExcludeSemaphoreFromTrace(handle) \ -TRACE_SET_SEMAPHORE_FLAG_ISEXCLUDED(TRACE_GET_OBJECT_NUMBER(UNUSED, handle)); - -#define vTraceIncludeSemaphoreInTrace(handle) \ -TRACE_CLEAR_QUEUE_FLAG_ISEXCLUDED(TRACE_GET_OBJECT_NUMBER(UNUSED, handle)); - - -/* Mutex */ -#define vTraceExcludeMutexFromTrace(handle) \ -TRACE_SET_MUTEX_FLAG_ISEXCLUDED(TRACE_GET_OBJECT_NUMBER(UNUSED, handle)); - -#define vTraceIncludeMutexInTrace(handle) \ -TRACE_CLEAR_QUEUE_FLAG_ISEXCLUDED(TRACE_GET_OBJECT_NUMBER(UNUSED, handle)); - -/* Timer */ -#define vTraceExcludeTimerFromTrace(handle) \ -TRACE_SET_TIMER_FLAG_ISEXCLUDED(TRACE_GET_TIMER_NUMBER(handle)); - -#define vTraceIncludeTimerInTrace(handle) \ -TRACE_CLEAR_QUEUE_FLAG_ISEXCLUDED(TRACE_GET_TIMER_NUMBER(handle)); - -/* Event Group */ -#define vTraceExcludeEventGroupFromTrace(handle) \ -TRACE_SET_EVENTGROUP_FLAG_ISEXCLUDED(TRACE_GET_EVENTGROUP_NUMBER(handle)); - -#define vTraceIncludeEventGroupInTrace(handle) \ -TRACE_CLEAR_EVENTGROUP_FLAG_ISEXCLUDED(TRACE_GET_EVENTGROUP_NUMBER(handle)); - - -/* Kernel Services */ -#define vTraceExcludeKernelServiceDelayFromTrace() \ -TRACE_SET_EVENT_CODE_FLAG_ISEXCLUDED(TASK_DELAY); \ -TRACE_SET_EVENT_CODE_FLAG_ISEXCLUDED(TASK_DELAY_UNTIL); - -#define vTraceIncludeKernelServiceDelayInTrace() \ -TRACE_CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(TASK_DELAY); \ -TRACE_CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(TASK_DELAY_UNTIL); - -/* HELPER MACROS FOR KERNEL SERVICES FOR OBJECTS */ -#define vTraceExcludeKernelServiceSendFromTrace_HELPER(class) \ -TRACE_SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_SUCCESS + class); \ -TRACE_SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_BLOCK + class); \ -TRACE_SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_FAILED + class); \ -TRACE_SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_FROM_ISR_SUCCESS + class); \ -TRACE_SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_FROM_ISR_FAILED + class); - -#define vTraceIncludeKernelServiceSendInTrace_HELPER(class) \ -TRACE_CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_SUCCESS + class); \ -TRACE_CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_BLOCK + class); \ -TRACE_CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_FAILED + class); \ -TRACE_CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_FROM_ISR_SUCCESS + class); \ -TRACE_CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_FROM_ISR_FAILED + class); - -#define vTraceExcludeKernelServiceReceiveFromTrace_HELPER(class) \ -TRACE_SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_SUCCESS + class); \ -TRACE_SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_BLOCK + class); \ -TRACE_SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_FAILED + class); \ -TRACE_SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_FROM_ISR_SUCCESS + class); \ -TRACE_SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_FROM_ISR_FAILED + class); - -#define vTraceIncludeKernelServiceReceiveInTrace_HELPER(class) \ -TRACE_CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_SUCCESS + class); \ -TRACE_CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_BLOCK + class); \ -TRACE_CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_FAILED + class); \ -TRACE_CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_FROM_ISR_SUCCESS + class); \ -TRACE_CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_FROM_ISR_FAILED + class); - -/* EXCLUDE AND INCLUDE FOR QUEUE */ -#define vTraceExcludeKernelServiceQueueSendFromTrace() \ -vTraceExcludeKernelServiceSendFromTrace_HELPER(TRACE_CLASS_QUEUE); - -#define vTraceIncludeKernelServiceQueueSendInTrace() \ -vTraceIncludeKernelServiceSendInTrace_HELPER(TRACE_CLASS_QUEUE); - -#define vTraceExcludeKernelServiceQueueReceiveFromTrace() \ -vTraceExcludeKernelServiceReceiveFromTrace_HELPER(TRACE_CLASS_QUEUE); - -#define vTraceIncludeKernelServiceQueueReceiveInTrace() \ -vTraceIncludeKernelServiceReceiveInTrace_HELPER(TRACE_CLASS_QUEUE); - -/* EXCLUDE AND INCLUDE FOR SEMAPHORE */ -#define vTraceExcludeKernelServiceSemaphoreSendFromTrace() \ -vTraceExcludeKernelServiceSendFromTrace_HELPER(TRACE_CLASS_SEMAPHORE); - -#define vTraceIncludeKernelServicSemaphoreSendInTrace() \ -vTraceIncludeKernelServiceSendInTrace_HELPER(TRACE_CLASS_SEMAPHORE); - -#define vTraceExcludeKernelServiceSemaphoreReceiveFromTrace() \ -vTraceExcludeKernelServiceReceiveFromTrace_HELPER(TRACE_CLASS_SEMAPHORE); - -#define vTraceIncludeKernelServiceSemaphoreReceiveInTrace() \ -vTraceIncludeKernelServiceReceiveInTrace_HELPER(TRACE_CLASS_SEMAPHORE); - -/* EXCLUDE AND INCLUDE FOR MUTEX */ -#define vTraceExcludeKernelServiceMutexSendFromTrace() \ -vTraceExcludeKernelServiceSendFromTrace_HELPER(TRACE_CLASS_MUTEX); - -#define vTraceIncludeKernelServiceMutexSendInTrace() \ -vTraceIncludeKernelServiceSendInTrace_HELPER(TRACE_CLASS_MUTEX); - -#define vTraceExcludeKernelServiceMutexReceiveFromTrace() \ -vTraceExcludeKernelServiceReceiveFromTrace_HELPER(TRACE_CLASS_MUTEX); - -#define vTraceIncludeKernelServiceMutexReceiveInTrace() \ -vTraceIncludeKernelServiceReceiveInTrace_HELPER(TRACE_CLASS_MUTEX); - -/************************************************************************/ -/* KERNEL SPECIFIC MACROS TO NAME OBJECTS, IF NECESSARY */ -/************************************************************************/ -#define vTraceSetQueueName(object, name) \ -vTraceSetObjectName(TRACE_GET_OBJECT_TRACE_CLASS(UNUSED, object), TRACE_GET_OBJECT_NUMBER(UNUSED, object), name); - -#define vTraceSetSemaphoreName(object, name) \ -vTraceSetObjectName(TRACE_GET_OBJECT_TRACE_CLASS(UNUSED, object), TRACE_GET_OBJECT_NUMBER(UNUSED, object), name); - -#define vTraceSetMutexName(object, name) \ -vTraceSetObjectName(TRACE_GET_OBJECT_TRACE_CLASS(UNUSED, object), TRACE_GET_OBJECT_NUMBER(UNUSED, object), name); - -#define vTraceSetEventGroupName(object, name) \ -vTraceSetObjectName(TRACE_CLASS_EVENTGROUP, uxEventGroupGetNumber(object), name); - -#undef traceQUEUE_REGISTRY_ADD -#define traceQUEUE_REGISTRY_ADD(object, name) vTraceSetObjectName(TRACE_GET_OBJECT_TRACE_CLASS(UNUSED, object), TRACE_GET_OBJECT_NUMBER(UNUSED, object), name); -#endif +/* Change the included file below, if using the recorder with other kernels */ -#endif /* TRCKERNELPORT_H_ */ \ No newline at end of file +#include "trcKernelPortFreeRTOS.h" +/* #include "trcKernelPort.h" */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcTypes.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcTypes.h index f1d434a98..41a2b0ec6 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcTypes.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcTypes.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Tracealyzer v2.6.0 Recorder Library + * Tracealyzer v2.7.0 Recorder Library * Percepio AB, www.percepio.com * * trcTypes.h @@ -31,7 +31,9 @@ * damages, or the exclusion of implied warranties or limitations on how long an * implied warranty may last, so the above limitations may not apply to you. * - * Copyright Percepio AB, 2013. + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2014. * www.percepio.com ******************************************************************************/ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcUser.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcUser.h index dba4432e6..a2682e681 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcUser.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcUser.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Tracealyzer v2.6.0 Recorder Library + * Tracealyzer v2.7.0 Recorder Library * Percepio AB, www.percepio.com * * trcUser.h @@ -30,7 +30,9 @@ * damages, or the exclusion of implied warranties or limitations on how long an * implied warranty may last, so the above limitations may not apply to you. * - * Copyright Percepio AB, 2013. + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2014. * www.percepio.com ******************************************************************************/ @@ -82,6 +84,13 @@ void vTraceInitTraceData(void); void vTraceSetRecorderData(void* pRecorderData); #endif +/******************************************************************************* + * vTraceSetStopHook + * + * Sets a function to be called when the recorder is stopped. + ******************************************************************************/ +void vTraceSetStopHook(TRACE_STOP_HOOK stopHookFunction); + /******************************************************************************* * uiTraceStart * @@ -154,21 +163,17 @@ void vTraceClearError(int resetErrorMessage); * started. * * Example: - * #define ID_ISR_TIMER1 1 // lowest valid ID is 1 - * #define PRIO_OF_ISR_TIMER1 3 // the hardware priority of the interrupt - * ... - * vTraceSetISRProperties(ID_ISR_TIMER1, "ISRTimer1", PRIO_OF_ISR_TIMER1); - * ... - * void ISR_handler() - * { - * portENTER_CRITICAL(); // Required if nested ISRs are allowed - * vTraceStoreISRBegin(ID_OF_ISR_TIMER1); - * portEXIT_CRITICAL(); - * ... - * portENTER_CRITICAL(); // Required if nested ISRs are allowed - * vTraceStoreISREnd(); - * portEXIT_CRITICAL(); - * } + * #define ID_ISR_TIMER1 1 // lowest valid ID is 1 + * #define PRIO_OF_ISR_TIMER1 3 // the hardware priority of the interrupt + * ... + * vTraceSetISRProperties(ID_ISR_TIMER1, "ISRTimer1", PRIO_OF_ISR_TIMER1); + * ... + * void ISR_handler() + * { + * vTraceStoreISRBegin(ID_OF_ISR_TIMER1); + * ... + * vTraceStoreISREnd(0); + * } ******************************************************************************/ void vTraceSetISRProperties(objectHandleType handle, const char* name, char priority); @@ -179,21 +184,17 @@ void vTraceSetISRProperties(objectHandleType handle, const char* name, char prio * If allowing nested ISRs, this must be called with interrupts disabled. * * Example: - * #define ID_ISR_TIMER1 1 // lowest valid ID is 1 - * #define PRIO_OF_ISR_TIMER1 3 // the hardware priority of the interrupt - * ... - * vTraceSetISRProperties(ID_ISR_TIMER1, "ISRTimer1", PRIO_OF_ISR_TIMER1); - * ... - * void ISR_handler() - * { - * portENTER_CRITICAL(); // Required if nested ISRs are allowed - * vTraceStoreISRBegin(ID_OF_ISR_TIMER1); - * portEXIT_CRITICAL(); - * ... - * portENTER_CRITICAL(); // Required if nested ISRs are allowed - * vTraceStoreISREnd(); - * portEXIT_CRITICAL(); - * } + * #define ID_ISR_TIMER1 1 // lowest valid ID is 1 + * #define PRIO_OF_ISR_TIMER1 3 // the hardware priority of the interrupt + * ... + * vTraceSetISRProperties(ID_ISR_TIMER1, "ISRTimer1", PRIO_OF_ISR_TIMER1); + * ... + * void ISR_handler() + * { + * vTraceStoreISRBegin(ID_OF_ISR_TIMER1); + * ... + * vTraceStoreISREnd(0); + * } * ******************************************************************************/ void vTraceStoreISRBegin(objectHandleType id); @@ -203,30 +204,27 @@ void vTraceStoreISRBegin(objectHandleType id); * * Registers the end of an Interrupt Service Routine. * - * If allowing nested ISRs, this must be called with interrupts disabled. + * The parameter pendingISR indicates if the interrupt has requested a + * task-switch (= 1) or if the interrupt returns to the earlier context (= 0) * * Example: - * #define ID_ISR_TIMER1 1 // lowest valid ID is 1 - * #define PRIO_OF_ISR_TIMER1 3 // the hardware priority of the interrupt - * ... - * vTraceSetISRProperties(ID_ISR_TIMER1, "ISRTimer1", PRIO_OF_ISR_TIMER1); - * ... - * void ISR_handler() - * { - * portENTER_CRITICAL(); // Required if nested ISRs are allowed - * vTraceStoreISRBegin(ID_OF_ISR_TIMER1); - * portEXIT_CRITICAL(); - * ... - * portENTER_CRITICAL(); // Required if nested ISRs are allowed - * vTraceStoreISREnd(); - * portEXIT_CRITICAL(); - * } + * #define ID_ISR_TIMER1 1 // lowest valid ID is 1 + * #define PRIO_OF_ISR_TIMER1 3 // the hardware priority of the interrupt + * ... + * vTraceSetISRProperties(ID_ISR_TIMER1, "ISRTimer1", PRIO_OF_ISR_TIMER1); + * ... + * void ISR_handler() + * { + * vTraceStoreISRBegin(ID_OF_ISR_TIMER1); + * ... + * vTraceStoreISREnd(0); + * } * ******************************************************************************/ -void vTraceStoreISREnd(void); +void vTraceStoreISREnd(int pendingISR); #else - /* If not including the ISR recording */ + /* If not including the ISR recording */ void vTraceIncreaseISRActive(void); @@ -238,28 +236,59 @@ void vTraceDecreaseISRActive(void); #endif -/******************************************************************************* - * vvTraceTaskSkipDefaultInstanceFinishedEvents - * - * This is useful if there are implicit Instance Finish Events, such as - * vTaskDelayUntil or xQueueReceive, in a task where an explicit Instance Finish - * Event has been defined. This function tells the recorder that only the - * explicitly defined functions (using vTraceTaskInstanceIsFinished) should be - * treated as Instance Finish Events for this task. The implicit Instance Finish - * Events are thus disregarded for this task. - ******************************************************************************/ -void vTraceTaskSkipDefaultInstanceFinishedEvents(void); -/******************************************************************************* - * vTraceTaskInstanceIsFinished +/****************************************************************************** + * vTraceTaskInstanceFinish(void) * - * This defines an explicit Instance Finish Event for the current task. It tells - * the recorder that the current instance of this task is finished at the next - * kernel call of the task, e.g., a taskDelay or a queue receive. This function - * should be called right before the api function call considered to be the end - * of the task instamce, i.e., the Instance Finish Event. - ******************************************************************************/ -void vTraceTaskInstanceIsFinished(void); + * Marks the current task instance as finished on the next kernel call. + * + * If that kernel call is blocking, the instance ends after the blocking event + * and the corresponding return event is then the start of the next instance. + * If the kernel call is not blocking, the viewer instead splits the current + * fragment right before the kernel call, which makes this call the first event + * of the next instance. + * + * See also USE_IMPLICIT_IFE_RULES in trcConfig.h + * + * Example: + * + * while(1) + * { + * xQueueReceive(CommandQueue, &command, timeoutDuration); + * processCommand(command); + * vTraceInstanceFinish(); + * } + * + *****************************************************************************/ +void vTraceTaskInstanceFinish(void); + +/****************************************************************************** + * vTraceTaskInstanceFinishDirect(void) + * + * Marks the current task instance as finished at this very instant. + * This makes the viewer to splits the current fragment at this point and begin + * a new actor instance. + * + * See also USE_IMPLICIT_IFE_RULES in trcConfig.h + * + * Example: + * + * This example will generate two instances for each loop iteration. + * The first instance ends at vTraceInstanceFinishDirect(), while the second + * instance ends at the next xQueueReceive call. + * + * while (1) + * { + * xQueueReceive(CommandQueue, &command, timeoutDuration); + * ProcessCommand(command); + * vTraceInstanceFinishDirect(); + * DoSometingElse(); + * vTraceInstanceFinish(); + * } + * + * + *****************************************************************************/ +void vTraceTaskInstanceFinishDirect(void); /******************************************************************************* * vTraceGetTraceBuffer @@ -292,7 +321,7 @@ uint32_t uiTraceGetTraceBufferSize(void); * When logging a user event, a numeric handle (reference) to this string is * used to identify the event. This is obtained by calling * - * xTraceOpenLabel() + * xTraceOpenLabel() * * whihc adds the string to the symbol table (if not already present) * and returns the corresponding handle. @@ -302,15 +331,15 @@ uint32_t uiTraceGetTraceBufferSize(void); * 1. The handle is looked up every time, when storing the user event. * * Example: - * vTraceUserEvent(xTraceOpenLabel("MyUserEvent")); + * vTraceUserEvent(xTraceOpenLabel("MyUserEvent")); * * 2. The label is registered just once, with the handle stored in an - * application variable - much like using a file handle. + * application variable - much like using a file handle. * * Example: - * myEventHandle = xTraceOpenLabel("MyUserEvent"); - * ... - * vTraceUserEvent(myEventHandle); + * myEventHandle = xTraceOpenLabel("MyUserEvent"); + * ... + * vTraceUserEvent(myEventHandle); * * The second option is faster since no lookup is required on each event, and * therefore recommended for user events that are frequently @@ -342,17 +371,17 @@ void vTraceUserEvent(traceLabel eventLabel); * User Event labels are created using xTraceOpenLabel. * Example: * - * traceLabel adc_uechannel = xTraceOpenLabel("ADC User Events"); - * ... - * vTracePrint(adc_uechannel, - * "ADC channel %d: %lf volts", - * ch, (double)adc_reading/(double)scale); + * traceLabel adc_uechannel = xTraceOpenLabel("ADC User Events"); + * ... + * vTracePrint(adc_uechannel, + * "ADC channel %d: %lf volts", + * ch, (double)adc_reading/(double)scale); * * This can be combined into one line, if desired, but this is slower: * - * vTracePrint(xTraceOpenLabel("ADC User Events"), - * "ADC channel %d: %lf volts", - * ch, (double)adc_reading/(double)scale); + * vTracePrint(xTraceOpenLabel("ADC User Events"), + * "ADC channel %d: %lf volts", + * ch, (double)adc_reading/(double)scale); * * Calling xTraceOpenLabel multiple times will not create duplicate entries, but * it is of course faster to just do it once, and then keep the handle for later @@ -360,15 +389,15 @@ void vTraceUserEvent(traceLabel eventLabel); * better to use vTraceUserEvent - it is faster. * * Format specifiers supported: - * %d - 32 bit signed integer - * %u - 32 bit unsigned integer - * %f - 32 bit float - * %s - string (is copied to the recorder symbol table) - * %hd - 16 bit signed integer - * %hu - 16 bit unsigned integer - * %bd - 8 bit signed integer - * %bu - 8 bit unsigned integer - * %lf - double-precision float (Note! See below...) + * %d - 32 bit signed integer + * %u - 32 bit unsigned integer + * %f - 32 bit float + * %s - string (is copied to the recorder symbol table) + * %hd - 16 bit signed integer + * %hu - 16 bit unsigned integer + * %bd - 8 bit signed integer + * %bu - 8 bit unsigned integer + * %lf - double-precision float (Note! See below...) * * Up to 15 data arguments are allowed, with a total size of maximum 32 byte. * In case this is exceeded, the user event is changed into an error message. @@ -380,7 +409,7 @@ void vTraceUserEvent(traceLabel eventLabel); * unless the higher precision is really necessary. * * Note that the double-precision float (%lf) assumes a 64 bit double - * representation. This does not seem to be the case on e.g. PIC24F. + * representation. This does not seem to be the case on e.g. PIC24 and PIC32. * Before using a %lf argument on a 16-bit MCU, please verify that * "sizeof(double)" actually gives 8 as expected. If not, use %f instead. ******************************************************************************/ @@ -417,7 +446,6 @@ void vTraceChannelUserEvent(UserEventChannel channel); #define vTracePrintF(eventLabel,formatStr,...) #define vTraceExcludeTaskFromSchedulingTrace(name) -#define vTraceTaskSkipDefaultInstanceFinishedEvents() #define vTraceSetISRProperties(handle, name, priority) #define vTraceStoreISRBegin(id) #define vTraceStoreISREnd() @@ -427,6 +455,7 @@ void vTraceChannelUserEvent(UserEventChannel channel); #define vTraceSetSemaphoreName(a, b) #define vTraceSetEventGroupName(a, b) +#define vTraceSetStopHook(a) #endif #ifdef __cplusplus diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/readme.txt b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/readme.txt index 2c6c55195..44b321fef 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/readme.txt +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/readme.txt @@ -4,21 +4,22 @@ Tracealyzer Trace Recorder Library Percepio AB www.percepio.com -This directory contains the a generic trace recorder library for Tracealyzer v2.6. +This directory contains the a generic trace recorder library for Tracealyzer v2.7. For information on how to upload the trace data from your target system RAM to -Tracealyzer, see "debugger trace upload.txt" +Tracealyzer, see the User Manual (e.g., http://percepio.com/docs/FreeRTOS/manual/Recorder.html) Files included -------------- -- trcConfig.h - The recorder's configuration file, set your recorder configuration here! -- trcUser.c/.h - The main API towards the application (trcUser.h in the only include necessary). -- trcKernel.c/.h - Internal routines for storing kernel events. -- trcBase.c/.h - Internal routines for manipulating the data structures and calculating timestamps. -- trcHardwarePort.c/.h - The hardware interface, especially for timestamping. -- trcKernelPort.c/.h - Kernel specific implementations of macros and data. -- trcKernelHooks.h - The trace macro defines (OS independent). -- trcTypes.h - Type definitions used. +- trcConfig.h - The recorder's configuration file, set your recorder configuration here! +- trcUser.c/.h - The main API towards the application (trcUser.h in the only include necessary). +- trcKernel.c/.h - Internal routines for storing kernel events. +- trcBase.c/.h - Internal routines for manipulating the data structures and calculating timestamps. +- trcHardwarePort.c/.h - The hardware interface, especially for timestamping. +- trcKernelPort.h - Wrapper for trcKernelPortFreeRTOS.h (for portability). +- trcKernelPortFreeRTOS.c/.h - FreeRTOS-specific trace macros and helper functions. +- trcKernelHooks.h - Generic trace macros (OS independent), used by trcKernelPortFreeRTOS. +- trcTypes.h - Type definitions used. Hardware Timer Ports -------------------- @@ -29,17 +30,19 @@ This release contains hardware timer ports for the following hardware architectu - Atmel AT32UC3 (AVR32) - Renesas RX600 (e.g., RX62N) - Microchip dsPIC/PIC24 -- Microchip PIC32 +- Microchip PIC32MX +- Microchip PIC32MZ - NXP LPC2106 - Texas Instruments TMS570 (Cortex-R4) - Texas Instruments MSP430 - Xilinx PowerPC 405 - Xilinx PowerPC 440 - Xilinx Microblaze +- ARM Cortex-A9 These are defined in trcHardwarePort.h. Some of these are "unofficial" ports, provided by external contributors. By unofficial, it means that they are not yet verified by Percepio AB. Please refer to trcHardwarePort.h for detailed information. -If you use an unofficial port and beleive it is incorrect, please let us know! (support@percepio.com) +If you use an unofficial port and believe it is incorrect, please let us know! (support@percepio.com) In case your MCU is not yet supported directly, developing a new port is quite easy, just a matter of defining a few macros according to your specific MCU. See trcHardwarePort.h for further information. diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcBase.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcBase.c index be5f93530..57afa6483 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcBase.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcBase.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Tracealyzer v2.6.0 Recorder Library + * Tracealyzer v2.7.0 Recorder Library * Percepio AB, www.percepio.com * * trcBase.c @@ -31,7 +31,9 @@ * damages, or the exclusion of implied warranties or limitations on how long an * implied warranty may last, so the above limitations may not apply to you. * - * Copyright Percepio AB, 2013. + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2014. * www.percepio.com ******************************************************************************/ @@ -45,45 +47,54 @@ * Static data initializations ******************************************************************************/ -/* Structure to handle the exclude flags for all objects and tasks. We add some extra objects since index 0 is not used for each object class. */ +/* Tasks and kernel objects can be explicitly excluded from the trace to reduce +buffer usage. This structure handles the exclude flags for all objects and tasks. +Note that slot 0 is not used, since not a valid handle. */ uint8_t excludedObjects[(TRACE_KERNEL_OBJECT_COUNT + TRACE_NCLASSES) / 8 + 1] = { 0 }; -/* Structure to handle the exclude flags for all event codes */ +/* Specific events can also be excluded, i.e., by the event code. This can be +used to exclude kernel calls that don't refer to a kernel object, like a delay. +This structure handle the exclude flags for all event codes */ uint8_t excludedEventCodes[NEventCodes / 8 + 1] = { 0 }; -/* Keeps track of available handles */ +/* A set of stacks that keeps track of available object handles for each class. +The stacks are empty initially, meaning that allocation of new handles will be +based on a counter (for each object class). Any delete operation will +return the handle to the corresponding stack, for reuse on the next allocate.*/ objectHandleStackType objectHandleStacks = { { 0 }, { 0 }, { 0 }, { 0 }, { 0 } }; +/* Initial HWTC_COUNT value, for detecting if the time-stamping source is +enabled. If using the OS periodic timer for time-stamping, this might not +have been configured on the earliest events during the startup. */ uint32_t init_hwtc_count; /******************************************************************************* * RecorderData * - * The main data structure. This is the data read by Tracealyzer, typically - * through a debugger RAM dump. The recorder access this through the pointer - * RecorderDataPtr, to allow for dynamic memory allocation as well. + * The main data structure. This is the data read by the Tracealyzer tools, + * typically through a debugger RAM dump. The recorder uses the pointer + * RecorderDataPtr for accessing this, to allow for dynamic allocation. * * On the NXP LPC17xx you may use the secondary RAM bank (AHB RAM) for this * purpose. For instance, the LPC1766 has 32 KB AHB RAM which allows for * allocating a buffer size of at least 7500 events without affecting the main - * RAM. To place RecorderData in this RAM bank, use the below declaration. + * RAM. To place RecorderData in this RAM bank using IAR Embedded Workbench + * for ARM, use this pragma right before the declaration: * - * #pragma location="AHB_RAM_MEMORY" - * RecorderDataType RecorderData = ... + * #pragma location="AHB_RAM_MEMORY" * * This of course works for other hardware architectures with additional RAM - * banks as well, just replace "AHB_RAM_MEMORY" with the name of the right - * address section from the linker file. + * banks as well, just replace "AHB_RAM_MEMORY" with the section name from the + * linker .map file, or simply the desired address. * - * However, to keep trcBase.c portable and still have a preconfigured IAR demo - * using AHB RAM, we don't add the pragma directly in trcBase.c but in a header - * included where the pragma should go. This is used depending on the setting + * For portability reasons, we don't add the pragma directly in trcBase.c, but + * in a header file included below. To include this header, you need to enable * USE_LINKER_PRAGMA, defined in trcConfig.h. * - * If using GCC, this is instead done by adding a "section" attribute: - * - * RecorderDataType RecorderData __attribute__ ((section ("name"))) = ... + * If using GCC, you need to modify the declaration as follows: * + * RecorderDataType RecorderData __attribute__ ((section ("name"))) = ... + * * Remember to replace "name" with the correct section name. ******************************************************************************/ @@ -102,7 +113,7 @@ RecorderDataType* RecorderDataPtr = NULL; /* This version of the function dynamically allocates the trace data */ void prvTraceInitTraceData() -{ +{ init_hwtc_count = HWTC_COUNT; #if TRACE_DATA_ALLOCATION == TRACE_DATA_ALLOCATION_STATIC @@ -116,62 +127,62 @@ void prvTraceInitTraceData() TRACE_ASSERT(RecorderDataPtr != NULL, "prvTraceInitTraceData, RecorderDataPtr == NULL", ); - if (! RecorderDataPtr) - { - vTraceError("No recorder data structure allocated!"); - return; - } + if (! RecorderDataPtr) + { + vTraceError("No recorder data structure allocated!"); + return; + } - (void)memset(RecorderDataPtr, 0, sizeof(RecorderDataType)); - - RecorderDataPtr->startmarker0 = 0x00; - RecorderDataPtr->startmarker1 = 0x01; - RecorderDataPtr->startmarker2 = 0x02; - RecorderDataPtr->startmarker3 = 0x03; - RecorderDataPtr->startmarker4 = 0x70; - RecorderDataPtr->startmarker5 = 0x71; - RecorderDataPtr->startmarker6 = 0x72; - RecorderDataPtr->startmarker7 = 0x73; - RecorderDataPtr->startmarker8 = 0xF0; - RecorderDataPtr->startmarker9 = 0xF1; - RecorderDataPtr->startmarker10 = 0xF2; - RecorderDataPtr->startmarker11 = 0xF3; - - RecorderDataPtr->version = TRACE_KERNEL_VERSION; - RecorderDataPtr->minor_version = TRACE_MINOR_VERSION; - RecorderDataPtr->irq_priority_order = IRQ_PRIORITY_ORDER; - RecorderDataPtr->filesize = sizeof(RecorderDataType); - - RecorderDataPtr->maxEvents = EVENT_BUFFER_SIZE; - - RecorderDataPtr->debugMarker0 = 0xF0F0F0F0; + (void)memset(RecorderDataPtr, 0, sizeof(RecorderDataType)); + + RecorderDataPtr->startmarker0 = 0x00; + RecorderDataPtr->startmarker1 = 0x01; + RecorderDataPtr->startmarker2 = 0x02; + RecorderDataPtr->startmarker3 = 0x03; + RecorderDataPtr->startmarker4 = 0x70; + RecorderDataPtr->startmarker5 = 0x71; + RecorderDataPtr->startmarker6 = 0x72; + RecorderDataPtr->startmarker7 = 0x73; + RecorderDataPtr->startmarker8 = 0xF0; + RecorderDataPtr->startmarker9 = 0xF1; + RecorderDataPtr->startmarker10 = 0xF2; + RecorderDataPtr->startmarker11 = 0xF3; + + RecorderDataPtr->version = TRACE_KERNEL_VERSION; + RecorderDataPtr->minor_version = TRACE_MINOR_VERSION; + RecorderDataPtr->irq_priority_order = IRQ_PRIORITY_ORDER; + RecorderDataPtr->filesize = sizeof(RecorderDataType); + + RecorderDataPtr->maxEvents = EVENT_BUFFER_SIZE; + + RecorderDataPtr->debugMarker0 = 0xF0F0F0F0; RecorderDataPtr->isUsing16bitHandles = USE_16BIT_OBJECT_HANDLES; /* This function is kernel specific */ vTraceInitObjectPropertyTable(); - RecorderDataPtr->debugMarker1 = 0xF1F1F1F1; - RecorderDataPtr->SymbolTable.symTableSize = SYMBOL_TABLE_SIZE; - RecorderDataPtr->SymbolTable.nextFreeSymbolIndex = 1; + RecorderDataPtr->debugMarker1 = 0xF1F1F1F1; + RecorderDataPtr->SymbolTable.symTableSize = SYMBOL_TABLE_SIZE; + RecorderDataPtr->SymbolTable.nextFreeSymbolIndex = 1; #if (INCLUDE_FLOAT_SUPPORT == 1) - RecorderDataPtr->exampleFloatEncoding = (float)1.0; /* otherwise already zero */ + RecorderDataPtr->exampleFloatEncoding = (float)1.0; /* otherwise already zero */ #endif - RecorderDataPtr->debugMarker2 = 0xF2F2F2F2; - (void)strncpy(RecorderDataPtr->systemInfo, TRACE_DESCRIPTION, TRACE_DESCRIPTION_MAX_LENGTH); - RecorderDataPtr->debugMarker3 = 0xF3F3F3F3; - RecorderDataPtr->endmarker0 = 0x0A; - RecorderDataPtr->endmarker1 = 0x0B; - RecorderDataPtr->endmarker2 = 0x0C; - RecorderDataPtr->endmarker3 = 0x0D; - RecorderDataPtr->endmarker4 = 0x71; - RecorderDataPtr->endmarker5 = 0x72; - RecorderDataPtr->endmarker6 = 0x73; - RecorderDataPtr->endmarker7 = 0x74; - RecorderDataPtr->endmarker8 = 0xF1; - RecorderDataPtr->endmarker9 = 0xF2; - RecorderDataPtr->endmarker10 = 0xF3; - RecorderDataPtr->endmarker11 = 0xF4; + RecorderDataPtr->debugMarker2 = 0xF2F2F2F2; + (void)strncpy(RecorderDataPtr->systemInfo, "Trace Recorder Demo", 80); + RecorderDataPtr->debugMarker3 = 0xF3F3F3F3; + RecorderDataPtr->endmarker0 = 0x0A; + RecorderDataPtr->endmarker1 = 0x0B; + RecorderDataPtr->endmarker2 = 0x0C; + RecorderDataPtr->endmarker3 = 0x0D; + RecorderDataPtr->endmarker4 = 0x71; + RecorderDataPtr->endmarker5 = 0x72; + RecorderDataPtr->endmarker6 = 0x73; + RecorderDataPtr->endmarker7 = 0x74; + RecorderDataPtr->endmarker8 = 0xF1; + RecorderDataPtr->endmarker9 = 0xF2; + RecorderDataPtr->endmarker10 = 0xF3; + RecorderDataPtr->endmarker11 = 0xF4; #if USE_SEPARATE_USER_EVENT_BUFFER RecorderDataPtr->userEventBuffer.bufferID = 1; @@ -215,26 +226,36 @@ char* traceErrorMessage = NULL; void* xTraceNextFreeEventBufferSlot(void) { - if (RecorderDataPtr->nextFreeIndex >= EVENT_BUFFER_SIZE) - { - vTraceError("Attempt to index outside event buffer!"); - return NULL; - } - return (void*)(&RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex*4]); + if (! RecorderDataPtr->recorderActive) + { + // If the associated XTS or XPS event prio to the main event has filled the buffer and store mode "stop when full". + return NULL; + } + + if (RecorderDataPtr->nextFreeIndex >= EVENT_BUFFER_SIZE) + { + vTraceError("Attempt to index outside event buffer!"); + return NULL; + } + return (void*)(&RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex*4]); } uint16_t uiIndexOfObject(objectHandleType objecthandle, uint8_t objectclass) { - TRACE_ASSERT(objectclass < TRACE_NCLASSES, "uiIndexOfObject: Invalid value for objectclass", 0); - TRACE_ASSERT(objecthandle > 0 && objecthandle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "uiIndexOfObject: Invalid value for objecthandle", 0); + TRACE_ASSERT(objectclass < TRACE_NCLASSES, + "uiIndexOfObject: Invalid value for objectclass", 0); + TRACE_ASSERT(objecthandle > 0 && objecthandle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], + "uiIndexOfObject: Invalid value for objecthandle", 0); - if ((objectclass < TRACE_NCLASSES) && (objecthandle > 0) && (objecthandle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass])) - { - return (uint16_t)(RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[objectclass] + (RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[objectclass] * (objecthandle-1))); - } + if ((objectclass < TRACE_NCLASSES) && (objecthandle > 0) && + (objecthandle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass])) + { + return (uint16_t)(RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[objectclass] + + (RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[objectclass] * (objecthandle-1))); + } - vTraceError("Object table lookup with invalid object handle or object class!"); - return 0; + vTraceError("Object table lookup with invalid object handle or object class!"); + return 0; } /******************************************************************************* @@ -262,73 +283,76 @@ uint16_t uiIndexOfObject(objectHandleType objecthandle, uint8_t objectclass) objectHandleType xTraceGetObjectHandle(traceObjectClass objectclass) { - objectHandleType handle; - static int indexOfHandle; - - TRACE_ASSERT(objectclass < TRACE_NCLASSES, "xTraceGetObjectHandle: Invalid value for objectclass", (objectHandleType)0); - - indexOfHandle = objectHandleStacks.indexOfNextAvailableHandle[objectclass]; - if (objectHandleStacks.objectHandles[indexOfHandle] == 0) - { - /* Zero is used to indicate a never before used handle, i.e., - new slots in the handle stack. The handle slot needs to - be initialized here (starts at 1). */ - objectHandleStacks.objectHandles[indexOfHandle] = - (objectHandleType)(1 + indexOfHandle - - objectHandleStacks.lowestIndexOfClass[objectclass]); - } - - handle = objectHandleStacks.objectHandles[indexOfHandle]; - - if (objectHandleStacks.indexOfNextAvailableHandle[objectclass] - > objectHandleStacks.highestIndexOfClass[objectclass]) - { - /* ERROR */ + objectHandleType handle; + static int indexOfHandle; + + TRACE_ASSERT(objectclass < TRACE_NCLASSES, + "xTraceGetObjectHandle: Invalid value for objectclass", (objectHandleType)0); + + indexOfHandle = objectHandleStacks.indexOfNextAvailableHandle[objectclass]; + if (objectHandleStacks.objectHandles[indexOfHandle] == 0) + { + /* Zero is used to indicate a never before used handle, i.e., + new slots in the handle stack. The handle slot needs to + be initialized here (starts at 1). */ + objectHandleStacks.objectHandles[indexOfHandle] = + (objectHandleType)(1 + indexOfHandle - + objectHandleStacks.lowestIndexOfClass[objectclass]); + } + + handle = objectHandleStacks.objectHandles[indexOfHandle]; + + if (objectHandleStacks.indexOfNextAvailableHandle[objectclass] + > objectHandleStacks.highestIndexOfClass[objectclass]) + { + /* ERROR */ vTraceError(pszTraceGetErrorNotEnoughHandles(objectclass)); - handle = 0; /* an invalid/anonymous handle - but the recorder is stopped now... */ - } - else - { - int hndCount; - objectHandleStacks.indexOfNextAvailableHandle[objectclass]++; + handle = 0; /* an invalid/anonymous handle - but the recorder is stopped now... */ + } + else + { + int hndCount; + objectHandleStacks.indexOfNextAvailableHandle[objectclass]++; - hndCount = objectHandleStacks.indexOfNextAvailableHandle[objectclass] - - objectHandleStacks.lowestIndexOfClass[objectclass]; + hndCount = objectHandleStacks.indexOfNextAvailableHandle[objectclass] - + objectHandleStacks.lowestIndexOfClass[objectclass]; - if (hndCount > - objectHandleStacks.handleCountWaterMarksOfClass[objectclass]) - { - objectHandleStacks.handleCountWaterMarksOfClass[objectclass] = - (objectHandleType)hndCount; - } + if (hndCount > + objectHandleStacks.handleCountWaterMarksOfClass[objectclass]) + { + objectHandleStacks.handleCountWaterMarksOfClass[objectclass] = + (objectHandleType)hndCount; + } TRACE_CLEAR_OBJECT_FLAG_ISEXCLUDED(objectclass, handle); - } + } - return handle; + return handle; } void vTraceFreeObjectHandle(traceObjectClass objectclass, objectHandleType handle) { - int indexOfHandle; - - TRACE_ASSERT(objectclass < TRACE_NCLASSES, "vTraceFreeObjectHandle: Invalid value for objectclass", ); - TRACE_ASSERT(handle > 0 && handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "vTraceFreeObjectHandle: Invalid value for handle", ); - - /* Check that there is room to push the handle on the stack */ - if ((objectHandleStacks.indexOfNextAvailableHandle[objectclass] - 1) < - objectHandleStacks.lowestIndexOfClass[objectclass]) - { - /* Error */ - vTraceError("Attempt to free more handles than allocated!"); - } - else - { - objectHandleStacks.indexOfNextAvailableHandle[objectclass]--; - indexOfHandle = objectHandleStacks.indexOfNextAvailableHandle[objectclass]; - objectHandleStacks.objectHandles[indexOfHandle] = handle; - } + int indexOfHandle; + + TRACE_ASSERT(objectclass < TRACE_NCLASSES, + "vTraceFreeObjectHandle: Invalid value for objectclass", ); + TRACE_ASSERT(handle > 0 && handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], + "vTraceFreeObjectHandle: Invalid value for handle", ); + + /* Check that there is room to push the handle on the stack */ + if ((objectHandleStacks.indexOfNextAvailableHandle[objectclass] - 1) < + objectHandleStacks.lowestIndexOfClass[objectclass]) + { + /* Error */ + vTraceError("Attempt to free more handles than allocated!"); + } + else + { + objectHandleStacks.indexOfNextAvailableHandle[objectclass]--; + indexOfHandle = objectHandleStacks.indexOfNextAvailableHandle[objectclass]; + objectHandleStacks.objectHandles[indexOfHandle] = handle; + } } @@ -354,67 +378,66 @@ void vTraceFreeObjectHandle(traceObjectClass objectclass, objectHandleType handl * recorder's Object Property Table, at the given handle and object class. ******************************************************************************/ void vTraceSetObjectName(traceObjectClass objectclass, - objectHandleType handle, - const char* name) + objectHandleType handle, + const char* name) { - static uint16_t idx; + static uint16_t idx; TRACE_ASSERT(name != NULL, "vTraceSetObjectName: name == NULL", ); - if (objectclass >= TRACE_NCLASSES) - { - vTraceError("Illegal object class in vTraceSetObjectName"); - return; - } - - if (handle == 0) - { - vTraceError("Illegal handle (0) in vTraceSetObjectName."); - return; - } - - if (handle > RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass]) - { - /* ERROR */ - vTraceError(pszTraceGetErrorNotEnoughHandles(objectclass)); - } - else - { - idx = uiIndexOfObject(handle, objectclass); - - if (traceErrorMessage == NULL) - { - (void)strncpy((char*)&(RecorderDataPtr->ObjectPropertyTable.objbytes[idx]), - name, - RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[ objectclass ]); - } - } + if (objectclass >= TRACE_NCLASSES) + { + vTraceError("Illegal object class in vTraceSetObjectName"); + return; + } + + if (handle == 0) + { + vTraceError("Illegal handle (0) in vTraceSetObjectName."); + return; + } + + if (handle > RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass]) + { + /* ERROR */ + vTraceError(pszTraceGetErrorNotEnoughHandles(objectclass)); + } + else + { + idx = uiIndexOfObject(handle, objectclass); + + if (traceErrorMessage == NULL) + { + (void)strncpy((char*)&(RecorderDataPtr->ObjectPropertyTable.objbytes[idx]), + name, + RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[ objectclass ]); + } + } } traceLabel prvTraceOpenSymbol(const char* name, traceLabel userEventChannel) { - uint16_t result; - uint8_t len; - uint8_t crc; + uint16_t result; + uint8_t len; + uint8_t crc; TRACE_SR_ALLOC_CRITICAL_SECTION(); - len = 0; - crc = 0; - - - TRACE_ASSERT(name != NULL, "prvTraceOpenSymbol: name == NULL", (traceLabel)0); + len = 0; + crc = 0; + + TRACE_ASSERT(name != NULL, "prvTraceOpenSymbol: name == NULL", (traceLabel)0); - prvTraceGetChecksum(name, &crc, &len); + prvTraceGetChecksum(name, &crc, &len); - trcCRITICAL_SECTION_BEGIN(); - result = prvTraceLookupSymbolTableEntry(name, crc, len, userEventChannel); - if (!result) - { - result = prvTraceCreateSymbolTableEntry(name, crc, len, userEventChannel); - } - trcCRITICAL_SECTION_END(); + trcCRITICAL_SECTION_BEGIN(); + result = prvTraceLookupSymbolTableEntry(name, crc, len, userEventChannel); + if (!result) + { + result = prvTraceCreateSymbolTableEntry(name, crc, len, userEventChannel); + } + trcCRITICAL_SECTION_END(); - return result; + return result; } /******************************************************************************* @@ -443,12 +466,12 @@ void vTraceError(const char* msg) RecorderDataPtr->recorderActive = 0; - if (traceErrorMessage == NULL) - { - traceErrorMessage = (char*)msg; - (void)strncpy(RecorderDataPtr->systemInfo, traceErrorMessage, TRACE_DESCRIPTION_MAX_LENGTH); - RecorderDataPtr->internalErrorOccured = 1; - } + if (traceErrorMessage == NULL) + { + traceErrorMessage = (char*)msg; + (void)strncpy(RecorderDataPtr->systemInfo, traceErrorMessage, 80); + RecorderDataPtr->internalErrorOccured = 1; + } } @@ -469,40 +492,41 @@ void vTraceError(const char* msg) void prvCheckDataToBeOverwrittenForMultiEntryEvents(uint8_t nofEntriesToCheck) { - /* Generic "int" type is desired - should be 16 bit variable on 16 bit HW */ - unsigned int i = 0; - unsigned int e = 0; - - TRACE_ASSERT(nofEntriesToCheck != 0, "prvCheckDataToBeOverwrittenForMultiEntryEvents: nofEntriesToCheck == 0", ); - - while (i < nofEntriesToCheck) - { - e = RecorderDataPtr->nextFreeIndex + i; - if ((RecorderDataPtr->eventData[e*4] > USER_EVENT) && - (RecorderDataPtr->eventData[e*4] < USER_EVENT + 16)) - { - uint8_t nDataEvents = (uint8_t)(RecorderDataPtr->eventData[e*4] - USER_EVENT); - if ((e + nDataEvents) < RecorderDataPtr->maxEvents) - { - (void)memset(& RecorderDataPtr->eventData[e*4], 0, 4 + 4 * nDataEvents); - } - } + /* Generic "int" type is desired - should be 16 bit variable on 16 bit HW */ + unsigned int i = 0; + unsigned int e = 0; + + TRACE_ASSERT(nofEntriesToCheck != 0, + "prvCheckDataToBeOverwrittenForMultiEntryEvents: nofEntriesToCheck == 0", ); + + while (i < nofEntriesToCheck) + { + e = RecorderDataPtr->nextFreeIndex + i; + if ((RecorderDataPtr->eventData[e*4] > USER_EVENT) && + (RecorderDataPtr->eventData[e*4] < USER_EVENT + 16)) + { + uint8_t nDataEvents = (uint8_t)(RecorderDataPtr->eventData[e*4] - USER_EVENT); + if ((e + nDataEvents) < RecorderDataPtr->maxEvents) + { + (void)memset(& RecorderDataPtr->eventData[e*4], 0, 4 + 4 * nDataEvents); + } + } else if (RecorderDataPtr->eventData[e*4] == DIV_XPS) - { - if ((e + 1) < RecorderDataPtr->maxEvents) - { + { + if ((e + 1) < RecorderDataPtr->maxEvents) + { /* Clear 8 bytes */ - (void)memset(& RecorderDataPtr->eventData[e*4], 0, 4 + 4); - } - else - { - /* Clear 8 bytes, 4 first and 4 last */ - (void)memset(& RecorderDataPtr->eventData[0], 0, 4); - (void)memset(& RecorderDataPtr->eventData[e*4], 0, 4); - } - } - i++; - } + (void)memset(& RecorderDataPtr->eventData[e*4], 0, 4 + 4); + } + else + { + /* Clear 8 bytes, 4 first and 4 last */ + (void)memset(& RecorderDataPtr->eventData[0], 0, 4); + (void)memset(& RecorderDataPtr->eventData[e*4], 0, 4); + } + } + i++; + } } /******************************************************************************* @@ -513,35 +537,26 @@ void prvCheckDataToBeOverwrittenForMultiEntryEvents(uint8_t nofEntriesToCheck) void prvTraceUpdateCounters(void) { if (RecorderDataPtr->recorderActive == 0) - { - return; - } + { + return; + } - RecorderDataPtr->numEvents++; + RecorderDataPtr->numEvents++; - RecorderDataPtr->nextFreeIndex++; + RecorderDataPtr->nextFreeIndex++; - if (RecorderDataPtr->nextFreeIndex >= EVENT_BUFFER_SIZE) - { + if (RecorderDataPtr->nextFreeIndex >= EVENT_BUFFER_SIZE) + { #if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER) - RecorderDataPtr->bufferIsFull = 1; - RecorderDataPtr->nextFreeIndex = 0; + RecorderDataPtr->bufferIsFull = 1; + RecorderDataPtr->nextFreeIndex = 0; #else - vTraceStop(); + vTraceStop(); #endif - } + } #if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER) - prvCheckDataToBeOverwrittenForMultiEntryEvents(1); -#endif - -#ifdef STOP_AFTER_N_EVENTS -#if (STOP_AFTER_N_EVENTS > -1) - if (RecorderDataPtr->numEvents >= STOP_AFTER_N_EVENTS) - { - vTraceStop(); - } -#endif + prvCheckDataToBeOverwrittenForMultiEntryEvents(1); #endif } @@ -557,19 +572,19 @@ void prvTraceUpdateCounters(void) *****************************************************************************/ uint16_t prvTraceGetDTS(uint16_t param_maxDTS) { - static uint32_t old_timestamp = 0; - XTSEvent* xts = 0; - uint32_t dts = 0; - uint32_t timestamp = 0; + static uint32_t old_timestamp = 0; + XTSEvent* xts = 0; + uint32_t dts = 0; + uint32_t timestamp = 0; - TRACE_ASSERT(param_maxDTS == 0xFF || param_maxDTS == 0xFFFF, "prvTraceGetDTS: Invalid value for param_maxDTS", 0); + TRACE_ASSERT(param_maxDTS == 0xFF || param_maxDTS == 0xFFFF, "prvTraceGetDTS: Invalid value for param_maxDTS", 0); #if (SELECTED_PORT != PORT_ARM_CortexM) - if (RecorderDataPtr->frequency == 0 && init_hwtc_count != HWTC_COUNT) - { - /* If HWTC_PERIOD is mapped to the timer reload register, - it might not be initialized before the scheduler has been started. + if (RecorderDataPtr->frequency == 0 && init_hwtc_count != HWTC_COUNT) + { + /* If HWTC_PERIOD is mapped to the timer reload register, + it might not be initialized before the scheduler has been started. We therefore store the frequency of the timer when the counter register has changed from its initial value. (Note that this function is called also by vTraceStart and @@ -577,88 +592,88 @@ uint16_t prvTraceGetDTS(uint16_t param_maxDTS) has been started.) */ #if (SELECTED_PORT == PORT_Win32) - RecorderDataPtr->frequency = 100000; + RecorderDataPtr->frequency = 100000; #elif (SELECTED_PORT == PORT_HWIndependent) - RecorderDataPtr->frequency = TRACE_TICK_RATE_HZ; + RecorderDataPtr->frequency = TRACE_TICK_RATE_HZ; #else RecorderDataPtr->frequency = (HWTC_PERIOD * TRACE_TICK_RATE_HZ) / (uint32_t)HWTC_DIVISOR; #endif - } + } #endif - /************************************************************************** - * The below statements read the timestamp from the timer port module. - * If necessary, whole seconds are extracted using division while the rest - * comes from the modulo operation. - **************************************************************************/ - - vTracePortGetTimeStamp(×tamp); - - /*************************************************************************** - * Since dts is unsigned the result will be correct even if timestamp has + /************************************************************************** + * The below statements read the timestamp from the timer port module. + * If necessary, whole seconds are extracted using division while the rest + * comes from the modulo operation. + **************************************************************************/ + + vTracePortGetTimeStamp(×tamp); + + /*************************************************************************** + * Since dts is unsigned the result will be correct even if timestamp has * wrapped around. - ***************************************************************************/ + ***************************************************************************/ dts = timestamp - old_timestamp; - old_timestamp = timestamp; - - if (RecorderDataPtr->frequency > 0) - { - /* Check if dts > 1 second */ - if (dts > RecorderDataPtr->frequency) - { - /* More than 1 second has passed */ - RecorderDataPtr->absTimeLastEventSecond += dts / RecorderDataPtr->frequency; - /* The part that is not an entire second is added to absTimeLastEvent */ - RecorderDataPtr->absTimeLastEvent += dts % RecorderDataPtr->frequency; - } - else + old_timestamp = timestamp; + + if (RecorderDataPtr->frequency > 0) + { + /* Check if dts > 1 second */ + if (dts > RecorderDataPtr->frequency) + { + /* More than 1 second has passed */ + RecorderDataPtr->absTimeLastEventSecond += dts / RecorderDataPtr->frequency; + /* The part that is not an entire second is added to absTimeLastEvent */ + RecorderDataPtr->absTimeLastEvent += dts % RecorderDataPtr->frequency; + } + else + { + RecorderDataPtr->absTimeLastEvent += dts; + } + + /* Check if absTimeLastEvent >= 1 second */ + if (RecorderDataPtr->absTimeLastEvent >= RecorderDataPtr->frequency) { - RecorderDataPtr->absTimeLastEvent += dts; + /* RecorderDataPtr->absTimeLastEvent is more than or equal to 1 second, but always less than 2 seconds */ + RecorderDataPtr->absTimeLastEventSecond++; + RecorderDataPtr->absTimeLastEvent -= RecorderDataPtr->frequency; + /* RecorderDataPtr->absTimeLastEvent is now less than 1 second */ } + } + else + { + /* Special case if the recorder has not yet started (frequency may be uninitialized, i.e., zero) */ + RecorderDataPtr->absTimeLastEvent = timestamp; + } + + /* If the dts (time since last event) does not fit in event->dts (only 8 or 16 bits) */ + if (dts > param_maxDTS) + { + /* Create an XTS event (eXtended TimeStamp) containing the higher dts bits*/ + xts = (XTSEvent*) xTraceNextFreeEventBufferSlot(); - /* Check if absTimeLastEvent >= 1 second */ - if (RecorderDataPtr->absTimeLastEvent >= RecorderDataPtr->frequency) - { - /* RecorderDataPtr->absTimeLastEvent is more than or equal to 1 second, but always less than 2 seconds */ - RecorderDataPtr->absTimeLastEventSecond++; - RecorderDataPtr->absTimeLastEvent -= RecorderDataPtr->frequency; - /* RecorderDataPtr->absTimeLastEvent is now less than 1 second */ - } - } - else - { - /* Special case if the recorder has not yet started (frequency may be uninitialized, i.e., zero) */ - RecorderDataPtr->absTimeLastEvent = timestamp; - } - - /* If the dts (time since last event) does not fit in event->dts (only 8 or 16 bits) */ - if (dts > param_maxDTS) - { - /* Create an XTS event (eXtended TimeStamp) containing the higher dts bits*/ - xts = (XTSEvent*) xTraceNextFreeEventBufferSlot(); - - if (xts != NULL) - { - if (param_maxDTS == 0xFFFF) - { - xts->type = XTS16; - xts->xts_16 = (uint16_t)((dts / 0x10000) & 0xFFFF); - xts->xts_8 = 0; - } - else if (param_maxDTS == 0xFF) - { - xts->type = XTS8; - xts->xts_16 = (uint16_t)((dts / 0x100) & 0xFFFF); - xts->xts_8 = (uint8_t)((dts / 0x1000000) & 0xFF); - } - else - { - vTraceError("Bad param_maxDTS in prvTraceGetDTS"); - } - prvTraceUpdateCounters(); - } - } - - return (uint16_t)dts & param_maxDTS; + if (xts != NULL) + { + if (param_maxDTS == 0xFFFF) + { + xts->type = XTS16; + xts->xts_16 = (uint16_t)((dts / 0x10000) & 0xFFFF); + xts->xts_8 = 0; + } + else if (param_maxDTS == 0xFF) + { + xts->type = XTS8; + xts->xts_16 = (uint16_t)((dts / 0x100) & 0xFFFF); + xts->xts_8 = (uint8_t)((dts / 0x1000000) & 0xFF); + } + else + { + vTraceError("Bad param_maxDTS in prvTraceGetDTS"); + } + prvTraceUpdateCounters(); + } + } + + return (uint16_t)dts & param_maxDTS; } /******************************************************************************* @@ -675,33 +690,33 @@ uint16_t prvTraceGetDTS(uint16_t param_maxDTS) * zero-termination ******************************************************************************/ traceLabel prvTraceLookupSymbolTableEntry(const char* name, - uint8_t crc6, - uint8_t len, - traceLabel chn) + uint8_t crc6, + uint8_t len, + traceLabel chn) { - uint16_t i = RecorderDataPtr->SymbolTable.latestEntryOfChecksum[ crc6 ]; + uint16_t i = RecorderDataPtr->SymbolTable.latestEntryOfChecksum[ crc6 ]; TRACE_ASSERT(name != NULL, "prvTraceLookupSymbolTableEntry: name == NULL", (traceLabel)0); TRACE_ASSERT(len != 0, "prvTraceLookupSymbolTableEntry: len == 0", (traceLabel)0); - while (i != 0) - { - if (RecorderDataPtr->SymbolTable.symbytes[i + 2] == (chn & 0x00FF)) - { - if (RecorderDataPtr->SymbolTable.symbytes[i + 3] == (chn / 0x100)) - { - if (RecorderDataPtr->SymbolTable.symbytes[i + 4 + len] == '\0') - { - if (strncmp((char*)(& RecorderDataPtr->SymbolTable.symbytes[i + 4]), name, len) == 0) - { - break; /* found */ - } - } - } - } - i = (uint16_t)(RecorderDataPtr->SymbolTable.symbytes[i] + (RecorderDataPtr->SymbolTable.symbytes[i + 1] * 0x100)); - } - return i; + while (i != 0) + { + if (RecorderDataPtr->SymbolTable.symbytes[i + 2] == (chn & 0x00FF)) + { + if (RecorderDataPtr->SymbolTable.symbytes[i + 3] == (chn / 0x100)) + { + if (RecorderDataPtr->SymbolTable.symbytes[i + 4 + len] == '\0') + { + if (strncmp((char*)(& RecorderDataPtr->SymbolTable.symbytes[i + 4]), name, len) == 0) + { + break; /* found */ + } + } + } + } + i = (uint16_t)(RecorderDataPtr->SymbolTable.symbytes[i] + (RecorderDataPtr->SymbolTable.symbytes[i + 1] * 0x100)); + } + return i; } /******************************************************************************* @@ -718,58 +733,58 @@ traceLabel prvTraceLookupSymbolTableEntry(const char* name, * zero-termination ******************************************************************************/ uint16_t prvTraceCreateSymbolTableEntry(const char* name, - uint8_t crc6, - uint8_t len, - traceLabel channel) + uint8_t crc6, + uint8_t len, + traceLabel channel) { - uint16_t ret = 0; + uint16_t ret = 0; TRACE_ASSERT(name != NULL, "prvTraceCreateSymbolTableEntry: name == NULL", 0); TRACE_ASSERT(len != 0, "prvTraceCreateSymbolTableEntry: len == 0", 0); - if (RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + len + 4 >= SYMBOL_TABLE_SIZE) - { - vTraceError("Symbol table full. Increase SYMBOL_TABLE_SIZE in trcConfig.h"); - ret = 0; - } - else - { + if (RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + len + 4 >= SYMBOL_TABLE_SIZE) + { + vTraceError("Symbol table full. Increase SYMBOL_TABLE_SIZE in trcConfig.h"); + ret = 0; + } + else + { - RecorderDataPtr->SymbolTable.symbytes - [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex] = - (uint8_t)(RecorderDataPtr->SymbolTable.latestEntryOfChecksum[ crc6 ] & 0x00FF); + RecorderDataPtr->SymbolTable.symbytes + [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex] = + (uint8_t)(RecorderDataPtr->SymbolTable.latestEntryOfChecksum[ crc6 ] & 0x00FF); - RecorderDataPtr->SymbolTable.symbytes - [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 1] = - (uint8_t)(RecorderDataPtr->SymbolTable.latestEntryOfChecksum[ crc6 ] / 0x100); + RecorderDataPtr->SymbolTable.symbytes + [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 1] = + (uint8_t)(RecorderDataPtr->SymbolTable.latestEntryOfChecksum[ crc6 ] / 0x100); - RecorderDataPtr->SymbolTable.symbytes - [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 2] = - (uint8_t)(channel & 0x00FF); + RecorderDataPtr->SymbolTable.symbytes + [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 2] = + (uint8_t)(channel & 0x00FF); - RecorderDataPtr->SymbolTable.symbytes - [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 3] = - (uint8_t)(channel / 0x100); + RecorderDataPtr->SymbolTable.symbytes + [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 3] = + (uint8_t)(channel / 0x100); - /* set name (bytes 4...4+len-1) */ - (void)strncpy((char*)&(RecorderDataPtr->SymbolTable.symbytes - [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 4]), name, len); + /* set name (bytes 4...4+len-1) */ + (void)strncpy((char*)&(RecorderDataPtr->SymbolTable.symbytes + [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 4]), name, len); - /* Set zero termination (at offset 4+len) */ - RecorderDataPtr->SymbolTable.symbytes - [RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 4 + len] = '\0'; + /* Set zero termination (at offset 4+len) */ + RecorderDataPtr->SymbolTable.symbytes + [RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 4 + len] = '\0'; - /* store index of entry (for return value, and as head of LL[crc6]) */ - RecorderDataPtr->SymbolTable.latestEntryOfChecksum - [ crc6 ] = (uint16_t)RecorderDataPtr->SymbolTable.nextFreeSymbolIndex; + /* store index of entry (for return value, and as head of LL[crc6]) */ + RecorderDataPtr->SymbolTable.latestEntryOfChecksum + [ crc6 ] = (uint16_t)RecorderDataPtr->SymbolTable.nextFreeSymbolIndex; - RecorderDataPtr->SymbolTable.nextFreeSymbolIndex += (len + 5); + RecorderDataPtr->SymbolTable.nextFreeSymbolIndex += (len + 5); - ret = (uint16_t)(RecorderDataPtr->SymbolTable.nextFreeSymbolIndex - - (len + 5)); - } + ret = (uint16_t)(RecorderDataPtr->SymbolTable.nextFreeSymbolIndex - + (len + 5)); + } - return ret; + return ret; } @@ -781,24 +796,24 @@ uint16_t prvTraceCreateSymbolTableEntry(const char* name, ******************************************************************************/ void prvTraceGetChecksum(const char *pname, uint8_t* pcrc, uint8_t* plength) { - unsigned char c; - int length = 1; - int crc = 0; - - TRACE_ASSERT(pname != NULL, "prvTraceGetChecksum: pname == NULL", ); - TRACE_ASSERT(pcrc != NULL, "prvTraceGetChecksum: pcrc == NULL", ); - TRACE_ASSERT(plength != NULL, "prvTraceGetChecksum: plength == NULL", ); - - if (pname != (const char *) 0) - { - for (; (c = *pname++) != '\0';) - { - crc += c; - length++; - } - } - *pcrc = (uint8_t)(crc & 0x3F); - *plength = (uint8_t)length; + unsigned char c; + int length = 1; /* Should be 1 to account for '\0' */ + int crc = 0; + + TRACE_ASSERT(pname != NULL, "prvTraceGetChecksum: pname == NULL", ); + TRACE_ASSERT(pcrc != NULL, "prvTraceGetChecksum: pcrc == NULL", ); + TRACE_ASSERT(plength != NULL, "prvTraceGetChecksum: plength == NULL", ); + + if (pname != (const char *) 0) + { + for (; (c = *pname++) != '\0';) + { + crc += c; + length++; + } + } + *pcrc = (uint8_t)(crc & 0x3F); + *plength = (uint8_t)length; } #if (USE_16BIT_OBJECT_HANDLES == 1) @@ -829,7 +844,7 @@ void prvTraceStoreXID(objectHandleType handle) xid->type = XID; /* This function is (only) used when objectHandleType is 16 bit... */ - xid->xps_16 = handle; + xid->xps_16 = handle; prvTraceUpdateCounters(); } @@ -840,8 +855,8 @@ unsigned char prvTraceGet8BitHandle(objectHandleType handle) if (handle > 255) { prvTraceStoreXID(handle); - /* The full handle (16 bit) is stored in the XID event. - This code (255) is used instead of zero (which is an error code).*/ + /* The full handle (16 bit) is stored in the XID event. + This code (255) is used instead of zero (which is an error code).*/ return 255; } return (unsigned char)(handle & 0xFF); diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcHardwarePort.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcHardwarePort.c index ac4a6f263..7d3937b4a 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcHardwarePort.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcHardwarePort.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Tracealyzer v2.6.0 Recorder Library + * Tracealyzer v2.7.0 Recorder Library * Percepio AB, www.percepio.com * * trcHardwarePort.c @@ -32,7 +32,9 @@ * damages, or the exclusion of implied warranties or limitations on how long an * implied warranty may last, so the above limitations may not apply to you. * - * Copyright Percepio AB, 2013. + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2014. * www.percepio.com ******************************************************************************/ @@ -56,36 +58,37 @@ uint32_t last_timestamp = 0; ******************************************************************************/ uint32_t uiTraceTickCount = 0; -uint32_t DWT_CYCLES_ADDED = 0; +uint32_t DWT_CYCLES_ADDED = 0; /* Used on ARM Cortex-M only */ #if (SELECTED_PORT == PORT_ARM_CortexM) -void prvTraceEnableIRQ(void) -{ - asm volatile ("cpsie i"); -} - -void prvTraceDisableIRQ(void) -{ - asm volatile ("cpsid i"); -} - -void prvTraceSetIRQMask(uint32_t priMask) +void prvTraceInitCortexM() { - asm volatile ("MSR primask, %0" : : "r" (priMask) ); -} + /* Make sure DWT is enabled is enabled, if supported */ + REG_DEMCR |= DEMCR_TRCENA; + + do{ + /* Verify that DWT is supported */ + if (REG_DEMCR == 0) + { + vTraceError("DWT not supported by this chip!"); + break; + } + + /* Verify that DWT_CYCCNT is supported */ + if (REG_DWT_CTRL & DWT_CTRL_NOCYCCNT) + { + vTraceError("DWT_CYCCNT not supported by this chip!"); + break; + } + + /* Reset the cycle counter */ + REG_DWT_CYCCNT = 0; -uint32_t prvTraceGetIRQMask(void) -{ - uint32_t result; - asm volatile ("MRS %0, primask" : "=r" (result) ); - return result; -} + /* Enable the cycle counter */ + REG_DWT_CTRL |= DWT_CTRL_CYCCNTENA; -void prvTraceInitCortexM() -{ - DWT_CTRL_REG |= 1; /* Enable the cycle counter */ - DWT_CYCLE_COUNTER = 0; + }while(0); /* breaks above jump here */ if (RecorderDataPtr->frequency == 0) { @@ -109,10 +112,10 @@ void prvTraceInitCortexM() void vTracePortGetTimeStamp(uint32_t *pTimestamp) { static uint32_t last_traceTickCount = 0; - static uint32_t last_hwtc_count = 0; - uint32_t traceTickCount = 0; - uint32_t hwtc_count = 0; - + static uint32_t last_hwtc_count = 0; + uint32_t traceTickCount = 0; + uint32_t hwtc_count = 0; + if (trace_disable_timestamp == 1) { if (pTimestamp) @@ -120,51 +123,64 @@ void vTracePortGetTimeStamp(uint32_t *pTimestamp) return; } - /* Retrieve HWTC_COUNT only once since the same value should be used all throughout this function. */ + /* Retrieve HWTC_COUNT only once since the same value should be used all throughout this function. */ #if (HWTC_COUNT_DIRECTION == DIRECTION_INCREMENTING) - hwtc_count = HWTC_COUNT; + hwtc_count = HWTC_COUNT; #elif (HWTC_COUNT_DIRECTION == DIRECTION_DECREMENTING) - hwtc_count = HWTC_PERIOD - HWTC_COUNT; + hwtc_count = HWTC_PERIOD - HWTC_COUNT; #else - Junk text to cause compiler error - HWTC_COUNT_DIRECTION is not set correctly! - Should be DIRECTION_INCREMENTING or DIRECTION_DECREMENTING + Junk text to cause compiler error - HWTC_COUNT_DIRECTION is not set correctly! + Should be DIRECTION_INCREMENTING or DIRECTION_DECREMENTING #endif - - if (last_traceTickCount - uiTraceTickCount - 1 < 0x80000000) - { - /* This means last_traceTickCount is higher than uiTraceTickCount, - so we have previously compensated for a missed tick. - Therefore we use the last stored value because that is more accurate. */ - traceTickCount = last_traceTickCount; - } - else - { - /* Business as usual */ - traceTickCount = uiTraceTickCount; - } - - /* Check for overflow. May occur if the update of uiTraceTickCount has been - delayed due to disabled interrupts. */ - if (traceTickCount == last_traceTickCount && hwtc_count < last_hwtc_count) - { - /* A trace tick has occurred but not been executed by the kernel, so we compensate manually. */ - traceTickCount++; - } - - /* Check if the return address is OK, then we perform the calculation. */ - if (pTimestamp) - { - /* Get timestamp from trace ticks. Scale down the period to avoid unwanted overflows. */ - *pTimestamp = traceTickCount * (HWTC_PERIOD / HWTC_DIVISOR); - /* Increase timestamp by (hwtc_count + "lost hardware ticks from scaling down period") / HWTC_DIVISOR. */ - *pTimestamp += (hwtc_count + traceTickCount * (HWTC_PERIOD % HWTC_DIVISOR)) / HWTC_DIVISOR; + +#if (SELECTED_PORT == PORT_Win32) + /* The Win32 port uses ulGetRunTimeCounterValue for timestamping, which in turn + uses QueryPerformanceCounter. That function is not always reliable when used over + multiple threads. We must therefore handle rare cases where the timestamp is less + than the previous. In practice, the Win32 should "never" roll over since the + performance counter is 64 bit wide. */ + + if (last_hwtc_count > hwtc_count) + { + hwtc_count = last_hwtc_count; + } +#endif + + if (last_traceTickCount - uiTraceTickCount - 1 < 0x80000000) + { + /* This means last_traceTickCount is higher than uiTraceTickCount, + so we have previously compensated for a missed tick. + Therefore we use the last stored value because that is more accurate. */ + traceTickCount = last_traceTickCount; + } + else + { + /* Business as usual */ + traceTickCount = uiTraceTickCount; + } + + /* Check for overflow. May occur if the update of uiTraceTickCount has been + delayed due to disabled interrupts. */ + if (traceTickCount == last_traceTickCount && hwtc_count < last_hwtc_count) + { + /* A trace tick has occurred but not been executed by the kernel, so we compensate manually. */ + traceTickCount++; + } + + /* Check if the return address is OK, then we perform the calculation. */ + if (pTimestamp) + { + /* Get timestamp from trace ticks. Scale down the period to avoid unwanted overflows. */ + *pTimestamp = traceTickCount * (HWTC_PERIOD / HWTC_DIVISOR); + /* Increase timestamp by (hwtc_count + "lost hardware ticks from scaling down period") / HWTC_DIVISOR. */ + *pTimestamp += (hwtc_count + traceTickCount * (HWTC_PERIOD % HWTC_DIVISOR)) / HWTC_DIVISOR; last_timestamp = *pTimestamp; - } - - /* Store the previous values. */ - last_traceTickCount = traceTickCount; - last_hwtc_count = hwtc_count; + } + + /* Store the previous values. */ + last_traceTickCount = traceTickCount; + last_hwtc_count = hwtc_count; } -#endif \ No newline at end of file +#endif diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernel.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernel.c index e79294740..5cf073dc1 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernel.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernel.c @@ -1,10 +1,10 @@ /******************************************************************************* - * Tracealyzer v2.6.0 Recorder Library + * Tracealyzer v2.7.0 Recorder Library * Percepio AB, www.percepio.com * * trcKernel.c * - * Functions used by trcKernelHooks.h. + * Functions used by trcKernelHooks.h for storing various kernel events. * * Terms of Use * This software is copyright Percepio AB. The recorder library is free for @@ -31,7 +31,9 @@ * damages, or the exclusion of implied warranties or limitations on how long an * implied warranty may last, so the above limitations may not apply to you. * - * Copyright Percepio AB, 2013. + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2014. * www.percepio.com ******************************************************************************/ @@ -46,7 +48,12 @@ uint8_t nISRactive = 0; objectHandleType handle_of_last_logged_task = 0; uint8_t inExcludedTask = 0; +/* Current heap usage. Always updated. */ +static uint32_t heapMemUsage = 0; + +#if (TRACE_SCHEDULING_ONLY == 0) static uint32_t prvTraceGetParam(uint32_t, uint32_t); +#endif #if !defined INCLUDE_READY_EVENTS || INCLUDE_READY_EVENTS == 1 /******************************************************************************* @@ -56,44 +63,47 @@ static uint32_t prvTraceGetParam(uint32_t, uint32_t); ******************************************************************************/ void vTraceStoreTaskReady(objectHandleType handle) { - uint16_t dts3; - TREvent* tr; + uint16_t dts3; + TREvent* tr; + uint8_t hnd8; + TRACE_SR_ALLOC_CRITICAL_SECTION(); - - TRACE_ASSERT(handle > 0 && handle <= NTask, "vTraceStoreTaskReady: Invalid value for handle", ); - if (recorder_busy) - { - /*********************************************************************** - * This should never occur, as the tick- and kernel call ISR is on lowest - * interrupt priority and always are disabled during the critical sections - * of the recorder. - ***********************************************************************/ + if (handle == 0) + { + /* On FreeRTOS v7.3.0, this occurs when creating tasks due to a bad + placement of the trace macro. In that case, the events are ignored. */ + return; + } + + TRACE_ASSERT(handle <= NTask, "vTraceStoreTaskReady: Invalid value for handle", ); - vTraceError("Recorder busy - high priority ISR using syscall? (1)"); - return; - } + if (recorder_busy) + { + /*********************************************************************** + * This should never occur, as the tick- and kernel call ISR is on lowest + * interrupt priority and always are disabled during the critical sections + * of the recorder. + ***********************************************************************/ + + vTraceError("Recorder busy - high priority ISR using syscall? (1)"); + return; + } trcCRITICAL_SECTION_BEGIN(); - if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ + if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ { if (!TRACE_GET_TASK_FLAG_ISEXCLUDED(handle)) { dts3 = (uint16_t)prvTraceGetDTS(0xFFFF); - if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ + hnd8 = prvTraceGet8BitHandle(handle); + tr = (TREvent*)xTraceNextFreeEventBufferSlot(); + if (tr != NULL) { - uint8_t hnd8 = prvTraceGet8BitHandle(handle); - - tr = (TREvent*)xTraceNextFreeEventBufferSlot(); - - if (tr != NULL) - { - tr->type = DIV_TASK_READY; - tr->dts = dts3; - tr->objHandle = hnd8; - - prvTraceUpdateCounters(); - } + tr->type = DIV_TASK_READY; + tr->dts = dts3; + tr->objHandle = hnd8; + prvTraceUpdateCounters(); } } } @@ -108,38 +118,34 @@ void vTraceStoreTaskReady(objectHandleType handle) ******************************************************************************/ void vTraceStoreLowPower(uint32_t flag) { - uint16_t dts; - LPEvent* lp; + uint16_t dts; + LPEvent* lp; TRACE_SR_ALLOC_CRITICAL_SECTION(); - + TRACE_ASSERT(flag <= 1, "vTraceStoreLowPower: Invalid flag value", ); - if (recorder_busy) - { + if (recorder_busy) + { /*********************************************************************** * This should never occur, as the tick- and kernel call ISR is on lowest * interrupt priority and always are disabled during the critical sections * of the recorder. ***********************************************************************/ - + vTraceError("Recorder busy - high priority ISR using syscall? (1)"); return; - } - + } + trcCRITICAL_SECTION_BEGIN(); - if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ + if (RecorderDataPtr->recorderActive) { dts = (uint16_t)prvTraceGetDTS(0xFFFF); - if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ + lp = (LPEvent*)xTraceNextFreeEventBufferSlot(); + if (lp != NULL) { - lp = (LPEvent*)xTraceNextFreeEventBufferSlot(); - if (lp != NULL) - { - lp->type = LOW_POWER_BEGIN + ( uint8_t ) flag; /* BEGIN or END depending on flag */ - lp->dts = dts; - - prvTraceUpdateCounters(); - } + lp->type = LOW_POWER_BEGIN + ( uint8_t ) flag; /* BEGIN or END depending on flag */ + lp->dts = dts; + prvTraceUpdateCounters(); } } trcCRITICAL_SECTION_END(); @@ -149,62 +155,79 @@ void vTraceStoreLowPower(uint32_t flag) * vTraceStoreMemMangEvent * * This function stores malloc and free events. Each call requires two records, - * for size and address respectively. The event code parameter (ecode) is applied - * to the first record (size) and the following address record gets event + * for size and address respectively. The event code parameter (ecode) is applied + * to the first record (size) and the following address record gets event * code "ecode + 1", so make sure this is respected in the event code table. + * Note: On "free" calls, the signed_size parameter should be negative. ******************************************************************************/ #if (INCLUDE_MEMMANG_EVENTS == 1) -void vTraceStoreMemMangEvent(uint32_t ecode, uint32_t address, uint32_t size) -{ +void vTraceStoreMemMangEvent(uint32_t ecode, uint32_t address, int32_t signed_size) +{ +#if (TRACE_SCHEDULING_ONLY == 0) uint8_t dts1; MemEventSize * ms; MemEventAddr * ma; uint16_t size_low; uint16_t addr_low; uint8_t addr_high; + uint32_t size; + + if (signed_size < 0) + size = (uint32_t)(- signed_size); + else + size = (uint32_t)(signed_size); TRACE_SR_ALLOC_CRITICAL_SECTION(); trcCRITICAL_SECTION_BEGIN(); + + heapMemUsage += signed_size; + if (RecorderDataPtr->recorderActive) { /* If it is an ISR or NOT an excluded task, this kernel call will be stored in the trace */ if (nISRactive || !inExcludedTask) { dts1 = (uint8_t)prvTraceGetDTS(0xFF); - size_low = (uint16_t)prvTraceGetParam(0xFFFF, size); - ms = (MemEventSize *)xTraceNextFreeEventBufferSlot(); + if (ms != NULL) { ms->dts = dts1; - ms->type = (uint8_t)ecode; + ms->type = NULL_EVENT; /* Updated when all events are written */ ms->size = size_low; prvTraceUpdateCounters(); - + /* Storing a second record with address (signals "failed" if null) */ #if (HEAP_SIZE_BELOW_16M) - addr_low = address & 0xFFFF; + /* If the heap address range is within 16 MB, i.e., the upper 8 bits + of addresses are constant, this optimization avoids storing an extra + event record by ignoring the upper 8 bit of the address */ + addr_low = address & 0xFFFF; addr_high = (address >> 16) & 0xFF; #else + /* The whole 32 bit address is stored using a second event record + for the upper 16 bit */ addr_low = (uint16_t)prvTraceGetParam(0xFFFF, address); addr_high = 0; #endif - + ma = (MemEventAddr *) xTraceNextFreeEventBufferSlot(); - if (ma != NULL) { ma->addr_low = addr_low; ma->addr_high = addr_high; - ma->type = ( ( uint8_t) ecode ) + 1; /* Note this! */ - prvTraceUpdateCounters(); + ma->type = ( ( uint8_t) ecode ) + 1; /* Note this! */ + ms->type = (uint8_t)ecode; + prvTraceUpdateCounters(); + RecorderDataPtr->heapMemUsage = heapMemUsage; } } } } - trcCRITICAL_SECTION_END(); + trcCRITICAL_SECTION_END(); +#endif /* TRACE_SCHEDULING_ONLY */ } #endif @@ -216,126 +239,123 @@ void vTraceStoreMemMangEvent(uint32_t ecode, uint32_t address, uint32_t size) ******************************************************************************/ void vTraceStoreKernelCall(uint32_t ecode, traceObjectClass objectClass, uint32_t objectNumber) { - KernelCall * kse; - uint16_t dts1; - TRACE_SR_ALLOC_CRITICAL_SECTION(); - - TRACE_ASSERT(ecode < 0xFF, "vTraceStoreKernelCall: ecode >= 0xFF", ); - TRACE_ASSERT(objectClass < TRACE_NCLASSES, "vTraceStoreKernelCall: objectClass >= TRACE_NCLASSES", ); - TRACE_ASSERT(objectNumber <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectClass], "vTraceStoreKernelCall: Invalid value for objectNumber", ); - - if (recorder_busy) - { - /************************************************************************* - * This may occur if a high-priority ISR is illegally using a system call, - * or creates a user event. - * Only ISRs that are disabled by TRACE_ENTER_CRITICAL_SECTION may use system calls - * or user events (see TRACE_MAX_SYSCALL_INTERRUPT_PRIORITY). - *************************************************************************/ - - vTraceError("Recorder busy - high priority ISR using syscall? (2)"); - return; - } - - if (handle_of_last_logged_task == 0) - { - return; - } +#if (TRACE_SCHEDULING_ONLY == 0) + KernelCall * kse; + uint16_t dts1; + uint8_t hnd8; + TRACE_SR_ALLOC_CRITICAL_SECTION(); + + TRACE_ASSERT(ecode < 0xFF, "vTraceStoreKernelCall: ecode >= 0xFF", ); + TRACE_ASSERT(objectClass < TRACE_NCLASSES, "vTraceStoreKernelCall: objectClass >= TRACE_NCLASSES", ); + TRACE_ASSERT(objectNumber <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectClass], "vTraceStoreKernelCall: Invalid value for objectNumber", ); + + if (recorder_busy) + { + /************************************************************************* + * This may occur if a high-priority ISR is illegally using a system call, + * or creates a user event. + * Only ISRs that are disabled by TRACE_ENTER_CRITICAL_SECTION may use system calls + * or user events (see TRACE_MAX_SYSCALL_INTERRUPT_PRIORITY). + *************************************************************************/ + + vTraceError("Recorder busy - high priority ISR using syscall? (2)"); + return; + } + + if (handle_of_last_logged_task == 0) + { + return; + } trcCRITICAL_SECTION_BEGIN(); - if (RecorderDataPtr->recorderActive) - { - /* If it is an ISR or NOT an excluded task, this kernel call will be stored in the trace */ - if (nISRactive || !inExcludedTask) - { - /* Check if the referenced object or the event code is excluded */ - if (!uiTraceIsObjectExcluded(objectClass, (objectHandleType)objectNumber) && !TRACE_GET_EVENT_CODE_FLAG_ISEXCLUDED(ecode)) - { - dts1 = (uint16_t)prvTraceGetDTS(0xFFFF); - - if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ - { - uint8_t hnd8 = prvTraceGet8BitHandle(objectNumber); - - kse = (KernelCall*) xTraceNextFreeEventBufferSlot(); - if (kse != NULL) - { - kse->dts = dts1; - kse->type = (uint8_t)ecode; - kse->objHandle = hnd8; - prvTraceUpdateCounters(); - } - } - } - } - } + if (RecorderDataPtr->recorderActive) + { + /* If it is an ISR or NOT an excluded task, this kernel call will be stored in the trace */ + if (nISRactive || !inExcludedTask) + { + /* Check if the referenced object or the event code is excluded */ + if (!uiTraceIsObjectExcluded(objectClass, (objectHandleType)objectNumber) && !TRACE_GET_EVENT_CODE_FLAG_ISEXCLUDED(ecode)) + { + dts1 = (uint16_t)prvTraceGetDTS(0xFFFF); + hnd8 = prvTraceGet8BitHandle(objectNumber); + kse = (KernelCall*) xTraceNextFreeEventBufferSlot(); + if (kse != NULL) + { + kse->dts = dts1; + kse->type = (uint8_t)ecode; + kse->objHandle = hnd8; + prvTraceUpdateCounters(); + } + } + } + } trcCRITICAL_SECTION_END(); +#endif /* TRACE_SCHEDULING_ONLY */ } /******************************************************************************* * vTraceStoreKernelCallWithParam * - * Used for storing kernel calls with a handle and a numeric parameter. If the + * Used for storing kernel calls with a handle and a numeric parameter. If the * numeric parameter does not fit in one byte, and extra XPS event is inserted * before the kernel call event containing the three upper bytes. ******************************************************************************/ void vTraceStoreKernelCallWithParam(uint32_t evtcode, - traceObjectClass objectClass, - uint32_t objectNumber, - uint32_t param) + traceObjectClass objectClass, + uint32_t objectNumber, + uint32_t param) { - KernelCallWithParamAndHandle * kse; - uint8_t dts2; - TRACE_SR_ALLOC_CRITICAL_SECTION(); +#if (TRACE_SCHEDULING_ONLY == 0) + KernelCallWithParamAndHandle * kse; + uint8_t dts2; + uint8_t hnd8; + uint8_t p8; + TRACE_SR_ALLOC_CRITICAL_SECTION(); TRACE_ASSERT(evtcode < 0xFF, "vTraceStoreKernelCall: evtcode >= 0xFF", ); TRACE_ASSERT(objectClass < TRACE_NCLASSES, "vTraceStoreKernelCallWithParam: objectClass >= TRACE_NCLASSES", ); TRACE_ASSERT(objectNumber <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectClass], "vTraceStoreKernelCallWithParam: Invalid value for objectNumber", ); if (recorder_busy) - { - /************************************************************************* - * This may occur if a high-priority ISR is illegally using a system call, - * or creates a user event. - * Only ISRs that are disabled by TRACE_ENTER_CRITICAL_SECTION may use system calls - * or user events (see TRACE_MAX_SYSCALL_INTERRUPT_PRIORITY). - *************************************************************************/ - - vTraceError("Recorder busy - high priority ISR using syscall? (3)"); - return; - } + { + /************************************************************************* + * This may occur if a high-priority ISR is illegally using a system call, + * or creates a user event. + * Only ISRs that are disabled by TRACE_ENTER_CRITICAL_SECTION may use system calls + * or user events (see TRACE_MAX_SYSCALL_INTERRUPT_PRIORITY). + *************************************************************************/ + + vTraceError("Recorder busy - high priority ISR using syscall? (3)"); + return; + } trcCRITICAL_SECTION_BEGIN(); - if (RecorderDataPtr->recorderActive && handle_of_last_logged_task && - (! inExcludedTask || nISRactive)) - { - - /* Check if the referenced object or the event code is excluded */ - if (!uiTraceIsObjectExcluded(objectClass, (objectHandleType)objectNumber) && !TRACE_GET_EVENT_CODE_FLAG_ISEXCLUDED(evtcode)) - { - dts2 = (uint8_t)prvTraceGetDTS(0xFF); - - if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ - { - uint8_t p8 = (uint8_t) prvTraceGetParam(0xFF, param); - - uint8_t hnd8 = prvTraceGet8BitHandle((objectHandleType)objectNumber); - - kse = (KernelCallWithParamAndHandle*) xTraceNextFreeEventBufferSlot(); - if (kse != NULL) - { - kse->dts = dts2; - kse->type = (uint8_t)evtcode; - kse->objHandle = hnd8; - kse->param = p8; - prvTraceUpdateCounters(); - } - } - } - } + if (RecorderDataPtr->recorderActive && handle_of_last_logged_task && (! inExcludedTask || nISRactive)) + { + /* Check if the referenced object or the event code is excluded */ + if (!uiTraceIsObjectExcluded(objectClass, (objectHandleType)objectNumber) && + !TRACE_GET_EVENT_CODE_FLAG_ISEXCLUDED(evtcode)) + { + dts2 = (uint8_t)prvTraceGetDTS(0xFF); + p8 = (uint8_t) prvTraceGetParam(0xFF, param); + hnd8 = prvTraceGet8BitHandle((objectHandleType)objectNumber); + kse = (KernelCallWithParamAndHandle*) xTraceNextFreeEventBufferSlot(); + if (kse != NULL) + { + kse->dts = dts2; + kse->type = (uint8_t)evtcode; + kse->objHandle = hnd8; + kse->param = p8; + prvTraceUpdateCounters(); + } + } + } trcCRITICAL_SECTION_END(); +#endif /* TRACE_SCHEDULING_ONLY */ } +#if (TRACE_SCHEDULING_ONLY == 0) + /******************************************************************************* * prvTraceGetParam * @@ -346,9 +366,10 @@ void vTraceStoreKernelCallWithParam(uint32_t evtcode, static uint32_t prvTraceGetParam(uint32_t param_max, uint32_t param) { XPSEvent* xps; - - TRACE_ASSERT(param_max == 0xFF || param_max == 0xFFFF, "prvTraceGetParam: Invalid value for param_max", param); - + + TRACE_ASSERT(param_max == 0xFF || param_max == 0xFFFF, + "prvTraceGetParam: Invalid value for param_max", param); + if (param <= param_max) { return param; @@ -367,6 +388,7 @@ static uint32_t prvTraceGetParam(uint32_t param_max, uint32_t param) return param & param_max; } } +#endif /******************************************************************************* * vTraceStoreKernelCallWithNumericParamOnly @@ -376,56 +398,51 @@ static uint32_t prvTraceGetParam(uint32_t param_max, uint32_t param) ******************************************************************************/ void vTraceStoreKernelCallWithNumericParamOnly(uint32_t evtcode, uint32_t param) { - KernelCallWithParam16 * kse; - uint8_t dts6; +#if (TRACE_SCHEDULING_ONLY == 0) + KernelCallWithParam16 * kse; + uint8_t dts6; uint16_t restParam; - TRACE_SR_ALLOC_CRITICAL_SECTION(); + TRACE_SR_ALLOC_CRITICAL_SECTION(); restParam = 0; - TRACE_ASSERT(evtcode < 0xFF, "vTraceStoreKernelCallWithNumericParamOnly: Invalid value for evtcode", ); - + TRACE_ASSERT(evtcode < 0xFF, + "vTraceStoreKernelCallWithNumericParamOnly: Invalid value for evtcode", ); + if (recorder_busy) - { - /************************************************************************* - * This may occur if a high-priority ISR is illegally using a system call, - * or creates a user event. - * Only ISRs that are disabled by TRACE_ENTER_CRITICAL_SECTION may use system calls - * or user events (see TRACE_MAX_SYSCALL_INTERRUPT_PRIORITY). - *************************************************************************/ - - vTraceError("Recorder busy - high priority ISR using syscall? (4)"); - return; - } - + { + /************************************************************************* + * This may occur if a high-priority ISR is illegally using a system call, + * or creates a user event. + * Only ISRs that are disabled by TRACE_ENTER_CRITICAL_SECTION may use system calls + * or user events (see TRACE_MAX_SYSCALL_INTERRUPT_PRIORITY). + *************************************************************************/ + + vTraceError("Recorder busy - high priority ISR using syscall? (4)"); + return; + } + trcCRITICAL_SECTION_BEGIN(); - if (RecorderDataPtr->recorderActive && handle_of_last_logged_task - && (! inExcludedTask || nISRactive)) - { - /* Check if the event code is excluded */ - if (!TRACE_GET_EVENT_CODE_FLAG_ISEXCLUDED(evtcode)) - { - dts6 = (uint8_t)prvTraceGetDTS(0xFF); - - if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ - { - restParam = (uint16_t)prvTraceGetParam(0xFFFF, param); - - if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ - { - kse = (KernelCallWithParam16*) xTraceNextFreeEventBufferSlot(); - if (kse != NULL) - { - kse->dts = dts6; - kse->type = (uint8_t)evtcode; - kse->param = restParam; - prvTraceUpdateCounters(); - } - } - } - } - } + if (RecorderDataPtr->recorderActive && handle_of_last_logged_task + && (! inExcludedTask || nISRactive)) + { + /* Check if the event code is excluded */ + if (!TRACE_GET_EVENT_CODE_FLAG_ISEXCLUDED(evtcode)) + { + dts6 = (uint8_t)prvTraceGetDTS(0xFF); + restParam = (uint16_t)prvTraceGetParam(0xFFFF, param); + kse = (KernelCallWithParam16*) xTraceNextFreeEventBufferSlot(); + if (kse != NULL) + { + kse->dts = dts6; + kse->type = (uint8_t)evtcode; + kse->param = restParam; + prvTraceUpdateCounters(); + } + } + } trcCRITICAL_SECTION_END(); +#endif /* TRACE_SCHEDULING_ONLY */ } /******************************************************************************* @@ -435,39 +452,41 @@ void vTraceStoreKernelCallWithNumericParamOnly(uint32_t evtcode, uint32_t param) ******************************************************************************/ void vTraceStoreTaskswitch(objectHandleType task_handle) { - uint16_t dts3; - TSEvent* ts; - int8_t skipEvent; + uint16_t dts3; + TSEvent* ts; + int8_t skipEvent; + uint8_t hnd8; TRACE_SR_ALLOC_CRITICAL_SECTION(); - + skipEvent = 0; - TRACE_ASSERT(task_handle <= NTask, "vTraceStoreTaskswitch: Invalid value for task_handle", ); - - /*************************************************************************** - This is used to detect if a high-priority ISRs is illegally using the - recorder ISR trace functions (vTraceStoreISRBegin and ...End) while the - recorder is busy with a task-level event or lower priority ISR event. - - If this is detected, it triggers a call to vTraceError with the error - "Illegal call to vTraceStoreISRBegin/End". If you get this error, it means - that the macro trcCRITICAL_SECTION_BEGIN does not disable this ISR, as required. - - Note: Setting recorder_busy is normally handled in our macros - trcCRITICAL_SECTION_BEGIN and _END, but is needed explicitly in this - function since critical sections should not be used in the context switch - event...) - ***************************************************************************/ - - /* Skip the event if the task has been excluded, using vTraceExcludeTask */ - if (TRACE_GET_TASK_FLAG_ISEXCLUDED(task_handle)) - { - skipEvent = 1; - inExcludedTask = 1; - } - else + TRACE_ASSERT(task_handle <= NTask, + "vTraceStoreTaskswitch: Invalid value for task_handle", ); + + /*************************************************************************** + This is used to detect if a high-priority ISRs is illegally using the + recorder ISR trace functions (vTraceStoreISRBegin and ...End) while the + recorder is busy with a task-level event or lower priority ISR event. + + If this is detected, it triggers a call to vTraceError with the error + "Illegal call to vTraceStoreISRBegin/End". If you get this error, it means + that the macro trcCRITICAL_SECTION_BEGIN does not disable this ISR, as required. + + Note: Setting recorder_busy is normally handled in our macros + trcCRITICAL_SECTION_BEGIN and _END, but is needed explicitly in this + function since critical sections should not be used in the context switch + event...) + ***************************************************************************/ + + /* Skip the event if the task has been excluded, using vTraceExcludeTask */ + if (TRACE_GET_TASK_FLAG_ISEXCLUDED(task_handle)) { - inExcludedTask = 0; + skipEvent = 1; + inExcludedTask = 1; + } + else + { + inExcludedTask = 0; } trcCRITICAL_SECTION_BEGIN_ON_CORTEX_M_ONLY(); @@ -477,48 +496,42 @@ void vTraceStoreTaskswitch(objectHandleType task_handle) { skipEvent = 1; } - - if (!RecorderDataPtr->recorderActive) - { - skipEvent = 1; - } - - /* If this event should be logged, log it! */ - if (skipEvent == 0) - { - dts3 = (uint16_t)prvTraceGetDTS(0xFFFF); - - if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ - { - uint8_t hnd8; - handle_of_last_logged_task = task_handle; - hnd8 = prvTraceGet8BitHandle(handle_of_last_logged_task); - - ts = (TSEvent*)xTraceNextFreeEventBufferSlot(); - - if (ts != NULL) - { - if (uiTraceGetObjectState(TRACE_CLASS_TASK, - handle_of_last_logged_task) == TASK_STATE_INSTANCE_ACTIVE) - { - ts->type = TS_TASK_RESUME; - } - else - { - ts->type = TS_TASK_BEGIN; - } - - ts->dts = dts3; - ts->objHandle = hnd8; - - vTraceSetObjectState(TRACE_CLASS_TASK, - handle_of_last_logged_task, - TASK_STATE_INSTANCE_ACTIVE); - - prvTraceUpdateCounters(); - } - } - } + + if (!RecorderDataPtr->recorderActive) + { + skipEvent = 1; + } + + /* If this event should be logged, log it! */ + if (skipEvent == 0) + { + dts3 = (uint16_t)prvTraceGetDTS(0xFFFF); + handle_of_last_logged_task = task_handle; + hnd8 = prvTraceGet8BitHandle(handle_of_last_logged_task); + ts = (TSEvent*)xTraceNextFreeEventBufferSlot(); + + if (ts != NULL) + { + if (uiTraceGetObjectState(TRACE_CLASS_TASK, + handle_of_last_logged_task) == TASK_STATE_INSTANCE_ACTIVE) + { + ts->type = TS_TASK_RESUME; + } + else + { + ts->type = TS_TASK_BEGIN; + } + + ts->dts = dts3; + ts->objHandle = hnd8; + + vTraceSetObjectState(TRACE_CLASS_TASK, + handle_of_last_logged_task, + TASK_STATE_INSTANCE_ACTIVE); + + prvTraceUpdateCounters(); + } + } trcCRITICAL_SECTION_END_ON_CORTEX_M_ONLY(); } @@ -533,21 +546,21 @@ void vTraceStoreTaskswitch(objectHandleType task_handle) ******************************************************************************/ #if (INCLUDE_OBJECT_DELETE == 1) void vTraceStoreObjectNameOnCloseEvent(objectHandleType handle, - traceObjectClass objectclass) + traceObjectClass objectclass) { - ObjCloseNameEvent * ce; - const char * name; - traceLabel idx; + ObjCloseNameEvent * ce; + const char * name; + traceLabel idx; - TRACE_ASSERT(objectclass < TRACE_NCLASSES, "vTraceStoreObjectNameOnCloseEvent: objectclass >= TRACE_NCLASSES", ); - TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "vTraceStoreObjectNameOnCloseEvent: Invalid value for handle", ); + TRACE_ASSERT(objectclass < TRACE_NCLASSES, + "vTraceStoreObjectNameOnCloseEvent: objectclass >= TRACE_NCLASSES", ); + TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], + "vTraceStoreObjectNameOnCloseEvent: Invalid value for handle", ); - if (RecorderDataPtr->recorderActive) + if (RecorderDataPtr->recorderActive) { uint8_t hnd8 = prvTraceGet8BitHandle(handle); - name = TRACE_PROPERTY_NAME_GET(objectclass, handle); - idx = prvTraceOpenSymbol(name, 0); // Interrupt disable not necessary, already done in trcHooks.h macro @@ -555,7 +568,7 @@ void vTraceStoreObjectNameOnCloseEvent(objectHandleType handle, if (ce != NULL) { ce->type = EVENTGROUP_OBJCLOSE_NAME + objectclass; - ce->objHandle = hnd8; + ce->objHandle = hnd8; ce->symbolIndex = idx; prvTraceUpdateCounters(); } @@ -563,14 +576,16 @@ void vTraceStoreObjectNameOnCloseEvent(objectHandleType handle, } void vTraceStoreObjectPropertiesOnCloseEvent(objectHandleType handle, - traceObjectClass objectclass) + traceObjectClass objectclass) { - ObjClosePropEvent * pe; - - TRACE_ASSERT(objectclass < TRACE_NCLASSES, "vTraceStoreObjectPropertiesOnCloseEvent: objectclass >= TRACE_NCLASSES", ); - TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "vTraceStoreObjectPropertiesOnCloseEvent: Invalid value for handle", ); + ObjClosePropEvent * pe; + + TRACE_ASSERT(objectclass < TRACE_NCLASSES, + "vTraceStoreObjectPropertiesOnCloseEvent: objectclass >= TRACE_NCLASSES", ); + TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], + "vTraceStoreObjectPropertiesOnCloseEvent: Invalid value for handle", ); - if (RecorderDataPtr->recorderActive) + if (RecorderDataPtr->recorderActive) { // Interrupt disable not necessary, already done in trcHooks.h macro pe = (ObjClosePropEvent*) xTraceNextFreeEventBufferSlot(); @@ -579,9 +594,9 @@ void vTraceStoreObjectPropertiesOnCloseEvent(objectHandleType handle, if (objectclass == TRACE_CLASS_TASK) { pe->arg1 = TRACE_PROPERTY_ACTOR_PRIORITY(objectclass, handle); - pe->arg2 = 0; // Legacy - IFE info removed. - pe->arg3 = 0; // Legacy - IFE info removed. - }else{ + } + else + { pe->arg1 = TRACE_PROPERTY_OBJECT_STATE(objectclass, handle); } pe->type = EVENTGROUP_OBJCLOSE_PROP + objectclass; @@ -593,43 +608,52 @@ void vTraceStoreObjectPropertiesOnCloseEvent(objectHandleType handle, void vTraceSetPriorityProperty(uint8_t objectclass, objectHandleType id, uint8_t value) { - TRACE_ASSERT(objectclass < TRACE_NCLASSES, "vTraceSetPriorityProperty: objectclass >= TRACE_NCLASSES", ); - TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "vTraceSetPriorityProperty: Invalid value for id", ); + TRACE_ASSERT(objectclass < TRACE_NCLASSES, + "vTraceSetPriorityProperty: objectclass >= TRACE_NCLASSES", ); + TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], + "vTraceSetPriorityProperty: Invalid value for id", ); - TRACE_PROPERTY_ACTOR_PRIORITY(objectclass, id) = value; + TRACE_PROPERTY_ACTOR_PRIORITY(objectclass, id) = value; } uint8_t uiTraceGetPriorityProperty(uint8_t objectclass, objectHandleType id) { - TRACE_ASSERT(objectclass < TRACE_NCLASSES, "uiTraceGetPriorityProperty: objectclass >= TRACE_NCLASSES", 0); - TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "uiTraceGetPriorityProperty: Invalid value for id", 0); + TRACE_ASSERT(objectclass < TRACE_NCLASSES, + "uiTraceGetPriorityProperty: objectclass >= TRACE_NCLASSES", 0); + TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], + "uiTraceGetPriorityProperty: Invalid value for id", 0); - return TRACE_PROPERTY_ACTOR_PRIORITY(objectclass, id); + return TRACE_PROPERTY_ACTOR_PRIORITY(objectclass, id); } void vTraceSetObjectState(uint8_t objectclass, objectHandleType id, uint8_t value) { - TRACE_ASSERT(objectclass < TRACE_NCLASSES, "vTraceSetObjectState: objectclass >= TRACE_NCLASSES", ); - TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "vTraceSetObjectState: Invalid value for id", ); - - TRACE_PROPERTY_OBJECT_STATE(objectclass, id) = value; + TRACE_ASSERT(objectclass < TRACE_NCLASSES, + "vTraceSetObjectState: objectclass >= TRACE_NCLASSES", ); + TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], + "vTraceSetObjectState: Invalid value for id", ); + + TRACE_PROPERTY_OBJECT_STATE(objectclass, id) = value; } uint8_t uiTraceGetObjectState(uint8_t objectclass, objectHandleType id) { - TRACE_ASSERT(objectclass < TRACE_NCLASSES, "uiTraceGetObjectState: objectclass >= TRACE_NCLASSES", 0); - TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "uiTraceGetObjectState: Invalid value for id", 0); - - return TRACE_PROPERTY_OBJECT_STATE(objectclass, id); + TRACE_ASSERT(objectclass < TRACE_NCLASSES, + "uiTraceGetObjectState: objectclass >= TRACE_NCLASSES", 0); + TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], + "uiTraceGetObjectState: Invalid value for id", 0); + + return TRACE_PROPERTY_OBJECT_STATE(objectclass, id); } void vTraceSetTaskInstanceFinished(objectHandleType handle) { - TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[TRACE_CLASS_TASK], "vTraceSetTaskInstanceFinished: Invalid value for handle", ); - + TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[TRACE_CLASS_TASK], + "vTraceSetTaskInstanceFinished: Invalid value for handle", ); + #if (USE_IMPLICIT_IFE_RULES == 1) - TRACE_PROPERTY_OBJECT_STATE(TRACE_CLASS_TASK, handle) = 0; + TRACE_PROPERTY_OBJECT_STATE(TRACE_CLASS_TASK, handle) = 0; #endif } -#endif \ No newline at end of file +#endif diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernelPort.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernelPort.c index a4217e071..ff0b427a8 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernelPort.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernelPort.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Tracealyzer v2.6.0 Recorder Library + * Tracealyzer v2.7.0 Recorder Library * Percepio AB, www.percepio.com * * trcKernelPort.c @@ -31,7 +31,9 @@ * damages, or the exclusion of implied warranties or limitations on how long an * implied warranty may last, so the above limitations may not apply to you. * - * Copyright Percepio AB, 2013. + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2014. * www.percepio.com ******************************************************************************/ @@ -56,13 +58,27 @@ traceObjectClass TraceObjectClassTable[5] = { int uiInEventGroupSetBitsFromISR = 0; extern unsigned char ucQueueGetQueueType(void*); -extern BaseType_t uxQueueGetQueueNumber(void*); + +#if (FREERTOS_VERSION < FREERTOS_VERSION_8_0_OR_LATER) + +extern portBASE_TYPE ucQueueGetQueueNumber(void*); + +objectHandleType prvTraceGetObjectNumber(void* handle) +{ + return (objectHandleType) ucQueueGetQueueNumber(handle); +} + +#else + +extern portBASE_TYPE uxQueueGetQueueNumber(void*); objectHandleType prvTraceGetObjectNumber(void* handle) { - return ( objectHandleType ) uxQueueGetQueueNumber(handle); + return (objectHandleType) uxQueueGetQueueNumber(handle); } +#endif + unsigned char prvTraceGetObjectType(void* handle) { return ucQueueGetQueueType(handle); @@ -139,7 +155,7 @@ void vTraceInitObjectHandleStack() objectHandleStacks.indexOfNextAvailableHandle[5] = objectHandleStacks.lowestIndexOfClass[5] = NQueue + NSemaphore + NMutex + NTask + NISR; objectHandleStacks.indexOfNextAvailableHandle[6] = objectHandleStacks.lowestIndexOfClass[6] = NQueue + NSemaphore + NMutex + NTask + NISR + NTimer; - objectHandleStacks.highestIndexOfClass[0] = NQueue - 1; + objectHandleStacks.highestIndexOfClass[0] = NQueue - 1; objectHandleStacks.highestIndexOfClass[1] = NQueue + NSemaphore - 1; objectHandleStacks.highestIndexOfClass[2] = NQueue + NSemaphore + NMutex - 1; objectHandleStacks.highestIndexOfClass[3] = NQueue + NSemaphore + NMutex + NTask - 1; diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcUser.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcUser.c index 5f46a809d..57c53ffbc 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcUser.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcUser.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Tracealyzer v2.6.0 Recorder Library + * Tracealyzer v2.7.0 Recorder Library * Percepio AB, www.percepio.com * * trcUser.c @@ -31,7 +31,9 @@ * damages, or the exclusion of implied warranties or limitations on how long an * implied warranty may last, so the above limitations may not apply to you. * - * Copyright Percepio AB, 2013. + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2014. * www.percepio.com ******************************************************************************/ #include "FreeRTOS.h" @@ -56,7 +58,7 @@ extern uint32_t hwtc_count_sum_after_tick; extern uint32_t hwtc_count_sum_after_tick_counter; extern char* traceErrorMessage; -/*** private functions *******************************************************/ +/*** Private functions *******************************************************/ void vTracePrintF_Helper(traceLabel eventLabel, const char* formatStr, va_list vl); #if (USE_SEPARATE_USER_EVENT_BUFFER == 1) @@ -64,8 +66,8 @@ void vTraceChannelPrintF_Helper(UserEventChannel channelPair, va_list vl); static void prvTraceUserEventHelper1(UserEventChannel channel, traceLabel eventLabel, traceLabel formatLabel, va_list vl); static void prvTraceUserEventHelper2(UserEventChannel channel, uint32_t* data, uint32_t noOfSlots); #endif -/*****************************************************************************/ +static void prvTraceTaskInstanceFinish(int8_t direct); /******************************************************************************* @@ -93,6 +95,16 @@ void vTraceSetRecorderData(void* pRecorderData) } #endif +/******************************************************************************* + * vTraceSetStopHook + * + * Sets a function to be called when the recorder is stopped. + ******************************************************************************/ +void vTraceSetStopHook(TRACE_STOP_HOOK stopHookFunction) +{ + vTraceStopHookPtr = stopHookFunction; +} + /******************************************************************************* * vTraceClear * @@ -101,17 +113,21 @@ void vTraceSetRecorderData(void* pRecorderData) ******************************************************************************/ void vTraceClear(void) { - TRACE_SR_ALLOC_CRITICAL_SECTION(); - trcCRITICAL_SECTION_BEGIN(); + TRACE_SR_ALLOC_CRITICAL_SECTION(); + trcCRITICAL_SECTION_BEGIN(); - RecorderDataPtr->absTimeLastEvent = 0; - RecorderDataPtr->nextFreeIndex = 0; - RecorderDataPtr->numEvents = 0; - RecorderDataPtr->bufferIsFull = 0; + RecorderDataPtr->absTimeLastEventSecond = 0; + + RecorderDataPtr->absTimeLastEvent = 0; + RecorderDataPtr->nextFreeIndex = 0; + RecorderDataPtr->numEvents = 0; + RecorderDataPtr->bufferIsFull = 0; traceErrorMessage = NULL; RecorderDataPtr->internalErrorOccured = 0; - trcCRITICAL_SECTION_END(); + memset(RecorderDataPtr->eventData, 0, RecorderDataPtr->maxEvents * 4); + + trcCRITICAL_SECTION_END(); } @@ -131,7 +147,7 @@ void vTraceClear(void) uint32_t uiTraceStart(void) { objectHandleType handle; - TRACE_SR_ALLOC_CRITICAL_SECTION(); + TRACE_SR_ALLOC_CRITICAL_SECTION(); handle = 0; @@ -140,10 +156,11 @@ uint32_t uiTraceStart(void) vTraceError("RecorderDataPtr is NULL. Call vTraceInitTraceData() before starting trace."); return 0; } - if (traceErrorMessage == NULL) - { - trcCRITICAL_SECTION_BEGIN(); - RecorderDataPtr->recorderActive = 1; + + if (traceErrorMessage == NULL) + { + trcCRITICAL_SECTION_BEGIN(); + RecorderDataPtr->recorderActive = 1; handle = TRACE_GET_TASK_NUMBER(TRACE_GET_CURRENT_TASK()); if (handle == 0) @@ -157,11 +174,11 @@ uint32_t uiTraceStart(void) vTraceSetPriorityProperty(TRACE_CLASS_TASK, handle, 0); } - vTraceStoreTaskswitch(handle); /* Register the currently running task */ - trcCRITICAL_SECTION_END(); - } + vTraceStoreTaskswitch(handle); /* Register the currently running task */ + trcCRITICAL_SECTION_END(); + } - return RecorderDataPtr->recorderActive; + return RecorderDataPtr->recorderActive; } /******************************************************************************* @@ -176,7 +193,7 @@ uint32_t uiTraceStart(void) ******************************************************************************/ void vTraceStart(void) { - (void)uiTraceStart(); + (void)uiTraceStart(); } /******************************************************************************* @@ -187,11 +204,11 @@ void vTraceStart(void) ******************************************************************************/ void vTraceStop(void) { - RecorderDataPtr->recorderActive = 0; - + RecorderDataPtr->recorderActive = 0; + if (vTraceStopHookPtr != (TRACE_STOP_HOOK)0) { - (*vTraceStopHookPtr)(); /* Call an application level call back function. */ + (*vTraceStopHookPtr)(); /* An application call-back function. */ } } @@ -209,15 +226,15 @@ char* xTraceGetLastError(void) /******************************************************************************* * vTraceClearError * -* Removes any previous error message generated by recorder calling vTraceError. -* By calling this function, it may be possible to start/restart the trace -* despite errors in the recorder, but there is no guarantee that the trace +* Removes any previous error message generated by recorder calling vTraceError. +* By calling this function, it may be possible to start/restart the trace +* despite errors in the recorder, but there is no guarantee that the trace * recorder will work correctly in that case, depending on the type of error. ******************************************************************************/ void vTraceClearError(int resetErrorMessage) { ( void ) resetErrorMessage; - traceErrorMessage = NULL; + traceErrorMessage = NULL; RecorderDataPtr->internalErrorOccured = 0; } @@ -231,7 +248,7 @@ void vTraceClearError(int resetErrorMessage) ******************************************************************************/ void* vTraceGetTraceBuffer(void) { - return RecorderDataPtr; + return RecorderDataPtr; } /******************************************************************************* @@ -243,23 +260,101 @@ void* vTraceGetTraceBuffer(void) ******************************************************************************/ uint32_t uiTraceGetTraceBufferSize(void) { - return sizeof(RecorderDataType); + return sizeof(RecorderDataType); +} + +/****************************************************************************** + * prvTraceTaskInstanceFinish. + * + * Private common function for the vTraceTaskInstanceFinishXXX functions. + * + *****************************************************************************/ +void prvTraceTaskInstanceFinish(int8_t direct) +{ + TaskInstanceStatusEvent* tis; + uint8_t dts45; + + TRACE_SR_ALLOC_CRITICAL_SECTION(); + + trcCRITICAL_SECTION_BEGIN(); + if (RecorderDataPtr->recorderActive && (! inExcludedTask || nISRactive) && handle_of_last_logged_task) + { + dts45 = (uint8_t)prvTraceGetDTS(0xFF); + tis = (TaskInstanceStatusEvent*) xTraceNextFreeEventBufferSlot(); + if (tis != NULL) + { + if (direct == 0) + tis->type = TASK_INSTANCE_FINISHED_NEXT_KSE; + else + tis->type = TASK_INSTANCE_FINISHED_DIRECT; + + tis->dts = dts45; + prvTraceUpdateCounters(); + } + } + trcCRITICAL_SECTION_END(); } /****************************************************************************** - * vTraceTaskInstanceIsFinished + * vTraceTaskInstanceFinish(void) + * + * Marks the current task instance as finished on the next kernel call. + * + * If that kernel call is blocking, the instance ends after the blocking event + * and the corresponding return event is then the start of the next instance. + * If the kernel call is not blocking, the viewer instead splits the current + * fragment right before the kernel call, which makes this call the first event + * of the next instance. + * + * See also USE_IMPLICIT_IFE_RULES in trcConfig.h + * + * Example: + * + * while(1) + * { + * xQueueReceive(CommandQueue, &command, timeoutDuration); + * processCommand(command); + * vTraceInstanceFinish(); + * } + * + * Note: This is only supported in Tracealyzer tools v2.7 or later * - * This defines an explicit Instance Finish Event for the current task. It tells - * the recorder that the current instance of this task is finished at the - * context-switch. This function should be called right before the API function - * call considered to be the Instance Finish Event. *****************************************************************************/ -void vTraceTaskInstanceIsFinished() +void vTraceTaskInstanceFinish(void) { - if (handle_of_last_logged_task) - { - TRACE_PROPERTY_OBJECT_STATE(TRACE_CLASS_TASK, handle_of_last_logged_task) = 0; - } + prvTraceTaskInstanceFinish(0); +} + +/****************************************************************************** + * vTraceTaskInstanceFinishDirect(void) + * + * Marks the current task instance as finished at this very instant. + * This makes the viewer to splits the current fragment at this point and begin + * a new actor instance. + * + * See also USE_IMPLICIT_IFE_RULES in trcConfig.h + * + * Example: + * + * This example will generate two instances for each loop iteration. + * The first instance ends at vTraceInstanceFinishDirect(), while the second + * instance ends at the next xQueueReceive call. + * + * while (1) + * { + * xQueueReceive(CommandQueue, &command, timeoutDuration); + * ProcessCommand(command); + * vTraceInstanceFinishDirect(); + * DoSometingElse(); + * vTraceInstanceFinish(); + * } + * + * Note: This is only supported in Tracealyzer tools v2.7 or later + * + *****************************************************************************/ +void vTraceTaskInstanceFinishDirect(void) +{ + prvTraceTaskInstanceFinish(1); } /******************************************************************************* @@ -280,17 +375,17 @@ static uint8_t isrstack[MAX_ISR_NESTING]; * started. * * Example: - * #define ID_ISR_TIMER1 1 // lowest valid ID is 1 - * #define PRIO_OF_ISR_TIMER1 3 // the hardware priority of the interrupt - * ... - * vTraceSetISRProperties(ID_ISR_TIMER1, "ISRTimer1", PRIO_OF_ISR_TIMER1); - * ... - * void ISR_handler() - * { - * vTraceStoreISRBegin(ID_OF_ISR_TIMER1); - * ... - * vTraceStoreISREnd(); - * } + * #define ID_ISR_TIMER1 1 // lowest valid ID is 1 + * #define PRIO_OF_ISR_TIMER1 3 // the hardware priority of the interrupt + * ... + * vTraceSetISRProperties(ID_ISR_TIMER1, "ISRTimer1", PRIO_OF_ISR_TIMER1); + * ... + * void ISR_handler() + * { + * vTraceStoreISRBegin(ID_OF_ISR_TIMER1); + * ... + * vTraceStoreISREnd(0); + * } * * NOTE: To safely record ISRs, you need to make sure that all traced * interrupts actually are disabled by trcCRITICAL_SECTION_BEGIN(). However, @@ -302,10 +397,9 @@ void vTraceSetISRProperties(objectHandleType handle, const char* name, char prio { TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[TRACE_CLASS_ISR], "vTraceSetISRProperties: Invalid value for handle", ); TRACE_ASSERT(name != NULL, "vTraceSetISRProperties: name == NULL", ); - TRACE_ASSERT(priority >= 0, "vTraceSetISRProperties: Invalid value for priority", ); - vTraceSetObjectName(TRACE_CLASS_ISR, handle, name); - vTraceSetPriorityProperty(TRACE_CLASS_ISR, handle, priority); + vTraceSetObjectName(TRACE_CLASS_ISR, handle, name); + vTraceSetPriorityProperty(TRACE_CLASS_ISR, handle, priority); } #if (SELECTED_PORT == PORT_ARM_CortexM) @@ -314,31 +408,35 @@ void vTraceSetISRProperties(objectHandleType handle, const char* name, char prio * * ISR_TAILCHAINING_THRESHOLD (For Cortex-M devices only) * - * ARM Cortex-M devices may execute ISRs back-to-back (tail-chained) without - * resuming the previous context in between. Since this is decided in + * ARM Cortex-M devices may execute ISRs back-to-back (tail-chained) without + * resuming the previous context in between. Since this is decided in * hardware, we can only detect this indirectly, in the following manner: * - * When entering vTraceStoreISRBegin, we check the number of CPU cycles since + * When entering vTraceStoreISRBegin, we check the number of CPU cycles since * the last return of vTraceStoreISREnd. If less or equal to the constant * ISR_TAILCHAINING_THRESHOLD it is assumed that the ISRs executed back-to-back - * (tail-chained). In that case, the previously stored RESUME event - * (pointed to by ptrLastISRExitEvent) is then deleted to avoid showing a + * (tail-chained). In that case, the previously stored RESUME event + * (pointed to by ptrLastISRExitEvent) is then deleted to avoid showing a * fragment of the previous context in between the ISR events. The delete is * made by replacing the event code with a XTS16L event, that serves to keep * the differential timestamp from the earlier event. * - * The value of ISR_TAILCHAINING_THRESHOLD depends on the interrupt latency of - * the processor, on the compiler and on the compiler settings, but should be - * around 70 cycles. The default value is 66 cycles, which should be correct when + * The value of ISR_TAILCHAINING_THRESHOLD depends on the interrupt latency of + * the processor, on the compiler and on the compiler settings, but should be + * around 70 cycles. The default value is 66 cycles, which should be correct when * using GCC with optimizations disabled (-O0) and Cortex-M3/M4. * * To measure this value, see MEASURE_ISR_TAILCHAINING_THRESHOLD below. * - * If this value set too low, tail-chained ISRs will incorrectly be shown + * If this value set too low, tail-chained ISRs will incorrectly be shown * separated, with a short fragment of the previous task or ISR in between. - * If this value is set too high, you get the opposite effect - separate ISRs - * will appear to execute tail-chained and will appear to have higher execution + * If this value is set too high, you get the opposite effect - separate ISRs + * will appear to execute tail-chained and will appear to have higher execution * time and response time (maximum ISR_TAILCHAINING_THRESHOLD cycles more). + * + * Read the blog post explaining this on our website: + * http://percepio.com/2014/05/06/sw-based-exc-tracing-arm-cortex-m/ + * *****************************************************************************/ #define ISR_TAILCHAINING_THRESHOLD 66 @@ -350,52 +448,55 @@ uint32_t DWTCycleCountAtLastISRExit = 0; * * MEASURE_ISR_TAILCHAINING_THRESHOLD (For Cortex-M devices only) * - * Allows for measuring the value of ISR_TAILCHAINING_THRESHOLD (see above). + * Allows for calibrating the value of ISR_TAILCHAINING_THRESHOLD (see above). * * This is intended to measure the minimum number of clock cycles from the end * of vTraceStoreISREnd to the beginning of the following vTraceStoreISRBegin. - * For this purpose, we assume a test setup using the SysTick interrupt, which - * is available on most Cortex-M devices and typically used by the RTOS kernel. + * For this purpose, we assume a test setup using the SysTick interrupt, which + * is available on most Cortex-M devices and typically used by the RTOS kernel. * To do the measurement, follow these steps: - * + * * 1. Make sure MEASURE_ISR_TAILCHAINING_THRESHOLD is enabled (defined as 1) * * 2. Temporarily replace your SysTick handler with the following: - * - * void xPortSysTickHandler( void ) - * { - * vTraceStoreISRBegin(1); - * vTraceStoreISREnd(); - * } - * - * 3. To make sure that the ISRs execute back-to-back, increase the OS tick - * frequency to a very high level so that the OS tick interrupt execute - * continuously with no application tasks in between. A tick frequency of - * 1 MHz (1.000.000) should be sufficient. - * - * 4. Put a breakpoint in the highest priority task and make sure it is not - * reached. This means that the SysTick handler is executing at maximum rate - * and thereby tail-chained, where the interrupt latency is 6 cycles. - * - * 5. Let the system run without breakpoints and inspect the value of - * threshold_low_watermark. This is the minimum total latency observed. - * The hardware latency is 6 clock cycles due to the tail-chaining, so the - * software latency (SL) is then SL = threshold_low_watermark - 6. - * - * The threshold value ISR_TAILCHAINING_THRESHOLD should be SL + 2 * HL, where - * HL is the normal hardware interrupt latency, i.e., the number of CPU - * cycles to enter or exit the exception handler for an exception in task + * + * void xPortSysTickHandler( void ) + * { + * vTraceStoreISRBegin(1); + * vTraceStoreISREnd(0); + * } + * + * 3. To make sure that the ISRs execute back-to-back, increase the OS tick + * frequency to a very high level so that the OS tick interrupt execute + * continuously with no application tasks in between, e.g. 10 MHz. + * + * 4. Put a breakpoint in the highest priority task and make sure it is not + * reached. This means that the SysTick handler is executing at maximum rate + * and thereby tail-chained, where the interrupt latency is 6 cycles. + * + * 5. Let the system run without breakpoints and inspect the value of + * threshold_low_watermark. This is the minimum total latency observed. + * The hardware latency is 6 clock cycles due to the tail-chaining, so the + * software latency (SL) is then SL = threshold_low_watermark - 6. + * + * The threshold value ISR_TAILCHAINING_THRESHOLD should be SL + 2 * HL, where + * HL is the normal hardware interrupt latency, i.e., the number of CPU + * cycles to enter or exit the exception handler for an exception in task * context. The HL value is 12-16 depending on core, as shown below. - * + * * Values for ISR_TAILCHAINING_THRESHOLD, assuming SL = 42 - * Cortex-M3 and M4 (HL = 12): 66 cycles - * Cortex-M0 (HL = 16): 74 cycles - * Cortex-M0+ (HL = 15): 72 cycles + * Cortex-M3 and M4 (HL = 12): 66 cycles + * Cortex-M0 (HL = 16): 74 cycles + * Cortex-M0+ (HL = 15): 72 cycles * * If the ISR_TAILCHAINING_THRESHOLD value is set too low, some tail-chained - * ISRs be shown separated, with a short fragment of the previous actor. If - * the value is set too high, separate ISRs will appear to execute tail-chained - * and for too long time. + * ISRs be shown separated, with a short fragment of the previous context + * in between. On the other hand, if the value is set too high, ISRs that + * actually are separated may appear to execute back-to-back (tail-chained). + * + * Read the blog post explaining this on our website: + * http://percepio.com/2014/05/06/sw-based-exc-tracing-arm-cortex-m/ + * *****************************************************************************/ #define MEASURE_ISR_TAILCHAINING_THRESHOLD 1 @@ -411,94 +512,94 @@ volatile uint32_t threshold_low_watermark = 2000000000; * Registers the beginning of an Interrupt Service Routine. * * Example: - * #define ID_ISR_TIMER1 1 // lowest valid ID is 1 - * #define PRIO_OF_ISR_TIMER1 3 // the hardware priority of the interrupt - * ... - * vTraceSetISRProperties(ID_ISR_TIMER1, "ISRTimer1", PRIO_OF_ISR_TIMER1); - * ... - * void ISR_handler() - * { - * vTraceStoreISRBegin(ID_OF_ISR_TIMER1); - * ... - * vTraceStoreISREnd(); - * } + * #define ID_ISR_TIMER1 1 // lowest valid ID is 1 + * #define PRIO_OF_ISR_TIMER1 3 // the hardware priority of the interrupt + * ... + * vTraceSetISRProperties(ID_ISR_TIMER1, "ISRTimer1", PRIO_OF_ISR_TIMER1); + * ... + * void ISR_handler() + * { + * vTraceStoreISRBegin(ID_OF_ISR_TIMER1); + * ... + * vTraceStoreISREnd(0); + * } * ******************************************************************************/ void vTraceStoreISRBegin(objectHandleType handle) { - uint16_t dts4; + uint16_t dts4; #if (SELECTED_PORT == PORT_ARM_CortexM) - uint32_t CPUCyclesSinceLastISRExit = DWT_CYCLE_COUNTER - DWTCycleCountAtLastISRExit; - #endif - TSEvent* ts; - TRACE_SR_ALLOC_CRITICAL_SECTION(); + uint32_t CPUCyclesSinceLastISRExit = REG_DWT_CYCCNT - DWTCycleCountAtLastISRExit; + #endif + TSEvent* ts; + TRACE_SR_ALLOC_CRITICAL_SECTION(); ts = NULL; #if (SELECTED_PORT == PORT_ARM_CortexM) - if (DWTCycleCountAtLastISRExit > 0) + if (DWTCycleCountAtLastISRExit > 0) { - #if (MEASURE_ISR_TAILCHAINING_THRESHOLD == 1) + #if (MEASURE_ISR_TAILCHAINING_THRESHOLD == 1) /* Allows for verifying the value of ISR_TAILCHAINING_THRESHOLD */ if (CPUCyclesSinceLastISRExit < threshold_low_watermark) { threshold_low_watermark = CPUCyclesSinceLastISRExit; } #endif - - if (CPUCyclesSinceLastISRExit <= ISR_TAILCHAINING_THRESHOLD) - { - /* This is judged to be a case of ISR tail-chaining since the + + if (CPUCyclesSinceLastISRExit <= ISR_TAILCHAINING_THRESHOLD) + { + /* This is judged to be a case of ISR tail-chaining since the number of cycles since the last vTraceStoreISREnd is shorter or equal to the threshold (ISR_TAILCHAINING_THRESHOLD) */ - + if (ptrLastISRExitEvent != NULL) - { + { /* Overwrite the last ISR exit event with a "neutral" event that only - accounts for the time passed */ - *ptrLastISRExitEvent = XTS16L; - } + accounts for the time passed */ + *ptrLastISRExitEvent = XTS16L; + } } - + } #endif - - if (recorder_busy) - { - vTraceError("Illegal call to vTraceStoreISRBegin, recorder busy!"); - return; - } + + if (recorder_busy) + { + vTraceError("Illegal call to vTraceStoreISRBegin, recorder busy!"); + return; + } trcCRITICAL_SECTION_BEGIN(); - if (RecorderDataPtr->recorderActive && handle_of_last_logged_task) - { + if (RecorderDataPtr->recorderActive && handle_of_last_logged_task) + { - TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[TRACE_CLASS_ISR], "vTraceStoreISRBegin: Invalid value for handle", ); + TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[TRACE_CLASS_ISR], "vTraceStoreISRBegin: Invalid value for handle", ); - dts4 = (uint16_t)prvTraceGetDTS(0xFFFF); + dts4 = (uint16_t)prvTraceGetDTS(0xFFFF); - if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ - { - if (nISRactive < MAX_ISR_NESTING) - { + if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ + { + if (nISRactive < MAX_ISR_NESTING) + { uint8_t hnd8 = prvTraceGet8BitHandle(handle); - isrstack[nISRactive] = handle; - nISRactive++; - ts = (TSEvent*)xTraceNextFreeEventBufferSlot(); - if (ts != NULL) - { - ts->type = TS_ISR_BEGIN; - ts->dts = dts4; - ts->objHandle = hnd8; - prvTraceUpdateCounters(); - } - } - else - { - /* This should not occur unless something is very wrong */ - vTraceError("Too many nested interrupts!"); - } - } - } + isrstack[nISRactive] = handle; + nISRactive++; + ts = (TSEvent*)xTraceNextFreeEventBufferSlot(); + if (ts != NULL) + { + ts->type = TS_ISR_BEGIN; + ts->dts = dts4; + ts->objHandle = hnd8; + prvTraceUpdateCounters(); + } + } + else + { + /* This should not occur unless something is very wrong */ + vTraceError("Too many nested interrupts!"); + } + } + } trcCRITICAL_SECTION_END(); } @@ -507,21 +608,25 @@ void vTraceStoreISRBegin(objectHandleType handle) * * Registers the end of an Interrupt Service Routine. * + * The parameter pendingISR indicates if the interrupt has requested a + * task-switch (= 1) or if the interrupt returns to the earlier context (= 0) + * * Example: - * #define ID_ISR_TIMER1 1 // lowest valid ID is 1 - * #define PRIO_OF_ISR_TIMER1 3 // the hardware priority of the interrupt - * ... - * vTraceSetISRProperties(ID_ISR_TIMER1, "ISRTimer1", PRIO_OF_ISR_TIMER1); - * ... - * void ISR_handler() - * { - * vTraceStoreISRBegin(ID_OF_ISR_TIMER1); - * ... - * vTraceStoreISREnd(); - * } + * + * #define ID_ISR_TIMER1 1 // lowest valid ID is 1 + * #define PRIO_OF_ISR_TIMER1 3 // the hardware priority of the interrupt + * ... + * vTraceSetISRProperties(ID_ISR_TIMER1, "ISRTimer1", PRIO_OF_ISR_TIMER1); + * ... + * void ISR_handler() + * { + * vTraceStoreISRBegin(ID_OF_ISR_TIMER1); + * ... + * vTraceStoreISREnd(0); + * } * ******************************************************************************/ -void vTraceStoreISREnd(void) +void vTraceStoreISREnd(int pendingISR) { TSEvent* ts; uint16_t dts5; @@ -534,13 +639,12 @@ void vTraceStoreISREnd(void) } trcCRITICAL_SECTION_BEGIN(); - if (RecorderDataPtr->recorderActive && handle_of_last_logged_task) - { - dts5 = (uint16_t)prvTraceGetDTS(0xFFFF); - - if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ + if (pendingISR == 0) + { + if (RecorderDataPtr->recorderActive && handle_of_last_logged_task) { uint8_t hnd8, type; + dts5 = (uint16_t)prvTraceGetDTS(0xFFFF); if (nISRactive > 1) { @@ -556,24 +660,26 @@ void vTraceStoreISREnd(void) } ts = (TSEvent*)xTraceNextFreeEventBufferSlot(); - if (ts != NULL) { ts->type = type; ts->objHandle = hnd8; ts->dts = dts5; - nISRactive--; prvTraceUpdateCounters(); } - + + #if (SELECTED_PORT == PORT_ARM_CortexM) + /* Remember the last ISR exit event, as the event needs to be modified in case of a following ISR entry (if tail-chained ISRs) */ + ptrLastISRExitEvent = (uint8_t*)ts; + #endif } - - #if (SELECTED_PORT == PORT_ARM_CortexM) - /* Remember the last ISR exit event, as the event needs to be modified in case of a following ISR entry (if tail-chained ISRs) */ - ptrLastISRExitEvent = (uint8_t*)ts; - DWTCycleCountAtLastISRExit = DWT_CYCLE_COUNTER; - #endif } + nISRactive--; + + #if (SELECTED_PORT == PORT_ARM_CortexM) + DWTCycleCountAtLastISRExit = REG_DWT_CYCCNT; + #endif + trcCRITICAL_SECTION_END(); } @@ -582,21 +688,21 @@ void vTraceStoreISREnd(void) /* ISR tracing is turned off */ void vTraceIncreaseISRActive(void) { - if (RecorderDataPtr->recorderActive && handle_of_last_logged_task) - nISRactive++; + if (RecorderDataPtr->recorderActive && handle_of_last_logged_task) + nISRactive++; } void vTraceDecreaseISRActive(void) { - if (RecorderDataPtr->recorderActive && handle_of_last_logged_task) - nISRactive--; + if (RecorderDataPtr->recorderActive && handle_of_last_logged_task) + nISRactive--; } #endif -/******************************************************************************* - * User Event functions - ******************************************************************************/ +/********************************************************************************/ +/* User Event functions */ +/********************************************************************************/ #if (INCLUDE_USER_EVENTS == 1) @@ -606,19 +712,19 @@ static uint8_t writeInt8(void * buffer, uint8_t i, uint8_t value) { TRACE_ASSERT(buffer != NULL, "writeInt8: buffer == NULL", 0); - if (i >= MAX_ARG_SIZE) - { - return 255; - } + if (i >= MAX_ARG_SIZE) + { + return 255; + } - ((uint8_t*)buffer)[i] = value; + ((uint8_t*)buffer)[i] = value; if (i + 1 > MAX_ARG_SIZE) { return 255; } - return i + 1; + return i + 1; } /*** Locally used in vTracePrintF ***/ @@ -626,26 +732,26 @@ static uint8_t writeInt16(void * buffer, uint8_t i, uint16_t value) { TRACE_ASSERT(buffer != NULL, "writeInt16: buffer == NULL", 0); - /* Align to multiple of 2 */ - while ((i % 2) != 0) - { + /* Align to multiple of 2 */ + while ((i % 2) != 0) + { if (i >= MAX_ARG_SIZE) { return 255; } - ((uint8_t*)buffer)[i] = 0; - i++; - } + ((uint8_t*)buffer)[i] = 0; + i++; + } - if (i + 2 > MAX_ARG_SIZE) - { - return 255; - } + if (i + 2 > MAX_ARG_SIZE) + { + return 255; + } - ((uint16_t*)buffer)[i/2] = value; + ((uint16_t*)buffer)[i/2] = value; - return i + 2; + return i + 2; } /*** Locally used in vTracePrintF ***/ @@ -653,26 +759,26 @@ static uint8_t writeInt32(void * buffer, uint8_t i, uint32_t value) { TRACE_ASSERT(buffer != NULL, "writeInt32: buffer == NULL", 0); - /* A 32 bit value should begin at an even 4-byte address */ - while ((i % 4) != 0) - { + /* A 32 bit value should begin at an even 4-byte address */ + while ((i % 4) != 0) + { if (i >= MAX_ARG_SIZE) { return 255; } - ((uint8_t*)buffer)[i] = 0; - i++; - } + ((uint8_t*)buffer)[i] = 0; + i++; + } - if (i + 4 > MAX_ARG_SIZE) - { - return 255; - } + if (i + 4 > MAX_ARG_SIZE) + { + return 255; + } - ((uint32_t*)buffer)[i/4] = value; + ((uint32_t*)buffer)[i/4] = value; - return i + 4; + return i + 4; } #if (INCLUDE_FLOAT_SUPPORT) @@ -682,59 +788,60 @@ static uint8_t writeFloat(void * buffer, uint8_t i, float value) { TRACE_ASSERT(buffer != NULL, "writeFloat: buffer == NULL", 0); - /* A 32 bit value should begin at an even 4-byte address */ - while ((i % 4) != 0) - { + /* A 32 bit value should begin at an even 4-byte address */ + while ((i % 4) != 0) + { if (i >= MAX_ARG_SIZE) { return 255; } - ((uint8_t*)buffer)[i] = 0; - i++; - } + ((uint8_t*)buffer)[i] = 0; + i++; + } - if (i + 4 > MAX_ARG_SIZE) - { - return 255; - } + if (i + 4 > MAX_ARG_SIZE) + { + return 255; + } - ((float*)buffer)[i/4] = value; + ((float*)buffer)[i/4] = value; - return i + 4; + return i + 4; } /*** Locally used in vTracePrintF ***/ static uint8_t writeDouble(void * buffer, uint8_t i, double value) { + uint32_t * dest; + uint32_t * src = (uint32_t*)&value; + TRACE_ASSERT(buffer != NULL, "writeDouble: buffer == NULL", 0); - uint32_t * dest; - uint32_t * src = (void*)&value; - /* The double is written as two 32 bit values, and should begin at an even - 4-byte address (to avoid having to align with 8 byte) */ - while (i % 4 != 0) - { + /* The double is written as two 32 bit values, and should begin at an even + 4-byte address (to avoid having to align with 8 byte) */ + while (i % 4 != 0) + { if (i >= MAX_ARG_SIZE) { return 255; } - ((uint8_t*)buffer)[i] = 0; - i++; - } + ((uint8_t*)buffer)[i] = 0; + i++; + } + + if (i + 8 > MAX_ARG_SIZE) + { + return 255; + } - if (i + 8 > MAX_ARG_SIZE) - { - return 255; - } - - dest = &(((uint32_t *)buffer)[i]); + dest = &(((uint32_t *)buffer)[i/4]); - dest[0] = src[0]; - dest[1] = src[1]; + dest[0] = src[0]; + dest[1] = src[1]; - return i + 8; + return i + 8; } #endif @@ -751,40 +858,40 @@ static uint8_t prvTraceUserEventFormat(const char* formatStr, va_list vl, uint8_ uint8_t i = byteOffset; while (formatStr[formatStrIndex] != '\0') - { - if (formatStr[formatStrIndex] == '%') - { - argCounter++; + { + if (formatStr[formatStrIndex] == '%') + { + argCounter++; - if (argCounter > 15) - { - vTraceError("vTracePrintF - Too many arguments, max 15 allowed!"); - return 0; - } + if (argCounter > 15) + { + vTraceError("vTracePrintF - Too many arguments, max 15 allowed!"); + return 0; + } -/******************************************************************************* -* These below code writes raw data (primitive datatypes) in the event buffer, -* instead of the normal event structs (where byte 0 is event type). -* These data entries must never be interpreted as real event data, as the type -* field would be misleading since used for payload data. -* -* The correctness of this encoding depends on two mechanisms: -* -* 1. An initial USER_EVENT, which type code tells the number of 32-bit data -* entires that follows. (code - USER_EVENT = number of data entries). -* Note that a data entry corresponds to the slots that normally corresponds to -* one (1) event, i.e., 32 bits. vTracePrintF may encode several pieces of data -* in one data entry, e.g., two 16-bit values or four 8-bit values, one 16-bit -* value followed by two 8-bit values, etc. -* -* 2. A two-phase commit procedure, where the USER_EVENT and data entries are -* written to a local buffer at first, and when all checks are OK then copied to -* the main event buffer using a fast memcpy. The event code is finalized as the -* very last step. Before that step, the event code indicates an unfinished -* event, which causes it to be ignored and stop the loading of the file (since -* an unfinished event is the last event in the trace). -*******************************************************************************/ - formatStrIndex++; + /******************************************************************************* + * These below code writes raw data (primitive datatypes) in the event buffer, + * instead of the normal event structs (where byte 0 is event type). + * These data entries must never be interpreted as real event data, as the type + * field would be misleading since used for payload data. + * + * The correctness of this encoding depends on two mechanisms: + * + * 1. An initial USER_EVENT, which type code tells the number of 32-bit data + * entires that follows. (code - USER_EVENT = number of data entries). + * Note that a data entry corresponds to the slots that normally corresponds to + * one (1) event, i.e., 32 bits. vTracePrintF may encode several pieces of data + * in one data entry, e.g., two 16-bit values or four 8-bit values, one 16-bit + * value followed by two 8-bit values, etc. + * + * 2. A two-phase commit procedure, where the USER_EVENT and data entries are + * written to a local buffer at first, and when all checks are OK then copied to + * the main event buffer using a fast memcpy. The event code is finalized as the + * very last step. Before that step, the event code indicates an unfinished + * event, which causes it to be ignored and stop the loading of the file (since + * an unfinished event is the last event in the trace). + *******************************************************************************/ + formatStrIndex++; while ((formatStr[formatStrIndex] >= '0' && formatStr[formatStrIndex] <= '9') || formatStr[formatStrIndex] == '#' || formatStr[formatStrIndex] == '.') formatStrIndex++; @@ -793,105 +900,107 @@ static uint8_t prvTraceUserEventFormat(const char* formatStr, va_list vl, uint8_ { switch (formatStr[formatStrIndex]) { - case 'd': i = writeInt32(buffer, + case 'd': i = writeInt32( buffer, i, (uint32_t)va_arg(vl, uint32_t)); break; - case 'x': - case 'X': - case 'u': i = writeInt32(buffer, + case 'x': + case 'X': + case 'u': i = writeInt32( buffer, i, (uint32_t)va_arg(vl, uint32_t)); break; - case 's': i = writeInt16(buffer, + case 's': i = writeInt16( buffer, i, (uint16_t)xTraceOpenLabel((char*)va_arg(vl, char*))); break; #if (INCLUDE_FLOAT_SUPPORT) - /* Yes, "double" as type also in the float - case. This since "float" is promoted into "double" - by the va_arg stuff. */ - case 'f': i = writeFloat(buffer, + /* Yes, "double" as type also in the float + case. This since "float" is promoted into "double" + by the va_arg stuff. */ + case 'f': i = writeFloat( buffer, i, (float)va_arg(vl, double)); break; #else - /* No support for floats, but attempt to store a float user event - avoid a possible crash due to float reference. Instead store the - data on uint_32 format (will not be displayed anyway). This is just - to keep va_arg and i consistent. */ + /* No support for floats, but attempt to store a float user event + avoid a possible crash due to float reference. Instead store the + data on uint_32 format (will not be displayed anyway). This is just + to keep va_arg and i consistent. */ - case 'f': i = writeInt32(buffer, + case 'f': i = writeInt32( buffer, i, (uint32_t)va_arg(vl, double)); break; #endif - case 'l': - formatStrIndex++; - switch (formatStr[formatStrIndex]) - { + case 'l': + formatStrIndex++; + switch (formatStr[formatStrIndex]) + { #if (INCLUDE_FLOAT_SUPPORT) - case 'f': i = writeDouble(buffer, - i, - (double)va_arg(vl, double)); - break; + case 'f': i = writeDouble(buffer, + i, + (double)va_arg(vl, double)); + break; #else - /* No support for floats, but attempt to store a float user event - avoid a possible crash due to float reference. Instead store the - data on uint_32 format (will not be displayed anyway). This is just - to keep va_arg and i consistent. */ - case 'f': i = writeInt32(buffer, /* In this case, the value will not be shown anyway */ - i, - (uint32_t)va_arg(vl, double)); - i = writeInt32(buffer, /* Do it twice, to write in total 8 bytes */ - i, - (uint32_t)va_arg(vl, double)); - break; + /* No support for floats, but attempt to store a float user event + avoid a possible crash due to float reference. Instead store the + data on uint_32 format (will not be displayed anyway). This is just + to keep va_arg and i consistent. */ + case 'f': i = writeInt32( buffer, /* In this case, the value will not be shown anyway */ + i, + (uint32_t)va_arg(vl, double)); + + i = writeInt32( buffer, /* Do it twice, to write in total 8 bytes */ + i, + (uint32_t)va_arg(vl, double)); + break; #endif - } - break; - case 'h': - formatStrIndex++; - switch (formatStr[formatStrIndex]) - { - case 'd': i = writeInt16(buffer, - i, - (uint16_t)va_arg(vl, uint32_t)); - break; - case 'u': i = writeInt16(buffer, - i, - (uint16_t)va_arg(vl, uint32_t)); - break; - } - break; - case 'b': - formatStrIndex++; - switch (formatStr[formatStrIndex]) - { - case 'd': i = writeInt8(buffer, - i, - (uint8_t)va_arg(vl, uint32_t)); - break; - case 'u': i = writeInt8(buffer, - i, - (uint8_t)va_arg(vl, uint32_t)); - break; - } - break; + } + break; + case 'h': + formatStrIndex++; + switch (formatStr[formatStrIndex]) + { + case 'd': i = writeInt16( buffer, + i, + (uint16_t)va_arg(vl, uint32_t)); + break; + case 'u': i = writeInt16( buffer, + i, + (uint16_t)va_arg(vl, uint32_t)); + break; + } + break; + case 'b': + formatStrIndex++; + switch (formatStr[formatStrIndex]) + { + case 'd': i = writeInt8( buffer, + i, + (uint8_t)va_arg(vl, uint32_t)); + break; + + case 'u': i = writeInt8( buffer, + i, + (uint8_t)va_arg(vl, uint32_t)); + break; + } + break; } } else break; - } - formatStrIndex++; - if (i == 255) - { - vTraceError("vTracePrintF - Too large arguments, max 32 byte allowed!"); - return 0; - } - } + } + formatStrIndex++; + if (i == 255) + { + vTraceError("vTracePrintF - Too large arguments, max 32 byte allowed!"); + return 0; + } + } return (i+3)/4; } @@ -906,7 +1015,8 @@ static void prvTraceClearChannelBuffer(uint32_t count) { uint32_t slots; - TRACE_ASSERT(USER_EVENT_BUFFER_SIZE >= count, "prvTraceClearChannelBuffer: USER_EVENT_BUFFER_SIZE is too small to handle this event.", ); + TRACE_ASSERT(USER_EVENT_BUFFER_SIZE >= count, + "prvTraceClearChannelBuffer: USER_EVENT_BUFFER_SIZE is too small to handle this event.", ); /* Check if we're close to the end of the buffer */ if (RecorderDataPtr->userEventBuffer.nextSlotToWrite + count > USER_EVENT_BUFFER_SIZE) @@ -926,8 +1036,10 @@ static void prvTraceClearChannelBuffer(uint32_t count) ******************************************************************************/ static void prvTraceCopyToDataBuffer(uint32_t* data, uint32_t count) { - TRACE_ASSERT(data != NULL, "prvTraceCopyToDataBuffer: data == NULL.", ); - TRACE_ASSERT(count <= USER_EVENT_BUFFER_SIZE, "prvTraceCopyToDataBuffer: USER_EVENT_BUFFER_SIZE is too small to handle this event.", ); + TRACE_ASSERT(data != NULL, + "prvTraceCopyToDataBuffer: data == NULL.", ); + TRACE_ASSERT(count <= USER_EVENT_BUFFER_SIZE, + "prvTraceCopyToDataBuffer: USER_EVENT_BUFFER_SIZE is too small to handle this event.", ); uint32_t slots; /* Check if we're close to the end of the buffer */ @@ -946,7 +1058,8 @@ static void prvTraceCopyToDataBuffer(uint32_t* data, uint32_t count) /******************************************************************************* * prvTraceUserEventHelper1 * - * Calls on prvTraceUserEventFormat() to do the actual formatting, then goes on to the next helper function. + * Calls on prvTraceUserEventFormat() to do the actual formatting, then goes on + * to the next helper function. ******************************************************************************/ static void prvTraceUserEventHelper1(UserEventChannel channel, traceLabel eventLabel, traceLabel formatLabel, va_list vl) { @@ -984,7 +1097,10 @@ static void prvTraceUserEventHelper2(UserEventChannel channel, uint32_t* data, u vTracePortGetTimeStamp(data); if (*data < old_timestamp) + { RecorderDataPtr->userEventBuffer.wraparoundCounter++; + } + old_timestamp = *data; /* Start by erasing any information in the channel buffer */ @@ -997,9 +1113,14 @@ static void prvTraceUserEventHelper2(UserEventChannel channel, uint32_t* data, u /* Write to the channel buffer to indicate that this user event is ready to be used */ if (channel != 0) + { RecorderDataPtr->userEventBuffer.channelBuffer[old_nextSlotToWrite] = channel; + } else - RecorderDataPtr->userEventBuffer.channelBuffer[old_nextSlotToWrite] = (UserEventChannel)0xFF; /* 0xFF indicates that this is not a normal channel id */ + { + /* 0xFF indicates that this is not a normal channel id */ + RecorderDataPtr->userEventBuffer.channelBuffer[old_nextSlotToWrite] = (UserEventChannel)0xFF; + } trcCRITICAL_SECTION_END(); } @@ -1008,7 +1129,7 @@ static void prvTraceUserEventHelper2(UserEventChannel channel, uint32_t* data, u * * Attempts to create a pair of the channel and format string. * - * Note: This is only available if USE_SEPARATE_USER_EVENT_BUFFER is enabled in + * Note: This is only available if USE_SEPARATE_USER_EVENT_BUFFER is enabled in * trcConfig.h ******************************************************************************/ UserEventChannel xTraceRegisterChannelFormat(traceLabel channel, traceLabel formatStr) @@ -1052,11 +1173,13 @@ UserEventChannel xTraceRegisterChannelFormat(traceLabel channel, traceLabel form ******************************************************************************/ void vTraceChannelPrintF(UserEventChannel channelPair, ...) { +#if (TRACE_SCHEDULING_ONLY == 0) va_list vl; va_start(vl, channelPair); vTraceChannelPrintF_Helper(channelPair, vl); va_end(vl); +#endif /* TRACE_SCHEDULING_ONLY */ } void vTraceChannelPrintF_Helper(UserEventChannel channelPair, va_list vl) @@ -1080,16 +1203,18 @@ void vTraceChannelPrintF_Helper(UserEventChannel channelPair, va_list vl) ******************************************************************************/ void vTraceChannelUserEvent(UserEventChannel channelPair) { +#if (TRACE_SCHEDULING_ONLY == 0) uint32_t data[(3 + MAX_ARG_SIZE) / 4]; TRACE_ASSERT(channelPair != 0, "vTraceChannelPrintF: channelPair == 0", ); TRACE_ASSERT(channelPair <= CHANNEL_FORMAT_PAIRS, "vTraceChannelPrintF: ", ); prvTraceUserEventHelper2(channelPair, data, 1); /* Only need one slot for timestamp */ +#endif /* TRACE_SCHEDULING_ONLY */ } #endif /* USE_SEPARATE_USER_EVENT_BUFFER == 1 */ - /****************************************************************************** +/****************************************************************************** * vTracePrintF * * Advanced user events (Professional Edition only) @@ -1102,17 +1227,17 @@ void vTraceChannelUserEvent(UserEventChannel channelPair) * User Event labels are created using xTraceOpenLabel. * Example: * - * traceLabel adc_uechannel = xTraceOpenLabel("ADC User Events"); - * ... - * vTracePrint(adc_uechannel, - * "ADC channel %d: %lf volts", - * ch, (double)adc_reading/(double)scale); + * traceLabel adc_uechannel = xTraceOpenLabel("ADC User Events"); + * ... + * vTracePrint(adc_uechannel, + * "ADC channel %d: %lf volts", + * ch, (double)adc_reading/(double)scale); * * This can be combined into one line, if desired, but this is slower: * - * vTracePrint(xTraceOpenLabel("ADC User Events"), - * "ADC channel %d: %lf volts", - * ch, (double)adc_reading/(double)scale); + * vTracePrint(xTraceOpenLabel("ADC User Events"), + * "ADC channel %d: %lf volts", + * ch, (double)adc_reading/(double)scale); * * Calling xTraceOpenLabel multiple times will not create duplicate entries, but * it is of course faster to just do it once, and then keep the handle for later @@ -1120,77 +1245,84 @@ void vTraceChannelUserEvent(UserEventChannel channelPair) * better to use vTraceUserEvent - it is faster. * * Format specifiers supported: - * %d - 32 bit signed integer - * %u - 32 bit unsigned integer - * %f - 32 bit float - * %s - string (is copied to the recorder symbol table) - * %hd - 16 bit signed integer - * %hu - 16 bit unsigned integer - * %bd - 8 bit signed integer - * %bu - 8 bit unsigned integer - * %lf - double-precision float + * %d - 32 bit signed integer + * %u - 32 bit unsigned integer + * %f - 32 bit float + * %s - string (is copied to the recorder symbol table) + * %hd - 16 bit signed integer + * %hu - 16 bit unsigned integer + * %bd - 8 bit signed integer + * %bu - 8 bit unsigned integer + * %lf - double-precision float (Note! See below...) * * Up to 15 data arguments are allowed, with a total size of maximum 32 byte. * In case this is exceeded, the user event is changed into an error message. * * The data is stored in trace buffer, and is packed to allow storing multiple * smaller data entries in the same 4-byte record, e.g., four 8-bit values. - * A string requires two bytes, as the symbol table is limited to 64K. Storing a - * double (%lf) uses two records, so this is quite costly. Use float (%f) unless - * the higher precision is really necessary. + * A string requires two bytes, as the symbol table is limited to 64K. Storing + * a double (%lf) uses two records, so this is quite costly. Use float (%f) + * unless the higher precision is really necessary. + * + * Note that the double-precision float (%lf) assumes a 64 bit double + * representation. This does not seem to be the case on e.g. PIC24 and PIC32. + * Before using a %lf argument on a 16-bit MCU, please verify that + * "sizeof(double)" actually gives 8 as expected. If not, use %f instead. ******************************************************************************/ void vTracePrintF(traceLabel eventLabel, const char* formatStr, ...) { +#if (TRACE_SCHEDULING_ONLY == 0) va_list vl; va_start(vl, formatStr); vTracePrintF_Helper(eventLabel, formatStr, vl); va_end(vl); +#endif /* TRACE_SCHEDULING_ONLY */ } void vTracePrintF_Helper(traceLabel eventLabel, const char* formatStr, va_list vl) { #if (USE_SEPARATE_USER_EVENT_BUFFER == 0) uint32_t noOfSlots; - UserEvent* ue1; - uint32_t tempDataBuffer[(3 + MAX_ARG_SIZE) / 4]; - TRACE_SR_ALLOC_CRITICAL_SECTION(); - - /************************************************************************** - * The array tempDataBuffer is a local buffer used in a two-phase commit of - * the event data, since a vTracePrintF may span over multiple slots in the - * buffer. - * This buffer can be made larger, of course, but remember the risk for - * stack overflow. Note: This should be a LOCAL buffer, must not be made - * global. That would cause data corruption when two calls to vTracePrintF - * from different tasks overlaps (interrupts are only disabled in a small - * part of this function, otherwise enabled) - ***************************************************************************/ + UserEvent* ue1; + uint32_t tempDataBuffer[(3 + MAX_ARG_SIZE) / 4]; + TRACE_SR_ALLOC_CRITICAL_SECTION(); + + /************************************************************************** + * The array tempDataBuffer is a local buffer used in a two-phase commit of + * the event data, since a vTracePrintF may span over multiple slots in the + * buffer. + * This buffer can be made larger, of course, but remember the risk for + * stack overflow. Note: This should be a LOCAL buffer, must not be made + * global. That would cause data corruption when two calls to vTracePrintF + * from different tasks overlaps (interrupts are only disabled in a small + * part of this function, otherwise enabled) + ***************************************************************************/ TRACE_ASSERT(formatStr != NULL, "vTracePrintF: formatStr == NULL", ); trcCRITICAL_SECTION_BEGIN(); - - if (RecorderDataPtr->recorderActive && (! inExcludedTask || nISRactive) && handle_of_last_logged_task) - { - /* First, write the "primary" user event entry in the local buffer, but - let the event type be "EVENT_BEING_WRITTEN" for now...*/ - ue1 = (UserEvent*)(&tempDataBuffer[0]); - - ue1->type = EVENT_BEING_WRITTEN; /* Update this as the last step */ + if (RecorderDataPtr->recorderActive && (! inExcludedTask || nISRactive) && handle_of_last_logged_task) + { + /* First, write the "primary" user event entry in the local buffer, but + let the event type be "EVENT_BEING_WRITTEN" for now...*/ - noOfSlots = prvTraceUserEventFormat(formatStr, vl, (uint8_t*)tempDataBuffer, 4); + ue1 = (UserEvent*)(&tempDataBuffer[0]); - /* Store the format string, with a reference to the channel symbol */ - ue1->payload = prvTraceOpenSymbol(formatStr, eventLabel); + ue1->type = EVENT_BEING_WRITTEN; /* Update this as the last step */ + + noOfSlots = prvTraceUserEventFormat(formatStr, vl, (uint8_t*)tempDataBuffer, 4); + + /* Store the format string, with a reference to the channel symbol */ + ue1->payload = prvTraceOpenSymbol(formatStr, eventLabel); + + ue1->dts = (uint8_t)prvTraceGetDTS(0xFF); - ue1->dts = (uint8_t)prvTraceGetDTS(0xFF); - /* prvTraceGetDTS might stop the recorder in some cases... */ - if (RecorderDataPtr->recorderActive) - { + if (RecorderDataPtr->recorderActive) + { /* If the data does not fit in the remaining main buffer, wrap around to 0 if allowed, otherwise stop the recorder and quit). */ @@ -1198,21 +1330,21 @@ void vTracePrintF_Helper(traceLabel eventLabel, const char* formatStr, va_list v { #if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER) (void)memset(& RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4], - 0, - (RecorderDataPtr->maxEvents - RecorderDataPtr->nextFreeIndex)*4); + 0, + (RecorderDataPtr->maxEvents - RecorderDataPtr->nextFreeIndex)*4); RecorderDataPtr->nextFreeIndex = 0; RecorderDataPtr->bufferIsFull = 1; #else - + /* Stop recorder, since the event data will not fit in the - buffer and not circular buffer in this case... */ - vTraceStop(); + buffer and not circular buffer in this case... */ + vTraceStop(); #endif } - + /* Check if recorder has been stopped (i.e., vTraceStop above) */ if (RecorderDataPtr->recorderActive) - { + { /* Check that the buffer to be overwritten does not contain any user events that would be partially overwritten. If so, they must be "killed" by replacing the user event and following data with NULL events (i.e., @@ -1222,14 +1354,14 @@ void vTracePrintF_Helper(traceLabel eventLabel, const char* formatStr, va_list v #endif /* Copy the local buffer to the main buffer */ (void)memcpy(& RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4], - tempDataBuffer, - noOfSlots * 4); + tempDataBuffer, + noOfSlots * 4); /* Update the event type, i.e., number of data entries following the main USER_EVENT entry (Note: important that this is after the memcpy, but within the critical section!)*/ RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4] = - (uint8_t) ( USER_EVENT + noOfSlots - 1 ); + (uint8_t) ( USER_EVENT + noOfSlots - 1 ); /* Update the main buffer event index (already checked that it fits in the buffer, so no need to check for wrapping)*/ @@ -1248,21 +1380,13 @@ void vTracePrintF_Helper(traceLabel eventLabel, const char* formatStr, va_list v vTraceStop(); #endif } - - #if (STOP_AFTER_N_EVENTS > -1) - /* Check if we have reached the desired number of events */ - if (RecorderDataPtr->numEvents >= STOP_AFTER_N_EVENTS) - { - vTraceStop(); - } - #endif } - + #if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER) /* Make sure the next entry is cleared correctly */ prvCheckDataToBeOverwrittenForMultiEntryEvents(1); #endif - + } } trcCRITICAL_SECTION_END(); @@ -1273,10 +1397,10 @@ void vTracePrintF_Helper(traceLabel eventLabel, const char* formatStr, va_list v UserEventChannel channel; if (RecorderDataPtr->recorderActive && (! inExcludedTask || nISRactive) && handle_of_last_logged_task) - { - formatLabel = xTraceOpenLabel(formatStr); + { + formatLabel = xTraceOpenLabel(formatStr); - channel = xTraceRegisterChannelFormat(eventLabel, formatLabel); + channel = xTraceRegisterChannelFormat(eventLabel, formatLabel); prvTraceUserEventHelper1(channel, eventLabel, formatLabel, vl); } @@ -1293,36 +1417,33 @@ void vTracePrintF_Helper(traceLabel eventLabel, const char* formatStr, va_list v ******************************************************************************/ void vTraceUserEvent(traceLabel eventLabel) { +#if (TRACE_SCHEDULING_ONLY == 0) #if (USE_SEPARATE_USER_EVENT_BUFFER == 0) - UserEvent* ue; - uint8_t dts1; - TRACE_SR_ALLOC_CRITICAL_SECTION(); + UserEvent* ue; + uint8_t dts1; + TRACE_SR_ALLOC_CRITICAL_SECTION(); TRACE_ASSERT(eventLabel > 0, "vTraceUserEvent: Invalid value for eventLabel", ); - trcCRITICAL_SECTION_BEGIN(); - if (RecorderDataPtr->recorderActive && (! inExcludedTask || nISRactive) && handle_of_last_logged_task) - { - dts1 = (uint8_t)prvTraceGetDTS(0xFF); - - if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ - { - ue = (UserEvent*) xTraceNextFreeEventBufferSlot(); - if (ue != NULL) - { - ue->dts = dts1; - ue->type = USER_EVENT; - ue->payload = eventLabel; - prvTraceUpdateCounters(); - } - } - } + trcCRITICAL_SECTION_BEGIN(); + if (RecorderDataPtr->recorderActive && (! inExcludedTask || nISRactive) && handle_of_last_logged_task) + { + dts1 = (uint8_t)prvTraceGetDTS(0xFF); + ue = (UserEvent*) xTraceNextFreeEventBufferSlot(); + if (ue != NULL) + { + ue->dts = dts1; + ue->type = USER_EVENT; + ue->payload = eventLabel; + prvTraceUpdateCounters(); + } + } trcCRITICAL_SECTION_END(); - + #elif (USE_SEPARATE_USER_EVENT_BUFFER == 1) UserEventChannel channel; uint32_t noOfSlots = 1; - uint32_t tempDataBuffer[(3 + MAX_ARG_SIZE) / 4]; + uint32_t tempDataBuffer[(3 + MAX_ARG_SIZE) / 4]; if (RecorderDataPtr->recorderActive && (! inExcludedTask || nISRactive) && handle_of_last_logged_task) { channel = xTraceRegisterChannelFormat(0, eventLabel); @@ -1336,8 +1457,9 @@ void vTraceUserEvent(traceLabel eventLabel) } prvTraceUserEventHelper2(channel, tempDataBuffer, noOfSlots); - } + } #endif +#endif /* TRACE_SCHEDULING_ONLY */ } /******************************************************************************* @@ -1350,7 +1472,7 @@ void vTraceUserEvent(traceLabel eventLabel) * When logging a user event, a numeric handle (reference) to this string is * used to identify the event. This is obtained by calling * - * xTraceOpenLabel() + * xTraceOpenLabel() * * which adds the string to the symbol table (if not already present) * and returns the corresponding handle. @@ -1360,15 +1482,15 @@ void vTraceUserEvent(traceLabel eventLabel) * 1. The handle is looked up every time, when storing the user event. * * Example: - * vTraceUserEvent(xTraceOpenLabel("MyUserEvent")); + * vTraceUserEvent(xTraceOpenLabel("MyUserEvent")); * * 2. The label is registered just once, with the handle stored in an - * application variable - much like using a file handle. + * application variable - much like using a file handle. * * Example: - * myEventHandle = xTraceOpenLabel("MyUserEvent"); - * ... - * vTraceUserEvent(myEventHandle); + * myEventHandle = xTraceOpenLabel("MyUserEvent"); + * ... + * vTraceUserEvent(myEventHandle); * * The second option is faster since no lookup is required on each event, and * therefore recommended for user events that are frequently @@ -1379,9 +1501,9 @@ traceLabel xTraceOpenLabel(const char* label) { TRACE_ASSERT(label != NULL, "xTraceOpenLabel: label == NULL", (traceLabel)0); - return prvTraceOpenSymbol(label, 0); + return prvTraceOpenSymbol(label, 0); } #endif -#endif \ No newline at end of file +#endif diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/portable/Compiler/GCC/pack_struct_end.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/portable/Compiler/GCC/pack_struct_end.h index 3ae163ea3..2ce162efd 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/portable/Compiler/GCC/pack_struct_end.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/portable/Compiler/GCC/pack_struct_end.h @@ -42,7 +42,7 @@ /***************************************************************************** * - * See the following URL for an exaplanation of this file: + * See the following URL for an explanation of this file: * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_UDP/Embedded_Compiler_Porting.shtml * *****************************************************************************/ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/portable/Compiler/GCC/pack_struct_start.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/portable/Compiler/GCC/pack_struct_start.h index 27dccd4b8..a809ba283 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/portable/Compiler/GCC/pack_struct_start.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/portable/Compiler/GCC/pack_struct_start.h @@ -42,7 +42,7 @@ /***************************************************************************** * - * See the following URL for an exaplanation of this file: + * See the following URL for an explanation of this file: * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_UDP/Embedded_Compiler_Porting.shtml * *****************************************************************************/ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/portable/Compiler/MSVC/pack_struct_end.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/portable/Compiler/MSVC/pack_struct_end.h index 2dc47872b..5cdd99bd2 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/portable/Compiler/MSVC/pack_struct_end.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/portable/Compiler/MSVC/pack_struct_end.h @@ -42,7 +42,7 @@ /***************************************************************************** * - * See the following URL for an exaplanation of this file: + * See the following URL for an explanation of this file: * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_UDP/Embedded_Compiler_Porting.shtml * *****************************************************************************/ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/portable/Compiler/MSVC/pack_struct_start.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/portable/Compiler/MSVC/pack_struct_start.h index 4cf530b81..c11e50cfc 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/portable/Compiler/MSVC/pack_struct_start.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/portable/Compiler/MSVC/pack_struct_start.h @@ -42,7 +42,7 @@ /***************************************************************************** * - * See the following URL for an exaplanation of this file: + * See the following URL for an explanation of this file: * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_UDP/Embedded_Compiler_Porting.shtml * *****************************************************************************/ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/portable/Compiler/Renesas/pack_struct_end.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/portable/Compiler/Renesas/pack_struct_end.h index 5c45ccf14..104f206dd 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/portable/Compiler/Renesas/pack_struct_end.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/portable/Compiler/Renesas/pack_struct_end.h @@ -42,7 +42,7 @@ /***************************************************************************** * - * See the following URL for an exaplanation of this file: + * See the following URL for an explanation of this file: * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_UDP/Embedded_Compiler_Porting.shtml * *****************************************************************************/ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/portable/Compiler/Renesas/pack_struct_start.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/portable/Compiler/Renesas/pack_struct_start.h index fa574dd14..4390c0760 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/portable/Compiler/Renesas/pack_struct_start.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/portable/Compiler/Renesas/pack_struct_start.h @@ -42,7 +42,7 @@ /***************************************************************************** * - * See the following URL for an exaplanation of this file: + * See the following URL for an explanation of this file: * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_UDP/Embedded_Compiler_Porting.shtml * *****************************************************************************/ diff --git a/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/Full_Demo/serial.c b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/Full_Demo/serial.c index 7a78ae763..6603a2937 100644 --- a/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/Full_Demo/serial.c +++ b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/Full_Demo/serial.c @@ -132,7 +132,7 @@ BaseType_t xStatus; XUartPs_Config *pxConfig; /* Create the queue used to hold received characters. NOTE THE COMMENTS AT - THE TOP OF THIS FILE REGARDING THE QUEUE OF QUEUES FOR THIS PURPSOE. */ + THE TOP OF THIS FILE REGARDING THE USE OF QUEUES FOR THIS PURPSOE. */ xRxQueue = xQueueCreate( uxQueueLength, sizeof( char ) ); configASSERT( xRxQueue ); diff --git a/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/lwIP_Demo/lwIP_Apps/apps/BasicSocketCommandServer/BasicSocketCommandServer.c b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/lwIP_Demo/lwIP_Apps/apps/BasicSocketCommandServer/BasicSocketCommandServer.c index c16580670..f77b2fe61 100644 --- a/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/lwIP_Demo/lwIP_Apps/apps/BasicSocketCommandServer/BasicSocketCommandServer.c +++ b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/lwIP_Demo/lwIP_Apps/apps/BasicSocketCommandServer/BasicSocketCommandServer.c @@ -1,6 +1,6 @@ /* FreeRTOS V7.0.2 - Copyright (C) 2011 Real Time Engineers Ltd. - + *************************************************************************** * * @@ -100,7 +100,7 @@ extern void vRegisterSampleCLICommands( void ); sLocalAddr.sin_addr.s_addr = htonl(INADDR_ANY); sLocalAddr.sin_port = ntohs( ( ( unsigned short ) 23 ) ); - if( lwip_bind( lSocket, ( struct sockaddr *) &sLocalAddr, sizeof( sLocalAddr ) ) < 0 ) + if( lwip_bind( lSocket, ( struct sockaddr *) &sLocalAddr, sizeof( sLocalAddr ) ) < 0 ) { lwip_close( lSocket ); vTaskDelete( NULL ); @@ -125,14 +125,14 @@ extern void vRegisterSampleCLICommands( void ); memset( cInputString, 0x00, cmdMAX_INPUT_SIZE ); do - { + { lBytes = lwip_recv( lClientFd, &cInChar, sizeof( cInChar ), 0 ); - if( lBytes > 0L ) + if( lBytes > 0L ) { if( cInChar == '\n' ) { - /* The input string has been terminated. Was the + /* The input string has been terminated. Was the input a quit command? */ if( strcmp( "quit", ( const char * ) cInputString ) == 0 ) { @@ -141,18 +141,18 @@ extern void vRegisterSampleCLICommands( void ); } else { - /* The input string was not a quit command. + /* The input string was not a quit command. Pass the string to the command interpreter. */ do { /* Get the next output string from the command interpreter. */ - xReturned = FreeRTOS_CLIProcessCommand( cInputString, cOutputString, configCOMMAND_INT_MAX_OUTPUT_SIZE ); + xReturned = FreeRTOS_CLIProcessCommand( cInputString, cOutputString, cmdMAX_INPUT_SIZE ); lwip_send( lClientFd, cOutputString, strlen( ( const char * ) cOutputString ), 0 ); } while( xReturned != pdFALSE ); - /* All the strings generated by the input + /* All the strings generated by the input command have been sent. Clear the input string ready to receive the next command. */ lInputIndex = 0; @@ -168,7 +168,7 @@ extern void vRegisterSampleCLICommands( void ); } else if( cInChar == '\b' ) { - /* Backspace was pressed. Erase the last + /* Backspace was pressed. Erase the last character in the string - if any. */ if( lInputIndex > 0 ) { @@ -194,7 +194,7 @@ extern void vRegisterSampleCLICommands( void ); lwip_close( lClientFd ); } - } + } } /* Will only get here if a listening socket could not be created. */ diff --git a/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/main.c b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/main.c index 8b2da0837..108b39ee6 100644 --- a/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/main.c +++ b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/main.c @@ -80,7 +80,7 @@ * point registers. To avoid this causing corruption it is necessary to avoid * their use. For this reason main.c contains very basic C implementations of * the standard C library functions memset(), memcpy() and memcmp(), which are - * are used by FreeRTOS itself. Defining these functions in the project + * are used by FreeRTOS itself. Defining these functions in the project * prevents the linker pulling them in from the library. Any other standard C * library functions that are used by the application must likewise be defined * in C. @@ -145,7 +145,7 @@ static void prvSetupHardware( void ); extern void main_lwIP( void ); #else #error Invalid mainSELECTED_APPLICATION setting. See the comments at the top of this file and above the mainSELECTED_APPLICATION definition. -#endif /* #if mainCREATE_SIMPLE_BLINKY_DEMO_ONLY == 1 */ +#endif /* * The Xilinx projects use a BSP that do not allow the start up code to be diff --git a/FreeRTOS/Demo/Common/Minimal/TaskNotify.c b/FreeRTOS/Demo/Common/Minimal/TaskNotify.c new file mode 100644 index 000000000..b6a5ebf0f --- /dev/null +++ b/FreeRTOS/Demo/Common/Minimal/TaskNotify.c @@ -0,0 +1,505 @@ +/* + FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that has become a de facto standard. * + * * + * Help yourself get started quickly and support the FreeRTOS * + * project by purchasing a FreeRTOS tutorial book, reference * + * manual, or both from: http://www.FreeRTOS.org/Documentation * + * * + * Thank you! * + * * + *************************************************************************** + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available from the following + link: http://www.freertos.org/a00114.html + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + + +/* + * Tests the behaviour of direct task notifications. + */ + +/* Standard includes. */ +#include + +/* Scheduler include files. */ +#include "FreeRTOS.h" +#include "task.h" +#include "timers.h" + +/* Demo program include files. */ +#include "TaskNotify.h" + +#define notifyTASK_PRIORITY ( tskIDLE_PRIORITY ) + +/*-----------------------------------------------------------*/ + +/* + * Implementation of the task that gets notified. + */ +static void prvNotifiedTask( void *pvParameters ); + +/* + * Performs a few initial tests that can be done prior to creating the second + * task. + */ +static void prvSingleTaskTests( void ); + +/* + * Software timer callback function from which xTaskNotify() is called. + */ +static void prvNotifyingTimer( TimerHandle_t xTimer ); + +/* + * Utility function to create pseudo random numbers. + */ +static UBaseType_t prvRand( void ); + +/*-----------------------------------------------------------*/ + +/* Used to latch errors during the test's execution. */ +static BaseType_t xErrorStatus = pdPASS; + +/* Used to ensure the task has not stalled. */ +static volatile uint32_t ulNotifyCycleCount = 0; + +/* The handle of the task that receives the notifications. */ +static TaskHandle_t xTaskToNotify = NULL; + +/* Used to count the notifications sent to the task from a software timer and +the number of notifications received by the task from the software timer. The +two should stay synchronised. */ +static uint32_t ulTimerNotificationsReceived = 0UL, ulTimerNotificationsSent = 0UL; + +/* The timer used to notify the task. */ +static TimerHandle_t xTimer = NULL; + +/*-----------------------------------------------------------*/ + +void vStartTaskNotifyTask( void ) +{ + /* Create the task that performs some tests by itself, then loops around + being notified by both a software timer and an interrupt. */ + xTaskCreate( prvNotifiedTask, "Notified", configMINIMAL_STACK_SIZE, NULL, notifyTASK_PRIORITY, &xTaskToNotify ); +} +/*-----------------------------------------------------------*/ + +static void prvSingleTaskTests( void ) +{ +const TickType_t xTicksToWait = pdMS_TO_TICKS( 100UL ); +BaseType_t xReturned; +uint32_t ulNotifiedValue, ulLoop, ulNotifyingValue; +TickType_t xTimeOnEntering; +const uint32_t ulFirstNotifiedConst = 100001UL, ulSecondNotifiedValueConst = 5555UL, ulMaxLoops = 5UL; +const uint32_t ulBit0 = 0x01UL, ulBit1 = 0x02UL; + + /* ------------------------------------------------------------------------- + Check blocking when there are no notifications. */ + xTimeOnEntering = xTaskGetTickCount(); + xReturned = xTaskNotifyWait( ULONG_MAX, 0, &ulNotifiedValue, xTicksToWait ); + + /* Should have blocked for the entire block time. */ + if( ( xTaskGetTickCount() - xTimeOnEntering ) < xTicksToWait ) + { + xErrorStatus = pdFAIL; + } + configASSERT( xReturned == pdFAIL ); + configASSERT( ulNotifiedValue == 0UL ); + + + + + /* ------------------------------------------------------------------------- + Check no blocking when notifications are pending. First notify itself - + this would not be a normal thing to do and is done here for test purposes + only. */ + xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite ); + + /* Even through the 'without overwrite' action was used the update should + have been successful. */ + configASSERT( xReturned == pdPASS ); + + /* The task should now have a notification pending, and so not time out. */ + xTimeOnEntering = xTaskGetTickCount(); + xReturned = xTaskNotifyWait( ULONG_MAX, 0, &ulNotifiedValue, xTicksToWait ); + + if( ( xTaskGetTickCount() - xTimeOnEntering ) >= xTicksToWait ) + { + xErrorStatus = pdFAIL; + } + + /* The task should have been notified, and the notified value should + be equal to ulFirstNotifiedConst. */ + configASSERT( xReturned == pdPASS ); + configASSERT( ulNotifiedValue == ulFirstNotifiedConst ); + + /* Incremented to show the task is still running. */ + ulNotifyCycleCount++; + + + + + + /*-------------------------------------------------------------------------- + Check the non-overwriting functionality. The notification is done twice + using two different notification values. The action says don't overwrite so + only the first notification should pass and the value read back should also + be that used with the first notification. */ + xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite ); + configASSERT( xReturned == pdPASS ); + + xReturned = xTaskNotify( xTaskToNotify, ulSecondNotifiedValueConst, eSetValueWithoutOverwrite ); + configASSERT( xReturned == pdFAIL ); + + /* Waiting for the notification should now return immediately so a block + time of zero is used. */ + xReturned = xTaskNotifyWait( ULONG_MAX, 0, &ulNotifiedValue, 0 ); + + configASSERT( xReturned == pdPASS ); + configASSERT( ulNotifiedValue == ulFirstNotifiedConst ); + + + + + + /*-------------------------------------------------------------------------- + Do the same again, only this time use the overwriting version. This time + both notifications should pass, and the value written the second time should + overwrite the value written the first time, and so be the value that is read + back. */ + xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithOverwrite ); + configASSERT( xReturned == pdPASS ); + xReturned = xTaskNotify( xTaskToNotify, ulSecondNotifiedValueConst, eSetValueWithOverwrite ); + configASSERT( xReturned == pdPASS ); + xReturned = xTaskNotifyWait( ULONG_MAX, 0, &ulNotifiedValue, 0 ); + configASSERT( xReturned == pdPASS ); + configASSERT( ulNotifiedValue == ulSecondNotifiedValueConst ); + + + + + /*-------------------------------------------------------------------------- + Check notifications with no action pass without updating the value. Even + though ulFirstNotifiedConst is used as the value the value read back should + remain at ulSecondNotifiedConst. */ + xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eNoAction ); + configASSERT( xReturned == pdPASS ); + xReturned = xTaskNotifyWait( ULONG_MAX, 0, &ulNotifiedValue, 0 ); + configASSERT( ulNotifiedValue == ulSecondNotifiedValueConst ); + + + + + /*-------------------------------------------------------------------------- + Check incrementing values. Send ulMaxLoop increment notifications, then + ensure the received value is as expected - which should be + ulSecondNotificationValueConst plus how ever many times to loop iterated. */ + for( ulLoop = 0; ulLoop < ulMaxLoops; ulLoop++ ) + { + xReturned = xTaskNotify( xTaskToNotify, 0, eIncrement ); + configASSERT( xReturned == pdPASS ); + } + + xReturned = xTaskNotifyWait( ULONG_MAX, 0, &ulNotifiedValue, 0 ); + configASSERT( xReturned == pdPASS ); + configASSERT( ulNotifiedValue == ( ulSecondNotifiedValueConst + ulMaxLoops ) ); + + /* Should not be any notifications pending now. */ + xReturned = xTaskNotifyWait( 0, 0, &ulNotifiedValue, 0 ); + configASSERT( xReturned == pdFAIL ); + + + + + /*-------------------------------------------------------------------------- + Check all bits can be set by notifying the task with one additional bit set + on each notification, and exiting the loop when all the bits are found to be + set. As there are 32-bits the loop should execute 32 times before all the + bits are found to be set. */ + ulNotifyingValue = 0x01; + ulLoop = 0; + + /* Start with all bits clear. */ + xTaskNotifyWait( ULONG_MAX, 0, &ulNotifiedValue, 0 ); + + do + { + /* Set the next bit in the task's notified value. */ + xTaskNotify( xTaskToNotify, ulNotifyingValue, eSetBits ); + + /* Wait for the notified value - which of course will already be + available. Don't clear the bits on entry or exit as this loop is exited + when all the bits are set. */ + xReturned = xTaskNotifyWait( 0, 0, &ulNotifiedValue, 0 ); + configASSERT( xReturned == pdPASS ); + + ulLoop++; + + /* Use the next bit on the next iteration around this loop. */ + ulNotifyingValue <<= 1UL; + + } while ( ulNotifiedValue != ULONG_MAX ); + + /* As a 32-bit value was used the loop should have executed 32 times before + all the bits were set. */ + configASSERT( ulLoop == 32 ); + + + + + /*-------------------------------------------------------------------------- + Check bits are cleared on entry but not on exit when a notification fails + to arrive before timing out - both with and without a timeout value. Wait + for the notification again - but this time it is not given by anything and + should return pdFAIL. The parameters are set to clear bit zero on entry and + bit one on exit. As no notification was received only the bit cleared on + entry should actually get cleared. */ + xReturned = xTaskNotifyWait( ulBit0, ulBit1, &ulNotifiedValue, xTicksToWait ); + configASSERT( xReturned == pdFAIL ); + + /* Notify the task with no action so as not to update the bits even though + ULONG_MAX is used as the notification value. */ + xTaskNotify( xTaskToNotify, ULONG_MAX, eNoAction ); + + /* Reading back the value should should find bit 0 is clear, as this was + cleared on entry, but bit 1 is not clear as it will not have been cleared on + exit as no notification was received. */ + xReturned = xTaskNotifyWait( 0x00UL, 0x00UL, &ulNotifiedValue, 0 ); + configASSERT( xReturned == pdPASS ); + configASSERT( ulNotifiedValue == ( ULONG_MAX & ~ulBit0 ) ); + + + + + + /*-------------------------------------------------------------------------- + Now try clearing the bit on exit. For that to happen a notification must be + received, so the task is notified first. */ + xTaskNotify( xTaskToNotify, 0, eNoAction ); + xTaskNotifyWait( 0x00, ulBit1, &ulNotifiedValue, 0 ); + + /* However as the bit is cleared on exit, after the returned notification + value is set, the returned notification value should not have the bit + cleared... */ + configASSERT( ulNotifiedValue == ( ULONG_MAX & ~ulBit0 ) ); + + /* ...but reading the value back again should find that the bit was indeed + cleared internally. The returned value should be pdFAIL however as nothing + has notified the task in the mean time. */ + xReturned = xTaskNotifyWait( 0x00, 0x00, &ulNotifiedValue, 0 ); + configASSERT( xReturned == pdFAIL ); + configASSERT( ulNotifiedValue == ( ULONG_MAX & ~( ulBit0 | ulBit1 ) ) ); + + + + /* Incremented to show the task is still running. */ + ulNotifyCycleCount++; + + /* Leave all bits cleared. */ + xTaskNotifyWait( ULONG_MAX, 0, NULL, 0 ); +} +/*-----------------------------------------------------------*/ + +static void prvNotifyingTimer( TimerHandle_t xTimer ) +{ + ( void ) xTimer; + + xTaskNotifyGive( xTaskToNotify ); + + /* This value is also incremented from an interrupt. */ + taskENTER_CRITICAL(); + { + ulTimerNotificationsSent++; + } + taskEXIT_CRITICAL(); +} +/*-----------------------------------------------------------*/ + +static void prvNotifiedTask( void *pvParameters ) +{ +const TickType_t xMaxPeriod = pdMS_TO_TICKS( 90 ), xMinPeriod = pdMS_TO_TICKS( 10 ), xDontBlock = 0; +TickType_t xPeriod; + + /* Remove compiler warnings about unused parameters. */ + ( void ) pvParameters; + + /* Run a few tests that can be done from a single task before entering the + main loop. */ + prvSingleTaskTests(); + + /* Create the software timer that is used to send notifications to this + task. Notifications are also received from an interrupt. */ + xTimer = xTimerCreate( "Notifier", xMaxPeriod, pdFALSE, NULL, prvNotifyingTimer ); + + for( ;; ) + { + /* Start the timer again with a different period. Sometimes the period + will be higher than the tasks block time, sometimes it will be lower + than the tasks block time. */ + xPeriod = prvRand() % xMaxPeriod; + if( xPeriod < xMinPeriod ) + { + xPeriod = xMinPeriod; + } + + xTimerChangePeriod( xTimer, xPeriod, portMAX_DELAY ); + xTimerStart( xTimer, portMAX_DELAY ); + + /* Block waiting for the notification again with a different period. + Sometimes the period will be higher than the tasks block time, sometimes + it will be lower than the tasks block time. */ + xPeriod = prvRand() % xMaxPeriod; + if( xPeriod < xMinPeriod ) + { + xPeriod = xMinPeriod; + } + + /* Block to wait for a notification but without clearing the + notification count, so only add one to the count of received + notifications as any other notifications will remain pending. */ + if( ulTaskNotifyTake( pdFALSE, xPeriod ) != 0 ) + { + ulTimerNotificationsReceived++; + } + + + /* Take a notification without clearing again, but this time without a + block time specified. */ + if( ulTaskNotifyTake( pdFALSE, xDontBlock ) != 0 ) + { + ulTimerNotificationsReceived++; + } + + /* Wait for the next notification from the timer, clearing all + notifications if one is received, so this time adding the total number + of notifications that were pending as none will be left pending after + the function call. */ + ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, xPeriod ); + + /* Wait for the next notification again, clearing all notifications if + one is received, but this time blocking indefinitely. */ + ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, portMAX_DELAY ); + + /* Incremented to show the task is still running. */ + ulNotifyCycleCount++; + } +} +/*-----------------------------------------------------------*/ + +void xNotifyTaskFromISR( void ) +{ +static BaseType_t xCallCount = 0; +const BaseType_t xCallInterval = pdMS_TO_TICKS( 50 ); + + /* The task performs some tests before starting the timer that gives the + notification from this interrupt. If the timer has not been created yet + then the initial tests have not yet completed and the notification should + not be sent. */ + if( xTimer != NULL ) + { + xCallCount++; + + if( xCallCount >= xCallInterval ) + { + /* It is time to 'give' the notification again. */ + xCallCount = 0; + + xTaskNotifyGiveFromISR( xTaskToNotify, NULL ); + ulTimerNotificationsSent++; + } + } +} +/*-----------------------------------------------------------*/ + +/* This is called to check the created tasks are still running and have not +detected any errors. */ +BaseType_t xAreTaskNotificationTasksStillRunning( void ) +{ +static uint32_t ulLastNotifyCycleCount = 0; +const uint32_t ulMaxSendReceiveDeviation = 5UL; + + /* Check the cycle count is still incrementing to ensure the task is still + actually running. */ + if( ulLastNotifyCycleCount == ulNotifyCycleCount ) + { + xErrorStatus = pdFAIL; + } + else + { + ulLastNotifyCycleCount = ulNotifyCycleCount; + } + + /* Check the count of 'takes' from the software timer is keeping track with + the amount of 'gives'. */ + if( ulTimerNotificationsSent > ulTimerNotificationsSent ) + { + if( ( ulTimerNotificationsSent - ulTimerNotificationsReceived ) > ulMaxSendReceiveDeviation ) + { + xErrorStatus = pdFAIL; + } + } + + return xErrorStatus; +} +/*-----------------------------------------------------------*/ + +static UBaseType_t prvRand( void ) +{ + static uint32_t ulNextRand = ( uint32_t ) prvRand; + + const uint32_t ulMultiplier = 0x015a4e35UL, ulIncrement = 1UL; + + /* Utility function to generate a pseudo random number. */ + ulNextRand = ( ulMultiplier * ulNextRand ) + ulIncrement; + return( ( int ) ( ulNextRand >> 16UL ) & 0x7fffUL ); +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Demo/Common/Minimal/TimerDemo.c b/FreeRTOS/Demo/Common/Minimal/TimerDemo.c index 6aec77927..893928e97 100644 --- a/FreeRTOS/Demo/Common/Minimal/TimerDemo.c +++ b/FreeRTOS/Demo/Common/Minimal/TimerDemo.c @@ -739,11 +739,16 @@ static TickType_t uxTick = ( TickType_t ) -1; will expire when the kernel's tick count is (100 + xBasePeriod). For this reason xMargin is used as an allowable margin for premature timer expiries as well as late timer expiries. */ - const TickType_t xMargin = 6; + #ifdef _WINDOWS_ + /* Windows is not real real time. */ + const TickType_t xMargin = 20; + #else + const TickType_t xMargin = 6; + #endif /* _WINDOWS_ */ #else #ifdef _WINDOWS_ /* Windows is not real real time. */ - const TickType_t xMargin = 10; + const TickType_t xMargin = 20; #else const TickType_t xMargin = 4; #endif /* _WINDOWS_ */ diff --git a/FreeRTOS/Demo/Common/include/TaskNotify.h b/FreeRTOS/Demo/Common/include/TaskNotify.h new file mode 100644 index 000000000..94cd80d3e --- /dev/null +++ b/FreeRTOS/Demo/Common/include/TaskNotify.h @@ -0,0 +1,76 @@ +/* + FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that has become a de facto standard. * + * * + * Help yourself get started quickly and support the FreeRTOS * + * project by purchasing a FreeRTOS tutorial book, reference * + * manual, or both from: http://www.FreeRTOS.org/Documentation * + * * + * Thank you! * + * * + *************************************************************************** + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available from the following + link: http://www.freertos.org/a00114.html + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef TASK_NOTIFY_H +#define TASK_NOTIFY_H + +void vStartTaskNotifyTask( void ); +BaseType_t xAreTaskNotificationTasksStillRunning( void ); +void xNotifyTaskFromISR( void ); + +#endif /* TASK_NOTIFY_H */ + + + diff --git a/FreeRTOS/Demo/RX600_RX630-RSK_Renesas/RTOSDemo/Renesas-Files/cgc_set.h b/FreeRTOS/Demo/RX600_RX630-RSK_Renesas/RTOSDemo/Renesas-Files/cgc_set.h index b155b1149..f05b93366 100644 --- a/FreeRTOS/Demo/RX600_RX630-RSK_Renesas/RTOSDemo/Renesas-Files/cgc_set.h +++ b/FreeRTOS/Demo/RX600_RX630-RSK_Renesas/RTOSDemo/Renesas-Files/cgc_set.h @@ -1,7 +1,7 @@ #ifndef CGC_SET_VALUES_H_ #define CGC_SET_VALUES_H_ -/* Do not modify these macros. These values are used to initialise +/* Do not modify these macros. These values are used to initialise the SCKCR and SCKCR2 registers based upon the above values. */ #if (FCLK_DIV == 64) #define FCLK_SCKCR 0x60000000L @@ -40,12 +40,12 @@ #define ICLK_SCKCR 0x01000000L #endif - + #if (BCLK_PIN == 1) #define PSTOP1_SCKCR 0x00800000L -#elif +#else #define PSTOP1_SCKCR 0x00000000L -#endif +#endif #if (BCLK_DIV == 64) @@ -120,7 +120,7 @@ #elif (PCLK47_DIV == 1) #define PCLK47_SCKCR 0x00000000L #else - #define PCLK47_SCKCR 0x00000010L + #define PCLK47_SCKCR 0x00000010L #endif @@ -139,7 +139,7 @@ #elif (PCLK03_DIV == 1) #define PCLK03_SCKCR 0x00000000L #else - #define PCLK03_SCKCR 0x00000001L + #define PCLK03_SCKCR 0x00000001L #endif @@ -173,7 +173,7 @@ #if (CLK_SOURCE == CLK_SOURCE_LOCO) /* Internal LOCO circuit - 125kHz*/ -#define CLK_FREQUENCY (125000L) +#define CLK_FREQUENCY (125000L) #define FCLK_FREQUENCY (CLK_FREQUENCY / FCLK_DIV) #define ICLK_FREQUENCY (CLK_FREQUENCY / ICLK_DIV) #define BCLK_FREQUENCY (CLK_FREQUENCY / BCLK_DIV) @@ -185,7 +185,7 @@ #elif (CLK_SOURCE == CLK_SOURCE_HOCO) /* Internal high speed on-chip oscillator (HOCO) */ -#define CLK_FREQUENCY (50000000L) +#define CLK_FREQUENCY (50000000L) #define FCLK_FREQUENCY (CLK_FREQUENCY / FCLK_DIV) #define ICLK_FREQUENCY (CLK_FREQUENCY / ICLK_DIV) #define BCLK_FREQUENCY (CLK_FREQUENCY / BCLK_DIV) @@ -196,7 +196,7 @@ #elif (CLK_SOURCE == CLK_SOURCE_MAIN) -/* External XTAL, but not via the PLL circuit */ +/* External XTAL, but not via the PLL circuit */ #define FCLK_FREQUENCY (XTAL_FREQUENCY / FCLK_DIV) #define ICLK_FREQUENCY (XTAL_FREQUENCY / ICLK_DIV) #define BCLK_FREQUENCY (XTAL_FREQUENCY / BCLK_DIV) @@ -207,7 +207,7 @@ #elif (CLK_SOURCE == CLK_SOURCE_SUB) -/* External 32khZ XTAL */ +/* External 32khZ XTAL */ #define FCLK_FREQUENCY (SUB_FREQUENCY / FCLK_DIV) #define ICLK_FREQUENCY (SUB_FREQUENCY / ICLK_DIV) #define BCLK_FREQUENCY (SUB_FREQUENCY / BCLK_DIV) @@ -219,7 +219,7 @@ #elif (CLK_SOURCE == CLK_SOURCE_PLL) /* External XTAL, but using the PLL circuit */ -#define PLL_FREQUENCY (XTAL_FREQUENCY * (PLL_MUL / PLL_INPUT_FREQ_DIV)) +#define PLL_FREQUENCY (XTAL_FREQUENCY * (PLL_MUL / PLL_INPUT_FREQ_DIV)) #define FCLK_FREQUENCY (PLL_FREQUENCY / FCLK_DIV) #define ICLK_FREQUENCY (PLL_FREQUENCY / ICLK_DIV) #define BCLK_FREQUENCY (PLL_FREQUENCY / BCLK_DIV) diff --git a/FreeRTOS/Demo/RX600_RX64M_RSK_GCC_e2studio/src/main.c b/FreeRTOS/Demo/RX600_RX64M_RSK_GCC_e2studio/src/main.c index 1092a31d5..f1424d544 100644 --- a/FreeRTOS/Demo/RX600_RX64M_RSK_GCC_e2studio/src/main.c +++ b/FreeRTOS/Demo/RX600_RX64M_RSK_GCC_e2studio/src/main.c @@ -96,8 +96,8 @@ #include "rskrx64mdef.h" /* Set option bytes */ -#pragma address OFS0_location = 0xFFFFFF8CUL -#pragma address OFS1_location = 0xFFFFFF88UL +#pragma address OFS0_location 0xFFFFFF8CUL +#pragma address OFS1_location 0xFFFFFF88UL volatile const uint32_t OFS0_location = 0xFFFFFFFFUL; volatile const uint32_t OFS1_location = 0xFFFFFFFFUL; diff --git a/FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h b/FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h index 2f8243118..e4f6ce87b 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h +++ b/FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h @@ -83,7 +83,7 @@ #define configUSE_TICK_HOOK 1 #define configTICK_RATE_HZ ( 1000 ) /* In this non-real time simulated environment the tick frequency has to be at least a multiple of the Win32 tick frequency, and therefore very slow. */ #define configMINIMAL_STACK_SIZE ( ( unsigned short ) 50 ) /* In this simulated case, the stack only has to hold one small structure as the real stack is part of the win32 thread. */ -#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 22 * 1024 ) ) +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 23 * 1024 ) ) #define configMAX_TASK_NAME_LEN ( 12 ) #define configUSE_TRACE_FACILITY 1 #define configUSE_16_BIT_TICKS 0 @@ -97,6 +97,7 @@ #define configUSE_COUNTING_SEMAPHORES 1 #define configUSE_ALTERNATIVE_API 1 #define configUSE_QUEUE_SETS 1 +#define configUSE_TASK_NOTIFICATIONS 1 /* Software timer related configuration options. */ #define configUSE_TIMERS 1 @@ -104,18 +105,18 @@ #define configTIMER_QUEUE_LENGTH 20 #define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 ) -#define configMAX_PRIORITIES ( 7 ) +#define configMAX_PRIORITIES ( 7 ) /* Run time stats gathering configuration options. */ unsigned long ulGetRunTimeCounterValue( void ); /* Prototype of function that returns run time counter. */ void vConfigureTimerForRunTimeStats( void ); /* Prototype of function that initialises the run time counter. */ -#define configGENERATE_RUN_TIME_STATS 1 +#define configGENERATE_RUN_TIME_STATS 1 #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() vConfigureTimerForRunTimeStats() #define portGET_RUN_TIME_COUNTER_VALUE() ulGetRunTimeCounterValue() /* Co-routine related configuration options. */ -#define configUSE_CO_ROUTINES 1 -#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) +#define configUSE_CO_ROUTINES 1 +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) /* This demo makes use of one or more example stats formatting functions. These format the raw data provided by the uxTaskGetSystemState() function in to human @@ -148,6 +149,8 @@ extern void vAssertCalled( unsigned long ulLine, const char * const pcFileName ) #define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __LINE__, __FILE__ ) /* Include the FreeRTOS+Trace FreeRTOS trace macro definitions. */ +#define TRACE_ENTER_CRITICAL_SECTION() portENTER_CRITICAL() +#define TRACE_EXIT_CRITICAL_SECTION() portEXIT_CRITICAL() #include "trcKernelPort.h" #endif /* FREERTOS_CONFIG_H */ diff --git a/FreeRTOS/Demo/WIN32-MSVC/Trace_Recorder_Configuration/trcConfig.h b/FreeRTOS/Demo/WIN32-MSVC/Trace_Recorder_Configuration/trcConfig.h index 289384a28..7039112bf 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/Trace_Recorder_Configuration/trcConfig.h +++ b/FreeRTOS/Demo/WIN32-MSVC/Trace_Recorder_Configuration/trcConfig.h @@ -1,14 +1,14 @@ /******************************************************************************* - * Tracealyzer v2.6.0 Recorder Library + * Tracealyzer v2.7.0 Recorder Library * Percepio AB, www.percepio.com * * trcConfig.h * - * Configuration parameters for the trace recorder library. Before using the - * trace recorder library, please check that the default settings are - * appropriate for your system, and if necessary adjust these. Most likely, you - * will need to adjust the NTask, NISR, NQueue, NMutex and NSemaphore values to - * reflect the number of such objects in your system. These may be + * Configuration parameters for the trace recorder library. Before using the + * trace recorder library, please check that the default settings are + * appropriate for your system, and if necessary adjust these. Most likely, you + * will need to adjust the NTask, NISR, NQueue, NMutex and NSemaphore values to + * reflect the number of such objects in your system. These may be * over-approximated, although larger values values implies more RAM usage. * * Terms of Use @@ -16,515 +16,460 @@ * use together with Percepio products. You may distribute the recorder library * in its original form, including modifications in trcHardwarePort.c/.h * given that these modification are clearly marked as your own modifications - * and documented in the initial comment section of these source files. - * This software is the intellectual property of Percepio AB and may not be - * sold or in other ways commercially redistributed without explicit written + * and documented in the initial comment section of these source files. + * This software is the intellectual property of Percepio AB and may not be + * sold or in other ways commercially redistributed without explicit written * permission by Percepio AB. * - * Disclaimer - * The trace tool and recorder library is being delivered to you AS IS and - * Percepio AB makes no warranty as to its use or performance. Percepio AB does - * not and cannot warrant the performance or results you may obtain by using the - * software or documentation. Percepio AB make no warranties, express or - * implied, as to noninfringement of third party rights, merchantability, or - * fitness for any particular purpose. In no event will Percepio AB, its - * technology partners, or distributors be liable to you for any consequential, - * incidental or special damages, including any lost profits or lost savings, - * even if a representative of Percepio AB has been advised of the possibility - * of such damages, or for any claim by any third party. Some jurisdictions do - * not allow the exclusion or limitation of incidental, consequential or special - * damages, or the exclusion of implied warranties or limitations on how long an + * Disclaimer + * The trace tool and recorder library is being delivered to you AS IS and + * Percepio AB makes no warranty as to its use or performance. Percepio AB does + * not and cannot warrant the performance or results you may obtain by using the + * software or documentation. Percepio AB make no warranties, express or + * implied, as to noninfringement of third party rights, merchantability, or + * fitness for any particular purpose. In no event will Percepio AB, its + * technology partners, or distributors be liable to you for any consequential, + * incidental or special damages, including any lost profits or lost savings, + * even if a representative of Percepio AB has been advised of the possibility + * of such damages, or for any claim by any third party. Some jurisdictions do + * not allow the exclusion or limitation of incidental, consequential or special + * damages, or the exclusion of implied warranties or limitations on how long an * implied warranty may last, so the above limitations may not apply to you. * - * Copyright Percepio AB, 2013. + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2014. * www.percepio.com ******************************************************************************/ #ifndef TRCCONFIG_H #define TRCCONFIG_H -/******************************************************************************* - * CONFIGURATION RELATED TO CAPACITY AND ALLOCATION - ******************************************************************************/ - -/******************************************************************************* - * EVENT_BUFFER_SIZE - * - * Macro which should be defined as an integer value. - * - * This defines the capacity of the event buffer, i.e., the number of records - * it may store. Each registered event typically use one record (4 byte), but - * vTracePrintF may use multiple records depending on the number of data args. - ******************************************************************************/ +/****************************************************************************** + * SELECTED_PORT + * + * Macro that specifies what hardware port that should be used. + * Available ports are: + * + * Port Name Code Official OS supported + * PORT_APPLICATION_DEFINED -2 - - + * PORT_NOT_SET -1 - - + * PORT_HWIndependent 0 Yes Any + * PORT_Win32 1 Yes FreeRTOS on Win32 + * PORT_Atmel_AT91SAM7 2 No Any + * PORT_Atmel_UC3A0 3 No Any + * PORT_ARM_CortexM 4 Yes Any + * PORT_Renesas_RX600 5 Yes Any + * PORT_Microchip_dsPIC_AND_PIC24 6 Yes Any + * PORT_TEXAS_INSTRUMENTS_TMS570 7 No Any + * PORT_TEXAS_INSTRUMENTS_MSP430 8 No Any + * PORT_MICROCHIP_PIC32MX 9 Yes Any + * PORT_XILINX_PPC405 10 No FreeRTOS + * PORT_XILINX_PPC440 11 No FreeRTOS + * PORT_XILINX_MICROBLAZE 12 No Any + * PORT_NXP_LPC210X 13 No Any + * PORT_MICROCHIP_PIC32MZ 14 Yes Any + * PORT_ARM_CORTEX_A9 15 No Any + *****************************************************************************/ -#define EVENT_BUFFER_SIZE 10000 /* Adjust wrt. to available RAM */ +#ifndef WIN32 + // Set the port setting here! + #define SELECTED_PORT PORT_NOT_SET + #if (SELECTED_PORT == PORT_NOT_SET) + #error "You need to define SELECTED_PORT here!" + #endif +#else + // For Win32 demo projects this is set automatically + #define SELECTED_PORT PORT_Win32 +#endif -/******************************************************************************* - * USE_LINKER_PRAGMA - * - * Macro which should be defined as an integer value, default is 0. +/****************************************************************************** + * FREERTOS_VERSION * - * If this is 1, the header file "recorderdata_linker_pragma.h" is included just - * before the declaration of RecorderData (in trcBase.c), i.e., the trace data - * structure. This allows the user to specify a pragma with linker options. + * Specify what version of FreeRTOS that is used. This is necessary compensate + * for renamed symbols in the FreeRTOS kernel (does not build if incorrect). * - * Example (for IAR Embedded Workbench and NXP LPC17xx): - * #pragma location="AHB_RAM_MEMORY" - * - * This example instructs the IAR linker to place RecorderData in another RAM - * bank, the AHB RAM. This can also be used for other compilers with a similar - * pragmas for linker options. - * - * Note that this only applies if using static allocation, see below. - ******************************************************************************/ - -#define USE_LINKER_PRAGMA 0 - + * FREERTOS_VERSION_7_3_OR_7_4 (= 1) If using FreeRTOS v7.3.0 - v7.4.2 + * FREERTOS_VERSION_7_5_OR_7_6 (= 2) If using FreeRTOS v7.5.0 - v7.6.0 + * FREERTOS_VERSION_8_0_OR_LATER (= 3) If using FreeRTOS v8.0.0 or later + *****************************************************************************/ +#define FREERTOS_VERSION FREERTOS_VERSION_8_0_OR_LATER -/******************************************************************************* - * SYMBOL_TABLE_SIZE +/****************************************************************************** + * TRACE_RECORDER_STORE_MODE * - * Macro which should be defined as an integer value. + * Macro which should be defined as one of: + * - TRACE_STORE_MODE_RING_BUFFER + * - TRACE_STORE_MODE_STOP_WHEN_FULL + * Default is TRACE_STORE_MODE_RING_BUFFER. * - * This defines the capacity of the symbol table, in bytes. This symbol table - * stores User Events labels and names of deleted tasks, queues, or other kernel - * objects. Note that the names of active objects not stored here but in the - * Object Table. Thus, if you don't use User Events or delete any kernel - * objects you set this to a very low value, e.g. 4, but not zero (0) since - * this causes a declaration of a zero-sized array, for which the C compiler - * behavior is not standardized and may cause misaligned data. - ******************************************************************************/ -#define SYMBOL_TABLE_SIZE 5000 - -#if (SYMBOL_TABLE_SIZE == 0) -#error "SYMBOL_TABLE_SIZE may not be zero!" -#endif + * With TRACE_RECORDER_STORE_MODE set to TRACE_STORE_MODE_RING_BUFFER, the + * events are stored in a ring buffer, i.e., where the oldest events are + * overwritten when the buffer becomes full. This allows you to get the last + * events leading up to an interesting state, e.g., an error, without having + * to store the whole run since startup. + * + * When TRACE_RECORDER_STORE_MODE is TRACE_STORE_MODE_STOP_WHEN_FULL, the + * recording is stopped when the buffer becomes full. This is useful for + * recording events following a specific state, e.g., the startup sequence. + *****************************************************************************/ +#define TRACE_RECORDER_STORE_MODE TRACE_STORE_MODE_RING_BUFFER /******************************************************************************* - * USE_SEPARATE_USER_EVENT_BUFFER + * TRACE_SCHEDULING_ONLY * * Macro which should be defined as an integer value. - * Default is zero (0). * - * This enables and disables the use of the separate user event buffer. + * If this setting is enabled (= 1), only scheduling events are recorded. + * If disabled (= 0), all events are recorded. * - * Note: When using the separate user event buffer, you may get an artificial - * task instance named "Unknown actor". This is added as a placeholder when the - * user event history is longer than the task scheduling history. - ******************************************************************************/ -#define USE_SEPARATE_USER_EVENT_BUFFER 0 - -/******************************************************************************* - * USER_EVENT_BUFFER_SIZE + * Users of FreeRTOS+Trace Free Edition only displays scheduling events, so this + * option can be used to avoid storing unsupported events. * - * Macro which should be defined as an integer value. + * Default value is 0 (store all enabled events). * - * This defines the capacity of the user event buffer, in number of slots. - * A single user event can use between 1 and X slots, depending on the data. - * - * Only in use if USE_SEPARATE_USER_EVENT_BUFFER is set to 1. ******************************************************************************/ -#define USER_EVENT_BUFFER_SIZE 500 +#define TRACE_SCHEDULING_ONLY 0 /******************************************************************************* - * USER_EVENT_CHANNELS + * EVENT_BUFFER_SIZE * * Macro which should be defined as an integer value. * - * This defines the number of allowed user event channels. + * This defines the capacity of the event buffer, i.e., the number of records + * it may store. Most events use one record (4 byte), although some events + * require multiple 4-byte records. You should adjust this to the amount of RAM + * available in the target system. * - * Only in use if USE_SEPARATE_USER_EVENT_BUFFER is set to 1. + * Default value is 1000, which means that 4000 bytes is allocated for the + * event buffer. ******************************************************************************/ -#define CHANNEL_FORMAT_PAIRS 32 +#define EVENT_BUFFER_SIZE 15000 /******************************************************************************* * NTask, NISR, NQueue, NSemaphore, NMutex * - * A group of Macros which should be defined as an integer value of zero (0) - * or larger. + * A group of macros which should be defined as integer values, zero or larger. * - * This defines the capacity of the Object Property Table - the maximum number - * of objects active at any given point within each object class. - * - * NOTE: In case objects are deleted and created during runtime, this setting - * does not limit the total amount of objects, only the number of concurrently - * active objects. + * These define the capacity of the Object Property Table, i.e., the maximum + * number of objects active at any given point, within each object class (e.g., + * task, queue, semaphore, ...). * - * Using too small values will give an error message through the vTraceError - * routine, which makes the error message appear when opening the trace data - * in Tracealyzer. If you are using the recorder status monitor task, - * any error messages are displayed in console prints, assuming that the - * print macro has been defined properly (vConsolePrintMessage). + * If tasks or other other objects are deleted in your system, this + * setting does not limit the total amount of objects created, only the number + * of objects that have been successfully created but not yet deleted. * - * It can be wise to start with very large values for these constants, - * unless you are very confident on these numbers. Then do a recording and - * check the actual usage in Tracealyzer. This is shown by selecting - * View -> Trace Details -> Resource Usage -> Object Table - * - * NOTE 2: Remember to account for all tasks and other objects created by - * the kernel, such as the IDLE task, any timer tasks, and any tasks created - * by other 3rd party software components, such as communication stacks. - * Moreover, one task slot is used to indicate "(startup)", i.e., a fictive - * task that represent the time before the scheduler starts. - * NTask should thus be at least 2-3 slots larger than your application task count. + * Using too small values will cause vTraceError to be called, which stores an + * error message in the trace that is shown when opening the trace file. * + * It can be wise to start with large values for these constants, + * unless you are very confident on these numbers. Then do a recording and + * check the actual usage by selecting View menu -> Trace Details -> + * Resource Usage -> Object Table. ******************************************************************************/ -#define NTask 100 -#define NISR 20 -#define NQueue 60 -#define NSemaphore 60 -#define NMutex 60 -#define NTimer 200 -#define NEventGroup 60 - -/* Maximum object name length for each class (includes zero termination) */ -#define NameLenTask 15 -#define NameLenISR 15 -#define NameLenQueue 15 -#define NameLenSemaphore 15 -#define NameLenMutex 15 -#define NameLenTimer 15 -#define NameLenEventGroup 15 +#define NTask 100 +#define NISR 60 +#define NQueue 60 +#define NSemaphore 60 +#define NMutex 60 +#define NTimer 200 +#define NEventGroup 60 /****************************************************************************** - * TRACE_DESCRIPTION + * INCLUDE_MEMMANG_EVENTS * - * Macro which should be defined as a string. + * Macro which should be defined as either zero (0) or one (1). * - * This string is stored in the trace and displayed in Tracealyzer. Can be - * used to store, e.g., system version or build date. This is also used to store - * internal error messages from the recorder, which if occurs overwrites the - * value defined here. This may be maximum 256 chars. - *****************************************************************************/ -#define TRACE_DESCRIPTION "Tracealyzer Recorder Test Program" - -/****************************************************************************** - * TRACE_DESCRIPTION_MAX_LENGTH + * This controls if malloc and free calls should be traced. Set this to zero to + * exclude malloc/free calls, or one (1) to include such events in the trace. * - * The maximum length (including zero termination) for the TRACE_DESCRIPTION - * string. Since this string also is used for internal error messages from the - * recorder do not make it too short, as this may truncate the error messages. - * Default is 80. - * Maximum allowed length is 256 - the trace will fail to load if longer. + * Default value is 1. *****************************************************************************/ -#define TRACE_DESCRIPTION_MAX_LENGTH 80 - +#define INCLUDE_MEMMANG_EVENTS 1 /****************************************************************************** - * TRACE_DATA_ALLOCATION - * - * This defines how to allocate the recorder data structure, i.e., using a - * static declaration or using a dynamic allocation in runtime (malloc). - * - * Should be one of these two options: - * - TRACE_DATA_ALLOCATION_STATIC (default) - * - TRACE_DATA_ALLOCATION_DYNAMIC + * INCLUDE_USER_EVENTS * - * Using static allocation has the benefits of compile-time errors if the buffer - * is too large (too large constants in trcConfig.h) and no need to call the - * initialization routine (xTraceInitTraceData). + * Macro which should be defined as either zero (0) or one (1). * - * Using dynamic allocation may give more flexibility in some cases. - *****************************************************************************/ - -#define TRACE_DATA_ALLOCATION TRACE_DATA_ALLOCATION_STATIC - - -/****************************************************************************** - * CONFIGURATION REGARDING WHAT CODE/FEATURES TO INCLUDE - *****************************************************************************/ - -/****************************************************************************** - * USE_TRACE_ASSERT + * If this is zero (0) the code for creating User Events is excluded to + * reduce code size. User Events are application-generated events, like + * "printf" but for the trace log instead of console output. User Events are + * much faster than a printf and can therefore be used in timing critical code. + * See vTraceUserEvent() and vTracePrintF() in trcUser.h * - * Macro which should be defined as either zero (0) or one (1). - * Default is 0. + * Default value is 1. * - * If this is one (1), the TRACE_ASSERT macro will verify that a condition is - * true. If the condition is false, vTraceError() will be called. + * Note that User Events are only displayed in Professional Edition. *****************************************************************************/ -#define USE_TRACE_ASSERT 1 +#define INCLUDE_USER_EVENTS 1 -/****************************************************************************** - * INCLUDE_FLOAT_SUPPORT - * - * Macro which should be defined as either zero (0) or one (1). - * Default is 1. +/***************************************************************************** + * INCLUDE_ISR_TRACING * - * If this is zero (0), all references to floating point values are removed, - * in case floating point values are not supported by the platform used. - * Floating point values are only used in vTracePrintF and its subroutines, to - * store float (%f) or double (%lf) argments. + * Macro which should be defined as either zero (0) or one (1). * - * Note: vTracePrintF can still be used with integer and string arguments in - * either case. - *****************************************************************************/ -#define INCLUDE_FLOAT_SUPPORT 0 - -/****************************************************************************** - * INCLUDE_USER_EVENTS + * If this is zero (0), the code for recording Interrupt Service Routines is + * excluded to reduce code size. * - * Macro which should be defined as either zero (0) or one (1). - * Default is 1. + * Default value is 1. * - * If this is zero (0) the code for creating User Events is excluded to - * reduce code size. User Events are application-generated events, like - * "printf" but for the trace log instead of console output. User Events are - * much faster than a printf and can therefore be used in timing critical code. - * See vTraceUserEvent() and vTracePrintF() in trcUser.h - * - * Note that User Events are not displayed in FreeRTOS+Trace Free Edition. + * Note, if the kernel has no central interrupt dispatcher, recording ISRs + * require that you insert calls to vTraceStoreISRBegin and vTraceStoreISREnd + * in your interrupt handlers. *****************************************************************************/ -#define INCLUDE_USER_EVENTS 1 +#define INCLUDE_ISR_TRACING 1 /***************************************************************************** * INCLUDE_READY_EVENTS * - * Macro which should be defined as either zero (0) or one (1). - * Default is 1. + * Macro which should be defined as either zero (0) or one (1). * - * If this is zero (0), the code for recording Ready events is - * excluded. Note, this will make it impossible to calculate the correct - * response times. + * If one (1), events are recorded when tasks enter scheduling state "ready". + * This uses a lot of space in the event buffer, so excluding "ready events" + * will allow for longer traces. Including ready events however allows for + * showing the initial pending time before tasks enter the execution state, and + * for presenting accurate response times. + * + * Default value is 1. *****************************************************************************/ #define INCLUDE_READY_EVENTS 1 /***************************************************************************** * INCLUDE_NEW_TIME_EVENTS * - * Macro which should be defined as either zero (0) or one (1). - * Default is 0. + * Macro which should be defined as either zero (0) or one (1). * - * If this is zero (1), events will be generated whenever the os clock is + * If this is zero (1), events will be generated whenever the OS clock is * increased. + * + * Default value is 0. *****************************************************************************/ -#define INCLUDE_NEW_TIME_EVENTS 0 +#define INCLUDE_NEW_TIME_EVENTS 1 -/***************************************************************************** - * INCLUDE_ISR_TRACING +/****************************************************************************** + * INCLUDE_FLOAT_SUPPORT * - * Macro which should be defined as either zero (0) or one (1). - * Default is 1. + * Macro which should be defined as either zero (0) or one (1). * - * If this is zero (0), the code for recording Interrupt Service Routines is - * excluded to reduce code size. - * - * Note, if the kernel has no central interrupt dispatcher, recording ISRs - * require that you insert calls to vTraceStoreISRBegin and vTraceStoreISREnd - * in your interrupt handlers. + * If this is zero (0), all references to floating point values are removed, + * in case floating point values are not supported by the platform used. + * Floating point values are only used in vTracePrintF and its subroutines, to + * store float (%f) or double (%lf) arguments. + * + * vTracePrintF can be used with integer and string arguments in either case. + * + * Default value is 1. *****************************************************************************/ -#define INCLUDE_ISR_TRACING 1 +#define INCLUDE_FLOAT_SUPPORT 0 /****************************************************************************** * INCLUDE_OBJECT_DELETE - * - * Macro which should be defined as either zero (0) or one (1). - * Default is 1. * - * This must be enabled (1) if tasks, queues or other - * traced kernel objects are deleted at runtime. If no deletes are made, this + * Macro which should be defined as either zero (0) or one (1). + * + * This must be enabled (1) if tasks, queues or other + * traced kernel objects are deleted at runtime. If no deletes are made, this * can be set to 0 in order to exclude the delete-handling code. + * + * Default value is 1. *****************************************************************************/ #define INCLUDE_OBJECT_DELETE 1 -/****************************************************************************** - * INCLUDE_MEMMANG_EVENTS - * - * Macro which should be defined as either zero (0) or one (1). - * Default is 1. +/******************************************************************************* + * SYMBOL_TABLE_SIZE * - * This controls if malloc and free calls should be traced. Set this to zero to - * exclude malloc/free calls from the tracing. - *****************************************************************************/ -#define INCLUDE_MEMMANG_EVENTS 1 + * Macro which should be defined as an integer value. + * + * This defines the capacity of the symbol table, in bytes. This symbol table + * stores User Events labels and names of deleted tasks, queues, or other kernel + * objects. If you don't use User Events or delete any kernel + * objects you set this to a very low value. The minimum recommended value is 4. + * A size of zero (0) is not allowed since a zero-sized array may result in a + * 32-bit pointer, i.e., using 4 bytes rather than 0. + * + * Default value is 800. + ******************************************************************************/ +#define SYMBOL_TABLE_SIZE 5000 + +#if (SYMBOL_TABLE_SIZE == 0) +#error "SYMBOL_TABLE_SIZE may not be zero!" +#endif /****************************************************************************** - * CONFIGURATION RELATED TO BEHAVIOR + * NameLenTask, NameLenQueue, ... + * + * Macros that specify the maximum lengths (number of characters) for names of + * kernel objects, such as tasks and queues. If longer names are used, they will + * be truncated when stored in the recorder. *****************************************************************************/ +#define NameLenTask 15 +#define NameLenISR 15 +#define NameLenQueue 15 +#define NameLenSemaphore 15 +#define NameLenMutex 15 +#define NameLenTimer 15 +#define NameLenEventGroup 15 /****************************************************************************** - * TRACE_RECORDER_STORE_MODE + * TRACE_DATA_ALLOCATION * - * Macro which should be defined as one of: - * - TRACE_STORE_MODE_RING_BUFFER - * - TRACE_STORE_MODE_STOP_WHEN_FULL - * Default is TRACE_STORE_MODE_RING_BUFFER. + * This defines how to allocate the recorder data structure, i.e., using a + * static declaration or using a dynamic allocation in runtime (malloc). + * + * Should be one of these two options: + * - TRACE_DATA_ALLOCATION_STATIC (default) + * - TRACE_DATA_ALLOCATION_DYNAMIC + * + * Using static allocation has the benefits of compile-time errors if the buffer + * is too large (too large constants in trcConfig.h) and no need to call the + * initialization routine (xTraceInitTraceData). * - * With TRACE_RECORDER_STORE_MODE set to TRACE_STORE_MODE_RING_BUFFER, the events are - * stored in a ring buffer, i.e., where the oldest events are overwritten when - * the buffer becomes full. This allows you to get the last events leading up - * to an interesting state, e.g., an error, without having a large trace buffer - * for string the whole run since startup. In this mode, the recorder can run - * "forever" as the buffer never gets full, i.e., in the sense that it always - * has room for more events. - * - * To fetch the trace in mode TRACE_STORE_MODE_RING_BUFFER, you need to first halt the - * system using your debugger and then do a RAM dump, or to explicitly stop the - * recorder using vTraceStop() and then store/upload the trace data using a - * task that you need to provide yourself. The trace data is found in the struct - * RecorderData, initialized in trcBase.c. - * - * Note that, if you upload the trace using a RAM dump, i.e., when the system is - * halted on a breakpoint or by a debugger command, there is no need to stop the - * recorder first. - * - * When TRACE_RECORDER_STORE_MODE is TRACE_STORE_MODE_STOP_WHEN_FULL, the recording is - * stopped when the buffer becomes full. When the recorder stops itself this way - * vTracePortEnd() is called which allows for custom actions, such as triggering - * a task that stores the trace buffer, i.e., in case taking a RAM dump - * using an on-chip debugger is not possible. In the Windows port, vTracePortEnd - * saves the trace to file directly, but this is not recommended in a real-time - * system since the scheduler is blocked during the processing of vTracePortEnd. + * Using dynamic allocation may give more flexibility in some cases. *****************************************************************************/ +#define TRACE_DATA_ALLOCATION TRACE_DATA_ALLOCATION_STATIC + -#define TRACE_RECORDER_STORE_MODE TRACE_STORE_MODE_RING_BUFFER /****************************************************************************** - * STOP_AFTER_N_EVENTS + *** ADVANCED SETTINGS ******************************************************** + ****************************************************************************** + * The remaining settings are not necessary to modify but allows for optimizing + * the recorder setup for your specific needs, e.g., to exclude events that you + * are not interested in, in order to get longer traces. + *****************************************************************************/ + +/****************************************************************************** +* HEAP_SIZE_BELOW_16M +* +* An integer constant that can be used to reduce the buffer usage of memory +* allocation events (malloc/free). This value should be 1 if the heap size is +* below 16 MB (2^24 byte), and you can live with reported addresses showing the +* lower 24 bits only. If 0, you get the full 32-bit addresses. +* +* Default value is 0. +******************************************************************************/ +#define HEAP_SIZE_BELOW_16M 0 + +/****************************************************************************** + * USE_LINKER_PRAGMA * - * Macro which should be defined as an integer value, or not defined. - * Default is -1 + * Macro which should be defined as an integer value, default is 0. * - * STOP_AFTER_N_EVENTS is intended for tests of the ring buffer mode (when - * RECORDER_STORE_MODE is STORE_MODE_RING_BUFFER). It stops the recording when - * the specified number of events has been observed. This value can be larger - * than the buffer size, to allow for test of the "wrapping around" that occurs - * in ring buffer mode . A negative value (or no definition of this macro) - * disables this feature. - *****************************************************************************/ -#define STOP_AFTER_N_EVENTS -1 + * If this is 1, the header file "recorderdata_linker_pragma.h" is included just + * before the declaration of RecorderData (in trcBase.c), i.e., the trace data + * structure. This allows the user to specify a pragma with linker options. + * + * Example (for IAR Embedded Workbench and NXP LPC17xx): + * #pragma location="AHB_RAM_MEMORY" + * + * This example instructs the IAR linker to place RecorderData in another RAM + * bank, the AHB RAM. This can also be used for other compilers with a similar + * pragmas for linker options. + * + * Note that this only applies if using static allocation, see below. + ******************************************************************************/ +#define USE_LINKER_PRAGMA 0 /****************************************************************************** * USE_IMPLICIT_IFE_RULES * - * Macro which should be defined as either zero (0) or one (1). + * Macro which should be defined as either zero (0) or one (1). * Default is 1. * - * ### Instance Finish Events (IFE) ### - * - * For tasks with "infinite" main loops (non-terminating tasks), the concept - * of a task instance has no clear definition, it is an application-specific - * thing. Tracealyzer allows you to define Instance Finish Events (IFEs), - * which marks the point in a cyclic task when the "task instance" ends. - * The IFE is a blocking kernel call, typically in the main loop of a task - * which typically reads a message queue, waits for a semaphore or performs - * an explicit delay. - * - * If USE_IMPLICIT_IFE_RULES is one (1), the kernel macros (trcKernelPort.h) - * will define what kernel calls are considered by default to be IFEs. - * - * However, Implicit IFEs only applies to blocking kernel calls. If a - * service reads a message without blocking, it does not create a new - * instance since no blocking occurred. - * - * Moreover, the actual IFE might sometimes be another blocking call. We - * therefore allow for user-defined Explicit IFEs by calling - * - * vTraceTaskInstanceIsFinished() - * - * right before the kernel call considered as IFE. This does not create an - * additional event but instead stores the service code and object handle - * of the IFE call as properties of the task. - * - * If using Explicit IFEs and the task also calls an Implicit IFE, this may - * result in additional incorrect task instances. - * This is solved by disabling the Implicit IFEs for the task, by adding - * a call to - * - * vTraceTaskSkipDefaultInstanceFinishedEvents() - * - * in the very beginning of that task. This allows you to combine Explicit IFEs - * for some tasks with Implicit IFEs for the rest of the tasks, if - * USE_IMPLICIT_IFE_RULES is 1. - * - * By setting USE_IMPLICIT_IFE_RULES to zero (0), the implicit IFEs are disabled - * for all tasks. Tasks will then be considered to have a single instance only, - * covering all execution fragments, unless you define an explicit IFE in each - * task by calling vTraceTaskInstanceIsFinished before the blocking call. + * Tracealyzer groups the events into actor instances, based on context-switches + * and a definition of "Instance Finish Events", or IFEs. These are kernel calls + * considered to be the last event in a task instance. Some kernel calls are + * considered IFEs by default (e.g., delay functions), but it is also possible + * to specify this individually for each task (see vTraceTaskInstanceFinish). + * + * If USE_IMPLICIT_IFE_RULES is one (1), the default IFEs will be enabled, which + * gives a "typical" grouping of events into instances. You can combine this + * with calls to vTraceTaskInstanceFinish for specific tasks. + * + * If USE_IMPLICIT_IFE_RULES is zero (0), the implicit IFEs are disabled and all + * events withing each task is then shown as a single instance, unless you call + * vTraceTaskInstanceFinish() at suitable locations to mark the IFEs. *****************************************************************************/ #define USE_IMPLICIT_IFE_RULES 1 - /****************************************************************************** * USE_16BIT_OBJECT_HANDLES * * Macro which should be defined as either zero (0) or one (1). - * Default is 0. * - * If set to 0 (zero), the recorder uses 8-bit handles to identify kernel + * If set to 0 (zero), the recorder uses 8-bit handles to identify kernel * objects such as tasks and queues. This limits the supported number of * concurrently active objects to 255 of each type (object class). * - * If set to 1 (one), the recorder uses 16-bit handles to identify kernel + * If set to 1 (one), the recorder uses 16-bit handles to identify kernel * objects such as tasks and queues. This limits the supported number of * concurrent objects to 65535 of each type (object class). However, since the * object property table is limited to 64 KB, the practical limit is about - * 3000 objects in total. - * - * NOTE: An object with a high ID (> 255) will generate an extra event - * (= 4 byte) in the event buffer. - * - * NOTE: Some internal tables in the recorder gets larger when using 16-bit - * handles. The additional RAM usage is 5-10 byte plus 1 byte per kernel object - *, i.e., task, queue, semaphore, mutex, etc. + * 3000 objects in total. + * + * Default is 0. + * + * NOTE: An object with handle above 255 will use an extra 4-byte record in + * the event buffer whenever referenced. Moreover, some internal tables in the + * recorder gets larger when using 16-bit handles. The additional RAM usage is + * 5-10 byte plus 1 byte per kernel object i.e., task, queue, mutex, etc. *****************************************************************************/ #define USE_16BIT_OBJECT_HANDLES 0 -/****** Port Name ******************** Code ** Official ** OS Platform ****** -* PORT_APPLICATION_DEFINED -2 - - -* PORT_NOT_SET -1 - - -* PORT_HWIndependent 0 Yes Any -* PORT_Win32 1 Yes FreeRTOS Win32 -* PORT_Atmel_AT91SAM7 2 No Any -* PORT_Atmel_UC3A0 3 No Any -* PORT_ARM_CortexM 4 Yes Any -* PORT_Renesas_RX600 5 Yes Any -* PORT_Microchip_dsPIC_AND_PIC24 6 Yes Any -* PORT_TEXAS_INSTRUMENTS_TMS570 7 No Any -* PORT_TEXAS_INSTRUMENTS_MSP430 8 No Any -* PORT_MICROCHIP_PIC32 9 No Any -* PORT_XILINX_PPC405 10 No FreeRTOS -* PORT_XILINX_PPC440 11 No FreeRTOS -* PORT_XILINX_MICROBLAZE 12 No Any -* PORT_NXP_LPC210X 13 No Any -*****************************************************************************/ -#define SELECTED_PORT PORT_Win32 - -#if (SELECTED_PORT == PORT_NOT_SET) -#error "You need to define SELECTED_PORT here!" -#endif - /****************************************************************************** -* USE_PRIMASK_CS (for Cortex M devices only) -* -* An integer constant that selects between two options for the critical -* sections of the recorder library. + * USE_TRACE_ASSERT * -* 0: The default FreeRTOS critical section (BASEPRI) - default setting -* 1: Always disable ALL interrupts (using PRIMASK) + * Macro which should be defined as either zero (0) or one (1). + * Default is 1. * -* Option 0 uses the standard FreeRTOS macros for critical sections. -* However, on Cortex-M devices they only disable interrupts with priorities -* below a certain configurable level, while higher priority ISRs remain active. -* Such high-priority ISRs may not use the recorder functions in this mode. -* -* Option 1 allows you to safely call the recorder from any ISR, independent of -* the interrupt priority. This mode may however cause higher IRQ latencies -* (some microseconds) since ALL configurable interrupts are disabled during -* the recorder's critical sections in this mode, using the PRIMASK register. + * If this is one (1), the TRACE_ASSERT macro will verify that a condition is + * true. If the condition is false, vTraceError() will be called. + * This is used on several places in the recorder code for sanity checks on + * parameters. Can be switched off to reduce CPU usage of the tracing. + *****************************************************************************/ +#define USE_TRACE_ASSERT 1 + +/******************************************************************************* + * USE_SEPARATE_USER_EVENT_BUFFER + * + * Macro which should be defined as an integer value. + * Default is zero (0). + * + * This enables and disables the use of the separate user event buffer. Using + * this separate buffer has the benefit of not overwriting the user events with + * kernel events (usually generated at a much higher rate), i.e., when using + * ring-buffer mode. + * + * Note: When using the separate user event buffer, you may get an artificial + * task instance named "Unknown actor". This is added as a placeholder when the + * user event history is longer than the task scheduling history. ******************************************************************************/ -#define USE_PRIMASK_CS 0 +#define USE_SEPARATE_USER_EVENT_BUFFER 0 -/****************************************************************************** -* HEAP_SIZE_BELOW_16M -* -* An integer constant that can be used to reduce the buffer usage of memory -* allocation events (malloc/free). This value should be 1 if the heap size is -* below 16 MB (2^24 byte), and you can live with addresses truncated to the -* lower 24 bit. Otherwise set it to 0 to get the full 32-bit addresses. -******************************************************************************/ -#define HEAP_SIZE_BELOW_16M 0 +/******************************************************************************* + * USER_EVENT_BUFFER_SIZE + * + * Macro which should be defined as an integer value. + * + * This defines the capacity of the user event buffer, in number of slots. + * A single user event can use between 1 and X slots, depending on the data. + * + * Only in use if USE_SEPARATE_USER_EVENT_BUFFER is set to 1. + ******************************************************************************/ +#define USER_EVENT_BUFFER_SIZE 10 + +/******************************************************************************* + * USER_EVENT_CHANNELS + * + * Macro which should be defined as an integer value. + * + * This defines the number of allowed user event channels. + * + * Only in use if USE_SEPARATE_USER_EVENT_BUFFER is set to 1. + ******************************************************************************/ +#define CHANNEL_FORMAT_PAIRS 32 #endif diff --git a/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj b/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj index 5e65e3e17..39234651c 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj +++ b/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj @@ -149,6 +149,7 @@ + diff --git a/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj.filters b/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj.filters index debd11c01..d4e210a8d 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj.filters +++ b/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj.filters @@ -139,6 +139,9 @@ Demo App Source\Common Demo Tasks + + Demo App Source\Common Demo Tasks + diff --git a/FreeRTOS/Demo/WIN32-MSVC/main.c b/FreeRTOS/Demo/WIN32-MSVC/main.c index 064c91375..6c10d8dde 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/main.c +++ b/FreeRTOS/Demo/WIN32-MSVC/main.c @@ -113,8 +113,8 @@ being used as this demo could easily create one large heap region instead of multiple smaller heap regions - in which case heap_4.c would be the more appropriate choice. */ #define mainREGION_1_SIZE 3001 -#define mainREGION_2_SIZE 18005 -#define mainREGION_3_SIZE 1007 +#define mainREGION_2_SIZE 18105 +#define mainREGION_3_SIZE 1407 /* * main_blinky() is used when mainCREATE_SIMPLE_BLINKY_DEMO_ONLY is set to 1. @@ -228,10 +228,10 @@ void vApplicationIdleHook( void ) function, because it is the responsibility of the idle task to clean up memory allocated by the kernel to any task that has since been deleted. */ - /* Uncomment the following code to allow the trace to be stopped with any + /* Uncomment the following code to allow the trace to be stopped with any key press. The code is commented out by default as the kbhit() function interferes with the run time behaviour. */ - /* + /* if( _kbhit() != pdFALSE ) { if( xTraceRunning == pdTRUE ) @@ -369,4 +369,5 @@ const HeapRegion_t xHeapRegions[] = vPortDefineHeapRegions( xHeapRegions ); } +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Demo/WIN32-MSVC/main_blinky.c b/FreeRTOS/Demo/WIN32-MSVC/main_blinky.c index b37b5d6e0..0dc818902 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/main_blinky.c +++ b/FreeRTOS/Demo/WIN32-MSVC/main_blinky.c @@ -128,7 +128,7 @@ /* The rate at which data is sent to the queue. The 200ms value is converted to ticks using the portTICK_PERIOD_MS constant. */ -#define mainQUEUE_SEND_FREQUENCY_MS ( 200 ) +#define mainQUEUE_SEND_FREQUENCY_MS ( 200 / portTICK_PERIOD_MS ) /* The number of items the queue can hold. This is 1 as the receive task will remove items as they are added, meaning the send task should always find diff --git a/FreeRTOS/Demo/WIN32-MSVC/main_full.c b/FreeRTOS/Demo/WIN32-MSVC/main_full.c index 74fc3f29e..85691c225 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/main_full.c +++ b/FreeRTOS/Demo/WIN32-MSVC/main_full.c @@ -112,10 +112,10 @@ /* Kernel includes. */ #include -#include "task.h" -#include "queue.h" -#include "timers.h" -#include "semphr.h" +#include +#include +#include +#include /* Standard demo includes. */ #include "BlockQ.h" @@ -134,6 +134,7 @@ #include "QueueOverwrite.h" #include "EventGroupsDemo.h" #include "IntSemTest.h" +#include "TaskNotify.h" /* Priorities at which the tasks are created. */ #define mainCHECK_TASK_PRIORITY ( configMAX_PRIORITIES - 2 ) @@ -196,6 +197,7 @@ int main_full( void ) xTaskCreate( prvCheckTask, "Check", configMINIMAL_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY, NULL ); /* Create the standard demo tasks. */ + vStartTaskNotifyTask(); vStartBlockingQueueTasks( mainBLOCK_Q_PRIORITY ); vStartSemaphoreTasks( mainSEM_TEST_PRIORITY ); vStartPolledQueueTasks( mainQUEUE_POLL_PRIORITY ); @@ -265,6 +267,11 @@ const TickType_t xCycleFrequency = 2500 / portTICK_PERIOD_MS; } #endif + if( xAreTaskNotificationTasksStillRunning() != pdTRUE ) + { + pcStatusMessage = "Error: Notification"; + } + if( xAreInterruptSemaphoreTasksStillRunning() != pdTRUE ) { pcStatusMessage = "Error: IntSem"; @@ -379,7 +386,7 @@ void *pvAllocated; xMutexToDelete = NULL; } - /* Exercise heap_4 a bit. The malloc failed hook will trap failed + /* Exercise heap_5 a bit. The malloc failed hook will trap failed allocations so there is no need to test here. */ pvAllocated = pvPortMalloc( ( rand() % 100 ) + 1 ); vPortFree( pvAllocated ); @@ -410,6 +417,9 @@ void vFullDemoTickHookFunction( void ) /* Exercise giving mutexes from an interrupt. */ vInterruptSemaphorePeriodicTest(); + + /* Exercise using task notifications from an interrupt. */ + xNotifyTaskFromISR(); } /*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Demo/WIN32-MingW/.project b/FreeRTOS/Demo/WIN32-MingW/.project index 4d3dee903..2df612dba 100644 --- a/FreeRTOS/Demo/WIN32-MingW/.project +++ b/FreeRTOS/Demo/WIN32-MingW/.project @@ -56,7 +56,7 @@ - 0 + 1418321193247 Standard_Demo_Tasks 5 @@ -65,7 +65,7 @@ - 0 + 1418321193247 Standard_Demo_Tasks 5 @@ -74,7 +74,7 @@ - 0 + 1418321193257 Standard_Demo_Tasks 5 @@ -83,7 +83,7 @@ - 0 + 1418321193257 Standard_Demo_Tasks 5 @@ -92,7 +92,7 @@ - 0 + 1418321193267 Standard_Demo_Tasks 5 @@ -101,7 +101,7 @@ - 0 + 1418321193277 Standard_Demo_Tasks 5 @@ -110,7 +110,7 @@ - 0 + 1418321193277 Standard_Demo_Tasks 5 @@ -119,7 +119,7 @@ - 0 + 1418321193287 Standard_Demo_Tasks 5 @@ -128,7 +128,7 @@ - 0 + 1418321193297 Standard_Demo_Tasks 5 @@ -137,7 +137,7 @@ - 0 + 1418321193297 Standard_Demo_Tasks 5 @@ -146,7 +146,7 @@ - 0 + 1418321193308 Standard_Demo_Tasks 5 @@ -155,7 +155,7 @@ - 0 + 1418321193313 Standard_Demo_Tasks 5 @@ -164,7 +164,7 @@ - 0 + 1418321193319 Standard_Demo_Tasks 5 @@ -173,7 +173,7 @@ - 0 + 1418321193325 Standard_Demo_Tasks 5 @@ -182,7 +182,7 @@ - 0 + 1418321193349 Standard_Demo_Tasks 5 @@ -190,6 +190,24 @@ 1.0-name-matches-false-false-timerdemo.c + + 1418321193369 + Standard_Demo_Tasks + 5 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-IntSemTest.c + + + + 1418321193379 + Standard_Demo_Tasks + 5 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-TaskNotify.c + + 0 FreeRTOS_Source/portable @@ -209,12 +227,12 @@ - 0 + 1418321226214 FreeRTOS_Source/portable/MemMang 5 org.eclipse.ui.ide.multiFilter - 1.0-name-matches-false-false-heap_4.c + 1.0-name-matches-false-false-heap_5.c diff --git a/FreeRTOS/Demo/WIN32-MingW/FreeRTOSConfig.h b/FreeRTOS/Demo/WIN32-MingW/FreeRTOSConfig.h index b6e429ca9..e4f6ce87b 100644 --- a/FreeRTOS/Demo/WIN32-MingW/FreeRTOSConfig.h +++ b/FreeRTOS/Demo/WIN32-MingW/FreeRTOSConfig.h @@ -83,7 +83,7 @@ #define configUSE_TICK_HOOK 1 #define configTICK_RATE_HZ ( 1000 ) /* In this non-real time simulated environment the tick frequency has to be at least a multiple of the Win32 tick frequency, and therefore very slow. */ #define configMINIMAL_STACK_SIZE ( ( unsigned short ) 50 ) /* In this simulated case, the stack only has to hold one small structure as the real stack is part of the win32 thread. */ -#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 20 * 1024 ) ) +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 23 * 1024 ) ) #define configMAX_TASK_NAME_LEN ( 12 ) #define configUSE_TRACE_FACILITY 1 #define configUSE_16_BIT_TICKS 0 @@ -97,6 +97,7 @@ #define configUSE_COUNTING_SEMAPHORES 1 #define configUSE_ALTERNATIVE_API 1 #define configUSE_QUEUE_SETS 1 +#define configUSE_TASK_NOTIFICATIONS 1 /* Software timer related configuration options. */ #define configUSE_TIMERS 1 @@ -104,18 +105,18 @@ #define configTIMER_QUEUE_LENGTH 20 #define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 ) -#define configMAX_PRIORITIES ( 8 ) +#define configMAX_PRIORITIES ( 7 ) /* Run time stats gathering configuration options. */ unsigned long ulGetRunTimeCounterValue( void ); /* Prototype of function that returns run time counter. */ void vConfigureTimerForRunTimeStats( void ); /* Prototype of function that initialises the run time counter. */ -#define configGENERATE_RUN_TIME_STATS 1 +#define configGENERATE_RUN_TIME_STATS 1 #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() vConfigureTimerForRunTimeStats() #define portGET_RUN_TIME_COUNTER_VALUE() ulGetRunTimeCounterValue() /* Co-routine related configuration options. */ -#define configUSE_CO_ROUTINES 1 -#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) +#define configUSE_CO_ROUTINES 1 +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) /* This demo makes use of one or more example stats formatting functions. These format the raw data provided by the uxTaskGetSystemState() function in to human @@ -147,7 +148,9 @@ uses the same semantics as the standard C assert() macro. */ extern void vAssertCalled( unsigned long ulLine, const char * const pcFileName ); #define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __LINE__, __FILE__ ) - /* Include the FreeRTOS+Trace FreeRTOS trace macro definitions. */ +#define TRACE_ENTER_CRITICAL_SECTION() portENTER_CRITICAL() +#define TRACE_EXIT_CRITICAL_SECTION() portEXIT_CRITICAL() #include "trcKernelPort.h" + #endif /* FREERTOS_CONFIG_H */ diff --git a/FreeRTOS/Demo/WIN32-MingW/Trace_Recorder_Configuration/trcConfig.h b/FreeRTOS/Demo/WIN32-MingW/Trace_Recorder_Configuration/trcConfig.h index 289384a28..7039112bf 100644 --- a/FreeRTOS/Demo/WIN32-MingW/Trace_Recorder_Configuration/trcConfig.h +++ b/FreeRTOS/Demo/WIN32-MingW/Trace_Recorder_Configuration/trcConfig.h @@ -1,14 +1,14 @@ /******************************************************************************* - * Tracealyzer v2.6.0 Recorder Library + * Tracealyzer v2.7.0 Recorder Library * Percepio AB, www.percepio.com * * trcConfig.h * - * Configuration parameters for the trace recorder library. Before using the - * trace recorder library, please check that the default settings are - * appropriate for your system, and if necessary adjust these. Most likely, you - * will need to adjust the NTask, NISR, NQueue, NMutex and NSemaphore values to - * reflect the number of such objects in your system. These may be + * Configuration parameters for the trace recorder library. Before using the + * trace recorder library, please check that the default settings are + * appropriate for your system, and if necessary adjust these. Most likely, you + * will need to adjust the NTask, NISR, NQueue, NMutex and NSemaphore values to + * reflect the number of such objects in your system. These may be * over-approximated, although larger values values implies more RAM usage. * * Terms of Use @@ -16,515 +16,460 @@ * use together with Percepio products. You may distribute the recorder library * in its original form, including modifications in trcHardwarePort.c/.h * given that these modification are clearly marked as your own modifications - * and documented in the initial comment section of these source files. - * This software is the intellectual property of Percepio AB and may not be - * sold or in other ways commercially redistributed without explicit written + * and documented in the initial comment section of these source files. + * This software is the intellectual property of Percepio AB and may not be + * sold or in other ways commercially redistributed without explicit written * permission by Percepio AB. * - * Disclaimer - * The trace tool and recorder library is being delivered to you AS IS and - * Percepio AB makes no warranty as to its use or performance. Percepio AB does - * not and cannot warrant the performance or results you may obtain by using the - * software or documentation. Percepio AB make no warranties, express or - * implied, as to noninfringement of third party rights, merchantability, or - * fitness for any particular purpose. In no event will Percepio AB, its - * technology partners, or distributors be liable to you for any consequential, - * incidental or special damages, including any lost profits or lost savings, - * even if a representative of Percepio AB has been advised of the possibility - * of such damages, or for any claim by any third party. Some jurisdictions do - * not allow the exclusion or limitation of incidental, consequential or special - * damages, or the exclusion of implied warranties or limitations on how long an + * Disclaimer + * The trace tool and recorder library is being delivered to you AS IS and + * Percepio AB makes no warranty as to its use or performance. Percepio AB does + * not and cannot warrant the performance or results you may obtain by using the + * software or documentation. Percepio AB make no warranties, express or + * implied, as to noninfringement of third party rights, merchantability, or + * fitness for any particular purpose. In no event will Percepio AB, its + * technology partners, or distributors be liable to you for any consequential, + * incidental or special damages, including any lost profits or lost savings, + * even if a representative of Percepio AB has been advised of the possibility + * of such damages, or for any claim by any third party. Some jurisdictions do + * not allow the exclusion or limitation of incidental, consequential or special + * damages, or the exclusion of implied warranties or limitations on how long an * implied warranty may last, so the above limitations may not apply to you. * - * Copyright Percepio AB, 2013. + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2014. * www.percepio.com ******************************************************************************/ #ifndef TRCCONFIG_H #define TRCCONFIG_H -/******************************************************************************* - * CONFIGURATION RELATED TO CAPACITY AND ALLOCATION - ******************************************************************************/ - -/******************************************************************************* - * EVENT_BUFFER_SIZE - * - * Macro which should be defined as an integer value. - * - * This defines the capacity of the event buffer, i.e., the number of records - * it may store. Each registered event typically use one record (4 byte), but - * vTracePrintF may use multiple records depending on the number of data args. - ******************************************************************************/ +/****************************************************************************** + * SELECTED_PORT + * + * Macro that specifies what hardware port that should be used. + * Available ports are: + * + * Port Name Code Official OS supported + * PORT_APPLICATION_DEFINED -2 - - + * PORT_NOT_SET -1 - - + * PORT_HWIndependent 0 Yes Any + * PORT_Win32 1 Yes FreeRTOS on Win32 + * PORT_Atmel_AT91SAM7 2 No Any + * PORT_Atmel_UC3A0 3 No Any + * PORT_ARM_CortexM 4 Yes Any + * PORT_Renesas_RX600 5 Yes Any + * PORT_Microchip_dsPIC_AND_PIC24 6 Yes Any + * PORT_TEXAS_INSTRUMENTS_TMS570 7 No Any + * PORT_TEXAS_INSTRUMENTS_MSP430 8 No Any + * PORT_MICROCHIP_PIC32MX 9 Yes Any + * PORT_XILINX_PPC405 10 No FreeRTOS + * PORT_XILINX_PPC440 11 No FreeRTOS + * PORT_XILINX_MICROBLAZE 12 No Any + * PORT_NXP_LPC210X 13 No Any + * PORT_MICROCHIP_PIC32MZ 14 Yes Any + * PORT_ARM_CORTEX_A9 15 No Any + *****************************************************************************/ -#define EVENT_BUFFER_SIZE 10000 /* Adjust wrt. to available RAM */ +#ifndef WIN32 + // Set the port setting here! + #define SELECTED_PORT PORT_NOT_SET + #if (SELECTED_PORT == PORT_NOT_SET) + #error "You need to define SELECTED_PORT here!" + #endif +#else + // For Win32 demo projects this is set automatically + #define SELECTED_PORT PORT_Win32 +#endif -/******************************************************************************* - * USE_LINKER_PRAGMA - * - * Macro which should be defined as an integer value, default is 0. +/****************************************************************************** + * FREERTOS_VERSION * - * If this is 1, the header file "recorderdata_linker_pragma.h" is included just - * before the declaration of RecorderData (in trcBase.c), i.e., the trace data - * structure. This allows the user to specify a pragma with linker options. + * Specify what version of FreeRTOS that is used. This is necessary compensate + * for renamed symbols in the FreeRTOS kernel (does not build if incorrect). * - * Example (for IAR Embedded Workbench and NXP LPC17xx): - * #pragma location="AHB_RAM_MEMORY" - * - * This example instructs the IAR linker to place RecorderData in another RAM - * bank, the AHB RAM. This can also be used for other compilers with a similar - * pragmas for linker options. - * - * Note that this only applies if using static allocation, see below. - ******************************************************************************/ - -#define USE_LINKER_PRAGMA 0 - + * FREERTOS_VERSION_7_3_OR_7_4 (= 1) If using FreeRTOS v7.3.0 - v7.4.2 + * FREERTOS_VERSION_7_5_OR_7_6 (= 2) If using FreeRTOS v7.5.0 - v7.6.0 + * FREERTOS_VERSION_8_0_OR_LATER (= 3) If using FreeRTOS v8.0.0 or later + *****************************************************************************/ +#define FREERTOS_VERSION FREERTOS_VERSION_8_0_OR_LATER -/******************************************************************************* - * SYMBOL_TABLE_SIZE +/****************************************************************************** + * TRACE_RECORDER_STORE_MODE * - * Macro which should be defined as an integer value. + * Macro which should be defined as one of: + * - TRACE_STORE_MODE_RING_BUFFER + * - TRACE_STORE_MODE_STOP_WHEN_FULL + * Default is TRACE_STORE_MODE_RING_BUFFER. * - * This defines the capacity of the symbol table, in bytes. This symbol table - * stores User Events labels and names of deleted tasks, queues, or other kernel - * objects. Note that the names of active objects not stored here but in the - * Object Table. Thus, if you don't use User Events or delete any kernel - * objects you set this to a very low value, e.g. 4, but not zero (0) since - * this causes a declaration of a zero-sized array, for which the C compiler - * behavior is not standardized and may cause misaligned data. - ******************************************************************************/ -#define SYMBOL_TABLE_SIZE 5000 - -#if (SYMBOL_TABLE_SIZE == 0) -#error "SYMBOL_TABLE_SIZE may not be zero!" -#endif + * With TRACE_RECORDER_STORE_MODE set to TRACE_STORE_MODE_RING_BUFFER, the + * events are stored in a ring buffer, i.e., where the oldest events are + * overwritten when the buffer becomes full. This allows you to get the last + * events leading up to an interesting state, e.g., an error, without having + * to store the whole run since startup. + * + * When TRACE_RECORDER_STORE_MODE is TRACE_STORE_MODE_STOP_WHEN_FULL, the + * recording is stopped when the buffer becomes full. This is useful for + * recording events following a specific state, e.g., the startup sequence. + *****************************************************************************/ +#define TRACE_RECORDER_STORE_MODE TRACE_STORE_MODE_RING_BUFFER /******************************************************************************* - * USE_SEPARATE_USER_EVENT_BUFFER + * TRACE_SCHEDULING_ONLY * * Macro which should be defined as an integer value. - * Default is zero (0). * - * This enables and disables the use of the separate user event buffer. + * If this setting is enabled (= 1), only scheduling events are recorded. + * If disabled (= 0), all events are recorded. * - * Note: When using the separate user event buffer, you may get an artificial - * task instance named "Unknown actor". This is added as a placeholder when the - * user event history is longer than the task scheduling history. - ******************************************************************************/ -#define USE_SEPARATE_USER_EVENT_BUFFER 0 - -/******************************************************************************* - * USER_EVENT_BUFFER_SIZE + * Users of FreeRTOS+Trace Free Edition only displays scheduling events, so this + * option can be used to avoid storing unsupported events. * - * Macro which should be defined as an integer value. + * Default value is 0 (store all enabled events). * - * This defines the capacity of the user event buffer, in number of slots. - * A single user event can use between 1 and X slots, depending on the data. - * - * Only in use if USE_SEPARATE_USER_EVENT_BUFFER is set to 1. ******************************************************************************/ -#define USER_EVENT_BUFFER_SIZE 500 +#define TRACE_SCHEDULING_ONLY 0 /******************************************************************************* - * USER_EVENT_CHANNELS + * EVENT_BUFFER_SIZE * * Macro which should be defined as an integer value. * - * This defines the number of allowed user event channels. + * This defines the capacity of the event buffer, i.e., the number of records + * it may store. Most events use one record (4 byte), although some events + * require multiple 4-byte records. You should adjust this to the amount of RAM + * available in the target system. * - * Only in use if USE_SEPARATE_USER_EVENT_BUFFER is set to 1. + * Default value is 1000, which means that 4000 bytes is allocated for the + * event buffer. ******************************************************************************/ -#define CHANNEL_FORMAT_PAIRS 32 +#define EVENT_BUFFER_SIZE 15000 /******************************************************************************* * NTask, NISR, NQueue, NSemaphore, NMutex * - * A group of Macros which should be defined as an integer value of zero (0) - * or larger. + * A group of macros which should be defined as integer values, zero or larger. * - * This defines the capacity of the Object Property Table - the maximum number - * of objects active at any given point within each object class. - * - * NOTE: In case objects are deleted and created during runtime, this setting - * does not limit the total amount of objects, only the number of concurrently - * active objects. + * These define the capacity of the Object Property Table, i.e., the maximum + * number of objects active at any given point, within each object class (e.g., + * task, queue, semaphore, ...). * - * Using too small values will give an error message through the vTraceError - * routine, which makes the error message appear when opening the trace data - * in Tracealyzer. If you are using the recorder status monitor task, - * any error messages are displayed in console prints, assuming that the - * print macro has been defined properly (vConsolePrintMessage). + * If tasks or other other objects are deleted in your system, this + * setting does not limit the total amount of objects created, only the number + * of objects that have been successfully created but not yet deleted. * - * It can be wise to start with very large values for these constants, - * unless you are very confident on these numbers. Then do a recording and - * check the actual usage in Tracealyzer. This is shown by selecting - * View -> Trace Details -> Resource Usage -> Object Table - * - * NOTE 2: Remember to account for all tasks and other objects created by - * the kernel, such as the IDLE task, any timer tasks, and any tasks created - * by other 3rd party software components, such as communication stacks. - * Moreover, one task slot is used to indicate "(startup)", i.e., a fictive - * task that represent the time before the scheduler starts. - * NTask should thus be at least 2-3 slots larger than your application task count. + * Using too small values will cause vTraceError to be called, which stores an + * error message in the trace that is shown when opening the trace file. * + * It can be wise to start with large values for these constants, + * unless you are very confident on these numbers. Then do a recording and + * check the actual usage by selecting View menu -> Trace Details -> + * Resource Usage -> Object Table. ******************************************************************************/ -#define NTask 100 -#define NISR 20 -#define NQueue 60 -#define NSemaphore 60 -#define NMutex 60 -#define NTimer 200 -#define NEventGroup 60 - -/* Maximum object name length for each class (includes zero termination) */ -#define NameLenTask 15 -#define NameLenISR 15 -#define NameLenQueue 15 -#define NameLenSemaphore 15 -#define NameLenMutex 15 -#define NameLenTimer 15 -#define NameLenEventGroup 15 +#define NTask 100 +#define NISR 60 +#define NQueue 60 +#define NSemaphore 60 +#define NMutex 60 +#define NTimer 200 +#define NEventGroup 60 /****************************************************************************** - * TRACE_DESCRIPTION + * INCLUDE_MEMMANG_EVENTS * - * Macro which should be defined as a string. + * Macro which should be defined as either zero (0) or one (1). * - * This string is stored in the trace and displayed in Tracealyzer. Can be - * used to store, e.g., system version or build date. This is also used to store - * internal error messages from the recorder, which if occurs overwrites the - * value defined here. This may be maximum 256 chars. - *****************************************************************************/ -#define TRACE_DESCRIPTION "Tracealyzer Recorder Test Program" - -/****************************************************************************** - * TRACE_DESCRIPTION_MAX_LENGTH + * This controls if malloc and free calls should be traced. Set this to zero to + * exclude malloc/free calls, or one (1) to include such events in the trace. * - * The maximum length (including zero termination) for the TRACE_DESCRIPTION - * string. Since this string also is used for internal error messages from the - * recorder do not make it too short, as this may truncate the error messages. - * Default is 80. - * Maximum allowed length is 256 - the trace will fail to load if longer. + * Default value is 1. *****************************************************************************/ -#define TRACE_DESCRIPTION_MAX_LENGTH 80 - +#define INCLUDE_MEMMANG_EVENTS 1 /****************************************************************************** - * TRACE_DATA_ALLOCATION - * - * This defines how to allocate the recorder data structure, i.e., using a - * static declaration or using a dynamic allocation in runtime (malloc). - * - * Should be one of these two options: - * - TRACE_DATA_ALLOCATION_STATIC (default) - * - TRACE_DATA_ALLOCATION_DYNAMIC + * INCLUDE_USER_EVENTS * - * Using static allocation has the benefits of compile-time errors if the buffer - * is too large (too large constants in trcConfig.h) and no need to call the - * initialization routine (xTraceInitTraceData). + * Macro which should be defined as either zero (0) or one (1). * - * Using dynamic allocation may give more flexibility in some cases. - *****************************************************************************/ - -#define TRACE_DATA_ALLOCATION TRACE_DATA_ALLOCATION_STATIC - - -/****************************************************************************** - * CONFIGURATION REGARDING WHAT CODE/FEATURES TO INCLUDE - *****************************************************************************/ - -/****************************************************************************** - * USE_TRACE_ASSERT + * If this is zero (0) the code for creating User Events is excluded to + * reduce code size. User Events are application-generated events, like + * "printf" but for the trace log instead of console output. User Events are + * much faster than a printf and can therefore be used in timing critical code. + * See vTraceUserEvent() and vTracePrintF() in trcUser.h * - * Macro which should be defined as either zero (0) or one (1). - * Default is 0. + * Default value is 1. * - * If this is one (1), the TRACE_ASSERT macro will verify that a condition is - * true. If the condition is false, vTraceError() will be called. + * Note that User Events are only displayed in Professional Edition. *****************************************************************************/ -#define USE_TRACE_ASSERT 1 +#define INCLUDE_USER_EVENTS 1 -/****************************************************************************** - * INCLUDE_FLOAT_SUPPORT - * - * Macro which should be defined as either zero (0) or one (1). - * Default is 1. +/***************************************************************************** + * INCLUDE_ISR_TRACING * - * If this is zero (0), all references to floating point values are removed, - * in case floating point values are not supported by the platform used. - * Floating point values are only used in vTracePrintF and its subroutines, to - * store float (%f) or double (%lf) argments. + * Macro which should be defined as either zero (0) or one (1). * - * Note: vTracePrintF can still be used with integer and string arguments in - * either case. - *****************************************************************************/ -#define INCLUDE_FLOAT_SUPPORT 0 - -/****************************************************************************** - * INCLUDE_USER_EVENTS + * If this is zero (0), the code for recording Interrupt Service Routines is + * excluded to reduce code size. * - * Macro which should be defined as either zero (0) or one (1). - * Default is 1. + * Default value is 1. * - * If this is zero (0) the code for creating User Events is excluded to - * reduce code size. User Events are application-generated events, like - * "printf" but for the trace log instead of console output. User Events are - * much faster than a printf and can therefore be used in timing critical code. - * See vTraceUserEvent() and vTracePrintF() in trcUser.h - * - * Note that User Events are not displayed in FreeRTOS+Trace Free Edition. + * Note, if the kernel has no central interrupt dispatcher, recording ISRs + * require that you insert calls to vTraceStoreISRBegin and vTraceStoreISREnd + * in your interrupt handlers. *****************************************************************************/ -#define INCLUDE_USER_EVENTS 1 +#define INCLUDE_ISR_TRACING 1 /***************************************************************************** * INCLUDE_READY_EVENTS * - * Macro which should be defined as either zero (0) or one (1). - * Default is 1. + * Macro which should be defined as either zero (0) or one (1). * - * If this is zero (0), the code for recording Ready events is - * excluded. Note, this will make it impossible to calculate the correct - * response times. + * If one (1), events are recorded when tasks enter scheduling state "ready". + * This uses a lot of space in the event buffer, so excluding "ready events" + * will allow for longer traces. Including ready events however allows for + * showing the initial pending time before tasks enter the execution state, and + * for presenting accurate response times. + * + * Default value is 1. *****************************************************************************/ #define INCLUDE_READY_EVENTS 1 /***************************************************************************** * INCLUDE_NEW_TIME_EVENTS * - * Macro which should be defined as either zero (0) or one (1). - * Default is 0. + * Macro which should be defined as either zero (0) or one (1). * - * If this is zero (1), events will be generated whenever the os clock is + * If this is zero (1), events will be generated whenever the OS clock is * increased. + * + * Default value is 0. *****************************************************************************/ -#define INCLUDE_NEW_TIME_EVENTS 0 +#define INCLUDE_NEW_TIME_EVENTS 1 -/***************************************************************************** - * INCLUDE_ISR_TRACING +/****************************************************************************** + * INCLUDE_FLOAT_SUPPORT * - * Macro which should be defined as either zero (0) or one (1). - * Default is 1. + * Macro which should be defined as either zero (0) or one (1). * - * If this is zero (0), the code for recording Interrupt Service Routines is - * excluded to reduce code size. - * - * Note, if the kernel has no central interrupt dispatcher, recording ISRs - * require that you insert calls to vTraceStoreISRBegin and vTraceStoreISREnd - * in your interrupt handlers. + * If this is zero (0), all references to floating point values are removed, + * in case floating point values are not supported by the platform used. + * Floating point values are only used in vTracePrintF and its subroutines, to + * store float (%f) or double (%lf) arguments. + * + * vTracePrintF can be used with integer and string arguments in either case. + * + * Default value is 1. *****************************************************************************/ -#define INCLUDE_ISR_TRACING 1 +#define INCLUDE_FLOAT_SUPPORT 0 /****************************************************************************** * INCLUDE_OBJECT_DELETE - * - * Macro which should be defined as either zero (0) or one (1). - * Default is 1. * - * This must be enabled (1) if tasks, queues or other - * traced kernel objects are deleted at runtime. If no deletes are made, this + * Macro which should be defined as either zero (0) or one (1). + * + * This must be enabled (1) if tasks, queues or other + * traced kernel objects are deleted at runtime. If no deletes are made, this * can be set to 0 in order to exclude the delete-handling code. + * + * Default value is 1. *****************************************************************************/ #define INCLUDE_OBJECT_DELETE 1 -/****************************************************************************** - * INCLUDE_MEMMANG_EVENTS - * - * Macro which should be defined as either zero (0) or one (1). - * Default is 1. +/******************************************************************************* + * SYMBOL_TABLE_SIZE * - * This controls if malloc and free calls should be traced. Set this to zero to - * exclude malloc/free calls from the tracing. - *****************************************************************************/ -#define INCLUDE_MEMMANG_EVENTS 1 + * Macro which should be defined as an integer value. + * + * This defines the capacity of the symbol table, in bytes. This symbol table + * stores User Events labels and names of deleted tasks, queues, or other kernel + * objects. If you don't use User Events or delete any kernel + * objects you set this to a very low value. The minimum recommended value is 4. + * A size of zero (0) is not allowed since a zero-sized array may result in a + * 32-bit pointer, i.e., using 4 bytes rather than 0. + * + * Default value is 800. + ******************************************************************************/ +#define SYMBOL_TABLE_SIZE 5000 + +#if (SYMBOL_TABLE_SIZE == 0) +#error "SYMBOL_TABLE_SIZE may not be zero!" +#endif /****************************************************************************** - * CONFIGURATION RELATED TO BEHAVIOR + * NameLenTask, NameLenQueue, ... + * + * Macros that specify the maximum lengths (number of characters) for names of + * kernel objects, such as tasks and queues. If longer names are used, they will + * be truncated when stored in the recorder. *****************************************************************************/ +#define NameLenTask 15 +#define NameLenISR 15 +#define NameLenQueue 15 +#define NameLenSemaphore 15 +#define NameLenMutex 15 +#define NameLenTimer 15 +#define NameLenEventGroup 15 /****************************************************************************** - * TRACE_RECORDER_STORE_MODE + * TRACE_DATA_ALLOCATION * - * Macro which should be defined as one of: - * - TRACE_STORE_MODE_RING_BUFFER - * - TRACE_STORE_MODE_STOP_WHEN_FULL - * Default is TRACE_STORE_MODE_RING_BUFFER. + * This defines how to allocate the recorder data structure, i.e., using a + * static declaration or using a dynamic allocation in runtime (malloc). + * + * Should be one of these two options: + * - TRACE_DATA_ALLOCATION_STATIC (default) + * - TRACE_DATA_ALLOCATION_DYNAMIC + * + * Using static allocation has the benefits of compile-time errors if the buffer + * is too large (too large constants in trcConfig.h) and no need to call the + * initialization routine (xTraceInitTraceData). * - * With TRACE_RECORDER_STORE_MODE set to TRACE_STORE_MODE_RING_BUFFER, the events are - * stored in a ring buffer, i.e., where the oldest events are overwritten when - * the buffer becomes full. This allows you to get the last events leading up - * to an interesting state, e.g., an error, without having a large trace buffer - * for string the whole run since startup. In this mode, the recorder can run - * "forever" as the buffer never gets full, i.e., in the sense that it always - * has room for more events. - * - * To fetch the trace in mode TRACE_STORE_MODE_RING_BUFFER, you need to first halt the - * system using your debugger and then do a RAM dump, or to explicitly stop the - * recorder using vTraceStop() and then store/upload the trace data using a - * task that you need to provide yourself. The trace data is found in the struct - * RecorderData, initialized in trcBase.c. - * - * Note that, if you upload the trace using a RAM dump, i.e., when the system is - * halted on a breakpoint or by a debugger command, there is no need to stop the - * recorder first. - * - * When TRACE_RECORDER_STORE_MODE is TRACE_STORE_MODE_STOP_WHEN_FULL, the recording is - * stopped when the buffer becomes full. When the recorder stops itself this way - * vTracePortEnd() is called which allows for custom actions, such as triggering - * a task that stores the trace buffer, i.e., in case taking a RAM dump - * using an on-chip debugger is not possible. In the Windows port, vTracePortEnd - * saves the trace to file directly, but this is not recommended in a real-time - * system since the scheduler is blocked during the processing of vTracePortEnd. + * Using dynamic allocation may give more flexibility in some cases. *****************************************************************************/ +#define TRACE_DATA_ALLOCATION TRACE_DATA_ALLOCATION_STATIC + -#define TRACE_RECORDER_STORE_MODE TRACE_STORE_MODE_RING_BUFFER /****************************************************************************** - * STOP_AFTER_N_EVENTS + *** ADVANCED SETTINGS ******************************************************** + ****************************************************************************** + * The remaining settings are not necessary to modify but allows for optimizing + * the recorder setup for your specific needs, e.g., to exclude events that you + * are not interested in, in order to get longer traces. + *****************************************************************************/ + +/****************************************************************************** +* HEAP_SIZE_BELOW_16M +* +* An integer constant that can be used to reduce the buffer usage of memory +* allocation events (malloc/free). This value should be 1 if the heap size is +* below 16 MB (2^24 byte), and you can live with reported addresses showing the +* lower 24 bits only. If 0, you get the full 32-bit addresses. +* +* Default value is 0. +******************************************************************************/ +#define HEAP_SIZE_BELOW_16M 0 + +/****************************************************************************** + * USE_LINKER_PRAGMA * - * Macro which should be defined as an integer value, or not defined. - * Default is -1 + * Macro which should be defined as an integer value, default is 0. * - * STOP_AFTER_N_EVENTS is intended for tests of the ring buffer mode (when - * RECORDER_STORE_MODE is STORE_MODE_RING_BUFFER). It stops the recording when - * the specified number of events has been observed. This value can be larger - * than the buffer size, to allow for test of the "wrapping around" that occurs - * in ring buffer mode . A negative value (or no definition of this macro) - * disables this feature. - *****************************************************************************/ -#define STOP_AFTER_N_EVENTS -1 + * If this is 1, the header file "recorderdata_linker_pragma.h" is included just + * before the declaration of RecorderData (in trcBase.c), i.e., the trace data + * structure. This allows the user to specify a pragma with linker options. + * + * Example (for IAR Embedded Workbench and NXP LPC17xx): + * #pragma location="AHB_RAM_MEMORY" + * + * This example instructs the IAR linker to place RecorderData in another RAM + * bank, the AHB RAM. This can also be used for other compilers with a similar + * pragmas for linker options. + * + * Note that this only applies if using static allocation, see below. + ******************************************************************************/ +#define USE_LINKER_PRAGMA 0 /****************************************************************************** * USE_IMPLICIT_IFE_RULES * - * Macro which should be defined as either zero (0) or one (1). + * Macro which should be defined as either zero (0) or one (1). * Default is 1. * - * ### Instance Finish Events (IFE) ### - * - * For tasks with "infinite" main loops (non-terminating tasks), the concept - * of a task instance has no clear definition, it is an application-specific - * thing. Tracealyzer allows you to define Instance Finish Events (IFEs), - * which marks the point in a cyclic task when the "task instance" ends. - * The IFE is a blocking kernel call, typically in the main loop of a task - * which typically reads a message queue, waits for a semaphore or performs - * an explicit delay. - * - * If USE_IMPLICIT_IFE_RULES is one (1), the kernel macros (trcKernelPort.h) - * will define what kernel calls are considered by default to be IFEs. - * - * However, Implicit IFEs only applies to blocking kernel calls. If a - * service reads a message without blocking, it does not create a new - * instance since no blocking occurred. - * - * Moreover, the actual IFE might sometimes be another blocking call. We - * therefore allow for user-defined Explicit IFEs by calling - * - * vTraceTaskInstanceIsFinished() - * - * right before the kernel call considered as IFE. This does not create an - * additional event but instead stores the service code and object handle - * of the IFE call as properties of the task. - * - * If using Explicit IFEs and the task also calls an Implicit IFE, this may - * result in additional incorrect task instances. - * This is solved by disabling the Implicit IFEs for the task, by adding - * a call to - * - * vTraceTaskSkipDefaultInstanceFinishedEvents() - * - * in the very beginning of that task. This allows you to combine Explicit IFEs - * for some tasks with Implicit IFEs for the rest of the tasks, if - * USE_IMPLICIT_IFE_RULES is 1. - * - * By setting USE_IMPLICIT_IFE_RULES to zero (0), the implicit IFEs are disabled - * for all tasks. Tasks will then be considered to have a single instance only, - * covering all execution fragments, unless you define an explicit IFE in each - * task by calling vTraceTaskInstanceIsFinished before the blocking call. + * Tracealyzer groups the events into actor instances, based on context-switches + * and a definition of "Instance Finish Events", or IFEs. These are kernel calls + * considered to be the last event in a task instance. Some kernel calls are + * considered IFEs by default (e.g., delay functions), but it is also possible + * to specify this individually for each task (see vTraceTaskInstanceFinish). + * + * If USE_IMPLICIT_IFE_RULES is one (1), the default IFEs will be enabled, which + * gives a "typical" grouping of events into instances. You can combine this + * with calls to vTraceTaskInstanceFinish for specific tasks. + * + * If USE_IMPLICIT_IFE_RULES is zero (0), the implicit IFEs are disabled and all + * events withing each task is then shown as a single instance, unless you call + * vTraceTaskInstanceFinish() at suitable locations to mark the IFEs. *****************************************************************************/ #define USE_IMPLICIT_IFE_RULES 1 - /****************************************************************************** * USE_16BIT_OBJECT_HANDLES * * Macro which should be defined as either zero (0) or one (1). - * Default is 0. * - * If set to 0 (zero), the recorder uses 8-bit handles to identify kernel + * If set to 0 (zero), the recorder uses 8-bit handles to identify kernel * objects such as tasks and queues. This limits the supported number of * concurrently active objects to 255 of each type (object class). * - * If set to 1 (one), the recorder uses 16-bit handles to identify kernel + * If set to 1 (one), the recorder uses 16-bit handles to identify kernel * objects such as tasks and queues. This limits the supported number of * concurrent objects to 65535 of each type (object class). However, since the * object property table is limited to 64 KB, the practical limit is about - * 3000 objects in total. - * - * NOTE: An object with a high ID (> 255) will generate an extra event - * (= 4 byte) in the event buffer. - * - * NOTE: Some internal tables in the recorder gets larger when using 16-bit - * handles. The additional RAM usage is 5-10 byte plus 1 byte per kernel object - *, i.e., task, queue, semaphore, mutex, etc. + * 3000 objects in total. + * + * Default is 0. + * + * NOTE: An object with handle above 255 will use an extra 4-byte record in + * the event buffer whenever referenced. Moreover, some internal tables in the + * recorder gets larger when using 16-bit handles. The additional RAM usage is + * 5-10 byte plus 1 byte per kernel object i.e., task, queue, mutex, etc. *****************************************************************************/ #define USE_16BIT_OBJECT_HANDLES 0 -/****** Port Name ******************** Code ** Official ** OS Platform ****** -* PORT_APPLICATION_DEFINED -2 - - -* PORT_NOT_SET -1 - - -* PORT_HWIndependent 0 Yes Any -* PORT_Win32 1 Yes FreeRTOS Win32 -* PORT_Atmel_AT91SAM7 2 No Any -* PORT_Atmel_UC3A0 3 No Any -* PORT_ARM_CortexM 4 Yes Any -* PORT_Renesas_RX600 5 Yes Any -* PORT_Microchip_dsPIC_AND_PIC24 6 Yes Any -* PORT_TEXAS_INSTRUMENTS_TMS570 7 No Any -* PORT_TEXAS_INSTRUMENTS_MSP430 8 No Any -* PORT_MICROCHIP_PIC32 9 No Any -* PORT_XILINX_PPC405 10 No FreeRTOS -* PORT_XILINX_PPC440 11 No FreeRTOS -* PORT_XILINX_MICROBLAZE 12 No Any -* PORT_NXP_LPC210X 13 No Any -*****************************************************************************/ -#define SELECTED_PORT PORT_Win32 - -#if (SELECTED_PORT == PORT_NOT_SET) -#error "You need to define SELECTED_PORT here!" -#endif - /****************************************************************************** -* USE_PRIMASK_CS (for Cortex M devices only) -* -* An integer constant that selects between two options for the critical -* sections of the recorder library. + * USE_TRACE_ASSERT * -* 0: The default FreeRTOS critical section (BASEPRI) - default setting -* 1: Always disable ALL interrupts (using PRIMASK) + * Macro which should be defined as either zero (0) or one (1). + * Default is 1. * -* Option 0 uses the standard FreeRTOS macros for critical sections. -* However, on Cortex-M devices they only disable interrupts with priorities -* below a certain configurable level, while higher priority ISRs remain active. -* Such high-priority ISRs may not use the recorder functions in this mode. -* -* Option 1 allows you to safely call the recorder from any ISR, independent of -* the interrupt priority. This mode may however cause higher IRQ latencies -* (some microseconds) since ALL configurable interrupts are disabled during -* the recorder's critical sections in this mode, using the PRIMASK register. + * If this is one (1), the TRACE_ASSERT macro will verify that a condition is + * true. If the condition is false, vTraceError() will be called. + * This is used on several places in the recorder code for sanity checks on + * parameters. Can be switched off to reduce CPU usage of the tracing. + *****************************************************************************/ +#define USE_TRACE_ASSERT 1 + +/******************************************************************************* + * USE_SEPARATE_USER_EVENT_BUFFER + * + * Macro which should be defined as an integer value. + * Default is zero (0). + * + * This enables and disables the use of the separate user event buffer. Using + * this separate buffer has the benefit of not overwriting the user events with + * kernel events (usually generated at a much higher rate), i.e., when using + * ring-buffer mode. + * + * Note: When using the separate user event buffer, you may get an artificial + * task instance named "Unknown actor". This is added as a placeholder when the + * user event history is longer than the task scheduling history. ******************************************************************************/ -#define USE_PRIMASK_CS 0 +#define USE_SEPARATE_USER_EVENT_BUFFER 0 -/****************************************************************************** -* HEAP_SIZE_BELOW_16M -* -* An integer constant that can be used to reduce the buffer usage of memory -* allocation events (malloc/free). This value should be 1 if the heap size is -* below 16 MB (2^24 byte), and you can live with addresses truncated to the -* lower 24 bit. Otherwise set it to 0 to get the full 32-bit addresses. -******************************************************************************/ -#define HEAP_SIZE_BELOW_16M 0 +/******************************************************************************* + * USER_EVENT_BUFFER_SIZE + * + * Macro which should be defined as an integer value. + * + * This defines the capacity of the user event buffer, in number of slots. + * A single user event can use between 1 and X slots, depending on the data. + * + * Only in use if USE_SEPARATE_USER_EVENT_BUFFER is set to 1. + ******************************************************************************/ +#define USER_EVENT_BUFFER_SIZE 10 + +/******************************************************************************* + * USER_EVENT_CHANNELS + * + * Macro which should be defined as an integer value. + * + * This defines the number of allowed user event channels. + * + * Only in use if USE_SEPARATE_USER_EVENT_BUFFER is set to 1. + ******************************************************************************/ +#define CHANNEL_FORMAT_PAIRS 32 #endif diff --git a/FreeRTOS/Demo/WIN32-MingW/main.c b/FreeRTOS/Demo/WIN32-MingW/main.c index 657c0305a..98305caf6 100644 --- a/FreeRTOS/Demo/WIN32-MingW/main.c +++ b/FreeRTOS/Demo/WIN32-MingW/main.c @@ -66,9 +66,9 @@ /****************************************************************************** * This project provides two demo applications. A simple blinky style project, * and a more comprehensive test and demo application. The - * mainCREATE_SIMPLE_BLINKY_DEMO_ONLY setting is used to select between the two. - * The simply blinky demo is implemented and described in main_blinky.c. The - * more comprehensive test and demo application is implemented and described in + * mainCREATE_SIMPLE_BLINKY_DEMO_ONLY setting is used to select between the two. + * The simply blinky demo is implemented and described in main_blinky.c. The + * more comprehensive test and demo application is implemented and described in * main_full.c. * * This file implements the code that is not demo specific, including the @@ -80,9 +80,9 @@ * application. It is provided as a convenient development and demonstration * test bed only. This was tested using Windows XP on a dual core laptop. * - * Windows will not be running the FreeRTOS simulator threads continuously, so - * the timing information in the FreeRTOS+Trace logs have no meaningful units. - * See the documentation page for the Windows simulator for an explanation of + * Windows will not be running the FreeRTOS simulator threads continuously, so + * the timing information in the FreeRTOS+Trace logs have no meaningful units. + * See the documentation page for the Windows simulator for an explanation of * the slow timing: * http://www.freertos.org/FreeRTOS-Windows-Simulator-Emulator-for-Visual-Studio-and-Eclipse-MingW.html * - READ THE WEB DOCUMENTATION FOR THIS PORT FOR MORE INFORMATION ON USING IT - @@ -101,11 +101,20 @@ /* This project provides two demo applications. A simple blinky style project, and a more comprehensive test and demo application. The -mainCREATE_SIMPLE_BLINKY_DEMO_ONLY setting is used to select between the two. -The simply blinky demo is implemented and described in main_blinky.c. The more -comprehensive test and demo application is implemented and described in +mainCREATE_SIMPLE_BLINKY_DEMO_ONLY setting is used to select between the two. +The simply blinky demo is implemented and described in main_blinky.c. The more +comprehensive test and demo application is implemented and described in main_full.c. */ -#define mainCREATE_SIMPLE_BLINKY_DEMO_ONLY 1 +#define mainCREATE_SIMPLE_BLINKY_DEMO_ONLY 0 + +/* This demo uses heap_5.c, and these constants define the sizes of the regions +that make up the total heap. This is only done to provide an example of heap_5 +being used as this demo could easily create one large heap region instead of +multiple smaller heap regions - in which case heap_4.c would be the more +appropriate choice. */ +#define mainREGION_1_SIZE 3001 +#define mainREGION_2_SIZE 18105 +#define mainREGION_3_SIZE 1107 /* * main_blinky() is used when mainCREATE_SIMPLE_BLINKY_DEMO_ONLY is set to 1. @@ -114,15 +123,28 @@ main_full.c. */ extern void main_blinky( void ); extern void main_full( void ); -/* Some of the RTOS hook (callback) functions only need special processing when -the full demo is being used. The simply blinky demo has no special requirements, -so these functions are called from the hook functions defined in this file, but -are defined in main_full.c. */ +/* + * Some of the RTOS hook (callback) functions only need special processing when + * the full demo is being used. The simply blinky demo has no special + * requirements, so these functions are called from the hook functions defined + * in this file, but are defined in main_full.c. + */ void vFullDemoTickHookFunction( void ); void vFullDemoIdleFunction( void ); -/* Prototypes for the standard FreeRTOS callback/hook functions implemented -within this file. */ +/* + * This demo uses heap_5.c, so start by defining some heap regions. This is + * only done to provide an example as this demo could easily create one large + * heap region instead of multiple smaller heap regions - in which case heap_4.c + * would be the more appropriate choice. No initialisation is required when + * heap_4.c is used. + */ +static void prvInitialiseHeap( void ); + +/* + * Prototypes for the standard FreeRTOS callback/hook functions implemented + * within this file. + */ void vApplicationMallocFailedHook( void ); void vApplicationIdleHook( void ); void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName ); @@ -145,6 +167,13 @@ static portBASE_TYPE xTraceRunning = pdTRUE; int main( void ) { + /* This demo uses heap_5.c, so start by defining some heap regions. This + is only done to provide an example as this demo could easily create one + large heap region instead of multiple smaller heap regions - in which case + heap_4.c would be the more appropriate choice. No initialisation is + required when heap_4.c is used. */ + prvInitialiseHeap(); + /* Initialise the trace recorder and create the label used to post user events to the trace recording on each tick interrupt. */ vTraceInitTraceData(); @@ -251,10 +280,10 @@ void vApplicationTickHook( void ) } #endif /* mainCREATE_SIMPLE_BLINKY_DEMO_ONLY */ - /* Write a user event to the trace log. + /* Write a user event to the trace log. Note tick events will not appear in the trace recording with regular period because this project runs in a Windows simulator, and does not therefore - exhibit deterministic behaviour. Windows will run the simulator in + exhibit deterministic behaviour. Windows will run the simulator in bursts. */ vTraceUserEvent( xTickTraceUserEvent ); } @@ -263,26 +292,35 @@ void vApplicationTickHook( void ) void vAssertCalled( unsigned long ulLine, const char * const pcFileName ) { static portBASE_TYPE xPrinted = pdFALSE; +volatile uint32_t ulSetToNonZeroInDebuggerToContinue = 0; /* Parameters are not used. */ ( void ) ulLine; ( void ) pcFileName; - taskDISABLE_INTERRUPTS(); - __asm volatile( "int $3" ); - - /* Stop the trace recording. */ - if( xPrinted == pdFALSE ) + taskENTER_CRITICAL(); { - xPrinted = pdTRUE; - if( xTraceRunning == pdTRUE ) + /* Stop the trace recording. */ + if( xPrinted == pdFALSE ) + { + xPrinted = pdTRUE; + if( xTraceRunning == pdTRUE ) + { + vTraceStop(); + prvSaveTraceFile(); + } + } + + /* You can step out of this function to debug the assertion by using + the debugger to set ulSetToNonZeroInDebuggerToContinue to a non-zero + value. */ + while( ulSetToNonZeroInDebuggerToContinue == 0 ) { - vTraceStop(); - prvSaveTraceFile(); + __asm volatile( "NOP" ); + __asm volatile( "NOP" ); } } - - taskENABLE_INTERRUPTS(); + taskEXIT_CRITICAL(); } /*-----------------------------------------------------------*/ @@ -303,3 +341,34 @@ FILE* pxOutputFile; printf( "\r\nFailed to create trace dump file\r\n" ); } } +/*-----------------------------------------------------------*/ + +static void prvInitialiseHeap( void ) +{ +/* This demo uses heap_5.c, so start by defining some heap regions. This is +only done to provide an example as this demo could easily create one large heap +region instead of multiple smaller heap regions - in which case heap_4.c would +be the more appropriate choice. No initialisation is required when heap_4.c is +used. The xHeapRegions structure requires the regions to be defined in order, +so this just creates one big array, then populates the structure with offsets +into the array - with gaps in between and messy alignment just for test +purposes. */ +static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ]; +volatile uint32_t ulAdditionalOffset = 19; /* Just to prevent 'condition is always true' warnings in configASSERT(). */ +const HeapRegion_t xHeapRegions[] = +{ + /* Start address with dummy offsets Size */ + { ucHeap + 1, mainREGION_1_SIZE }, + { ucHeap + 15 + mainREGION_1_SIZE, mainREGION_2_SIZE }, + { ucHeap + 19 + mainREGION_1_SIZE + mainREGION_2_SIZE, mainREGION_3_SIZE }, + { NULL, 0 } +}; + + /* Sanity check that the sizes and offsets defined actually fit into the + array. */ + configASSERT( ( ulAdditionalOffset + mainREGION_1_SIZE + mainREGION_2_SIZE + mainREGION_3_SIZE ) < configTOTAL_HEAP_SIZE ); + + vPortDefineHeapRegions( xHeapRegions ); +} +/*-----------------------------------------------------------*/ + diff --git a/FreeRTOS/Demo/WIN32-MingW/main_blinky.c b/FreeRTOS/Demo/WIN32-MingW/main_blinky.c index fa71ac8ec..4a64748d7 100644 --- a/FreeRTOS/Demo/WIN32-MingW/main_blinky.c +++ b/FreeRTOS/Demo/WIN32-MingW/main_blinky.c @@ -190,6 +190,7 @@ static void prvQueueSendTask( void *pvParameters ) { TickType_t xNextWakeTime; const unsigned long ulValueToSend = 100UL; +const TickType_t xBlockTime = pdMS_TO_TICKS( mainQUEUE_SEND_FREQUENCY_MS ); /* Remove compiler warning in the case that configASSERT() is not defined. */ @@ -207,7 +208,7 @@ const unsigned long ulValueToSend = 100UL; The block time is specified in ticks, the constant used converts ticks to ms. While in the Blocked state this task will not consume any CPU time. */ - vTaskDelayUntil( &xNextWakeTime, mainQUEUE_SEND_FREQUENCY_MS ); + vTaskDelayUntil( &xNextWakeTime, xBlockTime ); /* Send to the queue - causing the queue receive task to unblock and toggle the LED. 0 is used as the block time so the sending operation diff --git a/FreeRTOS/Demo/WIN32-MingW/main_full.c b/FreeRTOS/Demo/WIN32-MingW/main_full.c index aa27e22ac..0bc7d12f8 100644 --- a/FreeRTOS/Demo/WIN32-MingW/main_full.c +++ b/FreeRTOS/Demo/WIN32-MingW/main_full.c @@ -133,6 +133,8 @@ #include "QueueSet.h" #include "QueueOverwrite.h" #include "EventGroupsDemo.h" +#include "IntSemTest.h" +#include "TaskNotify.h" /* Priorities at which the tasks are created. */ #define mainCHECK_TASK_PRIORITY ( configMAX_PRIORITIES - 2 ) @@ -162,7 +164,7 @@ static void prvTestTask( void *pvParameters ); static void prvDemonstrateTaskStateAndHandleGetFunctions( void ); /* - * Called from the idle task hook function to demonstrate the use of + * Called from the idle task hook function to demonstrate the use of * xTimerPendFunctionCall() as xTimerPendFunctionCall() is not demonstrated by * any of the standard demo tasks. */ @@ -195,6 +197,7 @@ int main_full( void ) xTaskCreate( prvCheckTask, "Check", configMINIMAL_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY, NULL ); /* Create the standard demo tasks. */ + vStartTaskNotifyTask(); vStartBlockingQueueTasks( mainBLOCK_Q_PRIORITY ); vStartSemaphoreTasks( mainSEM_TEST_PRIORITY ); vStartPolledQueueTasks( mainQUEUE_POLL_PRIORITY ); @@ -209,6 +212,7 @@ int main_full( void ) vStartQueueOverwriteTask( mainQUEUE_OVERWRITE_PRIORITY ); xTaskCreate( prvDemoQueueSpaceFunctions, "QSpace", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL ); vStartEventGroupTasks(); + vStartInterruptSemaphoreTasks(); #if( configUSE_PREEMPTION != 0 ) { @@ -263,7 +267,16 @@ const TickType_t xCycleFrequency = 2500 / portTICK_PERIOD_MS; } #endif - if( xAreEventGroupTasksStillRunning() != pdTRUE ) + if( xAreTaskNotificationTasksStillRunning() != pdTRUE ) + { + pcStatusMessage = "Error: Notification"; + } + + if( xAreInterruptSemaphoreTasksStillRunning() != pdTRUE ) + { + pcStatusMessage = "Error: IntSem"; + } + else if( xAreEventGroupTasksStillRunning() != pdTRUE ) { pcStatusMessage = "Error: EventGroup"; } @@ -374,7 +387,7 @@ void *pvAllocated; xMutexToDelete = NULL; } - /* Exercise heap_4 a bit. The malloc failed hook will trap failed + /* Exercise heap_5 a bit. The malloc failed hook will trap failed allocations so there is no need to test here. */ pvAllocated = pvPortMalloc( ( rand() % 100 ) + 1 ); vPortFree( pvAllocated ); @@ -402,6 +415,12 @@ void vFullDemoTickHookFunction( void ) /* Exercise event groups from interrupts. */ vPeriodicEventGroupsProcessing(); + + /* Exercise giving mutexes from an interrupt. */ + vInterruptSemaphorePeriodicTest(); + + /* Exercise using task notifications from an interrupt. */ + xNotifyTaskFromISR(); } /*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Demo/links_to_doc_pages_for_these_demos.url b/FreeRTOS/Demo/links_to_doc_pages_for_these_demos.url new file mode 100644 index 000000000..1ae5cac2c --- /dev/null +++ b/FreeRTOS/Demo/links_to_doc_pages_for_these_demos.url @@ -0,0 +1,5 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,2 +[InternetShortcut] +URL=http://www.freertos.org/a00090.html +IDList= diff --git a/FreeRTOS/Demo/readme.txt b/FreeRTOS/Demo/readme.txt index 813c257cc..8a744ffd6 100644 --- a/FreeRTOS/Demo/readme.txt +++ b/FreeRTOS/Demo/readme.txt @@ -1,3 +1,6 @@ +Links to a documentation page for each demo are provided on the following +URL: http://www.freertos.org/a00090.html + Each RTOS port has a demo application to demonstrate it's use. + The Demo/Common directory contains the demo application files as described on diff --git a/FreeRTOS/License/license.txt b/FreeRTOS/License/license.txt index 536423100..423f3d181 100644 --- a/FreeRTOS/License/license.txt +++ b/FreeRTOS/License/license.txt @@ -35,8 +35,10 @@ work under terms of your choice, provided that + The combined work is not itself an RTOS, scheduler, kernel or related product. - + The independent modules add significant and primary functionality to FreeRTOS - and do not merely extend the existing functionality already present in FreeRTOS. + + The independent modules add significant and primary functionality that is + unrelated to multitasking, intertask communication or intertask signalling - + and therefore do not merely extend the functionality already present in + FreeRTOS. Clause 2: diff --git a/FreeRTOS/Source/event_groups.c b/FreeRTOS/Source/event_groups.c index 25017ad6f..f82a96d02 100644 --- a/FreeRTOS/Source/event_groups.c +++ b/FreeRTOS/Source/event_groups.c @@ -276,6 +276,7 @@ BaseType_t xTimeoutOccurred = pdFALSE; /* Check the user is not attempting to wait on the bits used by the kernel itself, and that at least one bit is being requested. */ + configASSERT( xEventGroup ); configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 ); configASSERT( uxBitsToWaitFor != 0 ); #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) @@ -421,6 +422,7 @@ EventBits_t uxReturn; /* Check the user is not attempting to clear the bits used by the kernel itself. */ + configASSERT( xEventGroup ); configASSERT( ( uxBitsToClear & eventEVENT_BITS_CONTROL_BYTES ) == 0 ); taskENTER_CRITICAL(); @@ -482,6 +484,7 @@ BaseType_t xMatchFound = pdFALSE; /* Check the user is not attempting to set the bits used by the kernel itself. */ + configASSERT( xEventGroup ); configASSERT( ( uxBitsToSet & eventEVENT_BITS_CONTROL_BYTES ) == 0 ); pxList = &( pxEventBits->xTasksWaitingForBits ); diff --git a/FreeRTOS/Source/include/FreeRTOS.h b/FreeRTOS/Source/include/FreeRTOS.h index 5b9f03107..7fa5d5d10 100644 --- a/FreeRTOS/Source/include/FreeRTOS.h +++ b/FreeRTOS/Source/include/FreeRTOS.h @@ -723,6 +723,10 @@ extern "C" { #define configAPPLICATION_ALLOCATED_HEAP 0 #endif +#ifndef configUSE_TASK_NOTIFICATIONS + #define configUSE_TASK_NOTIFICATIONS 1 +#endif + /* Definitions to allow backward compatibility with FreeRTOS versions prior to V8 if desired. */ #ifndef configENABLE_BACKWARD_COMPATIBILITY diff --git a/FreeRTOS/Source/include/deprecated_definitions.h b/FreeRTOS/Source/include/deprecated_definitions.h new file mode 100644 index 000000000..f9cd441b1 --- /dev/null +++ b/FreeRTOS/Source/include/deprecated_definitions.h @@ -0,0 +1,317 @@ +/* + FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that has become a de facto standard. * + * * + * Help yourself get started quickly and support the FreeRTOS * + * project by purchasing a FreeRTOS tutorial book, reference * + * manual, or both from: http://www.FreeRTOS.org/Documentation * + * * + * Thank you! * + * * + *************************************************************************** + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available from the following + link: http://www.freertos.org/a00114.html + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef DEPRECATED_DEFINITIONS_H +#define DEPRECATED_DEFINITIONS_H + + +/* Each FreeRTOS port has a unique portmacro.h header file. Originally a +pre-processor definition was used to ensure the pre-processor found the correct +portmacro.h file for the port being used. That scheme was deprecated in favour +of setting the compiler's include path such that it found the correct +portmacro.h file - removing the need for the constant and allowing the +portmacro.h file to be located anywhere in relation to the port being used. The +definitions below remain in the code for backward compatibility only. New +projects should not use them. */ + +#ifdef OPEN_WATCOM_INDUSTRIAL_PC_PORT + #include "..\..\Source\portable\owatcom\16bitdos\pc\portmacro.h" + typedef void ( __interrupt __far *pxISR )(); +#endif + +#ifdef OPEN_WATCOM_FLASH_LITE_186_PORT + #include "..\..\Source\portable\owatcom\16bitdos\flsh186\portmacro.h" + typedef void ( __interrupt __far *pxISR )(); +#endif + +#ifdef GCC_MEGA_AVR + #include "../portable/GCC/ATMega323/portmacro.h" +#endif + +#ifdef IAR_MEGA_AVR + #include "../portable/IAR/ATMega323/portmacro.h" +#endif + +#ifdef MPLAB_PIC24_PORT + #include "../../Source/portable/MPLAB/PIC24_dsPIC/portmacro.h" +#endif + +#ifdef MPLAB_DSPIC_PORT + #include "../../Source/portable/MPLAB/PIC24_dsPIC/portmacro.h" +#endif + +#ifdef MPLAB_PIC18F_PORT + #include "../../Source/portable/MPLAB/PIC18F/portmacro.h" +#endif + +#ifdef MPLAB_PIC32MX_PORT + #include "../../Source/portable/MPLAB/PIC32MX/portmacro.h" +#endif + +#ifdef _FEDPICC + #include "libFreeRTOS/Include/portmacro.h" +#endif + +#ifdef SDCC_CYGNAL + #include "../../Source/portable/SDCC/Cygnal/portmacro.h" +#endif + +#ifdef GCC_ARM7 + #include "../../Source/portable/GCC/ARM7_LPC2000/portmacro.h" +#endif + +#ifdef GCC_ARM7_ECLIPSE + #include "portmacro.h" +#endif + +#ifdef ROWLEY_LPC23xx + #include "../../Source/portable/GCC/ARM7_LPC23xx/portmacro.h" +#endif + +#ifdef IAR_MSP430 + #include "..\..\Source\portable\IAR\MSP430\portmacro.h" +#endif + +#ifdef GCC_MSP430 + #include "../../Source/portable/GCC/MSP430F449/portmacro.h" +#endif + +#ifdef ROWLEY_MSP430 + #include "../../Source/portable/Rowley/MSP430F449/portmacro.h" +#endif + +#ifdef ARM7_LPC21xx_KEIL_RVDS + #include "..\..\Source\portable\RVDS\ARM7_LPC21xx\portmacro.h" +#endif + +#ifdef SAM7_GCC + #include "../../Source/portable/GCC/ARM7_AT91SAM7S/portmacro.h" +#endif + +#ifdef SAM7_IAR + #include "..\..\Source\portable\IAR\AtmelSAM7S64\portmacro.h" +#endif + +#ifdef SAM9XE_IAR + #include "..\..\Source\portable\IAR\AtmelSAM9XE\portmacro.h" +#endif + +#ifdef LPC2000_IAR + #include "..\..\Source\portable\IAR\LPC2000\portmacro.h" +#endif + +#ifdef STR71X_IAR + #include "..\..\Source\portable\IAR\STR71x\portmacro.h" +#endif + +#ifdef STR75X_IAR + #include "..\..\Source\portable\IAR\STR75x\portmacro.h" +#endif + +#ifdef STR75X_GCC + #include "..\..\Source\portable\GCC\STR75x\portmacro.h" +#endif + +#ifdef STR91X_IAR + #include "..\..\Source\portable\IAR\STR91x\portmacro.h" +#endif + +#ifdef GCC_H8S + #include "../../Source/portable/GCC/H8S2329/portmacro.h" +#endif + +#ifdef GCC_AT91FR40008 + #include "../../Source/portable/GCC/ARM7_AT91FR40008/portmacro.h" +#endif + +#ifdef RVDS_ARMCM3_LM3S102 + #include "../../Source/portable/RVDS/ARM_CM3/portmacro.h" +#endif + +#ifdef GCC_ARMCM3_LM3S102 + #include "../../Source/portable/GCC/ARM_CM3/portmacro.h" +#endif + +#ifdef GCC_ARMCM3 + #include "../../Source/portable/GCC/ARM_CM3/portmacro.h" +#endif + +#ifdef IAR_ARM_CM3 + #include "../../Source/portable/IAR/ARM_CM3/portmacro.h" +#endif + +#ifdef IAR_ARMCM3_LM + #include "../../Source/portable/IAR/ARM_CM3/portmacro.h" +#endif + +#ifdef HCS12_CODE_WARRIOR + #include "../../Source/portable/CodeWarrior/HCS12/portmacro.h" +#endif + +#ifdef MICROBLAZE_GCC + #include "../../Source/portable/GCC/MicroBlaze/portmacro.h" +#endif + +#ifdef TERN_EE + #include "..\..\Source\portable\Paradigm\Tern_EE\small\portmacro.h" +#endif + +#ifdef GCC_HCS12 + #include "../../Source/portable/GCC/HCS12/portmacro.h" +#endif + +#ifdef GCC_MCF5235 + #include "../../Source/portable/GCC/MCF5235/portmacro.h" +#endif + +#ifdef COLDFIRE_V2_GCC + #include "../../../Source/portable/GCC/ColdFire_V2/portmacro.h" +#endif + +#ifdef COLDFIRE_V2_CODEWARRIOR + #include "../../Source/portable/CodeWarrior/ColdFire_V2/portmacro.h" +#endif + +#ifdef GCC_PPC405 + #include "../../Source/portable/GCC/PPC405_Xilinx/portmacro.h" +#endif + +#ifdef GCC_PPC440 + #include "../../Source/portable/GCC/PPC440_Xilinx/portmacro.h" +#endif + +#ifdef _16FX_SOFTUNE + #include "..\..\Source\portable\Softune\MB96340\portmacro.h" +#endif + +#ifdef BCC_INDUSTRIAL_PC_PORT + /* A short file name has to be used in place of the normal + FreeRTOSConfig.h when using the Borland compiler. */ + #include "frconfig.h" + #include "..\portable\BCC\16BitDOS\PC\prtmacro.h" + typedef void ( __interrupt __far *pxISR )(); +#endif + +#ifdef BCC_FLASH_LITE_186_PORT + /* A short file name has to be used in place of the normal + FreeRTOSConfig.h when using the Borland compiler. */ + #include "frconfig.h" + #include "..\portable\BCC\16BitDOS\flsh186\prtmacro.h" + typedef void ( __interrupt __far *pxISR )(); +#endif + +#ifdef __GNUC__ + #ifdef __AVR32_AVR32A__ + #include "portmacro.h" + #endif +#endif + +#ifdef __ICCAVR32__ + #ifdef __CORE__ + #if __CORE__ == __AVR32A__ + #include "portmacro.h" + #endif + #endif +#endif + +#ifdef __91467D + #include "portmacro.h" +#endif + +#ifdef __96340 + #include "portmacro.h" +#endif + + +#ifdef __IAR_V850ES_Fx3__ + #include "../../Source/portable/IAR/V850ES/portmacro.h" +#endif + +#ifdef __IAR_V850ES_Jx3__ + #include "../../Source/portable/IAR/V850ES/portmacro.h" +#endif + +#ifdef __IAR_V850ES_Jx3_L__ + #include "../../Source/portable/IAR/V850ES/portmacro.h" +#endif + +#ifdef __IAR_V850ES_Jx2__ + #include "../../Source/portable/IAR/V850ES/portmacro.h" +#endif + +#ifdef __IAR_V850ES_Hx2__ + #include "../../Source/portable/IAR/V850ES/portmacro.h" +#endif + +#ifdef __IAR_78K0R_Kx3__ + #include "../../Source/portable/IAR/78K0R/portmacro.h" +#endif + +#ifdef __IAR_78K0R_Kx3L__ + #include "../../Source/portable/IAR/78K0R/portmacro.h" +#endif + +#endif /* DEPRECATED_DEFINITIONS_H */ + diff --git a/FreeRTOS/Source/include/portable.h b/FreeRTOS/Source/include/portable.h index 0fbaa51e1..6664ee237 100644 --- a/FreeRTOS/Source/include/portable.h +++ b/FreeRTOS/Source/include/portable.h @@ -70,253 +70,22 @@ #ifndef PORTABLE_H #define PORTABLE_H -/* Include the macro file relevant to the port being used. -NOTE: The following definitions are *DEPRECATED* as it is preferred to instead -just add the path to the correct portmacro.h header file to the compiler's -include path. */ -#ifdef OPEN_WATCOM_INDUSTRIAL_PC_PORT - #include "..\..\Source\portable\owatcom\16bitdos\pc\portmacro.h" - typedef void ( __interrupt __far *pxISR )(); -#endif - -#ifdef OPEN_WATCOM_FLASH_LITE_186_PORT - #include "..\..\Source\portable\owatcom\16bitdos\flsh186\portmacro.h" - typedef void ( __interrupt __far *pxISR )(); -#endif - -#ifdef GCC_MEGA_AVR - #include "../portable/GCC/ATMega323/portmacro.h" -#endif - -#ifdef IAR_MEGA_AVR - #include "../portable/IAR/ATMega323/portmacro.h" -#endif - -#ifdef MPLAB_PIC24_PORT - #include "../../Source/portable/MPLAB/PIC24_dsPIC/portmacro.h" -#endif - -#ifdef MPLAB_DSPIC_PORT - #include "../../Source/portable/MPLAB/PIC24_dsPIC/portmacro.h" -#endif - -#ifdef MPLAB_PIC18F_PORT - #include "../../Source/portable/MPLAB/PIC18F/portmacro.h" -#endif - -#ifdef MPLAB_PIC32MX_PORT - #include "../../Source/portable/MPLAB/PIC32MX/portmacro.h" -#endif - -#ifdef _FEDPICC - #include "libFreeRTOS/Include/portmacro.h" -#endif - -#ifdef SDCC_CYGNAL - #include "../../Source/portable/SDCC/Cygnal/portmacro.h" -#endif - -#ifdef GCC_ARM7 - #include "../../Source/portable/GCC/ARM7_LPC2000/portmacro.h" -#endif - -#ifdef GCC_ARM7_ECLIPSE - #include "portmacro.h" -#endif - -#ifdef ROWLEY_LPC23xx - #include "../../Source/portable/GCC/ARM7_LPC23xx/portmacro.h" -#endif - -#ifdef IAR_MSP430 - #include "..\..\Source\portable\IAR\MSP430\portmacro.h" -#endif - -#ifdef GCC_MSP430 - #include "../../Source/portable/GCC/MSP430F449/portmacro.h" -#endif - -#ifdef ROWLEY_MSP430 - #include "../../Source/portable/Rowley/MSP430F449/portmacro.h" -#endif - -#ifdef ARM7_LPC21xx_KEIL_RVDS - #include "..\..\Source\portable\RVDS\ARM7_LPC21xx\portmacro.h" -#endif - -#ifdef SAM7_GCC - #include "../../Source/portable/GCC/ARM7_AT91SAM7S/portmacro.h" -#endif - -#ifdef SAM7_IAR - #include "..\..\Source\portable\IAR\AtmelSAM7S64\portmacro.h" -#endif - -#ifdef SAM9XE_IAR - #include "..\..\Source\portable\IAR\AtmelSAM9XE\portmacro.h" -#endif - -#ifdef LPC2000_IAR - #include "..\..\Source\portable\IAR\LPC2000\portmacro.h" -#endif - -#ifdef STR71X_IAR - #include "..\..\Source\portable\IAR\STR71x\portmacro.h" -#endif - -#ifdef STR75X_IAR - #include "..\..\Source\portable\IAR\STR75x\portmacro.h" -#endif - -#ifdef STR75X_GCC - #include "..\..\Source\portable\GCC\STR75x\portmacro.h" -#endif - -#ifdef STR91X_IAR - #include "..\..\Source\portable\IAR\STR91x\portmacro.h" -#endif - -#ifdef GCC_H8S - #include "../../Source/portable/GCC/H8S2329/portmacro.h" -#endif - -#ifdef GCC_AT91FR40008 - #include "../../Source/portable/GCC/ARM7_AT91FR40008/portmacro.h" -#endif - -#ifdef RVDS_ARMCM3_LM3S102 - #include "../../Source/portable/RVDS/ARM_CM3/portmacro.h" -#endif - -#ifdef GCC_ARMCM3_LM3S102 - #include "../../Source/portable/GCC/ARM_CM3/portmacro.h" -#endif - -#ifdef GCC_ARMCM3 - #include "../../Source/portable/GCC/ARM_CM3/portmacro.h" -#endif - -#ifdef IAR_ARM_CM3 - #include "../../Source/portable/IAR/ARM_CM3/portmacro.h" -#endif - -#ifdef IAR_ARMCM3_LM - #include "../../Source/portable/IAR/ARM_CM3/portmacro.h" -#endif - -#ifdef HCS12_CODE_WARRIOR - #include "../../Source/portable/CodeWarrior/HCS12/portmacro.h" -#endif - -#ifdef MICROBLAZE_GCC - #include "../../Source/portable/GCC/MicroBlaze/portmacro.h" -#endif - -#ifdef TERN_EE - #include "..\..\Source\portable\Paradigm\Tern_EE\small\portmacro.h" -#endif - -#ifdef GCC_HCS12 - #include "../../Source/portable/GCC/HCS12/portmacro.h" -#endif - -#ifdef GCC_MCF5235 - #include "../../Source/portable/GCC/MCF5235/portmacro.h" -#endif - -#ifdef COLDFIRE_V2_GCC - #include "../../../Source/portable/GCC/ColdFire_V2/portmacro.h" -#endif - -#ifdef COLDFIRE_V2_CODEWARRIOR - #include "../../Source/portable/CodeWarrior/ColdFire_V2/portmacro.h" -#endif - -#ifdef GCC_PPC405 - #include "../../Source/portable/GCC/PPC405_Xilinx/portmacro.h" -#endif - -#ifdef GCC_PPC440 - #include "../../Source/portable/GCC/PPC440_Xilinx/portmacro.h" -#endif - -#ifdef _16FX_SOFTUNE - #include "..\..\Source\portable\Softune\MB96340\portmacro.h" -#endif - -#ifdef BCC_INDUSTRIAL_PC_PORT - /* A short file name has to be used in place of the normal - FreeRTOSConfig.h when using the Borland compiler. */ - #include "frconfig.h" - #include "..\portable\BCC\16BitDOS\PC\prtmacro.h" - typedef void ( __interrupt __far *pxISR )(); -#endif - -#ifdef BCC_FLASH_LITE_186_PORT - /* A short file name has to be used in place of the normal - FreeRTOSConfig.h when using the Borland compiler. */ - #include "frconfig.h" - #include "..\portable\BCC\16BitDOS\flsh186\prtmacro.h" - typedef void ( __interrupt __far *pxISR )(); -#endif - -#ifdef __GNUC__ - #ifdef __AVR32_AVR32A__ - #include "portmacro.h" - #endif -#endif - -#ifdef __ICCAVR32__ - #ifdef __CORE__ - #if __CORE__ == __AVR32A__ - #include "portmacro.h" - #endif - #endif -#endif - -#ifdef __91467D - #include "portmacro.h" -#endif - -#ifdef __96340 - #include "portmacro.h" -#endif - - -#ifdef __IAR_V850ES_Fx3__ - #include "../../Source/portable/IAR/V850ES/portmacro.h" -#endif - -#ifdef __IAR_V850ES_Jx3__ - #include "../../Source/portable/IAR/V850ES/portmacro.h" -#endif - -#ifdef __IAR_V850ES_Jx3_L__ - #include "../../Source/portable/IAR/V850ES/portmacro.h" -#endif - -#ifdef __IAR_V850ES_Jx2__ - #include "../../Source/portable/IAR/V850ES/portmacro.h" -#endif - -#ifdef __IAR_V850ES_Hx2__ - #include "../../Source/portable/IAR/V850ES/portmacro.h" -#endif - -#ifdef __IAR_78K0R_Kx3__ - #include "../../Source/portable/IAR/78K0R/portmacro.h" -#endif - -#ifdef __IAR_78K0R_Kx3L__ - #include "../../Source/portable/IAR/78K0R/portmacro.h" -#endif - -/* Catch all to ensure portmacro.h is included in the build. Newer demos -have the path as part of the project options, rather than as relative from -the project location. If portENTER_CRITICAL() has not been defined then -portmacro.h has not yet been included - as every portmacro.h provides a -portENTER_CRITICAL() definition. Check the demo application for your demo -to find the path to the correct portmacro.h file. */ +/* Each FreeRTOS port has a unique portmacro.h header file. Originally a +pre-processor definition was used to ensure the pre-processor found the correct +portmacro.h file for the port being used. That scheme was deprecated in favour +of setting the compiler's include path such that it found the correct +portmacro.h file - removing the need for the constant and allowing the +portmacro.h file to be located anywhere in relation to the port being used. +Purely for reasons of backward compatibility the old method is still valid, but +to make it clear that new projects should not use it, support for the port +specific constants has been moved into the deprecated_definitions.h header +file. */ +#include "deprecated_definitions.h" + +/* If portENTER_CRITICAL is not defined then including deprecated_definitions.h +did not result in a portmacro.h header file being included - and it should be +included here. In this case the path to the correct portmacro.h header file +must be set in the compiler's include path. */ #ifndef portENTER_CRITICAL #include "portmacro.h" #endif @@ -370,15 +139,15 @@ typedef struct HeapRegion size_t xSizeInBytes; } HeapRegion_t; -/* +/* * Used to define multiple heap regions for use by heap_5.c. This function * must be called before any calls to pvPortMalloc() - not creating a task, * queue, semaphore, mutex, software timer, event group, etc. will result in * pvPortMalloc being called. * * pxHeapRegions passes in an array of HeapRegion_t structures - each of which - * defines a region of memory that can be used as the heap. The array is - * terminated by a HeapRegions_t structure that has a size of 0. The region + * defines a region of memory that can be used as the heap. The array is + * terminated by a HeapRegions_t structure that has a size of 0. The region * with the lowest start address must appear first in the array. */ void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions ); diff --git a/FreeRTOS/Source/include/task.h b/FreeRTOS/Source/include/task.h index 78418da87..1ba9748f9 100644 --- a/FreeRTOS/Source/include/task.h +++ b/FreeRTOS/Source/include/task.h @@ -114,13 +114,23 @@ typedef enum eDeleted /* The task being queried has been deleted, but its TCB has not yet been freed. */ } eTaskState; +/* Actions that can be performed when vTaskNotify() is called. */ +typedef enum +{ + eNoAction, /* Notify the task without updating its notify value. */ + eSetBits, /* Set bits in the task's notification value. */ + eIncrement, /* Increment the task's notification value. */ + eSetValueWithOverwrite, /* Set the task's notification value to a specific value even if the previous value has not yet been read by the task. */ + eSetValueWithoutOverwrite /* Set the task's notification value if the previous value has been read by the task. */ +} eNotifyAction; + /* * Used internally only. */ typedef struct xTIME_OUT { BaseType_t xOverflowCount; - TickType_t xTimeOnEntering; + TickType_t xTimeOnEntering; } TimeOut_t; /* @@ -1358,6 +1368,432 @@ void vTaskList( char * pcWriteBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unquali */ void vTaskGetRunTimeStats( char *pcWriteBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +/** + * task. h + *
BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction );
+ * + * configUSE_TASK_NOTIFICATIONS must be defined as 1 for this function to be + * available. + * + * When configUSE_TASK_NOTIFICATIONS is set to one each task has its own private + * "notification value", which is a 32-bit unsigned integer (uint32_t). + * + * Events can be sent to a task using an intermediary object. Examples of such + * objects are queues, semaphores, mutexes and event groups. Task notifications + * are a method of sending an event directly to a task without the need for such + * an intermediary object. + * + * A notification sent to a task can optionally perform an action, such as + * update, overwrite or increment the task's notification value. In that way + * task notifications can be used to send data to a task, or be used as light + * weight and fast binary or counting semaphores. + * + * A notification sent to a task will remain pending until it is cleared by the + * task calling xTaskNotifyWait() or ulTaskNotifyTake(). If the task was + * already in the Blocked state to wait for a notification when the notification + * arrives then the task will automatically be removed from the Blocked state + * (unblocked) and the notification cleared. + * + * A task can use xTaskNotifyWait() to [optionally] block to wait for a + * notification to be pending, or xTaskNotifyTake() to [optionally] block + * to wait for its notification value to have a non-zero value. The task does + * not consume any CPU time while it is in the Blocked state. + * + * See http://www.FreeRTOS.org/RTOS_task_notifications.html for details of when + * it is best to use a task notification to send an event to a task compared to + * when it is best to use an intermediary object (such as a queue, semaphore, + * mutex or event group) to send an event to a task. + * + * @param xTaskToNotify The handle of the task being notified. The handle to a + * task can be returned from the xTaskCreate() API function used to create the + * task, and the handle of the currently running task can be obtained by calling + * xTaskGetCurrentTaskHandle(). + * + * @param ulValue Data that can be sent with the notification. How the data is + * used depends on the value of the eAction parameter. + * + * @param eAction Specifies how the notification updates the task's notification + * value, if at all. Valid values for eAction are as follows: + * + * eSetBits - + * The task's notification value is bitwise ORed with ulValue. xTaskNofify() + * always returns pdPASS in this case. + * + * eIncrement - + * The task's notification value is incremented. ulValue is not used and + * xTaskNotify() always returns pdPASS in this case. + * + * eSetValueWithOverwrite - + * The task's notification value is set to the value of ulValue, even if the + * task being notified had not yet processed the previous notification (the + * task already had a notification pending). xTaskNotify() always returns + * pdPASS in this case. + * + * eSetValueWithoutOverwrite - + * If the task being notified did not already have a notification pending then + * the task's notification value is set to ulValue and xTaskNotify() will + * return pdPASS. If the task being notified already had a notification + * pending then no action is performed and pdFAIL is returned. + * + * eNoAction - + * The task receives a notification without its notification value being + * updated. ulValue is not used and xTaskNotify() always returns pdPASS in + * this case. + * + * @return Dependent on the value of eAction. See the description of the + * eAction parameter. + * + * \defgroup xTaskNotify xTaskNotify + * \ingroup TaskNotifications + */ +BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction ); + +/** + * task. h + *
BaseType_t xTaskNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, BaseType_t *pxHigherPriorityTaskWoken );
+ * + * configUSE_TASK_NOTIFICATIONS must be defined as 1 for this function to be + * available. + * + * When configUSE_TASK_NOTIFICATIONS is set to one each task has its own private + * "notification value", which is a 32-bit unsigned integer (uint32_t). + * + * A version of xTaskNotify() that can be used from an interrupt service routine + * (ISR). + * + * Events can be sent to a task using an intermediary object. Examples of such + * objects are queues, semaphores, mutexes and event groups. Task notifications + * are a method of sending an event directly to a task without the need for such + * an intermediary object. + * + * A notification sent to a task can optionally perform an action, such as + * update, overwrite or increment the task's notification value. In that way + * task notifications can be used to send data to a task, or be used as light + * weight and fast binary or counting semaphores. + * + * A notification sent to a task will remain pending until it is cleared by the + * task calling xTaskNotifyWait() or ulTaskNotifyTake(). If the task was + * already in the Blocked state to wait for a notification when the notification + * arrives then the task will automatically be removed from the Blocked state + * (unblocked) and the notification cleared. + * + * A task can use xTaskNotifyWait() to [optionally] block to wait for a + * notification to be pending, or xTaskNotifyTake() to [optionally] block + * to wait for its notification value to have a non-zero value. The task does + * not consume any CPU time while it is in the Blocked state. + * + * See http://www.FreeRTOS.org/RTOS_task_notifications.html for details of when + * it is best to use a task notification to send an event to a task compared to + * when it is best to use an intermediary object (such as a queue, semaphore, + * mutex or event group) to send an event to a task. + * + * @param xTaskToNotify The handle of the task being notified. The handle to a + * task can be returned from the xTaskCreate() API function used to create the + * task, and the handle of the currently running task can be obtained by calling + * xTaskGetCurrentTaskHandle(). + * + * @param ulValue Data that can be sent with the notification. How the data is + * used depends on the value of the eAction parameter. + * + * @param eAction Specifies how the notification updates the task's notification + * value, if at all. Valid values for eAction are as follows: + * + * eSetBits - + * The task's notification value is bitwise ORed with ulValue. xTaskNofify() + * always returns pdPASS in this case. + * + * eIncrement - + * The task's notification value is incremented. ulValue is not used and + * xTaskNotify() always returns pdPASS in this case. + * + * eSetValueWithOverwrite - + * The task's notification value is set to the value of ulValue, even if the + * task being notified had not yet processed the previous notification (the + * task already had a notification pending). xTaskNotify() always returns + * pdPASS in this case. + * + * eSetValueWithoutOverwrite - + * If the task being notified did not already have a notification pending then + * the task's notification value is set to ulValue and xTaskNotify() will + * return pdPASS. If the task being notified already had a notification + * pending then no action is performed and pdFAIL is returned. + * + * eNoAction - + * The task receives a notification without its notification value being + * updated. ulValue is not used and xTaskNotify() always returns pdPASS in + * this case. + * + * @param pxHigherPriorityTaskWoken xTaskNotifyFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if sending the notification caused the + * task to which the notification was sent to leave the Blocked state, and the + * unblocked task has a priority higher than the currently running task. If + * xTaskNotifyFromISR() sets this value to pdTRUE then a context switch should + * be requested before the interrupt is exited. How a context switch is + * requested from an ISR is dependent on the port - see the documentation page + * for the port in use. + * + * @return Dependent on the value of eAction. See the description of the + * eAction parameter. + * + * \defgroup xTaskNotify xTaskNotify + * \ingroup TaskNotifications + */ +BaseType_t xTaskNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, BaseType_t *pxHigherPriorityTaskWoken ); + +/** + * task. h + *
BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, BaseType_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait );
+ * + * configUSE_TASK_NOTIFICATIONS must be defined as 1 for this function to be + * available. + * + * When configUSE_TASK_NOTIFICATIONS is set to one each task has its own private + * "notification value", which is a 32-bit unsigned integer (uint32_t). + * + * Events can be sent to a task using an intermediary object. Examples of such + * objects are queues, semaphores, mutexes and event groups. Task notifications + * are a method of sending an event directly to a task without the need for such + * an intermediary object. + * + * A notification sent to a task can optionally perform an action, such as + * update, overwrite or increment the task's notification value. In that way + * task notifications can be used to send data to a task, or be used as light + * weight and fast binary or counting semaphores. + * + * A notification sent to a task will remain pending until it is cleared by the + * task calling xTaskNotifyWait() or ulTaskNotifyTake(). If the task was + * already in the Blocked state to wait for a notification when the notification + * arrives then the task will automatically be removed from the Blocked state + * (unblocked) and the notification cleared. + * + * A task can use xTaskNotifyWait() to [optionally] block to wait for a + * notification to be pending, or xTaskNotifyTake() to [optionally] block + * to wait for its notification value to have a non-zero value. The task does + * not consume any CPU time while it is in the Blocked state. + * + * See http://www.FreeRTOS.org/RTOS_task_notifications.html for details of when + * it is best to use a task notification to send an event to a task compared to + * when it is best to use an intermediary object (such as a queue, semaphore, + * mutex or event group) to send an event to a task. + * + * @param ulBitsToClearOnEntry Bits that are set in ulBitsToClearOnEntry value + * will be cleared in the calling task's notification value before the task + * checks to see if any notifications are pending, and optionally blocks if no + * notifications are pending. Setting ulBitsToClearOnEntry to ULONG_MAX (if + * limits.h is included) or 0xffffffffUL (if limits.h is not included) will have + * the effect of resetting the task's notification value to 0. Setting + * ulBitsToClearOnEntry to 0 will leave the task's notification value unchanged. + * + * @param ulBitsToClearOnExit If a notification is pending or received before + * the calling task exits the xTaskNotifyWait() function then the task's + * notification value (see the xTaskNotify() API function) is passed out using + * the pulNotificationValue parameter. Then any bits that are set in + * ulBitsToClearOnExit will be cleared in the task's notification value (note + * *pulNotificationValue is set before any bits are cleared). Setting + * ulBitsToClearOnExit to ULONG_MAX (if limits.h is included) or 0xffffffffUL + * (if limits.h is not included) will have the effect of resetting the task's + * notification value to 0 before the function exits. Setting + * ulBitsToClearOnExit to 0 will leave the task's notification value unchanged + * when the function exits (in which case the value passed out in + * pulNotificationValue will match the task's notification value). + * + * @param pulNotificationValue Used to pass the task's notification value out + * of the function. Note the value passed out will not be effected by the + * clearing of any bits caused by ulBitsToClearOnExit being non-zero. + * + * @param xTicksToWait The maximum amount of time that the task should wait in + * the Blocked state for a notification to be received, should a notification + * not already be pending when xTaskNotifyWait() was called. The task + * will not consume any processing time while it is in the Blocked state. This + * is specified in kernel ticks, the macro pdMS_TO_TICSK( value_in_ms ) can be + * used to convert a time specified in milliseconds to a time specified in + * ticks. + * + * @return If a notification was received (including notifications that were + * already pending when xTaskNotifyWait was called) then pdPASS is + * returned. Otherwise pdFAIL is returned. + * + * \defgroup xTaskNotifyWait xTaskNotifyWait + * \ingroup TaskNotifications + */ +BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, BaseType_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait ); + +/** + * task. h + *
BaseType_t xTaskNotifyGive( TaskHandle_t xTaskHandle, BaseType_t *pxHigherPriorityTaskWoken );
+ *
+ * configUSE_TASK_NOTIFICATIONS must be defined as 1 for this macro to be
+ * available.
+ *
+ * When configUSE_TASK_NOTIFICATIONS is set to one each task has its own private
+ * "notification value", which is a 32-bit unsigned integer (uint32_t).
+ *
+ * Events can be sent to a task using an intermediary object.  Examples of such
+ * objects are queues, semaphores, mutexes and event groups.  Task notifications
+ * are a method of sending an event directly to a task without the need for such
+ * an intermediary object.
+ *
+ * A notification sent to a task can optionally perform an action, such as
+ * update, overwrite or increment the task's notification value.  In that way
+ * task notifications can be used to send data to a task, or be used as light
+ * weight and fast binary or counting semaphores.
+ *
+ * xTaskNotifyGive() is a helper macro intended for use when task notifications
+ * are used as light weight and faster binary or counting semaphore equivalents.
+ * Actual FreeRTOS semaphores are given using the xSemaphoreGive() API function,
+ * the equivalent action that instead uses a task notification is
+ * xTaskNotifyGive().
+ *
+ * When task notifications are being used as a binary or counting semaphore
+ * equivalent then the task being notified should wait for the notification
+ * using the ulTaskNotificationTake() API function rather than the
+ * xTaskNotifyWait() API function.
+ *
+ * See http://www.FreeRTOS.org/RTOS_task_notifications.html for more details.
+ *
+ * @param xTaskToNotify The handle of the task being notified.  The handle to a
+ * task can be returned from the xTaskCreate() API function used to create the
+ * task, and the handle of the currently running task can be obtained by calling
+ * xTaskGetCurrentTaskHandle().
+ *
+ * @return xTaskNotifyGive() is a macro that calls xTaskNotify() with the
+ * eAction parameter set to eIncrement - so pdPASS is always returned.
+ *
+ * \defgroup xTaskNotifyGive xTaskNotifyGive
+ * \ingroup TaskNotifications
+ */
+#define xTaskNotifyGive( xTaskToNotify ) xTaskNotify( ( xTaskToNotify ), 0, eIncrement );
+
+/**
+ * task. h
+ * 
BaseType_t xTaskNotifyGiveFromISR( TaskHandle_t xTaskHandle, BaseType_t *pxHigherPriorityTaskWoken );
+ *
+ * configUSE_TASK_NOTIFICATIONS must be defined as 1 for this macro to be
+ * available.
+ *
+ * When configUSE_TASK_NOTIFICATIONS is set to one each task has its own private
+ * "notification value", which is a 32-bit unsigned integer (uint32_t).
+ *
+ * A version of xTaskNotifyGive() that can be called from an interrupt service
+ * routine (ISR).
+ *
+ * Events can be sent to a task using an intermediary object.  Examples of such
+ * objects are queues, semaphores, mutexes and event groups.  Task notifications
+ * are a method of sending an event directly to a task without the need for such
+ * an intermediary object.
+ *
+ * A notification sent to a task can optionally perform an action, such as
+ * update, overwrite or increment the task's notification value.  In that way
+ * task notifications can be used to send data to a task, or be used as light
+ * weight and fast binary or counting semaphores.
+ *
+ * xTaskNotifyGiveFromISR() is a helper macro intended for use when task
+ * notifications are used as light weight and faster binary or counting
+ * semaphore equivalents.  Actual FreeRTOS semaphores are given from an ISR
+ * using the xSemaphoreGiveFromISR() API function, the equivalent action that
+ * instead uses a task notification is xTaskNotifyGiveFromISR().
+ *
+ * When task notifications are being used as a binary or counting semaphore
+ * equivalent then the task being notified should wait for the notification
+ * using the ulTaskNotificationTake() API function rather than the
+ * xTaskNotifyWait() API function.
+ *
+ * See http://www.FreeRTOS.org/RTOS_task_notifications.html for more details.
+ *
+ * @param xTaskToNotify The handle of the task being notified.  The handle to a
+ * task can be returned from the xTaskCreate() API function used to create the
+ * task, and the handle of the currently running task can be obtained by calling
+ * xTaskGetCurrentTaskHandle().
+ *
+ * @param pxHigherPriorityTaskWoken  xTaskNotifyGiveFromISR() will set
+ * *pxHigherPriorityTaskWoken to pdTRUE if sending the notification caused the
+ * task to which the notification was sent to leave the Blocked state, and the
+ * unblocked task has a priority higher than the currently running task.  If
+ * xTaskNotifyGiveFromISR() sets this value to pdTRUE then a context switch
+ * should be requested before the interrupt is exited.  How a context switch is
+ * requested from an ISR is dependent on the port - see the documentation page
+ * for the port in use.
+ *
+ * @return xTaskNotifyGiveFromISR() is a macro that calls xTaskNotifyFromISR()
+ * with the eAction parameter set to eIncrement - so pdPASS is always returned.
+ *
+ * \defgroup xTaskNotifyWait xTaskNotifyWait
+ * \ingroup TaskNotifications
+ */
+#define xTaskNotifyGiveFromISR( xTaskToNotify, pxHigherPriorityTaskWoken ) xTaskNotifyFromISR( ( xTaskToNotify ), 0, eIncrement, ( pxHigherPriorityTaskWoken ) )
+
+/**
+ * task. h
+ * 
uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait );
+ * + * configUSE_TASK_NOTIFICATIONS must be defined as 1 for this function to be + * available. + * + * When configUSE_TASK_NOTIFICATIONS is set to one each task has its own private + * "notification value", which is a 32-bit unsigned integer (uint32_t). + * + * Events can be sent to a task using an intermediary object. Examples of such + * objects are queues, semaphores, mutexes and event groups. Task notifications + * are a method of sending an event directly to a task without the need for such + * an intermediary object. + * + * A notification sent to a task can optionally perform an action, such as + * update, overwrite or increment the task's notification value. In that way + * task notifications can be used to send data to a task, or be used as light + * weight and fast binary or counting semaphores. + * + * ulTaskNotifyTake() is intended for use when a task notification is used as a + * faster and lighter weight binary or counting semaphore alternative. Actual + * FreeRTOS semaphores are taken using the xSemaphoreTake() API function, the + * equivalent action that instead uses a task notification is + * xTaskNotifyTake(). + * + * When a task is using its notification value as a binary or counting semaphore + * other tasks should send notifications to it using the xTaskNotifyGive() + * macro, or xTaskNotify() function with the eAction parameter set to + * eIncrement. + * + * xTaskNotifyTake() can either clear the task's notification value to + * zero on exit, in which case the notification value acts like a binary + * semaphore, or decrement the task's notification value on exit, in which case + * the notification value acts like a counting semaphore. + * + * A task can use xTaskNotifyTake() to [optionally] block to wait for a + * the tasks notification value to be non-zero. The task does not consume any + * CPU time while it is in the Blocked state. + * + * Where as xTaskNotifyWait() will return when a notification is pending, + * xTaskNotifyTake() will return when the task's notification value is + * not zero. + * + * See http://www.FreeRTOS.org/RTOS_task_notifications.html for details of when + * it is best to use a task notification to send an event to a task compared to + * when it is best to use an intermediary object (such as a queue, semaphore, + * mutex or event group) to send an event to a task. + * + * @param xClearCountOnExit if xClearCountOnExit is pdFALSE then the task's + * notification value is decremented when the function exits. In this way the + * notification value acts like a counting semaphore. If xClearCountOnExit is + * not pdFALSE then the task's notification value is cleared to zero when the + * function exits. In this way the notification value acts like a binary + * semaphore. + * + * @param xTicksToWait The maximum amount of time that the task should wait in + * the Blocked state for the task's notification value to be greater than zero, + * should the count not already be greater than zero when + * xTaskNotifyTake() was called. The task will not consume any processing + * time while it is in the Blocked state. This is specified in kernel ticks, + * the macro pdMS_TO_TICSK( value_in_ms ) can be used to convert a time + * specified in milliseconds to a time specified in ticks. + * + * @return The task's notification count before it is either cleared to zero or + * decremented (see the xClearCountOnExit parameter). + * + * \defgroup ulTaskNotifyTake ulTaskNotifyTake + * \ingroup TaskNotifications + */ +uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait ); + /*----------------------------------------------------------- * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES *----------------------------------------------------------*/ diff --git a/FreeRTOS/Source/list.c b/FreeRTOS/Source/list.c index 01546e66e..a8d9d5b90 100644 --- a/FreeRTOS/Source/list.c +++ b/FreeRTOS/Source/list.c @@ -125,13 +125,12 @@ const TickType_t xValueOfInsertion = pxNewListItem->xItemValue; /* Insert the new list item into the list, sorted in xItemValue order. - If the list already contains a list item with the same item value then - the new list item should be placed after it. This ensures that TCB's which - are stored in ready lists (all of which have the same xItemValue value) - get an equal share of the CPU. However, if the xItemValue is the same as - the back marker the iteration loop below will not end. This means we need - to guard against this by checking the value first and modifying the - algorithm slightly if necessary. */ + If the list already contains a list item with the same item value then the + new list item should be placed after it. This ensures that TCB's which are + stored in ready lists (all of which have the same xItemValue value) get a + share of the CPU. However, if the xItemValue is the same as the back marker + the iteration loop below will not end. Therefore the value is checked + first, and the algorithm slightly modified if necessary. */ if( xValueOfInsertion == portMAX_DELAY ) { pxIterator = pxList->xListEnd.pxPrevious; @@ -139,27 +138,31 @@ const TickType_t xValueOfInsertion = pxNewListItem->xItemValue; else { /* *** NOTE *********************************************************** - If you find your application is crashing here then likely causes are: + If you find your application is crashing here then likely causes are + listed below. In addition see http://www.freertos.org/FAQHelp.html for + more tips, and ensure configASSERT() is defined! + http://www.freertos.org/a00110.html#configASSERT + 1) Stack overflow - see http://www.freertos.org/Stacks-and-stack-overflow-checking.html - 2) Incorrect interrupt priority assignment, especially on Cortex-M3 + 2) Incorrect interrupt priority assignment, especially on Cortex-M parts where numerically high priority values denote low actual interrupt priorities, which can seem counter intuitive. See - configMAX_SYSCALL_INTERRUPT_PRIORITY on http://www.freertos.org/a00110.html + http://www.freertos.org/RTOS-Cortex-M3-M4.html and the definition + of configMAX_SYSCALL_INTERRUPT_PRIORITY on + http://www.freertos.org/a00110.html 3) Calling an API function from within a critical section or when the scheduler is suspended, or calling an API function that does not end in "FromISR" from an interrupt. 4) Using a queue or semaphore before it has been initialised or before the scheduler has been started (are interrupts firing before vTaskStartScheduler() has been called?). - See http://www.freertos.org/FAQHelp.html for more tips, and ensure - configASSERT() is defined! http://www.freertos.org/a00110.html#configASSERT **********************************************************************/ for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ { - /* There is nothing to do here, we are just iterating to the - wanted insertion position. */ + /* There is nothing to do here, just iterating to the wanted + insertion position. */ } } diff --git a/FreeRTOS/Source/portable/GCC/ARM_CA9/port.c b/FreeRTOS/Source/portable/GCC/ARM_CA9/port.c index 9ce95e636..16998062e 100644 --- a/FreeRTOS/Source/portable/GCC/ARM_CA9/port.c +++ b/FreeRTOS/Source/portable/GCC/ARM_CA9/port.c @@ -167,8 +167,8 @@ the CPU itself before modifying certain hardware registers. */ { \ portCPU_IRQ_DISABLE(); \ portICCPMR_PRIORITY_MASK_REGISTER = portUNMASK_VALUE; \ - __asm( "DSB \n" \ - "ISB \n" ); \ + __asm volatile ( "DSB \n" \ + "ISB \n" ); \ portCPU_IRQ_ENABLE(); \ } diff --git a/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c b/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c index 666a09ddc..554667b7d 100644 --- a/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c +++ b/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c @@ -114,7 +114,7 @@ FreeRTOS.org versions prior to V4.4.0 did not include this definition. */ #define portPRIGROUP_SHIFT ( 8UL ) /* Masks off all bits but the VECTACTIVE bits in the ICSR register. */ -#define portVECTACTIVE_MASK ( 0x1FUL ) +#define portVECTACTIVE_MASK ( 0xFFUL ) /* Constants required to set up the initial stack. */ #define portINITIAL_XPSR ( 0x01000000UL ) diff --git a/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c b/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c index be0ef425a..f67f98f97 100644 --- a/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c +++ b/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c @@ -111,7 +111,7 @@ #define portPRIGROUP_SHIFT ( 8UL ) /* Masks off all bits but the VECTACTIVE bits in the ICSR register. */ -#define portVECTACTIVE_MASK ( 0x1FUL ) +#define portVECTACTIVE_MASK ( 0xFFUL ) /* Constants required to manipulate the VFP. */ #define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating point context control register. */ @@ -384,27 +384,13 @@ void vPortEndScheduler( void ) } /*-----------------------------------------------------------*/ -void vPortYield( void ) -{ - /* Set a PendSV to request a context switch. */ - portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; - - /* Barriers are normally not required but do ensure the code is completely - within the specified behaviour for the architecture. */ - __asm volatile( "dsb" ); - __asm volatile( "isb" ); -} -/*-----------------------------------------------------------*/ - void vPortEnterCritical( void ) { portDISABLE_INTERRUPTS(); uxCriticalNesting++; - __asm volatile( "dsb" ); - __asm volatile( "isb" ); - + /* This is not the interrupt safe version of the enter critical function so - assert() if it is being called from an interrupt context. Only API + assert() if it is being called from an interrupt context. Only API functions that end in "FromISR" can be used in an interrupt. Only assert if the critical nesting count is 1 to protect against recursive calls if the assert function also uses a critical section. */ @@ -426,37 +412,6 @@ void vPortExitCritical( void ) } /*-----------------------------------------------------------*/ -__attribute__(( naked )) uint32_t ulPortSetInterruptMask( void ) -{ - __asm volatile \ - ( \ - " mrs r0, basepri \n" \ - " mov r1, %0 \n" \ - " msr basepri, r1 \n" \ - " bx lr \n" \ - :: "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "r0", "r1" \ - ); - - /* This return will not be reached but is necessary to prevent compiler - warnings. */ - return 0; -} -/*-----------------------------------------------------------*/ - -__attribute__(( naked )) void vPortClearInterruptMask( uint32_t ulNewMaskValue ) -{ - __asm volatile \ - ( \ - " msr basepri, r0 \n" \ - " bx lr \n" \ - :::"r0" \ - ); - - /* Just to avoid compiler warnings. */ - ( void ) ulNewMaskValue; -} -/*-----------------------------------------------------------*/ - void xPortPendSVHandler( void ) { /* This is a naked function. */ @@ -480,6 +435,8 @@ void xPortPendSVHandler( void ) " stmdb sp!, {r3} \n" " mov r0, %0 \n" " msr basepri, r0 \n" + " dsb \n" + " isb \n" " bl vTaskSwitchContext \n" " mov r0, #0 \n" " msr basepri, r0 \n" diff --git a/FreeRTOS/Source/portable/GCC/ARM_CM4F/portmacro.h b/FreeRTOS/Source/portable/GCC/ARM_CM4F/portmacro.h index 763935dce..41f1fbc7d 100644 --- a/FreeRTOS/Source/portable/GCC/ARM_CM4F/portmacro.h +++ b/FreeRTOS/Source/portable/GCC/ARM_CM4F/portmacro.h @@ -109,25 +109,21 @@ typedef unsigned long UBaseType_t; #define portBYTE_ALIGNMENT 8 /*-----------------------------------------------------------*/ - /* Scheduler utilities. */ -extern void vPortYield( void ); #define portNVIC_INT_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000ed04 ) ) #define portNVIC_PENDSVSET_BIT ( 1UL << 28UL ) -#define portYIELD() vPortYield() -#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT +#define portYIELD() vPortYield() +#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) vPortYield() #define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x ) /*-----------------------------------------------------------*/ /* Critical section management. */ extern void vPortEnterCritical( void ); extern void vPortExitCritical( void ); -extern uint32_t ulPortSetInterruptMask( void ); -extern void vPortClearInterruptMask( uint32_t ulNewMaskValue ); -#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortSetInterruptMask() -#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortClearInterruptMask(x) -#define portDISABLE_INTERRUPTS() ulPortSetInterruptMask() -#define portENABLE_INTERRUPTS() vPortClearInterruptMask(0) +#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortRaiseBASEPRI() +#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortSetBASEPRI(x) +#define portDISABLE_INTERRUPTS() ulPortRaiseBASEPRI() +#define portENABLE_INTERRUPTS() vPortSetBASEPRI(0) #define portENTER_CRITICAL() vPortEnterCritical() #define portEXIT_CRITICAL() vPortExitCritical() @@ -188,6 +184,53 @@ not necessary for to use this port. They are defined so the common demo files /* portNOP() is not required by this port. */ #define portNOP() +#ifndef portFORCE_INLINE + #define portFORCE_INLINE inline __attribute__(( always_inline)) +#endif + +/*-----------------------------------------------------------*/ + +portFORCE_INLINE static uint32_t ulPortRaiseBASEPRI( void ) +{ +uint32_t ulOriginalBASEPRI, ulNewBASEPRI; + + __asm volatile + ( + " mrs %0, basepri \n" \ + " mov %1, %2 \n" \ + " msr basepri, %1 \n" \ + " isb \n" \ + " dsb \n" \ + :"=r" (ulOriginalBASEPRI), "=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) + ); + + /* This return will not be reached but is necessary to prevent compiler + warnings. */ + return ulOriginalBASEPRI; +} +/*-----------------------------------------------------------*/ + +portFORCE_INLINE static void vPortSetBASEPRI( uint32_t ulNewMaskValue ) +{ + __asm volatile + ( + " msr basepri, %0 " :: "r" ( ulNewMaskValue ) + ); +} +/*-----------------------------------------------------------*/ + +portFORCE_INLINE static void vPortYield( void ) +{ + /* Set a PendSV to request a context switch. */ + portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; + + /* Barriers are normally not required but do ensure the code is completely + within the specified behaviour for the architecture. */ + __asm volatile( "dsb" ); + __asm volatile( "isb" ); +} + + #ifdef __cplusplus } #endif diff --git a/FreeRTOS/Source/portable/GCC/MicroBlazeV8/portmacro.h b/FreeRTOS/Source/portable/GCC/MicroBlazeV8/portmacro.h index 528d45e2d..df14a0e79 100644 --- a/FreeRTOS/Source/portable/GCC/MicroBlazeV8/portmacro.h +++ b/FreeRTOS/Source/portable/GCC/MicroBlazeV8/portmacro.h @@ -217,7 +217,7 @@ typedef struct PORT_REGISTER_DUMP /* The human readable name of the task that was running at the time the exception occurred. This is the name that was given to the task when the task was created using the FreeRTOS xTaskCreate() API function. */ - int8_t *pcCurrentTaskName; + char *pcCurrentTaskName; /* The handle of the task that was running a the time the exception occurred. */ diff --git a/FreeRTOS/Source/portable/IAR/ARM_CM3/port.c b/FreeRTOS/Source/portable/IAR/ARM_CM3/port.c index 48e09c49d..1f4b0ab2e 100644 --- a/FreeRTOS/Source/portable/IAR/ARM_CM3/port.c +++ b/FreeRTOS/Source/portable/IAR/ARM_CM3/port.c @@ -114,7 +114,7 @@ #define portPRIGROUP_SHIFT ( 8UL ) /* Masks off all bits but the VECTACTIVE bits in the ICSR register. */ -#define portVECTACTIVE_MASK ( 0x1FUL ) +#define portVECTACTIVE_MASK ( 0xFFUL ) /* Constants required to set up the initial stack. */ #define portINITIAL_XPSR ( 0x01000000 ) @@ -327,9 +327,9 @@ void vPortEnterCritical( void ) uxCriticalNesting++; __DSB(); __ISB(); - + /* This is not the interrupt safe version of the enter critical function so - assert() if it is being called from an interrupt context. Only API + assert() if it is being called from an interrupt context. Only API functions that end in "FromISR" can be used in an interrupt. Only assert if the critical nesting count is 1 to protect against recursive calls if the assert function also uses a critical section. */ diff --git a/FreeRTOS/Source/portable/IAR/ARM_CM4F/port.c b/FreeRTOS/Source/portable/IAR/ARM_CM4F/port.c index 7cef15c0a..295e46902 100644 --- a/FreeRTOS/Source/portable/IAR/ARM_CM4F/port.c +++ b/FreeRTOS/Source/portable/IAR/ARM_CM4F/port.c @@ -118,7 +118,7 @@ #define portPRIGROUP_SHIFT ( 8UL ) /* Masks off all bits but the VECTACTIVE bits in the ICSR register. */ -#define portVECTACTIVE_MASK ( 0x1FUL ) +#define portVECTACTIVE_MASK ( 0xFFUL ) /* Constants required to manipulate the VFP. */ #define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating point context control register. */ @@ -335,27 +335,13 @@ void vPortEndScheduler( void ) } /*-----------------------------------------------------------*/ -void vPortYield( void ) -{ - /* Set a PendSV to request a context switch. */ - portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; - - /* Barriers are normally not required but do ensure the code is completely - within the specified behaviour for the architecture. */ - __DSB(); - __ISB(); -} -/*-----------------------------------------------------------*/ - void vPortEnterCritical( void ) { portDISABLE_INTERRUPTS(); uxCriticalNesting++; - __DSB(); - __ISB(); - + /* This is not the interrupt safe version of the enter critical function so - assert() if it is being called from an interrupt context. Only API + assert() if it is being called from an interrupt context. Only API functions that end in "FromISR" can be used in an interrupt. Only assert if the critical nesting count is 1 to protect against recursive calls if the assert function also uses a critical section. */ diff --git a/FreeRTOS/Source/portable/IAR/ARM_CM4F/portasm.s b/FreeRTOS/Source/portable/IAR/ARM_CM4F/portasm.s index c7d07afd7..546c95479 100644 --- a/FreeRTOS/Source/portable/IAR/ARM_CM4F/portasm.s +++ b/FreeRTOS/Source/portable/IAR/ARM_CM4F/portasm.s @@ -72,8 +72,6 @@ EXTERN vTaskSwitchContext PUBLIC xPortPendSVHandler - PUBLIC ulPortSetInterruptMask - PUBLIC vPortClearInterruptMask PUBLIC vPortSVCHandler PUBLIC vPortStartFirstTask PUBLIC vPortEnableVFP @@ -102,6 +100,8 @@ xPortPendSVHandler: stmdb sp!, {r3} mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY msr basepri, r0 + dsb + isb bl vTaskSwitchContext mov r0, #0 msr basepri, r0 @@ -134,20 +134,6 @@ xPortPendSVHandler: /*-----------------------------------------------------------*/ -ulPortSetInterruptMask: - mrs r0, basepri - mov r1, #configMAX_SYSCALL_INTERRUPT_PRIORITY - msr basepri, r1 - bx r14 - -/*-----------------------------------------------------------*/ - -vPortClearInterruptMask: - msr basepri, r0 - bx r14 - -/*-----------------------------------------------------------*/ - vPortSVCHandler: /* Get the location of the current TCB. */ ldr r3, =pxCurrentTCB diff --git a/FreeRTOS/Source/portable/IAR/ARM_CM4F/portmacro.h b/FreeRTOS/Source/portable/IAR/ARM_CM4F/portmacro.h index 92f41753c..3c3b76f2e 100644 --- a/FreeRTOS/Source/portable/IAR/ARM_CM4F/portmacro.h +++ b/FreeRTOS/Source/portable/IAR/ARM_CM4F/portmacro.h @@ -110,11 +110,10 @@ typedef unsigned long UBaseType_t; /*-----------------------------------------------------------*/ /* Scheduler utilities. */ -extern void vPortYield( void ); #define portNVIC_INT_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000ed04 ) ) #define portNVIC_PENDSVSET_BIT ( 1UL << 28UL ) #define portYIELD() vPortYield() -#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT +#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) vPortYield() #define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x ) /*-----------------------------------------------------------*/ @@ -145,15 +144,13 @@ extern void vPortYield( void ); /* Critical section management. */ extern void vPortEnterCritical( void ); extern void vPortExitCritical( void ); -extern uint32_t ulPortSetInterruptMask( void ); -extern void vPortClearInterruptMask( uint32_t ulNewMask ); -#define portDISABLE_INTERRUPTS() ulPortSetInterruptMask() -#define portENABLE_INTERRUPTS() vPortClearInterruptMask( 0 ) +#define portDISABLE_INTERRUPTS() ulPortRaiseBASEPRI() +#define portENABLE_INTERRUPTS() vPortSetBASEPRI( 0 ) #define portENTER_CRITICAL() vPortEnterCritical() #define portEXIT_CRITICAL() vPortExitCritical() -#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortSetInterruptMask() -#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortClearInterruptMask( x ) +#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortRaiseBASEPRI() +#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortSetBASEPRI( x ) /*-----------------------------------------------------------*/ /* Tickless idle/low power functionality. */ @@ -179,6 +176,51 @@ not necessary for to use this port. They are defined so the common demo files /* portNOP() is not required by this port. */ #define portNOP() +#ifndef portFORCE_INLINE + #define portFORCE_INLINE _Pragma("inline=forced") +#endif + +portFORCE_INLINE static void vPortYield( void ) +{ + /* Set a PendSV to request a context switch. */ + portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; + + /* Barriers are normally not required but do ensure the code is completely + within the specified behaviour for the architecture. */ + __DSB(); + __ISB(); +} +/*-----------------------------------------------------------*/ + +portFORCE_INLINE static uint32_t ulPortRaiseBASEPRI( void ) +{ +uint32_t ulOriginalBASEPRI; + + __asm volatile + ( + " mrs %0, basepri \n" \ + " mov r1, %1 \n" \ + " msr basepri, r1 \n" \ + " isb \n" \ + " dsb \n" \ + :"=r" (ulOriginalBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "r1" + ); + + /* This return will not be reached but is necessary to prevent compiler + warnings. */ + return ulOriginalBASEPRI; +} +/*-----------------------------------------------------------*/ + +portFORCE_INLINE static void vPortSetBASEPRI( uint32_t ulNewMaskValue ) +{ + __asm volatile + ( + " msr basepri, %0 " :: "r" ( ulNewMaskValue ) + ); +} +/*-----------------------------------------------------------*/ + /* Suppress warnings that are generated by the IAR tools, but cannot be fixed in the source code because to do so would cause other compilers to generate warnings. */ diff --git a/FreeRTOS/Source/portable/RVDS/ARM_CM3/port.c b/FreeRTOS/Source/portable/RVDS/ARM_CM3/port.c index 0a8323643..77610ac1d 100644 --- a/FreeRTOS/Source/portable/RVDS/ARM_CM3/port.c +++ b/FreeRTOS/Source/portable/RVDS/ARM_CM3/port.c @@ -111,7 +111,7 @@ is defined. */ #define portNVIC_PEND_SYSTICK_CLEAR_BIT ( 1UL << 25UL ) /* Masks off all bits but the VECTACTIVE bits in the ICSR register. */ -#define portVECTACTIVE_MASK ( 0x1FUL ) +#define portVECTACTIVE_MASK ( 0xFFUL ) #define portNVIC_PENDSV_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL ) #define portNVIC_SYSTICK_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL ) diff --git a/FreeRTOS/Source/portable/RVDS/ARM_CM4F/port.c b/FreeRTOS/Source/portable/RVDS/ARM_CM4F/port.c index 2b8560682..3628b34b3 100644 --- a/FreeRTOS/Source/portable/RVDS/ARM_CM4F/port.c +++ b/FreeRTOS/Source/portable/RVDS/ARM_CM4F/port.c @@ -124,7 +124,7 @@ is defined. */ #define portPRIGROUP_SHIFT ( 8UL ) /* Masks off all bits but the VECTACTIVE bits in the ICSR register. */ -#define portVECTACTIVE_MASK ( 0x1FUL ) +#define portVECTACTIVE_MASK ( 0xFFUL ) /* Constants required to manipulate the VFP. */ #define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating point context control register. */ @@ -134,9 +134,6 @@ is defined. */ #define portINITIAL_XPSR ( 0x01000000 ) #define portINITIAL_EXEC_RETURN ( 0xfffffffd ) -/* Constants used with memory barrier intrinsics. */ -#define portSY_FULL_READ_WRITE ( 15 ) - /* The systick is a 24-bit counter. */ #define portMAX_24_BIT_NUMBER ( 0xffffffUL ) @@ -401,24 +398,10 @@ void vPortEndScheduler( void ) } /*-----------------------------------------------------------*/ -void vPortYield( void ) -{ - /* Set a PendSV to request a context switch. */ - portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; - - /* Barriers are normally not required but do ensure the code is completely - within the specified behaviour for the architecture. */ - __dsb( portSY_FULL_READ_WRITE ); - __isb( portSY_FULL_READ_WRITE ); -} -/*-----------------------------------------------------------*/ - void vPortEnterCritical( void ) { portDISABLE_INTERRUPTS(); uxCriticalNesting++; - __dsb( portSY_FULL_READ_WRITE ); - __isb( portSY_FULL_READ_WRITE ); /* This is not the interrupt safe version of the enter critical function so assert() if it is being called from an interrupt context. Only API @@ -471,6 +454,8 @@ __asm void xPortPendSVHandler( void ) stmdb sp!, {r3} mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY msr basepri, r0 + dsb + isb bl vTaskSwitchContext mov r0, #0 msr basepri, r0 @@ -702,26 +687,6 @@ void xPortSysTickHandler( void ) #endif /* configOVERRIDE_DEFAULT_TICK_CONFIGURATION */ /*-----------------------------------------------------------*/ -__asm uint32_t ulPortSetInterruptMask( void ) -{ - PRESERVE8 - - mrs r0, basepri - mov r1, #configMAX_SYSCALL_INTERRUPT_PRIORITY - msr basepri, r1 - bx r14 -} -/*-----------------------------------------------------------*/ - -__asm void vPortClearInterruptMask( uint32_t ulNewMask ) -{ - PRESERVE8 - - msr basepri, r0 - bx r14 -} -/*-----------------------------------------------------------*/ - __asm uint32_t vPortGetIPSR( void ) { PRESERVE8 diff --git a/FreeRTOS/Source/portable/RVDS/ARM_CM4F/portmacro.h b/FreeRTOS/Source/portable/RVDS/ARM_CM4F/portmacro.h index fa39a3a4e..93a055555 100644 --- a/FreeRTOS/Source/portable/RVDS/ARM_CM4F/portmacro.h +++ b/FreeRTOS/Source/portable/RVDS/ARM_CM4F/portmacro.h @@ -107,29 +107,30 @@ typedef unsigned long UBaseType_t; #define portSTACK_GROWTH ( -1 ) #define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ ) #define portBYTE_ALIGNMENT 8 + +/* Constants used with memory barrier intrinsics. */ +#define portSY_FULL_READ_WRITE ( 15 ) + /*-----------------------------------------------------------*/ /* Scheduler utilities. */ -extern void vPortYield( void ); #define portNVIC_INT_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000ed04 ) ) #define portNVIC_PENDSVSET_BIT ( 1UL << 28UL ) #define portYIELD() vPortYield() -#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT +#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) vPortYield() #define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x ) /*-----------------------------------------------------------*/ /* Critical section management. */ -extern uint32_t ulPortSetInterruptMask( void ); -extern void vPortClearInterruptMask( uint32_t ulNewMask ); extern void vPortEnterCritical( void ); extern void vPortExitCritical( void ); -#define portDISABLE_INTERRUPTS() ulPortSetInterruptMask() -#define portENABLE_INTERRUPTS() vPortClearInterruptMask( 0 ) +#define portDISABLE_INTERRUPTS() ulPortRaiseBASEPRI() +#define portENABLE_INTERRUPTS() vPortSetBASEPRI( 0 ) #define portENTER_CRITICAL() vPortEnterCritical() #define portEXIT_CRITICAL() vPortExitCritical() -#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortSetInterruptMask() -#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortClearInterruptMask(x) +#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortRaiseBASEPRI() +#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortSetBASEPRI(x) /*-----------------------------------------------------------*/ @@ -178,6 +179,53 @@ not necessary for to use this port. They are defined so the common demo files /* portNOP() is not required by this port. */ #define portNOP() +#ifndef portFORCE_INLINE + #define portFORCE_INLINE __forceinline +#endif + +/*-----------------------------------------------------------*/ + +static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI ) +{ + __asm + { + /* Barrier instructions are not used as this function is only used to + lower the BASEPRI value. */ + msr basepri, ulBASEPRI + } +} +/*-----------------------------------------------------------*/ + +static portFORCE_INLINE uint32_t ulPortRaiseBASEPRI( void ) +{ +uint32_t ulReturn, ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY; + + __asm + { + /* Set BASEPRI to the max syscall priority to effect a critical + section. */ + mrs ulReturn, basepri + msr basepri, ulNewBASEPRI + dsb + isb + } + + return ulReturn; +} +/*-----------------------------------------------------------*/ + +static portFORCE_INLINE void vPortYield( void ) +{ + /* Set a PendSV to request a context switch. */ + portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; + + /* Barriers are normally not required but do ensure the code is completely + within the specified behaviour for the architecture. */ + __dsb( portSY_FULL_READ_WRITE ); + __isb( portSY_FULL_READ_WRITE ); +} +/*-----------------------------------------------------------*/ + #ifdef __cplusplus } #endif diff --git a/FreeRTOS/Source/portable/Tasking/ARM_CM4F/port.c b/FreeRTOS/Source/portable/Tasking/ARM_CM4F/port.c index 35c3e8b70..cadae7a3b 100644 --- a/FreeRTOS/Source/portable/Tasking/ARM_CM4F/port.c +++ b/FreeRTOS/Source/portable/Tasking/ARM_CM4F/port.c @@ -82,7 +82,7 @@ #define portNVIC_SYSTICK_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24 ) /* Masks off all bits but the VECTACTIVE bits in the ICSR register. */ -#define portVECTACTIVE_MASK ( 0x1FUL ) +#define portVECTACTIVE_MASK ( 0xFFUL ) /* Constants required to manipulate the VFP. */ #define portFPCCR ( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating point context control register. */ diff --git a/FreeRTOS/Source/queue.c b/FreeRTOS/Source/queue.c index 5ef81adc4..a7c6e749c 100644 --- a/FreeRTOS/Source/queue.c +++ b/FreeRTOS/Source/queue.c @@ -1377,8 +1377,8 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue; { taskENTER_CRITICAL(); { - /* Is there data in the queue now? To be running we must be - the highest priority task wanting to access the queue. */ + /* Is there data in the queue now? To be running the calling task + must be the highest priority task wanting to access the queue. */ if( pxQueue->uxMessagesWaiting > ( UBaseType_t ) 0 ) { /* Remember the read position in case the queue is only being diff --git a/FreeRTOS/Source/tasks.c b/FreeRTOS/Source/tasks.c index ddee4e4de..74edf06e1 100644 --- a/FreeRTOS/Source/tasks.c +++ b/FreeRTOS/Source/tasks.c @@ -114,6 +114,14 @@ functions but without including stdio.h here. */ #define taskYIELD_IF_USING_PREEMPTION() portYIELD_WITHIN_API() #endif +/* Value that can be assigned to the eNotifyState member of the TCB. */ +typedef enum +{ + eNotWaitingNotification, + eWaitingNotification, + eNotified +} eNotifyValue; + /* * Task control block. A task control block (TCB) is allocated for each task, * and stores task state information, including a pointer to the task's context @@ -170,6 +178,11 @@ typedef struct tskTaskControlBlock struct _reent xNewLib_reent; #endif + #if ( configUSE_TASK_NOTIFICATIONS == 1 ) + uint32_t ulNotifiedValue; + eNotifyValue eNotifyState; + #endif + } tskTCB; /* The old tskTCB name is maintained above then typedefed to the new TCB_t name @@ -228,8 +241,8 @@ PRIVILEGED_DATA static UBaseType_t uxTaskNumber = ( UBaseType_t ) 0U; PRIVILEGED_DATA static volatile TickType_t xNextTaskUnblockTime = portMAX_DELAY; /* Context switches are held pending while the scheduler is suspended. Also, -interrupts must not manipulate the xStateListItem of a TCB, or any of the -lists the xStateListItem can be referenced from, if the scheduler is suspended. +interrupts must not manipulate the xGenericListItem of a TCB, or any of the +lists the xGenericListItem can be referenced from, if the scheduler is suspended. If an interrupt needs to unblock a task while the scheduler is suspended then it moves the task's event list item into the xPendingReadyList, ready for the kernel to move the task from the pending ready list into the real ready list @@ -515,6 +528,15 @@ static TCB_t *prvAllocateTCBAndStack( const uint16_t usStackDepth, StackType_t * */ static void prvResetNextTaskUnblockTime( void ); +#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) + + /* + * Helper function used to pad task names with spaces when printing out + * human readable tables of task information. + */ + static char *prvWriteNameToBuffer( char *pcBuffer, const char *pcTaskName ); + +#endif /*-----------------------------------------------------------*/ BaseType_t xTaskGenericCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask, StackType_t * const puxStackBuffer, const MemoryRegion_t * const xRegions ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ @@ -995,7 +1017,7 @@ TCB_t * pxNewTCB; } #endif - else + else /*lint !e525 Negative indentation is intended to make use of pre-processor clearer. */ { /* If the task is not in any other state, it must be in the Ready (including pending ready) state. */ @@ -1031,6 +1053,46 @@ TCB_t * pxNewTCB; #endif /* INCLUDE_uxTaskPriorityGet */ /*-----------------------------------------------------------*/ +#if ( INCLUDE_uxTaskPriorityGet == 1 ) + + UBaseType_t uxTaskPriorityGetFromISR( TaskHandle_t xTask ) + { + TCB_t *pxTCB; + UBaseType_t uxReturn, uxSavedInterruptState; + + /* RTOS ports that support interrupt nesting have the concept of a + maximum system call (or maximum API call) interrupt priority. + Interrupts that are above the maximum system call priority are keep + permanently enabled, even when the RTOS kernel is in a critical section, + but cannot make any calls to FreeRTOS API functions. If configASSERT() + is defined in FreeRTOSConfig.h then + portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has + been assigned a priority above the configured maximum system call + priority. Only FreeRTOS functions that end in FromISR can be called + from interrupts that have been assigned a priority at or (logically) + below the maximum system call interrupt priority. FreeRTOS maintains a + separate interrupt safe API to ensure interrupt entry is as fast and as + simple as possible. More information (albeit Cortex-M specific) is + provided on the following link: + http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + + uxSavedInterruptState = portSET_INTERRUPT_MASK_FROM_ISR(); + { + /* If null is passed in here then we are changing the + priority of the calling function. */ + pxTCB = prvGetTCBFromHandle( xTask ); + uxReturn = pxTCB->uxPriority; + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptState ); + + return uxReturn; + } + +#endif /* INCLUDE_uxTaskPriorityGet */ +/*-----------------------------------------------------------*/ + #if ( INCLUDE_vTaskPrioritySet == 1 ) void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority ) @@ -1614,8 +1676,8 @@ BaseType_t xAlreadyYielded = pdFALSE; ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); prvAddTaskToReadyList( pxTCB ); - /* If we have moved a task that has a priority higher than - the current task then we should yield. */ + /* If the moved task has a priority higher than the current + task then a yield must be performed. */ if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) { xYieldPending = pdTRUE; @@ -1884,7 +1946,7 @@ BaseType_t xSwitchRequired = pdFALSE; /* See if this tick has made a timeout expire. Tasks are stored in the queue in the order of their wake time - meaning once one task has been found whose block time has not expired there is no need to - look any further down the list. */ + look any further down the list. */ if( xConstTickCount >= xNextTaskUnblockTime ) { for( ;; ) @@ -2395,6 +2457,20 @@ BaseType_t xReturn; xReturn = pdFALSE; } + #if( configUSE_TICKLESS_IDLE == 1 ) + { + /* If a task is blocked on a kernel object then xNextTaskUnblockTime + might be set to the blocked task's time out time. If the task is + unblocked for a reason other than a timeout xNextTaskUnblockTime is + normally left unchanged, because it is automatically get reset to a new + value when the tick count equals xNextTaskUnblockTime. However if + tickless idling is used it might be more important to enter sleep mode + at the earliest possible time - so reset xNextTaskUnblockTime here to + ensure it is updated at the earliest possible time. */ + prvResetNextTaskUnblockTime(); + } + #endif + return xReturn; } /*-----------------------------------------------------------*/ @@ -2788,6 +2864,13 @@ UBaseType_t x; } #endif /* portUSING_MPU_WRAPPERS */ + #if ( configUSE_TASK_NOTIFICATIONS == 1 ) + { + pxTCB->ulNotifiedValue = 0; + pxTCB->eNotifyState = eNotWaitingNotification; + } + #endif + #if ( configUSE_NEWLIB_REENTRANT == 1 ) { /* Initialise this task's Newlib reent structure. */ @@ -3416,6 +3499,32 @@ TCB_t *pxTCB; #endif /* portCRITICAL_NESTING_IN_TCB */ /*-----------------------------------------------------------*/ +#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) + + static char *prvWriteNameToBuffer( char *pcBuffer, const char *pcTaskName ) + { + BaseType_t x; + + /* Start by copying the entire string. */ + strcpy( pcBuffer, pcTaskName ); + + /* Pad the end of the string with spaces to ensure columns line up when + printed out. */ + for( x = strlen( pcBuffer ); x < configMAX_TASK_NAME_LEN; x++ ) + { + pcBuffer[ x ] = ' '; + } + + /* Terminate. */ + pcBuffer[ x ] = 0x00; + + /* Return the new end of string. */ + return &( pcBuffer[ x ] ); + } + +#endif /* ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) */ +/*-----------------------------------------------------------*/ + #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) void vTaskList( char * pcWriteBuffer ) @@ -3487,7 +3596,12 @@ TCB_t *pxTCB; break; } - sprintf( pcWriteBuffer, "%s\t\t%c\t%u\t%u\t%u\r\n", pxTaskStatusArray[ x ].pcTaskName, cStatus, ( unsigned int ) pxTaskStatusArray[ x ].uxCurrentPriority, ( unsigned int ) pxTaskStatusArray[ x ].usStackHighWaterMark, ( unsigned int ) pxTaskStatusArray[ x ].xTaskNumber ); + /* Write the task name to the string, padding with spaces so it + can be printed in tabular form more easily. */ + pcWriteBuffer = prvWriteNameToBuffer( pcWriteBuffer, pxTaskStatusArray[ x ].pcTaskName ); + + /* Write the rest of the string. */ + sprintf( pcWriteBuffer, "\t\t%c\t%u\t%u\t%u\r\n", cStatus, ( unsigned int ) pxTaskStatusArray[ x ].uxCurrentPriority, ( unsigned int ) pxTaskStatusArray[ x ].usStackHighWaterMark, ( unsigned int ) pxTaskStatusArray[ x ].xTaskNumber ); pcWriteBuffer += strlen( pcWriteBuffer ); } @@ -3573,15 +3687,20 @@ TCB_t *pxTCB; if( ulStatsAsPercentage > 0UL ) { + /* Write the task name to the string, padding with + spaces so it can be printed in tabular form more + easily. */ + pcWriteBuffer = prvWriteNameToBuffer( pcWriteBuffer, pxTaskStatusArray[ x ].pcTaskName ); + #ifdef portLU_PRINTF_SPECIFIER_REQUIRED { - sprintf( pcWriteBuffer, "%s\t\t%lu\t\t%lu%%\r\n", pxTaskStatusArray[ x ].pcTaskName, pxTaskStatusArray[ x ].ulRunTimeCounter, ulStatsAsPercentage ); + sprintf( pcWriteBuffer, "\t\t%lu\t\t%lu%%\r\n", pxTaskStatusArray[ x ].ulRunTimeCounter, ulStatsAsPercentage ); } #else { /* sizeof( int ) == sizeof( long ) so a smaller printf() library can be used. */ - sprintf( pcWriteBuffer, "%s\t\t%u\t\t%u%%\r\n", pxTaskStatusArray[ x ].pcTaskName, ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage ); + sprintf( pcWriteBuffer, "\t\t%u\t\t%u%%\r\n", ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage ); } #endif } @@ -3651,7 +3770,433 @@ TickType_t uxReturn; } #endif /* configUSE_MUTEXES */ +/*-----------------------------------------------------------*/ + +#if( configUSE_TASK_NOTIFICATIONS == 1 ) + + uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait ) + { + TickType_t xTimeToWake; + uint32_t ulReturn; + + taskENTER_CRITICAL(); + { + /* Only block if the notification count is not already non-zero. */ + if( pxCurrentTCB->ulNotifiedValue == 0UL ) + { + /* Mark this task as waiting for a notification. */ + pxCurrentTCB->eNotifyState = eWaitingNotification; + + if( xTicksToWait > 0 ) + { + /* The task is going to block. First it must be removed + from the ready list. */ + if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 ) + { + /* The current task must be in a ready list, so there is + no need to check, and the port reset macro can be called + directly. */ + portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + #if ( INCLUDE_vTaskSuspend == 1 ) + { + if( xTicksToWait == portMAX_DELAY ) + { + /* Add the task to the suspended task list instead + of a delayed task list to ensure the task is not + woken by a timing event. It will block + indefinitely. */ + vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xGenericListItem ) ); + } + else + { + /* Calculate the time at which the task should be + woken if no notification events occur. This may + overflow but this doesn't matter, the scheduler will + handle it. */ + xTimeToWake = xTickCount + xTicksToWait; + prvAddCurrentTaskToDelayedList( xTimeToWake ); + } + } + #else /* INCLUDE_vTaskSuspend */ + { + /* Calculate the time at which the task should be + woken if the event does not occur. This may + overflow but this doesn't matter, the scheduler will + handle it. */ + xTimeToWake = xTickCount + xTicksToWait; + prvAddCurrentTaskToDelayedList( xTimeToWake ); + } + #endif /* INCLUDE_vTaskSuspend */ + + /* All ports are written to allow a yield in a critical + section (some will yield immediately, others wait until the + critical section exits) - but it is not something that + application code should ever do. */ + portYIELD_WITHIN_API(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + + taskENTER_CRITICAL(); + { + ulReturn = pxCurrentTCB->ulNotifiedValue; + + if( ulReturn != 0 ) + { + if( xClearCountOnExit != pdFALSE ) + { + pxCurrentTCB->ulNotifiedValue = 0UL; + } + else + { + ( pxCurrentTCB->ulNotifiedValue )--; + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + pxCurrentTCB->eNotifyState = eNotWaitingNotification; + } + taskEXIT_CRITICAL(); + + return ulReturn; + } + +#endif /* configUSE_TASK_NOTIFICATIONS */ +/*-----------------------------------------------------------*/ + +#if( configUSE_TASK_NOTIFICATIONS == 1 ) + + BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, BaseType_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait ) + { + TickType_t xTimeToWake; + BaseType_t xReturn; + + taskENTER_CRITICAL(); + { + /* Only block if a notification is not already pending. */ + if( pxCurrentTCB->eNotifyState != eNotified ) + { + /* Clear bits in the task's notification value as bits may get + set by the notifying task or interrupt. This can be used to + clear the value to zero. */ + pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnEntry; + + /* Mark this task as waiting for a notification. */ + pxCurrentTCB->eNotifyState = eWaitingNotification; + + if( xTicksToWait > 0 ) + { + /* The task is going to block. First it must be removed + from the ready list. */ + if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 ) + { + /* The current task must be in a ready list, so there is + no need to check, and the port reset macro can be called + directly. */ + portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + #if ( INCLUDE_vTaskSuspend == 1 ) + { + if( xTicksToWait == portMAX_DELAY ) + { + /* Add the task to the suspended task list instead + of a delayed task list to ensure the task is not + woken by a timing event. It will block + indefinitely. */ + vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xGenericListItem ) ); + } + else + { + /* Calculate the time at which the task should be + woken if no notification events occur. This may + overflow but this doesn't matter, the scheduler will + handle it. */ + xTimeToWake = xTickCount + xTicksToWait; + prvAddCurrentTaskToDelayedList( xTimeToWake ); + } + } + #else /* INCLUDE_vTaskSuspend */ + { + /* Calculate the time at which the task should be + woken if the event does not occur. This may + overflow but this doesn't matter, the scheduler will + handle it. */ + xTimeToWake = xTickCount + xTicksToWait; + prvAddCurrentTaskToDelayedList( xTimeToWake ); + } + #endif /* INCLUDE_vTaskSuspend */ + + /* All ports are written to allow a yield in a critical + section (some will yield immediately, others wait until the + critical section exits) - but it is not something that + application code should ever do. */ + portYIELD_WITHIN_API(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + + taskENTER_CRITICAL(); + { + if( pulNotificationValue != NULL ) + { + /* Output the current notification value, which may or may not + have changed. */ + *pulNotificationValue = pxCurrentTCB->ulNotifiedValue; + } + + /* If eNotifyValue is set then either the task never entered the + blocked state (because a notification was already pending) or the + task unblocked because of a notification. Otherwise the task + unblocked because of a timeout. */ + if( pxCurrentTCB->eNotifyState == eWaitingNotification ) + { + /* A notification was not received. */ + xReturn = pdFALSE; + } + else + { + /* A notification was already pending or a notification was + received while the task was waiting. */ + pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnExit; + xReturn = pdTRUE; + } + + pxCurrentTCB->eNotifyState = eNotWaitingNotification; + } + taskEXIT_CRITICAL(); + + return xReturn; + } + +#endif /* configUSE_TASK_NOTIFICATIONS */ +/*-----------------------------------------------------------*/ + +#if( configUSE_TASK_NOTIFICATIONS == 1 ) + + BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction ) + { + TCB_t * pxTCB; + eNotifyValue eOriginalNotifyState; + BaseType_t xReturn = pdPASS; + + configASSERT( xTaskToNotify ); + pxTCB = ( TCB_t * ) xTaskToNotify; + + taskENTER_CRITICAL(); + { + eOriginalNotifyState = pxTCB->eNotifyState; + + pxTCB->eNotifyState = eNotified; + + switch( eAction ) + { + case eSetBits : + pxTCB->ulNotifiedValue |= ulValue; + break; + + case eIncrement : + ( pxTCB->ulNotifiedValue )++; + break; + + case eSetValueWithOverwrite : + pxTCB->ulNotifiedValue = ulValue; + break; + + case eSetValueWithoutOverwrite : + if( eOriginalNotifyState != eNotified ) + { + pxTCB->ulNotifiedValue = ulValue; + } + else + { + /* The value could not be written to the task. */ + xReturn = pdFAIL; + } + break; + + default : + /* The task is being notified without its notify value being + updated. */ + break; + } + + + /* If the task is in the blocked state specifically to wait for a + notification then unblock it now. */ + if( eOriginalNotifyState == eWaitingNotification ) + { + ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); + prvAddTaskToReadyList( pxTCB ); + + /* The task should not have been on an event list. */ + configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL ); + + if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) + { + /* The notified task has a priority above the currently + executing task so a yield is required. */ + portYIELD_WITHIN_API(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + + return xReturn; + } + +#endif /* configUSE_TASK_NOTIFICATIONS */ +/*-----------------------------------------------------------*/ + +#if( configUSE_TASK_NOTIFICATIONS == 1 ) + + BaseType_t xTaskNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, BaseType_t *pxHigherPriorityTaskWoken ) + { + TCB_t * pxTCB; + eNotifyValue eOriginalNotifyState; + BaseType_t xReturn = pdPASS; + UBaseType_t uxSavedInterruptStatus; + + configASSERT( xTaskToNotify ); + + /* RTOS ports that support interrupt nesting have the concept of a + maximum system call (or maximum API call) interrupt priority. + Interrupts that are above the maximum system call priority are keep + permanently enabled, even when the RTOS kernel is in a critical section, + but cannot make any calls to FreeRTOS API functions. If configASSERT() + is defined in FreeRTOSConfig.h then + portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has + been assigned a priority above the configured maximum system call + priority. Only FreeRTOS functions that end in FromISR can be called + from interrupts that have been assigned a priority at or (logically) + below the maximum system call interrupt priority. FreeRTOS maintains a + separate interrupt safe API to ensure interrupt entry is as fast and as + simple as possible. More information (albeit Cortex-M specific) is + provided on the following link: + http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + + pxTCB = ( TCB_t * ) xTaskToNotify; + + uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + { + eOriginalNotifyState = pxTCB->eNotifyState; + + pxTCB->eNotifyState = eNotified; + + switch( eAction ) + { + case eSetBits : + pxTCB->ulNotifiedValue |= ulValue; + break; + + case eIncrement : + ( pxTCB->ulNotifiedValue )++; + break; + + case eSetValueWithOverwrite : + pxTCB->ulNotifiedValue = ulValue; + break; + + case eSetValueWithoutOverwrite : + if( eOriginalNotifyState != eNotified ) + { + pxTCB->ulNotifiedValue = ulValue; + } + else + { + /* The value could not be written to the task. */ + xReturn = pdFAIL; + } + break; + + default : + /* The task is being notified without its notify value being + updated. */ + break; + } + + + /* If the task is in the blocked state specifically to wait for a + notification then unblock it now. */ + if( eOriginalNotifyState == eWaitingNotification ) + { + /* The task should not have been on an event list. */ + configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL ); + + if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) + { + ( void ) uxListRemove( &( pxTCB->xGenericListItem ) ); + prvAddTaskToReadyList( pxTCB ); + } + else + { + /* The delayed and ready lists cannot be accessed, so hold + this task pending until the scheduler is resumed. */ + vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) ); + } + + if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) + { + /* The notified task has a priority above the currently + executing task so a yield is required. */ + if( pxHigherPriorityTaskWoken != NULL ) + { + *pxHigherPriorityTaskWoken = pdTRUE; + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + + return xReturn; + } +#endif /* configUSE_TASK_NOTIFICATIONS */ /*-----------------------------------------------------------*/ #ifdef FREERTOS_MODULE_TEST