From 87049ac37c4f92ce527bee027b50606a506a8017 Mon Sep 17 00:00:00 2001 From: Richard Barry 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. --- .../RunTimeStatsTimer.c | 83 ++++++++++--------- .../Source/FreeRTOS_tick_config.c | 3 +- .../RTOSDemo/RunTimeStatsTimer.c | 83 ++++++++++--------- FreeRTOS/Source/tasks.c | 17 ++-- 4 files changed, 103 insertions(+), 83 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; +static unsigned long ulLastCounterValue = 0UL, ulOverflows = 0; +unsigned long ulValueNow; - /* 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. */ + ulValueNow = rtsDWT_CYCCNT; - - /* The SysTick is a down counter. How many clocks have passed since it was - last reloaded? */ - ulSysTickCounts = ulSysTickReloadValue - *pulCurrentSysTickCount; - - /* How many times has it overflowed? */ - ulTickCount = xTaskGetTickCountFromISR(); - - /* 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++; + ulOverflows++; + } + ulLastCounterValue = ulValueNow; - /* Read the SysTick again, as the overflow might have occurred since - it was read last. */ - ulSysTickCounts = ulSysTickReloadValue - *pulCurrentSysTickCount; + /* 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. */ + + /* 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 ); } - /* Convert the tick count into tenths of a millisecond. THIS ASSUMES - configTICK_RATE_HZ is 1000! */ - ulReturn = ( ulTickCount * 10UL ) ; - - /* Add on the number of tenths of a millisecond that have passed since the - tick count last got updated. */ - ulReturn += ( ulSysTickCounts / ulClocksPer10thOfAMilliSecond ); - - 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; +static unsigned long ulLastCounterValue = 0UL, ulOverflows = 0; +unsigned long ulValueNow; - /* 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. */ + ulValueNow = rtsDWT_CYCCNT; - - /* The SysTick is a down counter. How many clocks have passed since it was - last reloaded? */ - ulSysTickCounts = ulSysTickReloadValue - *pulCurrentSysTickCount; - - /* How many times has it overflowed? */ - ulTickCount = xTaskGetTickCountFromISR(); - - /* 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++; + ulOverflows++; + } + ulLastCounterValue = ulValueNow; - /* Read the SysTick again, as the overflow might have occurred since - it was read last. */ - ulSysTickCounts = ulSysTickReloadValue - *pulCurrentSysTickCount; + /* 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. */ + + /* 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 ); } - /* Convert the tick count into tenths of a millisecond. THIS ASSUMES - configTICK_RATE_HZ is 1000! */ - ulReturn = ( ulTickCount * 10UL ) ; - - /* Add on the number of tenths of a millisecond that have passed since the - tick count last got updated. */ - ulReturn += ( ulSysTickCounts / ulClocksPer10thOfAMilliSecond ); - - 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 */