I tried a taskENTER_CRITICAL() before the calc and a taskEXIT_CRITICAL() after the calc, but this killed the system. I then tried the taskDISABLE_INTERRUPTS() and its friend taskENABLE_INTERRUPTS() and the system behaved OK.
The RunTime function is called from the FreeRTOS function:
void vTaskSwitchContext( void )
{
if( uxSchedulerSuspended != ( UBaseType_t ) pdFALSE )
{
/* The scheduler is currently suspended - do not allow a context
switch. */
xYieldPending = pdTRUE;
}
else
{
xYieldPending = pdFALSE;
traceTASK_SWITCHED_OUT();
#if ( configGENERATE_RUN_TIME_STATS == 1 )
{
#ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime );
#else
ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
#endif ...
Just wondering whether my approach is OK and that it will not have nasty side effects.
One thing to note is that the concept of trying to avoid the counting of time from interrupts in the routine to read the counter is a concept that just introduces a race condition into its definition. That interrupt could have occurred just before the call to disable the interrupts, and thus still counted, so is attempting to determine something very dependent on the exact timing of events.
The other thing to note is that vTaskSwitchContext is generally called inside an interrupt routine, as most ports use a software-generated interrupt to trigger this. If you had looked at WHAT was killing your system, you would have found an assert on not being in an ISR. If you wanted to use a critical section there, it would have needed to have been the FromISR versions.
Also, as others have noted, there is a danger of the lower counter rolling over between the reading of the lower counter and the upper counter. One way to solve this is to use one of the 32-bit counters (if that part has them), or you need to read and check read one of the counters. @htibosch shows a method of reading the lower counter twice, I personally prefer to read the upper counter twice, before and after the lower counter, and if they differ do it again. This protects from the (hopefully rare) case where there is a full cycle of the lower counter between the two upper counter reads. Something like:
I figured it was due to the critical function being called by the task being called from the system tick ISR, routine. I did think of using the ISR version, but turning of IRQ’s worked so I left it at that.
The system does have two 32 bit timers, but I had to use them for a H Bridge pwm driver as I was constrained by pin-outs. Damn those pinouts!! I think your idea of reading the upper counter twice and comparing them is a good one. The machine can do this really fast in registers so it should not have much overhead. This is the best method and I will implement this. Turning off the interrupts has not caused any issues although it could affect fast stuff like ethernet in a heavily loaded system.
Turning off interrupts only makes the problem less likely, not eliminate it. You still have the problem that between the two reads, the lower counter can roll-over, no matter what you do (unless you programmatically pause the counters). Any time consumed by an interrupt, could have still happened, it just needed to occur before turning off the interrupts.
The Run Time stats system in FreeRTOS already inherently counts interrupts that occur during an ISR as using time in the task it interrupts, so including it here is just being consistent.
Another thing to note is that most of the STM32 processors the optional CYCCNT register, that can also be used for timing. This cycles fast enough on some processors you may want to enable the 64-bit run-time accumulation and have your routine keep track of overflows.