From 75dd0c7c915c088ada9be6e7e6e3d722cb5d3007 Mon Sep 17 00:00:00 2001 From: rtel Date: Mon, 17 Feb 2014 12:45:56 +0000 Subject: [PATCH] Update trace recorder to include heap tracing and new v8 features. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2207 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- .../ConfigurationTemplate/trcConfig.h | 121 ++++- .../FreeRTOS-Plus-Trace/Include/trcBase.h | 63 ++- .../trcHardwarePort.h | 260 +++++----- .../FreeRTOS-Plus-Trace/Include/trcKernel.h | 12 +- .../Include/trcKernelHooks.h | 31 +- .../Include/trcKernelPort.h | 368 ++++++++++--- .../FreeRTOS-Plus-Trace/Include/trcTypes.h | 7 +- .../FreeRTOS-Plus-Trace/Include/trcUser.h | 8 +- .../debugger trace upload.txt | 30 +- .../Source/FreeRTOS-Plus-Trace/readme.txt | 37 +- .../Source/FreeRTOS-Plus-Trace/trcBase.c | 102 +++- .../FreeRTOS-Plus-Trace/trcHardwarePort.c | 42 +- .../Source/FreeRTOS-Plus-Trace/trcKernel.c | 220 +++++--- .../FreeRTOS-Plus-Trace/trcKernelPort.c | 58 ++- .../Source/FreeRTOS-Plus-Trace/trcUser.c | 483 +++++++++++------- 15 files changed, 1226 insertions(+), 616 deletions(-) rename FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/{ConfigurationTemplate => Include}/trcHardwarePort.h (68%) diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/ConfigurationTemplate/trcConfig.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/ConfigurationTemplate/trcConfig.h index f7d3ff044..e2d22e053 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.5.0 Recorder Library + * Tracealyzer v2.6.0 Recorder Library * Percepio AB, www.percepio.com * * trcConfig.h @@ -91,9 +91,15 @@ * 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 zero (0) to minimize RAM usage. + * 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 1000 +#define SYMBOL_TABLE_SIZE 800 + +#if (SYMBOL_TABLE_SIZE == 0) +#error "SYMBOL_TABLE_SIZE may not be zero!" +#endif /******************************************************************************* * USE_SEPARATE_USER_EVENT_BUFFER @@ -119,7 +125,7 @@ * * Only in use if USE_SEPARATE_USER_EVENT_BUFFER is set to 1. ******************************************************************************/ -#define USER_EVENT_BUFFER_SIZE 500 +#define USER_EVENT_BUFFER_SIZE 10 /******************************************************************************* * USER_EVENT_CHANNELS @@ -169,6 +175,8 @@ #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 @@ -176,6 +184,8 @@ #define NameLenQueue 15 #define NameLenSemaphore 15 #define NameLenMutex 15 +#define NameLenTimer 15 +#define NameLenEventGroup 15 /****************************************************************************** * TRACE_DESCRIPTION @@ -234,7 +244,7 @@ * 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 0 +#define USE_TRACE_ASSERT 1 /****************************************************************************** * INCLUDE_FLOAT_SUPPORT @@ -264,8 +274,7 @@ * much faster than a printf and can therefore be used in timing critical code. * See vTraceUserEvent() and vTracePrintF() in trcUser.h * - * Note that Tracealyzer Professional Edition is required for User Events, - * they are not displayed in Tracealyzer Free Edition. + * Note that User Events are not displayed in FreeRTOS+Trace Free Edition. *****************************************************************************/ #define INCLUDE_USER_EVENTS 1 @@ -319,6 +328,17 @@ *****************************************************************************/ #define INCLUDE_OBJECT_DELETE 1 +/****************************************************************************** + * INCLUDE_MEMMANG_EVENTS + * + * Macro which should be defined as either zero (0) or one (1). + * Default is 1. + * + * 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 + /****************************************************************************** * CONFIGURATION RELATED TO BEHAVIOR *****************************************************************************/ @@ -425,29 +445,86 @@ *****************************************************************************/ #define USE_IMPLICIT_IFE_RULES 1 + /****************************************************************************** - * INCLUDE_SAVE_TO_FILE + * USE_16BIT_OBJECT_HANDLES * * Macro which should be defined as either zero (0) or one (1). * Default is 0. * - * If enabled (1), the recorder will include code for saving the trace - * to a local file system. - ******************************************************************************/ -#ifdef WIN32 - #define INCLUDE_SAVE_TO_FILE 1 -#else - #define INCLUDE_SAVE_TO_FILE 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). + * + * 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. + *****************************************************************************/ +#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 /****************************************************************************** - * TEAM_LICENSE_CODE - * - * Macro which defines a string - the team license code. - * If no team license is available, this should be an empty string "". - * This should be maximum 32 chars, including zero-termination. - *****************************************************************************/ -#define TEAM_LICENSE_CODE "" +* USE_PRIMASK_CS (for Cortex M devices only) +* +* An integer constant that selects between two options for the critical +* sections of the recorder library. + * +* 0: The default FreeRTOS critical section (BASEPRI) - default setting +* 1: Always disable ALL interrupts (using PRIMASK) + * +* 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. + ******************************************************************************/ +#define USE_PRIMASK_CS 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 #endif diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcBase.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcBase.h index e48dc88ec..31dad34e7 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.5.0 Recorder Library + * Tracealyzer v2.6.0 Recorder Library * Percepio AB, www.percepio.com * * trcBase.h @@ -38,7 +38,7 @@ #ifndef TRCBASE_H #define TRCBASE_H -#define TRACE_MINOR_VERSION 2 +#define TRACE_MINOR_VERSION 4 #define TRACE_STORE_MODE_STOP_WHEN_FULL 1 #define TRACE_STORE_MODE_RING_BUFFER 2 #define TRACE_DATA_ALLOCATION_STATIC 1 @@ -56,6 +56,10 @@ #define USE_SEPARATE_USER_EVENT_BUFFER 0 #endif +#ifndef TRACE_SR_ALLOC_CRITICAL_SECTION +#define TRACE_SR_ALLOC_CRITICAL_SECTION() +#endif + /* Max number of event codes supported */ #define NEventCodes 0x100 @@ -96,16 +100,16 @@ extern uint8_t excludedEventCodes[NEventCodes / 8 + 1]; typedef struct { /* For each object class, the index of the next handle to allocate */ - int16_t indexOfNextAvailableHandle[ TRACE_NCLASSES ]; + uint16_t indexOfNextAvailableHandle[ TRACE_NCLASSES ]; /* The lowest index of this class (constant) */ - int16_t lowestIndexOfClass[ TRACE_NCLASSES ]; + uint16_t lowestIndexOfClass[ TRACE_NCLASSES ]; /* The highest index of this class (constant) */ - int16_t highestIndexOfClass[ TRACE_NCLASSES ]; + uint16_t highestIndexOfClass[ TRACE_NCLASSES ]; /* The highest use count for this class (for statistics) */ - int16_t handleCountWaterMarksOfClass[ TRACE_NCLASSES ]; + uint16_t handleCountWaterMarksOfClass[ TRACE_NCLASSES ]; /* The free object handles - a set of stacks within this array */ objectHandleType objectHandles[ TRACE_KERNEL_OBJECT_COUNT ]; @@ -139,7 +143,11 @@ typedef struct /* This is used to calculate the index in the dynamic object table (handle - 1 - nofStaticObjects = index)*/ - uint8_t NumberOfObjectsPerClass[ 4*((TRACE_NCLASSES+3)/4)]; +#if (USE_16BIT_OBJECT_HANDLES == 1) + 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) ]; @@ -179,7 +187,7 @@ typedef struct typedef struct { uint8_t type; - objectHandleType objHandle; + uint8_t objHandle; uint16_t dts; /* differential timestamp - time since last event */ } TSEvent, TREvent; @@ -200,7 +208,7 @@ typedef struct typedef struct { uint8_t type; - objectHandleType objHandle; + uint8_t objHandle; uint8_t param; uint8_t dts; /* differential timestamp - time since last event */ } KernelCallWithParamAndHandle; @@ -215,7 +223,7 @@ typedef struct typedef struct { uint8_t type; - objectHandleType objHandle; /* the handle of the closed object */ + uint8_t objHandle; /* the handle of the closed object */ uint16_t symbolIndex; /* the name of the closed object */ } ObjCloseNameEvent; @@ -254,6 +262,18 @@ typedef struct uint16_t xps_16; } XPSEvent; +typedef struct{ + uint8_t type; + uint8_t dts; + uint16_t size; +} MemEventSize; + +typedef struct{ + uint8_t type; + uint8_t addr_high; + uint16_t addr_low; +} MemEventAddr; + /******************************************************************************* * The separate user event buffer structure. Can be enabled in trcConfig.h. ******************************************************************************/ @@ -305,7 +325,7 @@ typedef struct /* Used to determine Kernel and Endianess */ uint16_t version; - /* Currently 1 for v2.2.2 (0 earlier)*/ + /* Currently 3, since v2.6.0 */ uint8_t minor_version; /* This should be 0 if lower IRQ priority values implies higher priority @@ -342,12 +362,18 @@ typedef struct This is a 32 bit variable due to alignment issues. */ uint32_t recorderActive; - /* For storing a Team License key */ - uint8_t teamLicenceKey[32]; + /* 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; + /* 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. */ @@ -444,10 +470,16 @@ void vTraceSetObjectName(traceObjectClass objectclass, void* xTraceNextFreeEventBufferSlot(void); +#if (USE_16BIT_OBJECT_HANDLES == 1) +unsigned char prvTraceGet8BitHandle(objectHandleType handle); +#else +#define prvTraceGet8BitHandle(x) ((unsigned char)x) +#endif + + uint16_t uiIndexOfObject(objectHandleType objecthandle, uint8_t objectclass); - /******************************************************************************* * vTraceError * @@ -487,6 +519,9 @@ 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_UPDATE_HEAP_USAGE_POSITIVE(change) {if (RecorderDataPtr != NULL) RecorderDataPtr->heapMemUsage += change;} +#define TRACE_UPDATE_HEAP_USAGE_NEGATIVE(change) {if (RecorderDataPtr != NULL) RecorderDataPtr->heapMemUsage -= change;} + /* DEBUG ASSERTS */ #if defined USE_TRACE_ASSERT && USE_TRACE_ASSERT != 0 #define TRACE_ASSERT(eval, msg, defRetVal) \ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/ConfigurationTemplate/trcHardwarePort.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcHardwarePort.h similarity index 68% rename from FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/ConfigurationTemplate/trcHardwarePort.h rename to FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcHardwarePort.h index 993882b17..c66654e67 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/ConfigurationTemplate/trcHardwarePort.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcHardwarePort.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Tracealyzer v2.5.0 Recorder Library + * Tracealyzer v2.6.0 Recorder Library * Percepio AB, www.percepio.com * * trcHardwarePort.h @@ -38,8 +38,7 @@ #ifndef TRCPORT_H #define TRCPORT_H - -#include "trcKernelPort.h" +#include /* If Win32 port */ #ifdef WIN32 @@ -76,60 +75,41 @@ * typically 1 KHz. This means that a task or ISR that executes in less than * 1 ms get an execution time of zero. * - * PORT_Win32 - * "Accurate" timestamping based on the Windows performance counter for Win32 builds. - * Note that this gives the host machine time, not the kernel time. - * - * Officially supported hardware timer ports: - * - PORT_Atmel_AT91SAM7 - * - PORT_Atmel_UC3A0 - * - PORT_ARM_CortexM - * - PORT_Renesas_RX600 - * - PORT_Microchip_dsPIC_AND_PIC24 + * PORT_APPLICATION_DEFINED + * Allows for defining the port macros in other source code files. * - * We also provide several "unofficial" hardware-specific ports. There have - * been developed by external contributors, and have not yet been verified - * by Percepio AB. Let us know if you have problems getting these to work. - * - * Unofficial hardware specific ports provided are: - * - PORT_TEXAS_INSTRUMENTS_TMS570 - * - PORT_TEXAS_INSTRUMENTS_MSP430 - * - PORT_MICROCHIP_PIC32 - * - PORT_XILINX_PPC405 - * - PORT_XILINX_PPC440 - * - PORT_XILINX_MICROBLAZE - * - PORT_NXP_LPC210X + * PORT_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 a certain operating system. *****************************************************************************/ -#define PORT_NOT_SET -1 -#define PORT_APPLICATION_DEFINED -2 - -/*** Officially supported hardware timer ports *******************************/ -#define PORT_HWIndependent 0 -#define PORT_Win32 1 -#define PORT_Atmel_AT91SAM7 2 -#define PORT_Atmel_UC3A0 3 -#define PORT_ARM_CortexM 4 -#define PORT_Renesas_RX600 5 -#define PORT_Microchip_dsPIC_AND_PIC24 6 - -/*** Unofficial ports, provided by external developers, not yet verified *****/ -#define PORT_TEXAS_INSTRUMENTS_TMS570 7 -#define PORT_TEXAS_INSTRUMENTS_MSP430 8 -#define PORT_MICROCHIP_PIC32 9 -#define PORT_XILINX_PPC405 10 -#define PORT_XILINX_PPC440 11 -#define PORT_XILINX_MICROBLAZE 12 -#define PORT_NXP_LPC210X 13 - -/*** Select your port here! **************************************************/ -#define SELECTED_PORT PORT_NOT_SET -/*****************************************************************************/ - -#if (SELECTED_PORT == PORT_NOT_SET) -#error "You need to define SELECTED_PORT here!" -#endif +/****** 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 /******************************************************************************* * IRQ_PRIORITY_ORDER @@ -144,25 +124,6 @@ * interrupts in priority order, in case you record interrupts using * the vTraceStoreISRBegin and vTraceStoreISREnd routines. * - * We provide this setting for some hardware architectures below: - * - ARM Cortex M: 0 (lower IRQ priority values are more significant) - * - Atmel AT91SAM7x: 1 (higher IRQ priority values are more significant) - * - Atmel AVR32: 1 (higher IRQ priority values are more significant) - * - Renesas RX600: 1 (higher IRQ priority values are more significant) - * - Microchip PIC24: 0 (lower IRQ priority values are more significant) - * - Microchip dsPIC: 0 (lower IRQ priority values are more significant) - * - TI TMS570: 0 (lower IRQ priority values are more significant) - * - Freescale HCS08: 0 (lower IRQ priority values are more significant) - * - Freescale HCS12: 0 (lower IRQ priority values are more significant) - * - PowerPC 405: 0 (lower IRQ priority values are more significant) - * - PowerPC 440: 0 (lower IRQ priority values are more significant) - * - Freescale ColdFire: 1 (higher IRQ priority values are more significant) - * - NXP LPC210x: 0 (lower IRQ priority values are more significant) - * - MicroBlaze: 0 (lower IRQ priority values are more significant) - * - * If your chip is not on the above list, and you perhaps know this detail by - * heart, please inform us by e-mail to support@percepio.com. - * ****************************************************************************** * * HWTC Macros @@ -187,9 +148,11 @@ * interrupt is signaled. * * HWTC_PERIOD: The number of increments or decrements of HWTC_COUNT between - * two tick interrupts. This should preferably be mapped to the reload + * 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 * same family. The macro should in most cases be (reload register + 1). + * 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 @@ -209,56 +172,47 @@ ******************************************************************************/ #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 - - #define IRQ_PRIORITY_ORDER 1 // Please update according to your hardware... -#elif (SELECTED_PORT == PORT_HWIndependent) + // 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 - - #define IRQ_PRIORITY_ORDER 1 // Please update according to your hardware... - -#elif (SELECTED_PORT == PORT_Atmel_AT91SAM7) -#error HWTC_PERIOD must point to the reload register! Not verified for this hardware port! - - /* HWTC_PERIOD is hardcoded for AT91SAM7X256-EK Board (48 MHz) - A more generic solution is to get the period from pxPIT->PITC_PIMR */ - #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING - #define HWTC_COUNT (AT91C_BASE_PITC->PITC_PIIR & 0xFFFFF) - #define HWTC_PERIOD (AT91C_BASE_PITC->PITC_PIMR + 1) - #define HWTC_DIVISOR 1 + // Please update according to your system... + #define IRQ_PRIORITY_ORDER NOT_SET - #define IRQ_PRIORITY_ORDER 1 // higher IRQ priority values are more significant - -#elif (SELECTED_PORT == PORT_Atmel_UC3A0) -#error HWTC_PERIOD must point to the reload register! Not yet updated for this hardware port! - - /* For Atmel AVR32 (AT32UC3A) */ - #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING - #define HWTC_COUNT sysreg_read(AVR32_COUNT) - #define HWTC_PERIOD - #define HWTC_DIVISOR 1 - - #define IRQ_PRIORITY_ORDER 1 // higher IRQ priority values are more significant #elif (SELECTED_PORT == PORT_ARM_CortexM) - /* For all chips using ARM Cortex M cores */ + 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 HWTC_COUNT_DIRECTION DIRECTION_DECREMENTING - #define HWTC_COUNT (*((uint32_t*)0xE000E018)) - #define HWTC_PERIOD ((*(uint32_t*)0xE000E014) + 1) - #define HWTC_DIVISOR 2 - #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant #elif (SELECTED_PORT == PORT_Renesas_RX600) @@ -269,15 +223,14 @@ #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_dsPIC_AND_PIC24) /* For Microchip PIC24 and dsPIC (16 bit) */ - /* Note: The trace library was originally designed for 32-bit MCUs, and is slower - than intended on 16-bit MCUs. Storing an event on a PIC24 takes about 70 µs. + /* 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. */ @@ -286,24 +239,42 @@ #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_NXP_LPC210X) -#error HWTC_PERIOD must point to the reload register! Not yet updated for this hardware port! +#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 + +#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 + +#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 + #define HWTC_PERIOD *((uint32_t *)0xE0004018 ) #define HWTC_DIVISOR 1 - #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant #elif (SELECTED_PORT == PORT_TEXAS_INSTRUMENTS_TMS570) -#error HWTC_PERIOD must point to the reload register! Not verified for this hardware port! + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ #define RTIFRC0 *((uint32_t *)0xFFFFFC10) @@ -317,52 +288,60 @@ #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant #elif (SELECTED_PORT == PORT_TEXAS_INSTRUMENTS_MSP430) -#error HWTC_PERIOD must point to the reload register! Not verified for this hardware port! + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING #define HWTC_COUNT (TA0R) - #define HWTC_PERIOD TRACE_CPU_CLOCKS_PER_TICK + #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_MICROCHIP_PIC32) + /* 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 #elif (SELECTED_PORT == PORT_XILINX_PPC405) -#error HWTC_PERIOD must point to the reload register! Not verified for this hardware port! + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ #define HWTC_COUNT_DIRECTION DIRECTION_DECREMENTING - #define HWTC_COUNT mfspr( 0x3db) - #define HWTC_PERIOD + #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 + #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 #elif (SELECTED_PORT == PORT_XILINX_PPC440) -#error HWTC_PERIOD must point to the reload register! Not verified for this hardware port! - /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ - - /* This should work with most PowerPC chips */ - #define HWTC_COUNT_DIRECTION DIRECTION_DECREMENTING - #define HWTC_COUNT mfspr( 0x016 ) - #define HWTC_PERIOD + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ + /* This should work with most PowerPC chips */ + + #define HWTC_COUNT_DIRECTION DIRECTION_DECREMENTING + #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 + #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 #elif (SELECTED_PORT == PORT_XILINX_MICROBLAZE) -#error HWTC_PERIOD must point to the reload register! Not verified for this hardware port! + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ /* This should work with most Microblaze configurations. @@ -373,9 +352,8 @@ #define HWTC_COUNT_DIRECTION DIRECTION_DECREMENTING #define HWTC_COUNT XTmrCtr_GetTimerCounterReg( XPAR_TMRCTR_0_BASEADDR, 0 ) - #define HWTC_PERIOD + #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_APPLICATION_DEFINED) @@ -384,7 +362,6 @@ #error SELECTED_PORT is PORT_APPLICATION_DEFINED but not all of the necessary constants have been defined. #endif - #elif (SELECTED_PORT != PORT_NOT_SET) #error "SELECTED_PORT had unsupported value!" @@ -419,7 +396,7 @@ #if (HWTC_DIVISOR < 1) #error "HWTC_DIVISOR must be a non-zero positive value!" #endif - + #endif /******************************************************************************* * vTraceConsoleMessage @@ -428,11 +405,6 @@ * This needs to be correctly defined to see status reports from the trace * status monitor task (this is defined in trcUser.c). ******************************************************************************/ -#if (SELECTED_PORT == PORT_Atmel_AT91SAM7) -/* Port specific includes */ -#include "console.h" -#endif - #define vTraceConsoleMessage(x) /******************************************************************************* diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernel.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernel.h index 4c8bdd509..b92afa827 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.5.0 Recorder Library + * Tracealyzer v2.6.0 Recorder Library * Percepio AB, www.percepio.com * * trcKernel.h @@ -58,17 +58,17 @@ void vTraceStoreKernelCallWithNumericParamOnly(uint32_t evtcode, uint32_t param); void vTraceStoreKernelCallWithParam(uint32_t evtcode, traceObjectClass objectClass, - uint32_t objectNumber, uint8_t param); + uint32_t objectNumber, uint32_t param); void vTraceSetTaskInstanceFinished(objectHandleType handle); -void vTraceSetPriorityProperty(uint8_t objectclass, uint8_t id, uint8_t value); +void vTraceSetPriorityProperty(uint8_t objectclass, objectHandleType id, uint8_t value); -uint8_t uiTraceGetPriorityProperty(uint8_t objectclass, uint8_t id); +uint8_t uiTraceGetPriorityProperty(uint8_t objectclass, objectHandleType id); -void vTraceSetObjectState(uint8_t objectclass, uint8_t id, uint8_t value); +void vTraceSetObjectState(uint8_t objectclass, objectHandleType id, uint8_t value); -uint8_t uiTraceGetObjectState(uint8_t objectclass, uint8_t id); +uint8_t uiTraceGetObjectState(uint8_t objectclass, objectHandleType id); #if (INCLUDE_OBJECT_DELETE == 1) diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernelHooks.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernelHooks.h index 69431ee95..a029124e4 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.5.0 Recorder Library +* Tracealyzer v2.6.0 Recorder Library * Percepio AB, www.percepio.com * * trcKernelHooks.h @@ -97,7 +97,7 @@ /* This macro will create a task in the object table */ #undef trcKERNEL_HOOKS_TASK_CREATE -#define trcKERNEL_HOOKS_TASK_CREATE(SERVICE, pxTCB) \ +#define trcKERNEL_HOOKS_TASK_CREATE(SERVICE, CLASS, pxTCB) \ TRACE_SET_TASK_NUMBER(pxTCB) \ vTraceSetObjectName(TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB), TRACE_GET_TASK_NAME(pxTCB)); \ vTraceSetPriorityProperty(TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB), TRACE_GET_TASK_PRIORITY(pxTCB)); \ @@ -105,8 +105,8 @@ /* This macro will create a failed create call to create a task */ #undef trcKERNEL_HOOKS_TASK_CREATE_FAILED -#define trcKERNEL_HOOKS_TASK_CREATE_FAILED(SERVICE) \ - vTraceStoreKernelCall(TRACE_GET_TASK_EVENT_CODE(SERVICE, FAILED, CLASS, pxTCB), TRACE_CLASS_TASK, 0); +#define trcKERNEL_HOOKS_TASK_CREATE_FAILED(SERVICE, CLASS) \ + vTraceStoreKernelCall(TRACE_GET_TASK_EVENT_CODE(SERVICE, FAILED, CLASS, 0), TRACE_CLASS_TASK, 0); /* This macro will setup a task in the object table */ #undef trcKERNEL_HOOKS_OBJECT_CREATE @@ -132,7 +132,7 @@ /* This macro will flag a certain task as a finished instance */ #undef trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED -#define trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED(CLASS, pxObject) \ +#define trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED() \ vTraceSetTaskInstanceFinished(TRACE_GET_TASK_NUMBER(TRACE_GET_CURRENT_TASK())); #if INCLUDE_READY_EVENTS == 1 @@ -187,7 +187,24 @@ #undef trcKERNEL_HOOKS_TASK_RESUME #define trcKERNEL_HOOKS_TASK_RESUME(SERVICE, pxTCB) \ vTraceStoreKernelCall(SERVICE, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB)); - + +#undef trcKERNEL_HOOKS_TIMER_EVENT +#define trcKERNEL_HOOKS_TIMER_EVENT(SERVICE, pxTimer) \ + vTraceStoreKernelCall(SERVICE, TRACE_CLASS_TIMER, TRACE_GET_TIMER_NUMBER(pxTimer)); + +/* This macro will create a timer in the object table and assign the timer a trace handle (timer number).*/ +#undef trcKERNEL_HOOKS_TIMER_CREATE +#define trcKERNEL_HOOKS_TIMER_CREATE(SERVICE, pxTimer) \ +TRACE_SET_TIMER_NUMBER(pxTimer); \ +vTraceSetObjectName(TRACE_CLASS_TIMER, TRACE_GET_TIMER_NUMBER(pxTimer), TRACE_GET_TIMER_NAME(pxTimer)); \ +vTraceStoreKernelCall(SERVICE, TRACE_CLASS_TIMER, TRACE_GET_TIMER_NUMBER(pxTimer)); #endif -#endif /* TRCKERNELHOOKS_H */ +#undef trcKERNEL_HOOKS_TIMER_DELETE +#define trcKERNEL_HOOKS_TIMER_DELETE(SERVICE, pxTimer) \ +vTraceStoreKernelCall(SERVICE, TRACE_CLASS_TIMER, TRACE_GET_TIMER_NUMBER(pxTimer)); \ +vTraceStoreObjectNameOnCloseEvent(TRACE_GET_TIMER_NUMBER(pxTimer), TRACE_CLASS_TIMER); \ +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 diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernelPort.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernelPort.h index 211878a5d..b08a1f13b 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernelPort.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernelPort.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Tracealyzer v2.5.0 Recorder Library + * Tracealyzer v2.6.0 Recorder Library * Percepio AB, www.percepio.com * * trcKernelPort.h @@ -40,6 +40,9 @@ #define TRCKERNELPORT_H_ #include "FreeRTOS.h" // Defines configUSE_TRACE_FACILITY +#include "trcHardwarePort.h" + +extern int uiInEventGroupSetBitsFromISR; #define USE_TRACEALYZER_RECORDER configUSE_TRACE_FACILITY @@ -48,18 +51,42 @@ /* 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 5 +#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) +#define TRACE_KERNEL_OBJECT_COUNT (NQueue + NSemaphore + NMutex + NTask + NISR + NTimer + NEventGroup) /* The size of the Object Property Table entries, in bytes, per object */ @@ -82,22 +109,30 @@ 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 StartIndexISR + NISR * PropertyTableSizeISR - +#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 "trcConfig.h" #include "trcKernelHooks.h" -#include "trcHardwarePort.h" #include "trcBase.h" #include "trcKernel.h" #include "trcUser.h" @@ -187,7 +222,7 @@ const char* pszTraceGetErrorNotEnoughHandles(traceObjectClass objectclass); * 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_SUCCESS (EVENTGROUP_OBJCLOSE_PROP + 8) /*0x18*/ +#define EVENTGROUP_CREATE_OBJ_SUCCESS (EVENTGROUP_OBJCLOSE_PROP + 8) /*0x18*/ /******************************************************************************* * EVENTGROUP_SEND @@ -197,7 +232,7 @@ const char* pszTraceGetErrorNotEnoughHandles(traceObjectClass objectclass); * object class, i.e., what type of object that is operated on (queue, semaphore * or mutex). ******************************************************************************/ -#define EVENTGROUP_SEND_SUCCESS (EVENTGROUP_CREATE_SUCCESS + 8) /*0x20*/ +#define EVENTGROUP_SEND_SUCCESS (EVENTGROUP_CREATE_OBJ_SUCCESS + 8) /*0x20*/ /******************************************************************************* * EVENTGROUP_RECEIVE @@ -219,10 +254,10 @@ const char* pszTraceGetErrorNotEnoughHandles(traceObjectClass objectclass); #define EVENTGROUP_KSE_FAILED (EVENTGROUP_RECEIVE_FROM_ISR_SUCCESS + 8) /*0x40*/ /* Failed create calls - memory allocation failed */ -#define EVENTGROUP_CREATE_FAILED (EVENTGROUP_KSE_FAILED) /*0x40*/ +#define EVENTGROUP_CREATE_OBJ_FAILED (EVENTGROUP_KSE_FAILED) /*0x40*/ /* Failed send/give - timeout! */ -#define EVENTGROUP_SEND_FAILED (EVENTGROUP_CREATE_FAILED + 8) /*0x48*/ +#define EVENTGROUP_SEND_FAILED (EVENTGROUP_CREATE_OBJ_FAILED + 8) /*0x48*/ /* Failed receive/take - timeout! */ #define EVENTGROUP_RECEIVE_FAILED (EVENTGROUP_SEND_FAILED + 8) /*0x50*/ @@ -245,10 +280,10 @@ const char* pszTraceGetErrorNotEnoughHandles(traceObjectClass objectclass); #define EVENTGROUP_PEEK_SUCCESS (EVENTGROUP_SEND_BLOCK + 8) /*0x78*/ /* Events on object delete (vTaskDelete or vQueueDelete) */ -#define EVENTGROUP_DELETE_SUCCESS (EVENTGROUP_PEEK_SUCCESS + 8) /*0x80*/ +#define EVENTGROUP_DELETE_OBJ_SUCCESS (EVENTGROUP_PEEK_SUCCESS + 8) /*0x80*/ /* Other events - object class is implied: TASK */ -#define EVENTGROUP_OTHERS (EVENTGROUP_DELETE_SUCCESS + 8) /*0x88*/ +#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*/ @@ -258,11 +293,18 @@ const char* pszTraceGetErrorNotEnoughHandles(traceObjectClass objectclass); #define TASK_PRIORITY_INHERIT (EVENTGROUP_OTHERS + 6) /*0x8E*/ #define TASK_PRIORITY_DISINHERIT (EVENTGROUP_OTHERS + 7) /*0x8F*/ -/* Not yet used */ -#define EVENTGROUP_FTRACE_PLACEHOLDER (EVENTGROUP_OTHERS + 8) /*0x90*/ +#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_FTRACE_PLACEHOLDER + 8) /*0x98*/ +#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) */ @@ -300,7 +342,47 @@ const char* pszTraceGetErrorNotEnoughHandles(traceObjectClass objectclass); #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 */ @@ -330,20 +412,18 @@ objectHandleType prvTraceGetTaskNumber(void* handle); unsigned char prvTraceIsSchedulerActive(void); unsigned char prvTraceIsSchedulerSuspended(void); unsigned char prvTraceIsSchedulerStarted(void); -void prvTraceEnterCritical(void); -void prvTraceExitCritical(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_ENTER_CRITICAL_SECTION() prvTraceEnterCritical(); -#define TRACE_EXIT_CRITICAL_SECTION() prvTraceExitCritical(); - #define TRACE_IS_SCHEDULER_ACTIVE() prvTraceIsSchedulerActive() #define TRACE_IS_SCHEDULER_STARTED() prvTraceIsSchedulerStarted() #define TRACE_IS_SCHEDULER_SUSPENDED() prvTraceIsSchedulerSuspended() @@ -357,12 +437,20 @@ void* prvTraceGetCurrentTaskHandle(void); #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) (EVENTGROUP_##SERVICE##_##RESULT + TRACE_CLASS_TASK) +#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 */ @@ -386,17 +474,18 @@ void* prvTraceGetCurrentTaskHandle(void); vTraceStoreLowPower(1); \ } -/* A macro that will update the tick count when returning from tickless idle */ -#undef traceINCREASE_TICK_COUNT( xCount ) -#define traceINCREASE_TICK_COUNT( xCount ) { extern uint32_t uiTraceTickCount; uiTraceTickCount += xTickCount; } - #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 ) \ @@ -411,38 +500,38 @@ void* prvTraceGetCurrentTaskHandle(void); /* Called on vTaskSuspend */ #undef traceTASK_SUSPEND #define traceTASK_SUSPEND( pxTaskToSuspend ) \ - trcKERNEL_HOOKS_TASK_SUSPEND(TASK_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() \ - TRACE_ENTER_CRITICAL_SECTION(); \ trcKERNEL_HOOKS_TASK_DELAY(TASK_DELAY, pxCurrentTCB, xTicksToDelay); \ - trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED(UNUSED,pxCurrentTCB); \ - TRACE_EXIT_CRITICAL_SECTION(); + trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED(); /* Called on vTaskDelayUntil - note the use of FreeRTOS variable xTimeToWake */ #undef traceTASK_DELAY_UNTIL #define traceTASK_DELAY_UNTIL() \ - TRACE_ENTER_CRITICAL_SECTION(); \ trcKERNEL_HOOKS_TASK_DELAY(TASK_DELAY_UNTIL, pxCurrentTCB, xTimeToWake); \ - trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED(UNUSED,pxCurrentTCB); \ - TRACE_EXIT_CRITICAL_SECTION(); + trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED(); #if (INCLUDE_OBJECT_DELETE == 1) /* Called on vTaskDelete */ #undef traceTASK_DELETE #define traceTASK_DELETE( pxTaskToDelete ) \ - trcKERNEL_HOOKS_TASK_DELETE(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, UNUSED, pxQueue); \ - TRACE_EXIT_CRITICAL_SECTION(); + trcKERNEL_HOOKS_OBJECT_DELETE(DELETE_OBJ, UNUSED, pxQueue); \ + TRACE_EXIT_CRITICAL_SECTION(); } #endif /* Called on vTaskCreate */ @@ -450,94 +539,72 @@ void* prvTraceGetCurrentTaskHandle(void); #define traceTASK_CREATE(pxNewTCB) \ if (pxNewTCB != NULL) \ { \ - trcKERNEL_HOOKS_TASK_CREATE(CREATE, pxNewTCB); \ + 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() \ - TRACE_ENTER_CRITICAL_SECTION(); \ - trcKERNEL_HOOKS_TASK_CREATE_FAILED(CREATE); \ - TRACE_EXIT_CRITICAL_SECTION(); + 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 )\ - TRACE_ENTER_CRITICAL_SECTION(); \ - trcKERNEL_HOOKS_OBJECT_CREATE(CREATE, UNUSED, pxNewQueue); \ - TRACE_EXIT_CRITICAL_SECTION(); + 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 ) \ - TRACE_ENTER_CRITICAL_SECTION(); \ - trcKERNEL_HOOKS_OBJECT_CREATE_FAILED(CREATE, UNUSED, queueType); \ - TRACE_EXIT_CRITICAL_SECTION(); + 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 ) \ - TRACE_ENTER_CRITICAL_SECTION(); \ - trcKERNEL_HOOKS_OBJECT_CREATE(CREATE, UNUSED, pxNewQueue); \ - TRACE_EXIT_CRITICAL_SECTION(); - + 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() \ - TRACE_ENTER_CRITICAL_SECTION(); \ - trcKERNEL_HOOKS_OBJECT_CREATE_FAILED(CREATE, UNUSED, queueQUEUE_TYPE_MUTEX); \ - TRACE_EXIT_CRITICAL_SECTION(); + 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 ) \ - TRACE_ENTER_CRITICAL_SECTION(); \ - trcKERNEL_HOOKS_KERNEL_SERVICE(SEND, FAILED, UNUSED, pxMutex); \ - TRACE_EXIT_CRITICAL_SECTION(); + trcKERNEL_HOOKS_KERNEL_SERVICE(SEND, FAILED, UNUSED, pxMutex); -/* Called when a message is sent to a queue */ +/* 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)); /*For mutex, store the new owner rather than queue length */ + 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 ) \ - TRACE_ENTER_CRITICAL_SECTION();\ - trcKERNEL_HOOKS_KERNEL_SERVICE(SEND, FAILED, UNUSED, pxQueue); \ - TRACE_EXIT_CRITICAL_SECTION(); + 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 ) \ - TRACE_ENTER_CRITICAL_SECTION();\ - trcKERNEL_HOOKS_KERNEL_SERVICE(SEND, BLOCK, UNUSED, pxQueue); \ - TRACE_EXIT_CRITICAL_SECTION(); + 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)); /*For mutex, store the new owner rather than queue length */ + 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 ) \ - TRACE_ENTER_CRITICAL_SECTION(); \ - trcKERNEL_HOOKS_KERNEL_SERVICE(RECEIVE, FAILED, UNUSED, pxQueue); \ - TRACE_EXIT_CRITICAL_SECTION(); + 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 ) \ - TRACE_ENTER_CRITICAL_SECTION(); \ 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(UNUSED, pxQueue); \ - } \ - TRACE_EXIT_CRITICAL_SECTION(); + {trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED();} /* Called on xQueuePeek */ #undef traceQUEUE_PEEK @@ -554,43 +621,138 @@ void* prvTraceGetCurrentTaskHandle(void); #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_UPDATE_HEAP_USAGE_POSITIVE(uiSize);} + + +#undef traceFREE +#define traceFREE( pvAddress, uiSize ) {vTraceStoreMemMangEvent(MEM_FREE_SIZE, ( uint32_t ) pvAddress, uiSize); TRACE_UPDATE_HEAP_USAGE_NEGATIVE(uiSize);} + +#endif /************************************************************************/ /* KERNEL SPECIFIC MACROS TO EXCLUDE OR INCLUDE THINGS IN TRACE */ @@ -615,6 +777,15 @@ uint8_t uiTraceIsObjectExcluded(traceObjectClass objectclass, objectHandleType h #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) \ { \ @@ -630,6 +801,12 @@ case TRACE_CLASS_MUTEX: \ 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) \ @@ -647,6 +824,12 @@ case TRACE_CLASS_MUTEX: \ 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 */ @@ -680,6 +863,20 @@ 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() \ @@ -770,6 +967,11 @@ vTraceSetObjectName(TRACE_GET_OBJECT_TRACE_CLASS(UNUSED, object), TRACE_GET_OBJE #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 #endif /* TRCKERNELPORT_H_ */ \ No newline at end of file diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcTypes.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcTypes.h index e60b34ab9..f1d434a98 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.5.0 Recorder Library + * Tracealyzer v2.6.0 Recorder Library * Percepio AB, www.percepio.com * * trcTypes.h @@ -39,12 +39,17 @@ #define TRCTYPES_H #include +#include typedef uint16_t traceLabel; typedef uint8_t UserEventChannel; +#if (USE_16BIT_OBJECT_HANDLES == 1) +typedef uint16_t objectHandleType; +#else typedef uint8_t objectHandleType; +#endif typedef uint8_t traceObjectClass; diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcUser.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcUser.h index c6904008b..dba4432e6 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.5.0 Recorder Library + * Tracealyzer v2.6.0 Recorder Library * Percepio AB, www.percepio.com * * trcUser.h @@ -421,6 +421,12 @@ void vTraceChannelUserEvent(UserEventChannel channel); #define vTraceSetISRProperties(handle, name, priority) #define vTraceStoreISRBegin(id) #define vTraceStoreISREnd() +#define vTraceExcludeTaskFromTrace(handle) +#define vTraceSetQueueName(a, b) +#define vTraceSetMutexName(a, b) +#define vTraceSetSemaphoreName(a, b) +#define vTraceSetEventGroupName(a, b) + #endif #ifdef __cplusplus diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/debugger trace upload.txt b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/debugger trace upload.txt index f815e8b21..bb25213fd 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/debugger trace upload.txt +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/debugger trace upload.txt @@ -1,7 +1,7 @@ Tracealyzer - Uploading the trace data ----------------------------------------- -Percepio AB, Nov. 8, 2012 +Percepio AB, Jan. 23, 2014 This document decribes how to upload the trace data from the target system to Tracealyzer. @@ -11,15 +11,6 @@ chip RAM. This is a plain RAM dump, that is done whenever you want to look at the trace buffer contents. This means it works with essentially with any debug probe on the market. -If the device has a file system and some possibility of accessing this file -system from the development PC, it is also possible to write the recorder data -to a file, using vTraceGetTraceBuffer() and uiTraceGetTraceBufferSize() -found in trcUser.h/.c. - -Note that hardware-generated trace is not required (or used by) Tracealyzer. -We however plan to add support for that in future versions of Tracealyzer -and other Tracealyzer products. - Built-in support for Segger J-Link/J-Trace and Atmel SAM-ICE ------------------------------------------------------------ Tracealyzer v2.3 supports Segger J-Link and J-Link compatible debuggers @@ -27,9 +18,8 @@ directly, without any debugger IDE involved. Using other debug probes is also possible, but requires some extra steps, described below. If you have a Segger J-Link/J-Trace debug probe or another J-Link compatible -debug probe, just select - - "File" menu -> "Upload from ". +debug probe, just select "Read Trace" in the "J-Link" menu. Note that this +menu is only available if a compatible debug probe is found. This opens a dialog where you get to enter the memory region where the recorder data structure is located. Normally you select the entire @@ -37,23 +27,17 @@ internal RAM according to the datasheet of your MCU, but the exact address can be found can by inspecting the "RecorderData" struct or the "RecorderDataPtr" pointer with your debugger. -Typical values are 0x0, 0x10000000 or 0x20000000 as start address -and 0x10000 or 0x20000 as size (64 KB or 128 KB). - -This makes Tracealyzer reads the chip RAM and locate the trace data. -Note that this option is only available if a compatible debug probe is found. - J-Link compatible debug probes also include Atmel SAM-ICE and many built-in debug interfaces on demonstration/evaluation boards (where there is a USB connection directly to the board). Look for a Segger J-Link label on the board. MemoryLogger extension in Atmel Studio 6 ---------------------------------------- -Atmel's new MemoryLogger extension provides a superb integration with -Tracealyzer. Look for "MemoryLogger" in Atmel Gallery, available in -Atmel Studio and at the Atmel website. +Atmel's MemoryLogger extension provides a superb integration with FreeRTOS+Trace. +Look for "MemoryLogger" in Atmel Gallery, available in Atmel Studio and at the +Atmel website (http://gallery.atmel.com). -This extension automatically detects the path to Tracealyzer, if +This extension automatically detects the path to FreeRTOS+Trace, if installed, and gives you a single-click upload/refresh. You can use it while debugging and optionally get an automatic refresh eash time the MCU is halted, e.g., on each breakpoint. diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/readme.txt b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/readme.txt index 883f85ebb..2c6c55195 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/readme.txt +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/readme.txt @@ -4,38 +4,45 @@ Tracealyzer Trace Recorder Library Percepio AB www.percepio.com -This directory contains the a generic trace recorder library for Tracealyzer v2.5. +This directory contains the a generic trace recorder library for Tracealyzer v2.6. For information on how to upload the trace data from your target system RAM to Tracealyzer, see "debugger trace upload.txt" Files included -------------- -- trcConfig.h - The recorder's configuration file, check this! -- trcUser.c / trcUser.h - The main API towards the application (trcUser.h in the only include necessary). -- trcKernel.c / trcKernel.h - Internal routines for storing kernel events. -- trcBase.c / trcBase.h - Internal routines for manipulating the data structures and calculating timestamps. -- trcHardwarePort.c / trcHardwarePort.h - The port layer, abstracting the hardware (mainly the timer used for timestamping). -- trcKernelHooks.h - The interface between the Kernel and the recorder, containing trace macro defintions. -- trcKernelPort.h - Kernel specific implementations of macros and data. -- 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.c/.h - Kernel specific implementations of macros and data. +- trcKernelHooks.h - The trace macro defines (OS independent). +- trcTypes.h - Type definitions used. Hardware Timer Ports -------------------- This release contains hardware timer ports for the following hardware architectures: -- ARM Cortex M3/M4 (all brands, such as Atmel SAM3/SAM4, NXP 17xx, 18xx, 43xx, STM32, Freescale Kinetis, ...) +- ARM Cortex M3/M4/M0/M0+ (all brands, such as Atmel SAM3x/SAM4x/SAM D20, NXP 17xx, 18xx, 43xx, STM32, Freescale Kinetis, ...) - Atmel AT91SAM7x - Atmel AT32UC3 (AVR32) - Renesas RX600 (e.g., RX62N) - Microchip dsPIC/PIC24 - -These are defined in trcPort.h. This also contains several "unofficial" ports, provided by external contributors. -By unofficial, it means that they are not yet verified by Percepio AB. Please refer to trcPort.h for detailed information. -If you use an unofficial port and beleive it is incorrect, please let us know! +- Microchip PIC32 +- NXP LPC2106 +- Texas Instruments TMS570 (Cortex-R4) +- Texas Instruments MSP430 +- Xilinx PowerPC 405 +- Xilinx PowerPC 440 +- Xilinx Microblaze + +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) 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 trcPort.h for further information. +according to your specific MCU. See trcHardwarePort.h for further information. In case you have any questions, do not hesitate to contact support@percepio.com diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcBase.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcBase.c index bfd6cb28c..be5f93530 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.5.0 Recorder Library + * Tracealyzer v2.6.0 Recorder Library * Percepio AB, www.percepio.com * * trcBase.c @@ -113,6 +113,7 @@ void prvTraceInitTraceData() /* DO NOTHING */ #endif + TRACE_ASSERT(RecorderDataPtr != NULL, "prvTraceInitTraceData, RecorderDataPtr == NULL", ); if (! RecorderDataPtr) @@ -120,7 +121,7 @@ void prvTraceInitTraceData() vTraceError("No recorder data structure allocated!"); return; } - + (void)memset(RecorderDataPtr, 0, sizeof(RecorderDataType)); RecorderDataPtr->startmarker0 = 0x00; @@ -145,6 +146,8 @@ void prvTraceInitTraceData() RecorderDataPtr->debugMarker0 = 0xF0F0F0F0; + RecorderDataPtr->isUsing16bitHandles = USE_16BIT_OBJECT_HANDLES; + /* This function is kernel specific */ vTraceInitObjectPropertyTable(); @@ -182,6 +185,10 @@ void prvTraceInitTraceData() /* Fix the start markers of the trace data structure */ vInitStartMarkers(); + + #ifdef PORT_SPECIFIC_INIT + PORT_SPECIFIC_INIT(); + #endif } static void vInitStartMarkers() @@ -255,7 +262,7 @@ uint16_t uiIndexOfObject(objectHandleType objecthandle, uint8_t objectclass) objectHandleType xTraceGetObjectHandle(traceObjectClass objectclass) { - static objectHandleType handle; + objectHandleType handle; static int indexOfHandle; TRACE_ASSERT(objectclass < TRACE_NCLASSES, "xTraceGetObjectHandle: Invalid value for objectclass", (objectHandleType)0); @@ -314,7 +321,7 @@ void vTraceFreeObjectHandle(traceObjectClass objectclass, objectHandleType handl objectHandleStacks.lowestIndexOfClass[objectclass]) { /* Error */ - vTraceError("Attempt to free more handles than allocated! (duplicate xTaskDelete or xQueueDelete?)"); + vTraceError("Attempt to free more handles than allocated!"); } else { @@ -389,8 +396,11 @@ traceLabel prvTraceOpenSymbol(const char* name, traceLabel userEventChannel) 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); @@ -411,8 +421,6 @@ traceLabel prvTraceOpenSymbol(const char* name, traceLabel userEventChannel) * Supporting functions ******************************************************************************/ -extern volatile uint32_t rtest_error_flag; - /******************************************************************************* * vTraceError * @@ -430,8 +438,8 @@ void vTraceError(const char* msg) TRACE_ASSERT(msg != NULL, "vTraceError: msg == NULL", ); TRACE_ASSERT(RecorderDataPtr != NULL, "vTraceError: RecorderDataPtr == NULL", ); - // Stop the recorder. Note: We do not call vTraceStop, since that adds a weird - // and unnecessary dependency to trcUser.c. + /* Stop the recorder. Note: We do not call vTraceStop, since that adds a weird + and unnecessary dependency to trcUser.c */ RecorderDataPtr->recorderActive = 0; @@ -503,12 +511,12 @@ void prvCheckDataToBeOverwrittenForMultiEntryEvents(uint8_t nofEntriesToCheck) * Updates the index of the event buffer. ******************************************************************************/ void prvTraceUpdateCounters(void) -{ - if (RecorderDataPtr->recorderActive == 0) +{ + if (RecorderDataPtr->recorderActive == 0) { return; } - + RecorderDataPtr->numEvents++; RecorderDataPtr->nextFreeIndex++; @@ -556,13 +564,17 @@ uint16_t prvTraceGetDTS(uint16_t param_maxDTS) 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, - such as in the Cortex M port, it might not be initialized - before the Kernel scheduler has been started has been - started. We therefore store the frequency of the timer - once the counter register has changed. */ + 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 + uiTraceStart, which might be called before the scheduler + has been started.) */ #if (SELECTED_PORT == PORT_Win32) RecorderDataPtr->frequency = 100000; @@ -572,15 +584,15 @@ uint16_t prvTraceGetDTS(uint16_t param_maxDTS) 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); - + + vTracePortGetTimeStamp(×tamp); + /*************************************************************************** * Since dts is unsigned the result will be correct even if timestamp has * wrapped around. @@ -770,7 +782,7 @@ uint16_t prvTraceCreateSymbolTableEntry(const char* name, void prvTraceGetChecksum(const char *pname, uint8_t* pcrc, uint8_t* plength) { unsigned char c; - int length = 0; + int length = 1; int crc = 0; TRACE_ASSERT(pname != NULL, "prvTraceGetChecksum: pname == NULL", ); @@ -789,4 +801,52 @@ void prvTraceGetChecksum(const char *pname, uint8_t* pcrc, uint8_t* plength) *plength = (uint8_t)length; } -#endif \ No newline at end of file +#if (USE_16BIT_OBJECT_HANDLES == 1) + +void prvTraceStoreXID(objectHandleType handle); + +/****************************************************************************** + * prvTraceStoreXID + * + * Stores an XID (eXtended IDentifier) event. + * This is used if an object/task handle is larger than 255. + * The parameter "handle" is the full (16 bit) handle, assumed to be 256 or + * larger. Handles below 256 should not use this function. + * + * NOTE: this function MUST be called from within a critical section. + *****************************************************************************/ + +void prvTraceStoreXID(objectHandleType handle) +{ + XPSEvent* xid; + + TRACE_ASSERT(handle >= 256, "prvTraceStoreXID: Handle < 256", ); + + xid = (XPSEvent*)xTraceNextFreeEventBufferSlot(); + + if (xid != NULL) + { + xid->type = XID; + + /* This function is (only) used when objectHandleType is 16 bit... */ + xid->xps_16 = handle; + + prvTraceUpdateCounters(); + } +} + +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).*/ + return 255; + } + return (unsigned char)(handle & 0xFF); +} + +#endif + +#endif diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcHardwarePort.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcHardwarePort.c index 6570e3553..ac4a6f263 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.5.0 Recorder Library + * Tracealyzer v2.6.0 Recorder Library * Percepio AB, www.percepio.com * * trcHardwarePort.c @@ -37,6 +37,7 @@ ******************************************************************************/ #include "trcHardwarePort.h" +#include "trcKernelPort.h" #if (USE_TRACEALYZER_RECORDER == 1) @@ -55,6 +56,45 @@ uint32_t last_timestamp = 0; ******************************************************************************/ uint32_t uiTraceTickCount = 0; +uint32_t DWT_CYCLES_ADDED = 0; + +#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) +{ + asm volatile ("MSR primask, %0" : : "r" (priMask) ); +} + +uint32_t prvTraceGetIRQMask(void) +{ + uint32_t result; + asm volatile ("MRS %0, primask" : "=r" (result) ); + return result; +} + +void prvTraceInitCortexM() +{ + DWT_CTRL_REG |= 1; /* Enable the cycle counter */ + DWT_CYCLE_COUNTER = 0; + + if (RecorderDataPtr->frequency == 0) + { + RecorderDataPtr->frequency = TRACE_CPU_CLOCK_HZ / HWTC_DIVISOR; + } +} + +#endif + /****************************************************************************** * vTracePortGetTimeStamp * diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernel.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernel.c index 0b1770867..e79294740 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernel.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernel.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Tracealyzer v2.5.0 Recorder Library + * Tracealyzer v2.6.0 Recorder Library * Percepio AB, www.percepio.com * * trcKernel.c @@ -58,6 +58,7 @@ void vTraceStoreTaskReady(objectHandleType handle) { uint16_t dts3; TREvent* tr; + TRACE_SR_ALLOC_CRITICAL_SECTION(); TRACE_ASSERT(handle > 0 && handle <= NTask, "vTraceStoreTaskReady: Invalid value for handle", ); @@ -73,6 +74,7 @@ void vTraceStoreTaskReady(objectHandleType handle) return; } + trcCRITICAL_SECTION_BEGIN(); if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ { if (!TRACE_GET_TASK_FLAG_ISEXCLUDED(handle)) @@ -80,19 +82,22 @@ void vTraceStoreTaskReady(objectHandleType handle) dts3 = (uint16_t)prvTraceGetDTS(0xFFFF); if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ { + uint8_t hnd8 = prvTraceGet8BitHandle(handle); + tr = (TREvent*)xTraceNextFreeEventBufferSlot(); if (tr != NULL) { tr->type = DIV_TASK_READY; tr->dts = dts3; - tr->objHandle = handle; + tr->objHandle = hnd8; prvTraceUpdateCounters(); } } } } + trcCRITICAL_SECTION_END(); } #endif @@ -105,6 +110,7 @@ void vTraceStoreLowPower(uint32_t flag) { uint16_t dts; LPEvent* lp; + TRACE_SR_ALLOC_CRITICAL_SECTION(); TRACE_ASSERT(flag <= 1, "vTraceStoreLowPower: Invalid flag value", ); @@ -119,7 +125,8 @@ void vTraceStoreLowPower(uint32_t flag) vTraceError("Recorder busy - high priority ISR using syscall? (1)"); return; } - + + trcCRITICAL_SECTION_BEGIN(); if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ { dts = (uint16_t)prvTraceGetDTS(0xFFFF); @@ -135,8 +142,72 @@ void vTraceStoreLowPower(uint32_t flag) } } } + trcCRITICAL_SECTION_END(); } +/******************************************************************************* + * 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 + * code "ecode + 1", so make sure this is respected in the event code table. + ******************************************************************************/ +#if (INCLUDE_MEMMANG_EVENTS == 1) +void vTraceStoreMemMangEvent(uint32_t ecode, uint32_t address, uint32_t size) +{ + uint8_t dts1; + MemEventSize * ms; + MemEventAddr * ma; + uint16_t size_low; + uint16_t addr_low; + uint8_t addr_high; + + TRACE_SR_ALLOC_CRITICAL_SECTION(); + + 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) + { + 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->size = size_low; + prvTraceUpdateCounters(); + + /* Storing a second record with address (signals "failed" if null) */ + #if (HEAP_SIZE_BELOW_16M) + addr_low = address & 0xFFFF; + addr_high = (address >> 16) & 0xFF; + #else + 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(); + } + } + } + } + trcCRITICAL_SECTION_END(); +} +#endif + /******************************************************************************* * vTraceStoreKernelCall * @@ -147,7 +218,8 @@ void vTraceStoreKernelCall(uint32_t ecode, traceObjectClass objectClass, uint32_ { 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", ); @@ -170,96 +242,106 @@ void vTraceStoreKernelCall(uint32_t ecode, traceObjectClass objectClass, uint32_ 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)) - { - trcCRITICAL_SECTION_BEGIN(); + { 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 = (uint8_t)objectNumber; + kse->objHandle = hnd8; prvTraceUpdateCounters(); } - } - trcCRITICAL_SECTION_END(); + } } } } + trcCRITICAL_SECTION_END(); } /******************************************************************************* * vTraceStoreKernelCallWithParam * - * Used for storing kernel calls with a handle and a numeric parameter. This is - * only used for traceTASK_PRIORITY_SET at the moment. + * 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, - uint8_t param) + uint32_t param) { KernelCallWithParamAndHandle * kse; - uint8_t dts2; + uint8_t dts2; + 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; + } + + trcCRITICAL_SECTION_BEGIN(); if (RecorderDataPtr->recorderActive && handle_of_last_logged_task && (! inExcludedTask || nISRactive)) { - 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; - } - + /* Check if the referenced object or the event code is excluded */ if (!uiTraceIsObjectExcluded(objectClass, (objectHandleType)objectNumber) && !TRACE_GET_EVENT_CODE_FLAG_ISEXCLUDED(evtcode)) - { - trcCRITICAL_SECTION_BEGIN(); + { 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 = (uint8_t)objectNumber; - kse->param = param; + kse->objHandle = hnd8; + kse->param = p8; prvTraceUpdateCounters(); } - } - trcCRITICAL_SECTION_END(); + } } } + trcCRITICAL_SECTION_END(); } /******************************************************************************* * prvTraceGetParam * * Used for storing extra bytes for kernel calls with numeric parameters. + * + * May only be called within a critical section! ******************************************************************************/ static uint32_t prvTraceGetParam(uint32_t param_max, uint32_t param) { @@ -296,30 +378,33 @@ void vTraceStoreKernelCallWithNumericParamOnly(uint32_t evtcode, uint32_t param) { KernelCallWithParam16 * kse; uint8_t dts6; - uint16_t restParam = 0; + uint16_t restParam; + TRACE_SR_ALLOC_CRITICAL_SECTION(); + + restParam = 0; 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; + } + + 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)) - { - 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; - } - - trcCRITICAL_SECTION_BEGIN(); + { dts6 = (uint8_t)prvTraceGetDTS(0xFF); if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ @@ -337,10 +422,10 @@ void vTraceStoreKernelCallWithNumericParamOnly(uint32_t evtcode, uint32_t param) prvTraceUpdateCounters(); } } - } - trcCRITICAL_SECTION_END(); + } } } + trcCRITICAL_SECTION_END(); } /******************************************************************************* @@ -352,7 +437,10 @@ void vTraceStoreTaskswitch(objectHandleType task_handle) { uint16_t dts3; TSEvent* ts; - int8_t skipEvent = 0; + int8_t skipEvent; + TRACE_SR_ALLOC_CRITICAL_SECTION(); + + skipEvent = 0; TRACE_ASSERT(task_handle <= NTask, "vTraceStoreTaskswitch: Invalid value for task_handle", ); @@ -370,8 +458,7 @@ void vTraceStoreTaskswitch(objectHandleType task_handle) function since critical sections should not be used in the context switch event...) ***************************************************************************/ - recorder_busy++; - + /* Skip the event if the task has been excluded, using vTraceExcludeTask */ if (TRACE_GET_TASK_FLAG_ISEXCLUDED(task_handle)) { @@ -383,13 +470,14 @@ void vTraceStoreTaskswitch(objectHandleType task_handle) inExcludedTask = 0; } + trcCRITICAL_SECTION_BEGIN_ON_CORTEX_M_ONLY(); + /* Skip the event if the same task is scheduled */ if (task_handle == handle_of_last_logged_task) { skipEvent = 1; } - - + if (!RecorderDataPtr->recorderActive) { skipEvent = 1; @@ -402,7 +490,10 @@ void vTraceStoreTaskswitch(objectHandleType task_handle) 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) @@ -418,7 +509,7 @@ void vTraceStoreTaskswitch(objectHandleType task_handle) } ts->dts = dts3; - ts->objHandle = handle_of_last_logged_task; + ts->objHandle = hnd8; vTraceSetObjectState(TRACE_CLASS_TASK, handle_of_last_logged_task, @@ -429,8 +520,7 @@ void vTraceStoreTaskswitch(objectHandleType task_handle) } } - /* See comment on recorder_busy++ above. */ - recorder_busy--; + trcCRITICAL_SECTION_END_ON_CORTEX_M_ONLY(); } /******************************************************************************* @@ -454,6 +544,8 @@ void vTraceStoreObjectNameOnCloseEvent(objectHandleType handle, if (RecorderDataPtr->recorderActive) { + uint8_t hnd8 = prvTraceGet8BitHandle(handle); + name = TRACE_PROPERTY_NAME_GET(objectclass, handle); idx = prvTraceOpenSymbol(name, 0); @@ -463,7 +555,7 @@ void vTraceStoreObjectNameOnCloseEvent(objectHandleType handle, if (ce != NULL) { ce->type = EVENTGROUP_OBJCLOSE_NAME + objectclass; - ce->objHandle = handle; + ce->objHandle = hnd8; ce->symbolIndex = idx; prvTraceUpdateCounters(); } @@ -499,7 +591,7 @@ void vTraceStoreObjectPropertiesOnCloseEvent(objectHandleType handle, } #endif -void vTraceSetPriorityProperty(uint8_t objectclass, uint8_t id, uint8_t value) +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", ); @@ -507,7 +599,7 @@ void vTraceSetPriorityProperty(uint8_t objectclass, uint8_t id, uint8_t value) TRACE_PROPERTY_ACTOR_PRIORITY(objectclass, id) = value; } -uint8_t uiTraceGetPriorityProperty(uint8_t objectclass, uint8_t id) +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); @@ -515,7 +607,7 @@ uint8_t uiTraceGetPriorityProperty(uint8_t objectclass, uint8_t id) return TRACE_PROPERTY_ACTOR_PRIORITY(objectclass, id); } -void vTraceSetObjectState(uint8_t objectclass, uint8_t id, uint8_t value) +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", ); @@ -523,7 +615,7 @@ void vTraceSetObjectState(uint8_t objectclass, uint8_t id, uint8_t value) TRACE_PROPERTY_OBJECT_STATE(objectclass, id) = value; } -uint8_t uiTraceGetObjectState(uint8_t objectclass, uint8_t id) +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); diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernelPort.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernelPort.c index 91b6a8156..166dbcc34 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.5.0 Recorder Library + * Tracealyzer v2.6.0 Recorder Library * Percepio AB, www.percepio.com * * trcKernelPort.c @@ -43,6 +43,8 @@ #include "task.h" +/* For classes implemented as FreeRTOS Queues: +This translates queue.type to the corresponding trace object class. */ traceObjectClass TraceObjectClassTable[5] = { TRACE_CLASS_QUEUE, TRACE_CLASS_MUTEX, @@ -51,12 +53,14 @@ traceObjectClass TraceObjectClassTable[5] = { TRACE_CLASS_MUTEX }; +int uiInEventGroupSetBitsFromISR = 0; + extern unsigned char ucQueueGetQueueType(void*); -extern unsigned portBASE_TYPE uxQueueGetQueueNumber(void*); +extern portBASE_TYPE uxQueueGetQueueNumber(void*); objectHandleType prvTraceGetObjectNumber(void* handle) { - return uxQueueGetQueueNumber(handle); + return ( objectHandleType ) uxQueueGetQueueNumber(handle); } unsigned char prvTraceGetObjectType(void* handle) @@ -69,16 +73,6 @@ objectHandleType prvTraceGetTaskNumber(void* handle) return (objectHandleType)uxTaskGetTaskNumber(handle); } -void prvTraceEnterCritical() -{ - taskENTER_CRITICAL(); -} - -void prvTraceExitCritical() -{ - taskEXIT_CRITICAL(); -} - unsigned char prvTraceIsSchedulerActive() { return xTaskGetSchedulerState() == taskSCHEDULER_RUNNING; @@ -108,42 +102,50 @@ void vTraceInitObjectPropertyTable() RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[2] = NMutex; RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[3] = NTask; RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[4] = NISR; + RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[5] = NTimer; + RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[6] = NEventGroup; RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[0] = NameLenQueue; RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[1] = NameLenSemaphore; RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[2] = NameLenMutex; RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[3] = NameLenTask; RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[4] = NameLenISR; + RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[5] = NameLenTimer; + RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[6] = NameLenEventGroup; RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[0] = PropertyTableSizeQueue; RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[1] = PropertyTableSizeSemaphore; RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[2] = PropertyTableSizeMutex; RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[3] = PropertyTableSizeTask; RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[4] = PropertyTableSizeISR; + RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[5] = PropertyTableSizeTimer; + RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[6] = PropertyTableSizeEventGroup; RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[0] = StartIndexQueue; RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[1] = StartIndexSemaphore; RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[2] = StartIndexMutex; RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[3] = StartIndexTask; RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[4] = StartIndexISR; + RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[5] = StartIndexTimer; + RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[6] = StartIndexEventGroup; RecorderDataPtr->ObjectPropertyTable.ObjectPropertyTableSizeInBytes = TRACE_OBJECT_TABLE_SIZE; } /* Initialization of the handle mechanism, see e.g, xTraceGetObjectHandle */ void vTraceInitObjectHandleStack() { - objectHandleStacks.indexOfNextAvailableHandle[0] = 0; - objectHandleStacks.indexOfNextAvailableHandle[1] = NQueue; - objectHandleStacks.indexOfNextAvailableHandle[2] = NQueue + NSemaphore; - objectHandleStacks.indexOfNextAvailableHandle[3] = NQueue + NSemaphore + NMutex; - objectHandleStacks.indexOfNextAvailableHandle[4] = NQueue + NSemaphore + NMutex + NTask; - objectHandleStacks.lowestIndexOfClass[0] = 0; - objectHandleStacks.lowestIndexOfClass[1] = NQueue; - objectHandleStacks.lowestIndexOfClass[2] = NQueue + NSemaphore; - objectHandleStacks.lowestIndexOfClass[3] = NQueue + NSemaphore + NMutex; - objectHandleStacks.lowestIndexOfClass[4] = NQueue + NSemaphore + NMutex + NTask; + objectHandleStacks.indexOfNextAvailableHandle[0] = objectHandleStacks.lowestIndexOfClass[0] = 0; + objectHandleStacks.indexOfNextAvailableHandle[1] = objectHandleStacks.lowestIndexOfClass[1] = NQueue; + objectHandleStacks.indexOfNextAvailableHandle[2] = objectHandleStacks.lowestIndexOfClass[2] = NQueue + NSemaphore; + objectHandleStacks.indexOfNextAvailableHandle[3] = objectHandleStacks.lowestIndexOfClass[3] = NQueue + NSemaphore + NMutex; + objectHandleStacks.indexOfNextAvailableHandle[4] = objectHandleStacks.lowestIndexOfClass[4] = NQueue + NSemaphore + NMutex + NTask; + 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[1] = NQueue + NSemaphore - 1; objectHandleStacks.highestIndexOfClass[2] = NQueue + NSemaphore + NMutex - 1; objectHandleStacks.highestIndexOfClass[3] = NQueue + NSemaphore + NMutex + NTask - 1; objectHandleStacks.highestIndexOfClass[4] = NQueue + NSemaphore + NMutex + NTask + NISR - 1; + objectHandleStacks.highestIndexOfClass[5] = NQueue + NSemaphore + NMutex + NTask + NISR + NTimer - 1; + objectHandleStacks.highestIndexOfClass[6] = NQueue + NSemaphore + NMutex + NTask + NISR + NTimer + NEventGroup - 1; } /* Returns the "Not enough handles" error message for this object class */ @@ -161,6 +163,10 @@ const char* pszTraceGetErrorNotEnoughHandles(traceObjectClass objectclass) return "Not enough MUTEX handles - increase NMutex in trcConfig.h"; case TRACE_CLASS_QUEUE: return "Not enough QUEUE handles - increase NQueue in trcConfig.h"; + case TRACE_CLASS_TIMER: + return "Not enough TIMER handles - increase NTimer in trcConfig.h"; + case TRACE_CLASS_EVENTGROUP: + return "Not enough EVENTGROUP handles - increase NEventGroup in trcConfig.h"; default: return "pszTraceGetErrorHandles: Invalid objectclass!"; } @@ -182,8 +188,14 @@ uint8_t uiTraceIsObjectExcluded(traceObjectClass objectclass, objectHandleType h return TRACE_GET_MUTEX_FLAG_ISEXCLUDED(handle); case TRACE_CLASS_QUEUE: return TRACE_GET_QUEUE_FLAG_ISEXCLUDED(handle); + case TRACE_CLASS_TIMER: + return TRACE_GET_TIMER_FLAG_ISEXCLUDED(handle); + case TRACE_CLASS_EVENTGROUP: + return TRACE_GET_EVENTGROUP_FLAG_ISEXCLUDED(handle); } + vTraceError("Invalid object class ID in uiTraceIsObjectExcluded!"); + /* Must never reach */ return 1; } diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcUser.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcUser.c index 74dc8079e..5f46a809d 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.5.0 Recorder Library + * Tracealyzer v2.6.0 Recorder Library * Percepio AB, www.percepio.com * * trcUser.c @@ -34,6 +34,8 @@ * Copyright Percepio AB, 2013. * www.percepio.com ******************************************************************************/ +#include "FreeRTOS.h" +#include "task.h" #include "trcUser.h" @@ -47,7 +49,7 @@ TRACE_STOP_HOOK vTraceStopHookPtr = (TRACE_STOP_HOOK)0; extern uint8_t inExcludedTask; extern uint8_t nISRactive; -extern uint8_t handle_of_last_logged_task; +extern objectHandleType handle_of_last_logged_task; extern uint32_t dts_min; extern uint32_t hwtc_count_max_after_tick; extern uint32_t hwtc_count_sum_after_tick; @@ -99,12 +101,15 @@ void vTraceSetRecorderData(void* pRecorderData) ******************************************************************************/ void vTraceClear(void) { + TRACE_SR_ALLOC_CRITICAL_SECTION(); trcCRITICAL_SECTION_BEGIN(); RecorderDataPtr->absTimeLastEvent = 0; RecorderDataPtr->nextFreeIndex = 0; RecorderDataPtr->numEvents = 0; RecorderDataPtr->bufferIsFull = 0; + traceErrorMessage = NULL; + RecorderDataPtr->internalErrorOccured = 0; trcCRITICAL_SECTION_END(); @@ -125,7 +130,10 @@ void vTraceClear(void) uint32_t uiTraceStart(void) { - objectHandleType handle = 0; + objectHandleType handle; + TRACE_SR_ALLOC_CRITICAL_SECTION(); + + handle = 0; if (RecorderDataPtr == NULL) { @@ -300,6 +308,103 @@ void vTraceSetISRProperties(objectHandleType handle, const char* name, char prio vTraceSetPriorityProperty(TRACE_CLASS_ISR, handle, priority); } +#if (SELECTED_PORT == PORT_ARM_CortexM) +/****************************************************************************** + * (Advanced...) + * + * 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 + * hardware, we can only detect this indirectly, in the following manner: + * + * 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 + * 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 + * 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 + * 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 + * time and response time (maximum ISR_TAILCHAINING_THRESHOLD cycles more). + *****************************************************************************/ +#define ISR_TAILCHAINING_THRESHOLD 66 + +uint8_t* ptrLastISRExitEvent = NULL; +uint32_t DWTCycleCountAtLastISRExit = 0; + +/****************************************************************************** + * (Advanced...) + * + * MEASURE_ISR_TAILCHAINING_THRESHOLD (For Cortex-M devices only) + * + * Allows for measuring 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. + * 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 + * 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 + * + * 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. + *****************************************************************************/ +#define MEASURE_ISR_TAILCHAINING_THRESHOLD 1 + +#if (MEASURE_ISR_TAILCHAINING_THRESHOLD == 1) +volatile uint32_t threshold_low_watermark = 2000000000; +#endif + +#endif + /******************************************************************************* * vTraceStoreISRBegin * @@ -318,34 +423,64 @@ void vTraceSetISRProperties(objectHandleType handle, const char* name, char prio * vTraceStoreISREnd(); * } * - * NOTE: You need to make sure that any traced interrupts actually are - * disabled by trcCRITICAL_SECTION_BEGIN(). - * If an invalid call to vTraceStoreISRBegin is detected (i.e., that preempted - * a critical section of the recorder) this will generate a recorder error - * using vTraceError. ******************************************************************************/ void vTraceStoreISRBegin(objectHandleType handle) { uint16_t dts4; - TSEvent* ts = NULL; + #if (SELECTED_PORT == PORT_ARM_CortexM) + uint32_t CPUCyclesSinceLastISRExit = DWT_CYCLE_COUNTER - DWTCycleCountAtLastISRExit; + #endif + TSEvent* ts; + TRACE_SR_ALLOC_CRITICAL_SECTION(); - TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[TRACE_CLASS_ISR], "vTraceStoreISRBegin: Invalid value for handle", ); + ts = NULL; +#if (SELECTED_PORT == PORT_ARM_CortexM) + if (DWTCycleCountAtLastISRExit > 0) + { + #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 + 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; + } + } + + } +#endif + if (recorder_busy) { vTraceError("Illegal call to vTraceStoreISRBegin, recorder busy!"); return; } + trcCRITICAL_SECTION_BEGIN(); if (RecorderDataPtr->recorderActive && handle_of_last_logged_task) { - trcCRITICAL_SECTION_BEGIN(); + + TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[TRACE_CLASS_ISR], "vTraceStoreISRBegin: Invalid value for handle", ); + dts4 = (uint16_t)prvTraceGetDTS(0xFFFF); 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(); @@ -353,7 +488,7 @@ void vTraceStoreISRBegin(objectHandleType handle) { ts->type = TS_ISR_BEGIN; ts->dts = dts4; - ts->objHandle = handle; + ts->objHandle = hnd8; prvTraceUpdateCounters(); } } @@ -362,40 +497,11 @@ void vTraceStoreISRBegin(objectHandleType handle) /* This should not occur unless something is very wrong */ vTraceError("Too many nested interrupts!"); } - } - trcCRITICAL_SECTION_END(); - } -} - - -#if (SELECTED_PORT == PORT_ARM_CortexM) - -static int tailchain_irq_pending(void); - -/******************************************************************************* - * tailchain_irq_pending - * - * For Cortex-M chips only. Returns 1 if an interrupt is pending, by checking - * the 8 NVIC IRQ pend registers at 0xE000E200 to 0xE000E21C. Returns 0 if no - * interrupt is pending. This is used to predict tailchaining of ISRs. - ******************************************************************************/ -static int tailchain_irq_pending(void) -{ - uint32_t* pend_reg = ((uint32_t*)0xE000E200); - int i; - - for (i=0; i<8; i++) - { - if (pend_reg[i] != 0) - { - return 1; + } } - } - return 0; + trcCRITICAL_SECTION_END(); } -#endif - /******************************************************************************* * vTraceStoreISREnd * @@ -414,63 +520,61 @@ static int tailchain_irq_pending(void) * vTraceStoreISREnd(); * } * - * NOTE: You need to make sure that any traced interrupts actually are - * disabled by trcCRITICAL_SECTION_BEGIN(). - * If an invalid call to vTraceStoreISREnd is detected (i.e., that preempted - * a critical section of the recorder) this will generate a recorder error - * using vTraceError. ******************************************************************************/ void vTraceStoreISREnd(void) { - TSEvent* ts; - uint16_t dts5; + TSEvent* ts; + uint16_t dts5; + TRACE_SR_ALLOC_CRITICAL_SECTION(); - if (recorder_busy) - { - vTraceError("Illegal call to vTraceStoreISREnd, recorder busy!"); - return; - } + if (recorder_busy) + { + vTraceError("Illegal call to vTraceStoreISREnd, recorder busy!"); + return; + } - if (RecorderDataPtr->recorderActive && handle_of_last_logged_task) - { - #if (SELECTED_PORT == PORT_ARM_CortexM) - if (tailchain_irq_pending() > 0) - { - nISRactive--; /* If an IRQ strikes exactly here, the resulting - ISR tailchaining is not detected. The trace instead shows a very - short fragment of the earlier preempted task/ISR, and then the new - ISR begins. */ - return; - } - #endif + trcCRITICAL_SECTION_BEGIN(); + if (RecorderDataPtr->recorderActive && handle_of_last_logged_task) + { + dts5 = (uint16_t)prvTraceGetDTS(0xFFFF); - trcCRITICAL_SECTION_BEGIN(); - dts5 = (uint16_t)prvTraceGetDTS(0xFFFF); + if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ + { + uint8_t hnd8, type; - if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ - { - ts = (TSEvent*)xTraceNextFreeEventBufferSlot(); - if (ts != NULL) - { - if (nISRactive > 1) - { - /* return to another isr */ - ts->type = TS_ISR_RESUME; - ts->objHandle = isrstack[nISRactive]; - } - else - { - /* return to task */ - ts->type = TS_TASK_RESUME; - ts->objHandle = handle_of_last_logged_task; - } - ts->dts = dts5; - nISRactive--; - prvTraceUpdateCounters(); - } - } - trcCRITICAL_SECTION_END(); - } + if (nISRactive > 1) + { + /* return to another isr */ + type = TS_ISR_RESUME; + hnd8 = prvTraceGet8BitHandle(isrstack[nISRactive]); + } + else + { + /* return to task */ + type = TS_TASK_RESUME; + hnd8 = prvTraceGet8BitHandle(handle_of_last_logged_task); + } + + 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; + DWTCycleCountAtLastISRExit = DWT_CYCLE_COUNTER; + #endif + } + trcCRITICAL_SECTION_END(); } #else @@ -605,7 +709,7 @@ static uint8_t writeDouble(void * buffer, uint8_t i, double value) { TRACE_ASSERT(buffer != NULL, "writeDouble: buffer == NULL", 0); - uint32_t * dest = buffer; + 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) */ @@ -624,9 +728,11 @@ static uint8_t writeDouble(void * buffer, uint8_t i, double value) { return 255; } + + dest = &(((uint32_t *)buffer)[i]); - dest[i/4+0] = src[0]; - dest[i/4+1] = src[1]; + dest[0] = src[0]; + dest[1] = src[1]; return i + 8; } @@ -1049,6 +1155,7 @@ void vTracePrintF_Helper(traceLabel eventLabel, const char* formatStr, va_list v 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 @@ -1063,108 +1170,102 @@ void vTracePrintF_Helper(traceLabel eventLabel, const char* formatStr, va_list v 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 */ noOfSlots = prvTraceUserEventFormat(formatStr, vl, (uint8_t*)tempDataBuffer, 4); /* Store the format string, with a reference to the channel symbol */ - ue1->payload = prvTraceOpenSymbol(formatStr, eventLabel); - - trcCRITICAL_SECTION_BEGIN(); + ue1->payload = prvTraceOpenSymbol(formatStr, eventLabel); ue1->dts = (uint8_t)prvTraceGetDTS(0xFF); - if (! RecorderDataPtr->recorderActive) + + /* prvTraceGetDTS might stop the recorder in some cases... */ + if (RecorderDataPtr->recorderActive) { - /* Abort, since an XTS event (created by prvTraceGetDTS) filled the - buffer, and the recorder stopped since not circular buffer. */ - trcCRITICAL_SECTION_END(); - - return; - } - - /* If the data does not fit in the remaining main buffer, wrap around to - 0 if allowed, otherwise stop the recorder and quit). */ - if (RecorderDataPtr->nextFreeIndex + noOfSlots > RecorderDataPtr->maxEvents) - { -#if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER) - (void)memset(& RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4], - 0, - (RecorderDataPtr->maxEvents - RecorderDataPtr->nextFreeIndex)*4); - RecorderDataPtr->nextFreeIndex = 0; - RecorderDataPtr->bufferIsFull = 1; -#else - /* Abort and stop recorder, since the event data will not fit in the - buffer and not circular buffer in this case... */ - trcCRITICAL_SECTION_END(); - vTraceStop(); - - - return; -#endif - } - -#if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER) - /* 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., - using a memset to zero).*/ - prvCheckDataToBeOverwrittenForMultiEntryEvents((uint8_t)noOfSlots); -#endif - /* Copy the local buffer to the main buffer */ - (void)memcpy(& RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 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 ); - - /* Update the main buffer event index (already checked that it fits in - the buffer, so no need to check for wrapping)*/ - - RecorderDataPtr->nextFreeIndex += noOfSlots; - RecorderDataPtr->numEvents += noOfSlots; - - - - if (RecorderDataPtr->nextFreeIndex >= EVENT_BUFFER_SIZE) - { -#if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER) - /* We have reached the end, but this is a ring buffer. Start from the beginning again. */ - RecorderDataPtr->bufferIsFull = 1; - RecorderDataPtr->nextFreeIndex = 0; -#else - /* We have reached the end so we stop. */ - vTraceStop(); -#endif - } - -#if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER) - /* Make sure the next entry is cleared correctly */ - prvCheckDataToBeOverwrittenForMultiEntryEvents(1); -#endif - -#ifdef STOP_AFTER_N_EVENTS -#if (STOP_AFTER_N_EVENTS > -1) - /* Check if we have reached the desired number of events */ - if (RecorderDataPtr->numEvents >= STOP_AFTER_N_EVENTS) - { - vTraceStop(); + /* If the data does not fit in the remaining main buffer, wrap around to + 0 if allowed, otherwise stop the recorder and quit). */ + if (RecorderDataPtr->nextFreeIndex + noOfSlots > RecorderDataPtr->maxEvents) + { + #if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER) + (void)memset(& RecorderDataPtr->eventData[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(); + #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., + using a memset to zero).*/ + #if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER) + prvCheckDataToBeOverwrittenForMultiEntryEvents((uint8_t)noOfSlots); + #endif + /* Copy the local buffer to the main buffer */ + (void)memcpy(& RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 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 ); + + /* Update the main buffer event index (already checked that it fits in + the buffer, so no need to check for wrapping)*/ + + RecorderDataPtr->nextFreeIndex += noOfSlots; + RecorderDataPtr->numEvents += noOfSlots; + + if (RecorderDataPtr->nextFreeIndex >= EVENT_BUFFER_SIZE) + { + #if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER) + /* We have reached the end, but this is a ring buffer. Start from the beginning again. */ + RecorderDataPtr->bufferIsFull = 1; + RecorderDataPtr->nextFreeIndex = 0; + #else + /* We have reached the end so we stop. */ + 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 + } -#endif -#endif - - trcCRITICAL_SECTION_END(); - } + } + trcCRITICAL_SECTION_END(); #elif (USE_SEPARATE_USER_EVENT_BUFFER == 1) /* Use the separate user event buffer */ @@ -1195,13 +1296,13 @@ void vTraceUserEvent(traceLabel eventLabel) #if (USE_SEPARATE_USER_EVENT_BUFFER == 0) 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) - { - trcCRITICAL_SECTION_BEGIN(); - + { dts1 = (uint8_t)prvTraceGetDTS(0xFF); if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ @@ -1214,14 +1315,14 @@ void vTraceUserEvent(traceLabel eventLabel) ue->payload = eventLabel; prvTraceUpdateCounters(); } - } - trcCRITICAL_SECTION_END(); + } } + 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); @@ -1235,7 +1336,7 @@ void vTraceUserEvent(traceLabel eventLabel) } prvTraceUserEventHelper2(channel, tempDataBuffer, noOfSlots); - } + } #endif } -- 2.39.5