Crash after some hours when interrupts are enabled

I have an application on a Cortex-M with some tasks and FreeRTOS timers that runs properly for days. The cortex-M is inside NXP iMX8M-Plus.
When I enable an interrupt (from an ADC), the application works, but after some time (minutes, hours or a couple of days - maximum) it crashes.
When it crashes, all the Cortex-M registers have their “reset” values (the Program Counter PC too).
I think it’s almost sure I misconfigured something (priorities?).
I read all what I found, and it seems to me that I did what I should have done. But it’s not (for sure).
I added all the trace that found, but I never got any trace message before the crash.
Inside the IRQ handler I set a bit in an event group with xEventGroupGetBitsFromISR() and I return.
One task is waiting for the bit.

In FreeRTOSConfig.h I have
#define configMAX_PRIORITIES 5
(it comes from a NXP example)
and
#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1)

Am I allowed to set configMAX_PRIORITIES to any number (16, 32, ..)?
Does this change something?

Based on experience, what could be a possible reason for the crash?
For sure the deep investigation is up to me, but maybe someone can share ideas.

are you running your isr above max_syscall priority?

Hi @RAc
In FreeRTOSConfigBoard.h there is
#define configMAX_SYSCALL_INTERRUPT_PRIORITY (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))
where
#define configPRIO_BITS 4
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 2
and so configMAX_SYSCALL_INTERRUPT_PRIORITY is expanded to 32 (0x20) if I’m right.

The interrupt is at priority 3 in the NVIC.
And so I think is is correct.

But IMHO all the documentation about priority relations between FreeRTOS and Cortex-M irq is not clear enough.
So, I could be wrong somewhere.

NVIC prio 3 might be incorrect. See e.g. this related discussion: USART interrupt handler is invoked only once - #8 by hs2
Recent FreeRTOS versions have (configASSERT) checks of the interrupt prio on usage of FreeRTOS FromISR API being within the allowed/configured range.

I read that topic.
In my case, NVIC_SetPriority() shifts the value of 3 before writing into NVIC, and so it becomes 3 << 4 = 0x30 (48)

I’ve already re-implemented configASSERT macro to verify if I’m stuck inside it, and I’m not.
In another project it happened because I set the priorities with wrong values.

Another thing you can do is check whether the interrupt stack has overflown. It may be too tight to contain the frames of several nested interrupts.

Yes, you can set the number of task priorities to an arbitrary value, the one constraint is that each priority level defined takes a bit of memory to create a list pointer for task ready at that priority, and can take time to scan through the list.

Also, there is an optional hardware assist to find the highest priority with a ready task, and that will have a limited maximum number of priorities (like 32 for a 32 bit processor like a Cortex-M), so I wouldn’t use more than 32 priorities, and I doubt you actually have a need for that many. You never need more priorities than tasks, and often can use a lot less. Personally even 10 would be excessive for most of my systems.

As a related (almost trivial) remark, a corollary is that there should not be gaps in the task priority assignments, ie if tasks only have three disjoint priorities, do not use 1, 15 and 30 (requiring configMAX_PRIORITIES to be at least 31) but 1, 2 and 3 (and consequently set configMAX_PRIORITIES to 4).

Thanks.
Can you point me documentation describing how to do this?

In my case I have 5 maximum priorities.
And I use only 4 of them (1, 2, 3 and 4).

To be honest, the task with priority of 2 can be completely excluded with a compilation flag.
So, in some case, I only have 1, 3 and 4.
I hope that this is not an issue.
Otherwise I’m going to change the priorities based on the compilation flag.

Ok, as you probably know, the size and location of the interrupt stack (which is the recyled startup stack at bootup, eg before the scheduler is started) are determined by the linker command file (typically with identifiers like .STACK or something along those lines).

What I would do is write a signature into a few of the top bytes of the stack before starting the scheduler (not the entire area of course as the stack is still being used at that point) and at fault time check if the signature is still valid.

The only problem with unused priority levels is a little bit of wasted memory. In this case it won’t be an issue. Note, you DO have a priority 0 task, as you need to also remember that the system task created for you exist, and the Idle task will ALWAYS have priority 0, as should any task you create that doesn’t block periodically.

So, when I set the maximum number of priorities to 5, I should always consider the 0, 1, 2, 3 and 4.
And so 5 is not a valid value, if I set to 5 the number of priorities.
Right?

Right, Number of priority levels equal to 5 means 5 priority levels, 0, 1, 2, 3, and 4. Level 5 would be a 6th priority level.