I’m currently experiencing some undesirable behaviour that I wouldn’t expect when using xTaskNotifyFromISR. Hoping someone might be able to explain why.
I have some hardware based timers on a XMC4800 generating interrupts that I’m using to control the state of some other hardware. These interrupts are time critical and must have low jitter (<1us). Therefore they have a high priority below the configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY.
I also have a lot of ADC data to process on the same device. Four ADC’s that are storing their results in their conversion complete interrupts and then I am using xTaskNotifyFromISR as an events group to hand over to a FreeRTOS task to average and convert the results. It’s worth mentioning that these interrupts have a priority lower than the configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY.
Since using xTaskNotifyFromISR to process the ADC results I have noticed considerable jitter on my high priority interrupts (5 - 10us). Removing the call from ADC result interrupt causes it to go away.
I chose to use xTaskNotifyFromISR as an events group as from what I understand it’s considerably quicker than using an actual event group. And from what I have read and understand of configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY, the scheduler should not affect the interrupts with a priority greater than it. So why when I use xTaskNotifyFromISR in my ADC interrupts am I seeing my high priority interrupts performance affected.
I would like to avoid having to do all of my ADC processing in the interrupt as this is generally discouraged. Although unless I can get to the bottom of the scheduler causing the jitter I am going to be left with no choice.
Well, if nesting is used and the INT prios are right (which might be confusing for Cortex-M3/4) along with FreeRTOS config like configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY, there should be no jitter caused by lower prio ISRs …
Maybe double check the INT related config/ NVIC config to be sure things are setup as you need.
Hmm … looks fine.
Just to be sure: NVIC_SetPriorityGrouping is set to 0 as as recommended ?
Otherwise to be honest I’ve no idea what the problem might be
Some guys had issues with multiple FreeRTOSConfig.h files in their project space including a wrong one, but I assume that’s not the problem in your case.
Priority grouping was set to 1. Setting it to 0 hasn’t improved things though. Is that a FreeRTOS recommendation on ensuring it is set to 0? Wasn’t aware of that.
Yes definitely only the one FreeRTOSConfig.h file included in the project.
… found it … it’s probably also documented somewhere.
in CM3/CM4F port.c - vPortValidateInterruptPriority():
...
/* Priority grouping: The interrupt controller (NVIC) allows the bits
that define each interrupt's priority to be split between bits that
define the interrupt's pre-emption priority bits and bits that define
the interrupt's sub-priority. For simplicity all bits must be defined
to be pre-emption priority bits. The following assertion will fail if
this is not the case (if some bits represent a sub-priority).
If the application only uses CMSIS libraries for interrupt
configuration then the correct setting can be achieved on all Cortex-M
devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the
scheduler. Note however that some vendor specific peripheral libraries
assume a non-zero priority group setting, in which cases using a value
of zero will result in unpredictable behaviour. */
configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
While we’re at it. You’re using a decent FreeRTOS version with or w/o a 3rd party SDK (like ST HAL) ?
Sorry, I didn’t use sub-priorities yet and had also no need to do so. I just followed the default route
No idea what’s going on. If the interrupt prio partitioning and FreeRTOS configuration is right, the high prio interrupts outside the FreeRTOS world/range are not affected by FreeRTOS in any way.
This could be verified the simple way by using portDISABLE_INTERRUPTS() for testing and checking if the timers are still serviced.
Are you sure that nowhere in your ADC post processing code global __disable_irq/__enable_irq are used (disable/enable ALL interrupts) ?
No worries. I also have never made use of the sub priorities, just thought it was worth mentioning that they weren’t being used in this case.
I have just run some tests using taskENTER_CRITICAL(), effectively disabling all of the interrupts lower than the MAX_SYSCALL_INTERRUPT_PRIORITY. I placed it just after where I start the timers. The timers continued to be serviced but ADC interrupts and scheduler stopped as expected. Confirming MAX_SYSCALL_INTERRUPT_PRIORITY is working as I would expect.
At the moment I have commented out all of the post processing code in the task, so the ADC result interrupts are just notifying an empty task at the moment. So defiantly no __disable_irq/__enable_irq being used in any of my code, unless the task notification itself makes use of them?
FreeRTOS code at least for CortexM3/4F/7 doesn’t globally disable interrupts and make use of the MAX_SYSCALL_INTERRUPT_PRIORITY based interrupt (BASEPRI) masking.
Turns out the jitter isn’t being caused by FreeRTOS and is actually due to the Segger Systemview source code that was in my project. I haven’t figured out yet why the Systemview integration is causing it, although removing it from the project has sorted the problem.
If you think how these debuggers work on Cortex parts, a very high priority interrupt switches into firm code embedded in the processor to send the needed information out the debug port, there actions will necessarily cause some timing jitter.