Hi Experts,
This is regarding microcontroller: TMS320F28388D
I have implemented to gather the Runtime statistics in 33 ms TASK of FreeRTOS running on c28x cpu.
The issue: Idle task returns to give approx 96% of CPU load. That means CPU load is only at approx. 4%. But based on my calculation of CPU load contributed by ISRs, they alone contribute to 40% of CPU load. So, where is the issue?
Before jumping on this, let me clarify the way I calculated CPU load contributed by ISRs.
On C28x CPU:
6 Tasks run:
- Four are periodic tasks: “5ms task”, “20 ms task”, “33 ms task”, “500 ms task”
- Two are non-periodic tasks that are on blocking wait on semaphore given by ISR: “Zero Cross Task1” and “Zero Cross Task2”.
4 ISRs:
- ISR1 @ 70 KHz - Triggers ISR2 at every second pass
- ISR2 @ 35 KHz - Triggers ISR3 at every eighth pass
- ISR3 @ 4.35 KHz
In each ISR, at entry and exit points, I am using a counter to obtain start tick, stop tick and delta between them.
The timer configurations are:
- Free running
- Down counter
- clock pre-scaling = 1
- Period at 100000 where sys clock is 200 MHz
That means the CPU timer tick is 100000/100000000 = 1 ms
So, the code in the ISR looks like below:
__interrupt void isr1(void)
{
//Store timer ticks at start of ISR for calculating ISR execution time
isrExecutionTicks.invIsr.isrStartTicks = CPUTimer_getTimerCount(CPUTIMER2_BASE);
isr_count++;
/*code in ISR*/
isrExecutionTicks.invIsr.isrStopTicks = CPUTimer_getTimerCount(CPUTIMER2_BASE);
if(isrExecutionTicks.invIsr.isrStartTicks < isrExecutionTicks.invIsr.isrStopTicks) //overflow condition
{
//stores execution time in microseconds
Cpu1.IsrExecutionTime.invIsrExecutionParameters.deltaTime += (float)(( isrExecutionTicks.invIsr.isrStartTicks + (configCPU_CLOCK_HZ / configTICK_RATE_HZ) - isrExecutionTicks.invIsr.isrStopTicks ) * ( CONVERT_SEC_TO_US / (float)DEVICE_SYSCLK_FREQ));
}
else
{
//stores execution time in microseconds
Cpu1.IsrExecutionTime.invIsrExecutionParameters.deltaTime += (float)((isrExecutionTicks.invIsr.isrStartTicks - isrExecutionTicks.invIsr.isrStopTicks) * ( CONVERT_SEC_TO_US / (float)DEVICE_SYSCLK_FREQ));
}
}
In the 33 ms task, the code looks like below:
Cpu1.IsrExecutionTime.invIsrExecutionParameters.executionPercent = (Cpu1.IsrExecutionTime.invIsrExecutionParameters.deltaTime/TIME_SLICE)*100; //TIME_SLICE = 33000
In this way, sum of executionPercent of all ISRs are added and that brings approx. 40% CPU usage.
Now, coming back to FreeRTOS Runtime statistics, below are the configurations:
File: FreeRTOSConfig.h
// Run time statistics related configurations
#define configCPU_CLOCK_HZ 200000000
#define configTICK_RATE_HZ 1000
#define configGENERATE_RUN_TIME_STATS 1
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() configureTimeForRunTimeStats()
#define portGET_RUN_TIME_COUNTER_VALUE() getRunTimeCounterValue()
Definition of Timer configuration, which is being used by RUM_TIME_STATS:
void configureTimeForRunTimeStats()
{
CPUTimer_setEmulationMode(CPUTIMER1_BASE, CPUTIMER_EMULATIONMODE_RUNFREE);
CPUTimer_setPreScaler(CPUTIMER1_BASE, 0U); // no prescaling
CPUTimer_setPeriod(CPUTIMER1_BASE, 0xFFFFFFFE); //largest possible value
CPUTimer_disableInterrupt(CPUTIMER1_BASE);
CPUTimer_stopTimer(CPUTIMER1_BASE);
CPUTimer_reloadTimerCounter(CPUTIMER1_BASE); //reload the period
CPUTimer_startTimer(CPUTIMER1_BASE);
}
uint32_t getRunTimeCounterValue()
{
return (0xFFFFFFFE - CPUTimer_getTimerCount(CPUTIMER1_BASE));
}
And from 33 ms task, I am using below code to get the CPU load obtained using IDLE task contribution:
void calculateCPUUsageforTSKs(stCpu1IsrExecutionTime* executionParameters)
{
static uint32_t ulLastTotalRunTime = 0;
static uint32_t ulLastIdleTime = 0;
TaskStatus_t pxTaskStatusArray[7];
uint32_t ulTotalRunTime = 0;
volatile UBaseType_t uxArraySize, x;
uint32_t ulIdleTime = 0;
// Get number of tasks
uxArraySize = uxTaskGetNumberOfTasks();
// Allocate array for task status
//pxTaskStatusArray = (TaskStatus_t *)pvPortMalloc(uxArraySize * sizeof(TaskStatus_t));
if(pxTaskStatusArray != NULL)
{
// Get task information
uxArraySize = uxTaskGetSystemState(pxTaskStatusArray, uxArraySize, &ulTotalRunTime);
// Find idle task runtime
// Calculate CPU usage since last measurement
for(x = 0; x < uxArraySize; x++)
{
if(strstr(pxTaskStatusArray[x].pcTaskName, "IDLE") != NULL)
{
ulIdleTime = pxTaskStatusArray[x].ulRunTimeCounter;
break;
}
}
if(ulLastTotalRunTime != 0)
{
uint32_t ulDeltaTotalTime = ulTotalRunTime - ulLastTotalRunTime;
uint32_t ulDeltaIdleTime = ulIdleTime - ulLastIdleTime;
if(ulDeltaTotalTime > 0)
{
executionParameters->idleTSKExecutionParameters.executionPercent = ((float)ulDeltaIdleTime * 100.0 / (float)ulDeltaTotalTime);
}
}
// Update last values
ulLastTotalRunTime = ulTotalRunTime;
ulLastIdleTime = ulIdleTime;
}
}
The result from above function is subtracted from 100 to get the total CPU Load% and this is returning 4% of CPU Load.
I have used the modified version of above function to obtain the contribution of other 6 tasks but added together, all of them are contributing to 3~4% of CPU load.
In principle, (100 - IDLE task load%) should return CPU load contributed by everything, including ISRs.
So, why is IDLE task reporting 96% usage? where is the mistake I am doing in calculation? Is it in ISR calculation or in runtime statistics timer configuration?
Please help.
Thanks,
Rohit