FreeRTOS\Demo\RL78_RL78G13_Promo_Board_IAR Software Timer problem on RL78 G13 R5F100LEA

cijay1337 wrote on Monday, October 12, 2015:

Hello,

I am an electrical engineering student and i am currently implementing an
application using FreeRTOS v8.2.2

I want to report a Bug that appears in my projects and the Demo
FreeRTOS\Demo\RL78_RL78G13_Promo_Board_IAR, when using the software
timer functionality.

Currently I use the YRDKRL78-G13 REV2.1 for testing FreeRTOS
and other applications in combination with the IAR EW v1.2 for the RL78 series.

( If a portable layer exists for IAR EW v2.1 RL78, please notify me )

I noticed an error while testing the Demo application on my YRDKRL78-G13.
I left the Demo project unchanged, just the LED used in the project changed to
P63 which is LED 3 on my board. I set the Debugger to TK. The Demo seems to be
working fine on the first impression, but if you leave the
Demo running the LED will stop to toggle after some time approx. 1 minute.

Debugging the project revealed that the software timer stops working after the
first xTickCount overflow. I set a breakpoint into the TimerTask after the
Overflow the Timertask will not be called.

Further debugging reveals that the TimerTask gets to block indefinitely and is
moved into the suspended list and remains there the entire time.
This behavior was replicable in the release version and in new Projects that
used the Software Timer and the vSuspendTask functionality.

I found a quick dirty solution by simply changeing one line in the function
vTaskPlaceOnEventListRestricted

I inserted 0 instead of the xWaitIndefinitely == pdTRUE disabling the part
with the insertion to the suspended list

        #if( INCLUDE_vTaskSuspend == 1 )
	{
                    /* xWaitIndefinitely == pdTRUE set to 0 */
		if( 0 )
		{
			/* Add the task to the suspended task list instead of a delayed
			task list to ensure the task is not woken by a timing event.  It
			will block indefinitely. */
			traceTASK_DELAY_SUSPEND( pxCurrentTCB );
			vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xGenericListItem ) );

		}
		else
		{
			/* Calculate the time at which the task should be woken if the
			event does not occur.  This may overflow but this doesn't
			matter. */
			xTimeToWake = xTickCount + xTicksToWait;
			traceTASK_DELAY_UNTIL();
			prvAddCurrentTaskToDelayedList( xTimeToWake );
		}
	}
	#else

The modified version works fine. The LED keeps toggling even after the first
overflow.

I hope the behavior is replicable and if someone has a clue on where the
problem might be, please inform me.

Best regards from germany,

Patrick

rtel wrote on Monday, October 12, 2015:

Thank you for the detail in your report. This is an area of code that changed very recently (in the last release) and it looks like an error may mave been introduced. We will investigate immediately and report back.

rtel wrote on Monday, October 12, 2015:

This needs a lot more testing - but a possible fix is below.

  1. Find the call to vQueueWaitForMessageRestricted(), which is in the function prvProcessTimerOrBlockTask() within timers.c
  2. Add the following code immediately before the call to prvProcessTimerOrBlockTask():
if( xListWasEmpty != pdFALSE )
{
    /* The current timer list is empty - is the overflow list
    also empty? */
    xListWasEmpty = listLIST_IS_EMPTY( pxOverflowTimerList );
}

Please report back your findings.

cijay1337 wrote on Tuesday, October 13, 2015:

Hello,

this won t fix the problem since when you jump into the prvProcessTimerOrBlockTask() function

    /* The tick count has not overflowed, has the timer expired? */
    if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) )
    {
        ( void ) xTaskResumeAll();
        prvProcessExpiredTimer( xNextExpireTime, xTimeNow );
    }

The if statement will become true since we just set xListWasEmpty to 0 when the OverflowTimerList still contains elements and the second statement will be true as well since we are before the xTickCount overflow xNextExpireTime = 0 <= xTimeNow < 65535, thus calling prvProcessExpiredTimer( ). The problem here is there is nothing to process, the current Timerlist is empty.

I made modifications to your proposal and changed prvProcessTimerOrBlockTask() function the following way:

static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime, const BaseType_t xListWasEmpty )
{
TickType_t xTimeNow;
BaseType_t xTimerListsWereSwitched;
                /* Added Code for Software Timer Fix */
BaseType_t xOverflowListWasEmpty;

	vTaskSuspendAll();
	{
		/* Obtain the time now to make an assessment as to whether the timer
		has expired or not.  If obtaining the time causes the lists to switch
		then don't process this timer as any timers that remained in the list
		when the lists were switched will have been processed within the
		prvSampleTimeNow() function. */
		xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
		if( xTimerListsWereSwitched == pdFALSE )
		{
			/* The tick count has not overflowed, has the timer expired? */
			if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) )
			{
				( void ) xTaskResumeAll();
				prvProcessExpiredTimer( xNextExpireTime, xTimeNow );
			}
			else
			{
				/* The tick count has not overflowed, and the next expire
				time has not been reached yet.  This task should therefore
				block to wait for the next expire time or a command to be
				received - whichever comes first.  The following line cannot
				be reached unless xNextExpireTime > xTimeNow, except in the
				case when the current timer list is empty. */
                            
                                                /* Added Code for Software Timer Fix */
                                if( xListWasEmpty != pdFALSE )
                                {
                                /* The current timer list is empty - is the overflow list
                                also empty? */
                                xOverflowListWasEmpty = listLIST_IS_EMPTY( pxOverflowTimerList );
                                }
                            
				vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ), xOverflowListWasEmpty );

				if( xTaskResumeAll() == pdFALSE )
				{
					/* Yield to wait for either a command to arrive, or the
					block time to expire.  If a command arrived between the
					critical section being exited and this yield then the yield
					will not cause the task to block. */
					portYIELD_WITHIN_API();
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
		}
		else
		{
			( void ) xTaskResumeAll();
		}
	}
}
/*-----------------------------------------------------------*/

As you can see i added a new Variable** xOverflowListWasEmpty** who should check just before the Overflow occurs, if it is OK to set the TimerTask into the suspended list waiting there with no timeout.

I tested this version for some time and it seems to be working. I didn t look into the behavior what happens when i stop the timers midway trough and Restart them some time later.

rtel wrote on Tuesday, October 13, 2015:

Did you actually try the change? There were some ‘const’ keywords that would need to be removed to get it to compile.

I think the intent of your code is the same as the code I posted. The point at which it has been inserted in the code is identical, and its structure is identical, but your code is using a new variable, rather than re-using the xListWasEmpty variable. In your code however the new variable is not initialised, so will take a random value, and as such will probably never equal pdFALSE - hence it will appear to work most of the time (but not for code that uses the tick-less idle mode, which is what this change was included for). Also in your code there will (I think) be problems when the overflow timer list is empty, but the current timer list is not.

Background for others reading this - lets try and describe why the issue occurs (if I have it right):

[as you no doubt already know] In FreeRTOS there are two lists of software timers - a list that contains timers that are due to expire before the tick count overflows (called the current timer list), and a list that contains timers that are due to expire after the tick count has next overflow (called the overflow timer list). My understanding is (?) that the issue arose when the current timer list was empty, but the overflow timer list was not empty - and that the route cause of the problem was that the decision as to whether the timer task was placed into the Suspended or Blocked state was taken after only looking at the current timer list. Therefore, the timer task entered the Suspended state when there were still active timers.

The fix was to consider both the current and overflow timer lists - but that cannot be done until after the line:

if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) )

xListWasEmpty passed into prvProcessTimerOrBlockTask() is true if the current timer list is empty. In my fix, if xListWasEmpty is set to true, then a second check is performed to see if the overflow timer list is also true, and the value passed into vQueueWaitForMessageRestricted() therefore takes into account bother timer lists.

In your fix, if xListWasEmpty is true, then the value passed into vQueueWaitForMessageRestricted() is set to true if the overflow timer list is also empty, but if xListWasEmpty is false, the value passed into vQueueWaitForMessageRestricted() is an uninitalised variable - but I think the intent is the same.

If any of my post here is not correct, please let me know. If you didn’t try my fix then please do - all you need to do - it is almost the same as your fix.

Regards.

cijay1337 wrote on Tuesday, October 13, 2015:

Yes you are right, it seems I missunderstood your intentions since you said

2) Add the following code immediately before the call to prvProcessTimerOrBlockTask():

this way the statement in the function doesn t work properly. I tried it once and it failed

if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) )

I removed the const expresseion before xListWasEmpty and the Variable i used before.
Now it looks like this. It works fine so far. I m just thinking about the case if the TimerTask gets suspended due to the Timerlists being empty. Does it still work when I restart the Timers? I haven t looked into this case yet.

/*-----------------------------------------------------------*/

static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime, BaseType_t xListWasEmpty )
{
TickType_t xTimeNow;
BaseType_t xTimerListsWereSwitched;


	vTaskSuspendAll();
	{
		/* Obtain the time now to make an assessment as to whether the timer
		has expired or not.  If obtaining the time causes the lists to switch
		then don't process this timer as any timers that remained in the list
		when the lists were switched will have been processed within the
		prvSampleTimeNow() function. */
		xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
		if( xTimerListsWereSwitched == pdFALSE )
		{
			/* The tick count has not overflowed, has the timer expired? */
			if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) )
			{
				( void ) xTaskResumeAll();
				prvProcessExpiredTimer( xNextExpireTime, xTimeNow );
			}
			else
			{
				/* The tick count has not overflowed, and the next expire
				time has not been reached yet.  This task should therefore
				block to wait for the next expire time or a command to be
				received - whichever comes first.  The following line cannot
				be reached unless xNextExpireTime > xTimeNow, except in the
				case when the current timer list is empty. */
                            
                                                /* Added Code for Software Timer Fix */
                                if( xListWasEmpty != pdFALSE )
                                {
                                /* The current timer list is empty - is the overflow list
                                also empty? */
                                xListWasEmpty = listLIST_IS_EMPTY( pxOverflowTimerList );
                                }
                            
				vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ), xListWasEmpty );

				if( xTaskResumeAll() == pdFALSE )
				{
					/* Yield to wait for either a command to arrive, or the
					block time to expire.  If a command arrived between the
					critical section being exited and this yield then the yield
					will not cause the task to block. */
					portYIELD_WITHIN_API();
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
		}
		else
		{
			( void ) xTaskResumeAll();
		}
	}
}
/*-----------------------------------------------------------*/

rtel wrote on Tuesday, October 13, 2015:

Yes you are right, it seems I missunderstood your intentions since you said

2) Add the following code immediately before the call to
prvProcessTimerOrBlockTask():

Oops, my bad, sorry for the confusion. I meant to say “immediately
before the call to vQueueWaitForMessageRestricted()”.

Im just thinking about the case if the TimerTask gets suspended due
to the Timerlists being empty. Does it still work when I restart the
Timers?

Although internally the task is placed into the Suspended tasks list -
conceptually it is in the Blocked state, not the suspended state. It is
identical to blocking indefinitely on a queue - when data is written to
the queue the timer task is unblocked. In fact, that is exactly what is
happening - it is the timer command queue that is being blocked on.

You are getting into the guts of the internal implementation here -
which is good :o)

Note that the task’s “event list item” is placed into the event list of
the timer command queue, and its “generic list item” is placed into the
Suspended list. When you restart a timer, the API call you make sends a
command to the timer command queue (that happens inside the API
function). As soon as data arrives in the timer command queue the queue’s
event list is used to locate tasks that are waiting for data, which in
this case is the timer task, and the timer task is then removed from the
Suspended list and placed in a Ready list. Once in the Ready list it
will start running as soon as it is the higher priority task.

cijay1337 wrote on Tuesday, October 13, 2015:

Thank you, very much for your support so far. I will report back if any other issues arise or the robustness seems satisfactory within my projects.

There is still one question I have concerning a different topic.
I wanted to ask if there will be a FreeRTOS port available for the RL78 series that works on
IAR Embedded Workbench v2.1 . Due to changes to the Linker and directives the current port is not useable.

rtel wrote on Tuesday, October 13, 2015:

I wanted to ask if there will be a FreeRTOS port available for the RL78
series that works on
IAR Embedded Workbench v2.1 . Due to changes to the Linker and
directives the current port is not useable.

I wasn’t aware of this issue - hence there was no plan to update. Our
current work load and development schedule would mean an update would
not be scheduled for a while if there were.