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. */
#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;
}
/*-----------------------------------------------------------*/

View File

@ -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;
}

View File

@ -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;
}
/*-----------------------------------------------------------*/

View File

@ -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. */
/* 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 */