freeRTOS has the ability to collect run time statistics when you activate the configuration configGENERATE_RUN_TIME_STATS
. You still need to implement the timer yourself, though. On the Cortex-M processors, a pretty generic way is to use the system timer, so I adapted it to provide timing information with a 1µs resolution. Because freeRTOS uses 32bit numbers to store the counter, it will overflow after 70 minutes. For most performance checks that should be ample, but you can always change runTimeCountsPerSecond
below to match your needs.
The code avoids costly divisions by first calculating the inverse, and scaling it with a shift to achieve a good compromise between speed and accuracy. This optimization is because the counter will be retrieved with every context switch, and so slightly distort the measurements.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
#include "FreeRTOS.h" #include "task.h" uint32_t timerMultiplier; uint32_t maxTickValue; unsigned timerShift; __weak void configureTimerForRunTimeStats(void) { #define runTimeCountsPerSecond 1000000ULL maxTickValue = configCPU_CLOCK_HZ / configTICK_RATE_HZ - 1; timerShift = -1; do { timerShift++; timerMultiplier = ( uint32_t) ( ( 1ULL << timerShift) * runTimeCountsPerSecond / (uint64_t) configCPU_CLOCK_HZ); } while( timerMultiplier * maxTickValue < 0x8000000UL); } __weak unsigned long getRunTimeCounterValue(void) { #define NVIC_SYSTICK_CURRENT_VALUE_REG ( *( ( volatile uint32_t * ) 0xe000e018 ) ) return configTICK_RATE_HZ * xTaskGetTickCount() + ( maxTickValue - NVIC_SYSTICK_CURRENT_VALUE_REG) * timerMultiplier / ( 1 << timerShift); } |
Erich Styger shows a few alternatives. There I also learned that the tick counter must be atomic (portTICK_TYPE_IS_ATOMIC
), which is always the case on Cortex-M, but could trip you on other CPUs.