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.
This commit is contained in:
Richard Barry 2013-06-25 10:44:44 +00:00
parent cdae14a8cb
commit 87049ac37c
4 changed files with 103 additions and 83 deletions

View File

@ -74,65 +74,72 @@
/* FreeRTOS includes. */ /* FreeRTOS includes. */
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "task.h"
/* Utility functions to implement run time stats on Cortex-M CPUs. The collected /* 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 run time data can be viewed through the CLI interface. See the following URL for
more information on run time stats: more information on run time stats:
http://www.freertos.org/rtos-run-time-stats.html */ http://www.freertos.org/rtos-run-time-stats.html */
/* Used in the run time stats calculations. */ /* Addresses of registers in the Cortex-M debug hardware. */
static uint32_t ulClocksPer10thOfAMilliSecond = 0UL; #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 ) void vMainConfigureTimerForRunTimeStats( void )
{ {
/* How many clocks are there per tenth of a millisecond? */ /* Enable TRCENA. */
ulClocksPer10thOfAMilliSecond = configCPU_CLOCK_HZ / 10000UL; 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 ulMainGetRunTimeCounterValue( void )
{ {
uint32_t ulSysTickCounts, ulTickCount, ulReturn; static unsigned long ulLastCounterValue = 0UL, ulOverflows = 0;
const uint32_t ulSysTickReloadValue = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; unsigned long ulValueNow;
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 ulValueNow = rtsDWT_CYCCNT;
anyway to keep the examples simple, and to avoid reliance on a separate
timer peripheral. */
/* Has the value overflowed since it was last read. */
/* The SysTick is a down counter. How many clocks have passed since it was if( ulValueNow < ulLastCounterValue )
last reloaded? */
ulSysTickCounts = ulSysTickReloadValue - *pulCurrentSysTickCount;
/* How many times has it overflowed? */
ulTickCount = xTaskGetTickCountFromISR();
/* Is there a SysTick interrupt pending? */
if( ( *pulInterruptCTRLState & ulSysTickPendingBit ) != 0UL )
{ {
/* There is a SysTick interrupt pending, so the SysTick has overflowed ulOverflows++;
but the tick count not yet incremented. */ }
ulTickCount++; ulLastCounterValue = ulValueNow;
/* Read the SysTick again, as the overflow might have occurred since /* Cannot use configCPU_CLOCK_HZ directly as it may itself not be a constant
it was read last. */ but instead map to a variable that holds the clock speed. */
ulSysTickCounts = ulSysTickReloadValue - *pulCurrentSysTickCount;
/* 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 return ulValueNow;
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;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/

View File

@ -141,7 +141,8 @@ unsigned long ulValueNow;
ulLastCounterValue = ulValueNow; ulLastCounterValue = ulValueNow;
/* There is no prescale on the counter, so simulate in software. */ /* 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; return ulValueNow;
} }

View File

@ -74,65 +74,72 @@
/* FreeRTOS includes. */ /* FreeRTOS includes. */
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "task.h"
/* Utility functions to implement run time stats on Cortex-M CPUs. The collected /* 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 run time data can be viewed through the CLI interface. See the following URL for
more information on run time stats: more information on run time stats:
http://www.freertos.org/rtos-run-time-stats.html */ http://www.freertos.org/rtos-run-time-stats.html */
/* Used in the run time stats calculations. */ /* Addresses of registers in the Cortex-M debug hardware. */
static uint32_t ulClocksPer10thOfAMilliSecond = 0UL; #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 ) void vConfigureTimerForRunTimeStats( void )
{ {
/* How many clocks are there per tenth of a millisecond? */ /* Enable TRCENA. */
ulClocksPer10thOfAMilliSecond = configCPU_CLOCK_HZ / 10000UL; 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 ulGetRunTimeCounterValue( void )
{ {
uint32_t ulSysTickCounts, ulTickCount, ulReturn; static unsigned long ulLastCounterValue = 0UL, ulOverflows = 0;
const uint32_t ulSysTickReloadValue = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; unsigned long ulValueNow;
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 ulValueNow = rtsDWT_CYCCNT;
anyway to keep the examples simple, and to avoid reliance on a separate
timer peripheral. */
/* Has the value overflowed since it was last read. */
/* The SysTick is a down counter. How many clocks have passed since it was if( ulValueNow < ulLastCounterValue )
last reloaded? */
ulSysTickCounts = ulSysTickReloadValue - *pulCurrentSysTickCount;
/* How many times has it overflowed? */
ulTickCount = xTaskGetTickCountFromISR();
/* Is there a SysTick interrupt pending? */
if( ( *pulInterruptCTRLState & ulSysTickPendingBit ) != 0UL )
{ {
/* There is a SysTick interrupt pending, so the SysTick has overflowed ulOverflows++;
but the tick count not yet incremented. */ }
ulTickCount++; ulLastCounterValue = ulValueNow;
/* Read the SysTick again, as the overflow might have occurred since /* Cannot use configCPU_CLOCK_HZ directly as it may itself not be a constant
it was read last. */ but instead map to a variable that holds the clock speed. */
ulSysTickCounts = ulSysTickReloadValue - *pulCurrentSysTickCount;
/* 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 return ulValueNow;
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;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/

View File

@ -1843,12 +1843,17 @@ void vTaskSwitchContext( void )
ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE(); ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
#endif #endif
/* Add the amount of time the task has been running to the accumulated /* Add the amount of time the task has been running to the
time so far. The time the task started running was stored in accumulated time so far. The time the task started running was
ulTaskSwitchedInTime. Note that there is no overflow protection here stored in ulTaskSwitchedInTime. Note that there is no overflow
so count values are only valid until the timer overflows. Generally protection here so count values are only valid until the timer
this will be about 1 hour assuming a 1uS timer increment. */ overflows. The guard against negative values is to protect
pxCurrentTCB->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime ); 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; ulTaskSwitchedInTime = ulTotalRunTime;
} }
#endif /* configGENERATE_RUN_TIME_STATS */ #endif /* configGENERATE_RUN_TIME_STATS */