From 4de4c70f3640e7d758494ab8719978bf2a5f33fb Mon Sep 17 00:00:00 2001 From: richardbarry Date: Tue, 25 Jun 2013 10:44:44 +0000 Subject: [PATCH] Re-implement the LPC18xx and SmartFusion2 run time stats implementation to use the free running Cortex-M cycle counter in place of the systick. Correct the run-time stats counter implementation in the RZ demo. Guard against run time counters going backwards in tasks.c. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@1946 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- .../RunTimeStatsTimer.c | 81 ++++++++++--------- .../Source/FreeRTOS_tick_config.c | 3 +- .../RTOSDemo/RunTimeStatsTimer.c | 81 ++++++++++--------- FreeRTOS/Source/tasks.c | 17 ++-- 4 files changed, 101 insertions(+), 81 deletions(-) diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC/RunTimeStatsTimer.c b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC/RunTimeStatsTimer.c index d32dea7ea..737552f28 100644 --- a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC/RunTimeStatsTimer.c +++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC/RunTimeStatsTimer.c @@ -74,65 +74,72 @@ /* FreeRTOS includes. */ #include "FreeRTOS.h" -#include "task.h" /* Utility functions to implement run time stats on Cortex-M CPUs. The collected run time data can be viewed through the CLI interface. See the following URL for more information on run time stats: http://www.freertos.org/rtos-run-time-stats.html */ -/* Used in the run time stats calculations. */ -static uint32_t ulClocksPer10thOfAMilliSecond = 0UL; +/* Addresses of registers in the Cortex-M debug hardware. */ +#define rtsDWT_CYCCNT ( *( ( unsigned long * ) 0xE0001004 ) ) +#define rtsDWT_CONTROL ( *( ( unsigned long * ) 0xE0001000 ) ) +#define rtsSCB_DEMCR ( *( ( unsigned long * ) 0xE000EDFC ) ) +#define rtsTRCENA_BIT ( 0x01000000UL ) +#define rtsCOUNTER_ENABLE_BIT ( 0x01UL ) + +/* Simple shift divide for scaling to avoid an overflow occurring too soon. The +number of bits to shift depends on the clock speed. */ +#define runtimeSLOWER_CLOCK_SPEEDS ( 70000000UL ) +#define runtimeSHIFT_13 13 +#define runtimeOVERFLOW_BIT_13 ( 1UL << ( 32UL - runtimeSHIFT_13 ) ) +#define runtimeSHIFT_14 14 +#define runtimeOVERFLOW_BIT_14 ( 1UL << ( 32UL - runtimeSHIFT_14 ) ) +/*-----------------------------------------------------------*/ void vMainConfigureTimerForRunTimeStats( void ) { - /* How many clocks are there per tenth of a millisecond? */ - ulClocksPer10thOfAMilliSecond = configCPU_CLOCK_HZ / 10000UL; + /* Enable TRCENA. */ + rtsSCB_DEMCR = rtsSCB_DEMCR | rtsTRCENA_BIT; + + /* Reset counter. */ + rtsDWT_CYCCNT = 0; + + /* Enable counter. */ + rtsDWT_CONTROL = rtsDWT_CONTROL | rtsCOUNTER_ENABLE_BIT; } /*-----------------------------------------------------------*/ uint32_t ulMainGetRunTimeCounterValue( void ) { -uint32_t ulSysTickCounts, ulTickCount, ulReturn; -const uint32_t ulSysTickReloadValue = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; -volatile uint32_t * const pulCurrentSysTickCount = ( ( volatile uint32_t *) 0xe000e018 ); -volatile uint32_t * const pulInterruptCTRLState = ( ( volatile uint32_t *) 0xe000ed04 ); -const uint32_t ulSysTickPendingBit = 0x04000000UL; - - /* NOTE: There are potentially race conditions here. However, it is used - anyway to keep the examples simple, and to avoid reliance on a separate - timer peripheral. */ - - - /* The SysTick is a down counter. How many clocks have passed since it was - last reloaded? */ - ulSysTickCounts = ulSysTickReloadValue - *pulCurrentSysTickCount; +static unsigned long ulLastCounterValue = 0UL, ulOverflows = 0; +unsigned long ulValueNow; - /* How many times has it overflowed? */ - ulTickCount = xTaskGetTickCountFromISR(); + ulValueNow = rtsDWT_CYCCNT; - /* Is there a SysTick interrupt pending? */ - if( ( *pulInterruptCTRLState & ulSysTickPendingBit ) != 0UL ) + /* Has the value overflowed since it was last read. */ + if( ulValueNow < ulLastCounterValue ) { - /* There is a SysTick interrupt pending, so the SysTick has overflowed - but the tick count not yet incremented. */ - ulTickCount++; - - /* Read the SysTick again, as the overflow might have occurred since - it was read last. */ - ulSysTickCounts = ulSysTickReloadValue - *pulCurrentSysTickCount; + ulOverflows++; } + ulLastCounterValue = ulValueNow; - /* Convert the tick count into tenths of a millisecond. THIS ASSUMES - configTICK_RATE_HZ is 1000! */ - ulReturn = ( ulTickCount * 10UL ) ; + /* Cannot use configCPU_CLOCK_HZ directly as it may itself not be a constant + but instead map to a variable that holds the clock speed. */ - /* Add on the number of tenths of a millisecond that have passed since the - tick count last got updated. */ - ulReturn += ( ulSysTickCounts / ulClocksPer10thOfAMilliSecond ); + /* There is no prescale on the counter, so simulate in software. */ + if( configCPU_CLOCK_HZ < runtimeSLOWER_CLOCK_SPEEDS ) + { + ulValueNow >>= runtimeSHIFT_13; + ulValueNow += ( runtimeOVERFLOW_BIT_13 * ulOverflows ); + } + else + { + ulValueNow >>= runtimeSHIFT_14; + ulValueNow += ( runtimeOVERFLOW_BIT_14 * ulOverflows ); + } - return ulReturn; + return ulValueNow; } /*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Demo/CORTEX_A9_RZ_R7S72100_IAR_DS-5/Source/FreeRTOS_tick_config.c b/FreeRTOS/Demo/CORTEX_A9_RZ_R7S72100_IAR_DS-5/Source/FreeRTOS_tick_config.c index 71c755999..aca9378da 100644 --- a/FreeRTOS/Demo/CORTEX_A9_RZ_R7S72100_IAR_DS-5/Source/FreeRTOS_tick_config.c +++ b/FreeRTOS/Demo/CORTEX_A9_RZ_R7S72100_IAR_DS-5/Source/FreeRTOS_tick_config.c @@ -141,7 +141,8 @@ unsigned long ulValueNow; ulLastCounterValue = ulValueNow; /* There is no prescale on the counter, so simulate in software. */ - ulValueNow >>= runtimeCLOCK_SCALE_SHIFT + ( runtimeOVERFLOW_BIT * ulOverflows ); + ulValueNow >>= runtimeCLOCK_SCALE_SHIFT; + ulValueNow += ( runtimeOVERFLOW_BIT * ulOverflows ); return ulValueNow; } diff --git a/FreeRTOS/Demo/CORTEX_SmartFusion2_M2S050_SoftConsole/RTOSDemo/RunTimeStatsTimer.c b/FreeRTOS/Demo/CORTEX_SmartFusion2_M2S050_SoftConsole/RTOSDemo/RunTimeStatsTimer.c index 0ce8bc630..ba195276f 100644 --- a/FreeRTOS/Demo/CORTEX_SmartFusion2_M2S050_SoftConsole/RTOSDemo/RunTimeStatsTimer.c +++ b/FreeRTOS/Demo/CORTEX_SmartFusion2_M2S050_SoftConsole/RTOSDemo/RunTimeStatsTimer.c @@ -74,65 +74,72 @@ /* FreeRTOS includes. */ #include "FreeRTOS.h" -#include "task.h" /* Utility functions to implement run time stats on Cortex-M CPUs. The collected run time data can be viewed through the CLI interface. See the following URL for more information on run time stats: http://www.freertos.org/rtos-run-time-stats.html */ -/* Used in the run time stats calculations. */ -static uint32_t ulClocksPer10thOfAMilliSecond = 0UL; +/* Addresses of registers in the Cortex-M debug hardware. */ +#define rtsDWT_CYCCNT ( *( ( unsigned long * ) 0xE0001004 ) ) +#define rtsDWT_CONTROL ( *( ( unsigned long * ) 0xE0001000 ) ) +#define rtsSCB_DEMCR ( *( ( unsigned long * ) 0xE000EDFC ) ) +#define rtsTRCENA_BIT ( 0x01000000UL ) +#define rtsCOUNTER_ENABLE_BIT ( 0x01UL ) + +/* Simple shift divide for scaling to avoid an overflow occurring too soon. The +number of bits to shift depends on the clock speed. */ +#define runtimeSLOWER_CLOCK_SPEEDS ( 70000000UL ) +#define runtimeSHIFT_13 13 +#define runtimeOVERFLOW_BIT_13 ( 1UL << ( 32UL - runtimeSHIFT_13 ) ) +#define runtimeSHIFT_14 14 +#define runtimeOVERFLOW_BIT_14 ( 1UL << ( 32UL - runtimeSHIFT_14 ) ) +/*-----------------------------------------------------------*/ void vConfigureTimerForRunTimeStats( void ) { - /* How many clocks are there per tenth of a millisecond? */ - ulClocksPer10thOfAMilliSecond = configCPU_CLOCK_HZ / 10000UL; + /* Enable TRCENA. */ + rtsSCB_DEMCR = rtsSCB_DEMCR | rtsTRCENA_BIT; + + /* Reset counter. */ + rtsDWT_CYCCNT = 0; + + /* Enable counter. */ + rtsDWT_CONTROL = rtsDWT_CONTROL | rtsCOUNTER_ENABLE_BIT; } /*-----------------------------------------------------------*/ uint32_t ulGetRunTimeCounterValue( void ) { -uint32_t ulSysTickCounts, ulTickCount, ulReturn; -const uint32_t ulSysTickReloadValue = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; -volatile uint32_t * const pulCurrentSysTickCount = ( ( volatile uint32_t *) 0xe000e018 ); -volatile uint32_t * const pulInterruptCTRLState = ( ( volatile uint32_t *) 0xe000ed04 ); -const uint32_t ulSysTickPendingBit = 0x04000000UL; - - /* NOTE: There are potentially race conditions here. However, it is used - anyway to keep the examples simple, and to avoid reliance on a separate - timer peripheral. */ - - - /* The SysTick is a down counter. How many clocks have passed since it was - last reloaded? */ - ulSysTickCounts = ulSysTickReloadValue - *pulCurrentSysTickCount; +static unsigned long ulLastCounterValue = 0UL, ulOverflows = 0; +unsigned long ulValueNow; - /* How many times has it overflowed? */ - ulTickCount = xTaskGetTickCountFromISR(); + ulValueNow = rtsDWT_CYCCNT; - /* Is there a SysTick interrupt pending? */ - if( ( *pulInterruptCTRLState & ulSysTickPendingBit ) != 0UL ) + /* Has the value overflowed since it was last read. */ + if( ulValueNow < ulLastCounterValue ) { - /* There is a SysTick interrupt pending, so the SysTick has overflowed - but the tick count not yet incremented. */ - ulTickCount++; - - /* Read the SysTick again, as the overflow might have occurred since - it was read last. */ - ulSysTickCounts = ulSysTickReloadValue - *pulCurrentSysTickCount; + ulOverflows++; } + ulLastCounterValue = ulValueNow; - /* Convert the tick count into tenths of a millisecond. THIS ASSUMES - configTICK_RATE_HZ is 1000! */ - ulReturn = ( ulTickCount * 10UL ) ; + /* Cannot use configCPU_CLOCK_HZ directly as it may itself not be a constant + but instead map to a variable that holds the clock speed. */ - /* Add on the number of tenths of a millisecond that have passed since the - tick count last got updated. */ - ulReturn += ( ulSysTickCounts / ulClocksPer10thOfAMilliSecond ); + /* There is no prescale on the counter, so simulate in software. */ + if( configCPU_CLOCK_HZ < runtimeSLOWER_CLOCK_SPEEDS ) + { + ulValueNow >>= runtimeSHIFT_13; + ulValueNow += ( runtimeOVERFLOW_BIT_13 * ulOverflows ); + } + else + { + ulValueNow >>= runtimeSHIFT_14; + ulValueNow += ( runtimeOVERFLOW_BIT_14 * ulOverflows ); + } - return ulReturn; + return ulValueNow; } /*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Source/tasks.c b/FreeRTOS/Source/tasks.c index 91358b8a9..abe344066 100644 --- a/FreeRTOS/Source/tasks.c +++ b/FreeRTOS/Source/tasks.c @@ -1843,12 +1843,17 @@ void vTaskSwitchContext( void ) ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE(); #endif - /* Add the amount of time the task has been running to the accumulated - time so far. The time the task started running was stored in - ulTaskSwitchedInTime. Note that there is no overflow protection here - so count values are only valid until the timer overflows. Generally - this will be about 1 hour assuming a 1uS timer increment. */ - pxCurrentTCB->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime ); + /* Add the amount of time the task has been running to the + accumulated time so far. The time the task started running was + stored in ulTaskSwitchedInTime. Note that there is no overflow + protection here so count values are only valid until the timer + overflows. The guard against negative values is to protect + against suspect run time stat counter implementations - which + are provided by the application, not the kernel. */ + if( ulTotalRunTime > ulTaskSwitchedInTime ) + { + pxCurrentTCB->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime ); + } ulTaskSwitchedInTime = ulTotalRunTime; } #endif /* configGENERATE_RUN_TIME_STATS */ -- 2.39.5