Tickless/stm32/Interrupt issue

fizzyaid wrote on Friday, November 16, 2018:

Hi,

I’ve just tried to enable tickless mode, as expected it causes uart interrupts to be missed, so I redefined this:

#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) \ if( AppWantsToEnterSleepMode() == pdTRUE ) \ { \ vPortSuppressTicksAndSleep( xExpectedIdleTime ); \ }

My AppWantsToEnterSleepMode was set to return false, so never to allow the processor to sleep. Weirdly, the interrupts were getting lost.

So in tasks.c I commented out:

`#if ( configUSE_TICKLESS_IDLE != 0 )
{
TickType_t xExpectedIdleTime;

		/* It is not desirable to suspend then resume the scheduler on
		each iteration of the idle task.  Therefore, a preliminary
		test of the expected idle time is performed without the
		scheduler suspended.  The result here is not necessarily
		valid. */
		xExpectedIdleTime = prvGetExpectedIdleTime();

		if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
		{
			vTaskSuspendAll();
			{
				/* Now the scheduler is suspended, the expected idle
				time can be sampled again, and this time its value can
				be used. */
				configASSERT( xNextTaskUnblockTime >= xTickCount );
				xExpectedIdleTime = prvGetExpectedIdleTime();

				/* Define the following macro to set xExpectedIdleTime to 0
				if the application does not want
				portSUPPRESS_TICKS_AND_SLEEP() to be called. */
				configPRE_SUPPRESS_TICKS_AND_SLEEP_PROCESSING( xExpectedIdleTime );

				if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
				{
					traceLOW_POWER_IDLE_BEGIN();
					portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime );
					traceLOW_POWER_IDLE_END();
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
			( void ) xTaskResumeAll();
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}
	#endif /* configUSE_TICKLESS_IDLE */`

And ran the code and interrupts were working again, so then I just added:

                vTaskSuspendAll();
                xTaskResumeAll();

And the code starts losing interrupts, any explanation for this? I see that xTaskResumeAll has a critical section and these two lines are only in play when tickless is enabled (regardless of whether you actually enter tickless)

Any thoughts?

fizzyaid wrote on Friday, November 16, 2018:

Removing the define of portSUPPRESS_TICKS_AND_SLEEP and putting an "if AppWantsToEnterSleepMode() " around the tickless idle stuff solves the problem because it’ll only go into it if the application allows it to, outside of that it wont and therefore won’t call the Suspend and Resume all.

Obviously I have to patch tasks.c file every time I update.

rtel wrote on Saturday, November 17, 2018:

Not sure if I’m missing something - but the PRE_SLEEP_PROCESSING() and
POST_SLEEP_PROCESSING() macros are available to enable an application
abort entry to tickless mode if it wishes without needing to edit the C
code. Search for the macros on this page:
https://www.freertos.org/low-power-ARM-cortex-rtos.html

fizzyaid wrote on Saturday, November 17, 2018:

the issue im seeing is that the suspend and resume that happens way before it gets anywhere near that macro are causing me to miss serial interrupts as shown by my experiment above, those two line of code are executed regardless of whether the processor actually goes into sleep mode and seem to be causing me problems.

richarddamon wrote on Saturday, November 17, 2018:

Some questions come to mine, because you seem to be saying that the suspend is what is causing the issue:

  1. What rate are these serial interrupts happening?
  2. Are you fully getting the data in the ISR, or is part of the data fetch using a pend function?

If you are losing data because the ISR can’t run the task level code at each interrupt, then that is, in my opinion, an issue with program design, not FreeRTOS.

fizzyaid wrote on Saturday, November 17, 2018:

its receiving data at 115200, not many bytes.

the interrupt simply reads the register and posts the byte into a stream buffer.

what im seeing is that with the suspend and resume calls in play in the code i quoted, interrupts get missed.

fizzyaid wrote on Monday, November 19, 2018:

Richard, any thoughts on this behaviour?

richarddamon wrote on Monday, November 19, 2018:

115200 should be slow enough that critical sections used in FreeRTOS are short enough not to lose interrupts, and Suspending/Resuming the Scheduler won’t block them.

The one thought I have is that you are putting the device into too low of a low power mode that actually turns off the devices, and/or takes too long to wake up from when going into tickless idle.

There is also a possibility that there is some sort of hardware bug that is causing an issue, but my first guess is that your definition of ‘low powr idle’ is too low.

fizzyaid wrote on Monday, November 19, 2018:

I’m not going into sleep mode, I’ve commented the code out and just have:

vTaskSuspendAll();
xTaskResumeAll();

Added in to replace as it’s these lines of code causing the issue, these lines are code are executed before and after (one of each) sleep mode (or the decision on when to sleep) is made.

In normal (non tickless) mode of FreeRTOS these calls are not here and it works perfectly as you would expect, but the moment these calls are introduced into the equation I start losing serial interrupts.

fizzyaid wrote on Tuesday, November 20, 2018:

Richard Barry, do you have any suggestions or thoughts on what is happening here?

my “fix” is as i posted in the first link, modify the code in tasks.c so that the very first check is whether tickless is currently enabled before doing anything else. (straight after the first ifdef)

fizzyaid wrote on Wednesday, November 21, 2018:

bump for Richard! (sorry)

rtel wrote on Wednesday, November 21, 2018:

I’m not sure I fully understand the original question. Does this have
anything to do with tickless mode, or are you just noting that calling
xTaskResumeAll() causes interrupts to be missed?

vTaskSuspendAll() would have little if any effect on interrupts - hence
I’m ignoring that.

xTaskResumeAll() does have a critical section but that would do little
under normal circumstances.

Are you generating an interrupt on each 115200 characters per second?
If so, can you minimise the overhead using a DMA or FIFO?

fizzyaid wrote on Thursday, November 22, 2018:

I noticed that tickless was losing interrupts regardless of whether tickless was actually being entered, so I commented out the tickless code above and ran and no interrupts were missed.

I then started delving into what was causing the issue and found it was the xTaskResumeAll that was causing it.

So I simply commented out the tickless code and replaced it with a simple:

vTaskSuspendAll
xTaskResumeAll

And interrupts were getting lost, in tickless mode of operation both these lines of code are executed regardless of whether the decision to sleep is made (which with your macros happens later on in the code above).

I’m using an interrupt, but I’m concerned about what this might be doing to other interrupts in the system.

These particular lines of code are only “in play” when the OS is configured in tickless mode.

My solution is to make the decision right at the top of the code as to whether tickless is enabled, if it is I have to accept that there will be possible issues with interrupts, but given that I’ve opted to go to sleep then it’s something I can live with., but while I don’t allow the processor to sleep I don’t have issues with interrupts.

		#if ( configUSE_TICKLESS_IDLE != 0 )
                if (configALLOW_SLEEP_MODE())
		{
		TickType_t xExpectedIdleTime;

			/* It is not desirable to suspend then resume the scheduler on
			each iteration of the idle task.  Therefore, a preliminary
			test of the expected idle time is performed without the
			scheduler suspended.  The result here is not necessarily
			valid. */
			xExpectedIdleTime = prvGetExpectedIdleTime();

			if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )

rtel wrote on Thursday, November 22, 2018:

Hence you can’t use the pre and post sleep macros to abort entering low
power mode as they are in the section that executes with the scheduler
suspended. The tickless entry/exit actually has to be done with the
scheduler suspended to allow the kernel to know what the situation is on
exiting sleep mode. Likewise to give the pre/post sleep macros a known
execution state.

First, if the UART interrupt can be implemented without using any
FreeRTOS API calls then you can set its priority above
configMAX_SYSCALL_INTERRUPT_PRIORIY (which on a Cortex-M means a low
numeric priority value, 0 being the highest priority).

Other than that it is a curious situation. My thought process was that
suspending the scheduler is very fast and doesn’t have any critical
sections. Resuming the scheduler does however have a critical section -
and that if all your idle task is doing is calling xTaskResumeAll() over
and over again very rapidly then it will spend a good proportion of its
time in that function - however likewise as it is being called rapidly
the amount of time spent inside any single call of the function should
be extremely short. I’m afraid I don’t really have any other thoughts
at this point.

fizzyaid wrote on Thursday, November 22, 2018:

Hi Richard,

at this point with tasks.c as it stands the behavior tickless mode is (as far as i can tell) broken (i understand we may have opposing views on this! im trying to be as subjective asni can) the critical section there kills interrupts which it shouldnt,

any chance of implementing the “fix” as i have described above into the freertos code, by default the default defined value could be 1 so that it operates as it did, but allows tickless to be enabled with no extra overhead with the critical section. although it doesnt fix it with regards to lost interrupts whrn tickless mode is allowed, it does fix it when sleep is not allowed.

i was very surprised by this behaviour, especially when i implemented it as suggested and told it not to allow sleep, i didnt expect to see lost interrupts.

richarddamon wrote on Thursday, November 22, 2018:

Yes, if a critical section cause interrupts to be lost like this, then something is broken. It is NOT the fault of the critical section though, as that is done exactly as the ARM architecture says it should be done. My first guess is that somehow your ISR is written wrong, or the interrupt is configured wrong.