mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-05-28 16:09:03 -04:00
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:
parent
cdae14a8cb
commit
87049ac37c
|
@ -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;
|
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
Loading…
Reference in a new issue