FreeRTOS and using an ISR to unsuspend a suspended task (32F417) - Page 1
Forum section: electronics / general

author: peter-h
author_rank: Super Contributor
timestamp: September 20, 2025, 07:03:03 am
content: I have some code which is working fine, but should not!The context is herehttps://www.eevblog.com/forum/microcontrollers/fonts-and-driving-lcd-controllers-for-drawing-text/https://www.eevblog.com/forum/microcontrollers/screen-tearing-on-lcd-displays/https://community.st.com/t5/stm32-mcus-embedded-software/32f417-trying-to-interrupt-from-pe12-rising-edge/m-p/840817/highlight/true#M68253but I will describe it in a shorter way:I define a task in the usual way, but the handle, usually NULL, is defined this timeCode:TaskHandle_t xLCDHandle=NULL;xTaskCreate(vLCDTask, "LCD", configMINIMAL_STACK_SIZE*2, NULL, osPriorityLow, &xLCDHandle);Then at various points the task is suspended withCode:vTaskSuspend(xLCDHandle);Then I have an interrupt from PE12 rising edge, initialised withCode:// Configure PE12GPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.Pin = GPIO_PIN_12;GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; // Interrupt on rising edgeGPIO_InitStruct.Pull = GPIO_PULLDOWN;// pulldownGPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;// This does nothing on an input pinHAL_GPIO_Init(GPIOE, &GPIO_InitStruct);// Configure NVIC// Priority # must be >=configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY (5) but 2,3,4,5 works but 6+ does not!HAL_NVIC_SetPriority(EXTI15_10_IRQn, 4, 0);HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);The ISR isCode:// Handler for TE (PE12=1) interrupt.// This restarts the xLCDHandle task which was suspended with vTaskSuspend(xLCDHandle).// Exec time of this ISR is 1.5us.void EXTI15_10_IRQHandler(void){BaseType_t xYieldRequired;// Check if interrupt is from EXTI12 (PE12)if (EXTI->PR & (1 << 12)){// Clear the interrupt pending bitEXTI->PR = (1 << 12);// Check if task handle is valid before using itif (xLCDHandle != NULL){xYieldRequired = xTaskResumeFromISR(xLCDHandle);portYIELD_FROM_ISR(xYieldRequired);}}}The "problem" is that the above should not work, because FR doc has dire warnings regarding ISRs calling FR functions, stating that/* The highest interrupt priority that can be used by any interrupt serviceroutine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALLINTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHERPRIORITY THAN THIS! (higher priorities are lower numeric values. */#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5so my ISR should blow up the system if its priority us < 5, but actually it is the other way round: a priority of 6,7,8... blows it up in xTaskResumeFromISR(). Properly too; I cannot even single step through the code. It reaches a bit of asm like thisCode:portFORCE_INLINE static void vPortRaiseBASEPRI( void ){uint32_t ulNewBASEPRI;__asm volatile("mov %0, %1\n"\"msr basepri, %0\n" \"isb\n" \"dsb\n" \:"=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "memory");}As I said, it works if I take the rule as meaning the opposite!This is the NVIC function which sets up the priorityCode:/*** @brief Sets the priority of an interrupt.* @param IRQn External interrupt number.* This parameter can be an enumerator of IRQn_Type enumeration* (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f4xxxx.h))* @param PreemptPriority The preemption priority for the IRQn channel.* This parameter can be a value between 0 and 15* A lower priority value indicates a higher priority* @param SubPriority the subpriority level for the IRQ channel.* This parameter can be a value between 0 and 15* A lower priority value indicates a higher priority.* @retval None*/void HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority){uint32_t prioritygroup = 0x00U;/* Check the parameters */assert_param(IS_NVIC_SUB_PRIORITY(SubPriority));assert_param(IS_NVIC_PREEMPTION_PRIORITY(PreemptPriority));prioritygroup = NVIC_GetPriorityGrouping();NVIC_SetPriority(IRQn, NVIC_EncodePriority(prioritygroup, PreemptPriority, SubPriority));}The code in it is way too convoluted for me to understand

author: jc101
author_rank: Frequent Contributor
timestamp: September 20, 2025, 08:15:43 am
content: Depending on the FreeRTOS version, maybe check here. Some of the config values have changed over the years.https://freertos.org/Documentation/02-Kernel/03-Supported-devices/02-Customization#configkernel_interrupt_priority-configmax_syscall_interrupt_priority-and-configmax_api_call_interrupt_priorityThat leads to a section handling ISRs on ARM cores ->https://freertos.org/Documentation/02-Kernel/03-Supported-devices/04-Demos/ARM-Cortex/RTOS-Cortex-M3-M4Apologies if you already gone through that.I rarely use vTaskSuspend, I tend to have tasks block at a known point with a xTaskNotifyWait(portMAX_DELAY), then release them with an xTaskNotifyGive / xTaskNotifyGiveFromISR.

author: peter-h
author_rank: Super Contributor
timestamp: September 20, 2025, 08:30:30 am
content: I may have discovered the problem:HAL_NVIC_SetPriority()is not the same asNVIC_SetPriority()but the FR wording refers to the latter: the actual NVIC value.The actual priority in the NVIC is 0-255:The issue comes from how ARM Cortex-M priority values are interpreted differently at different layers.ARM Cortex-M Priority SystemHardware Level (NVIC Register):Lower numbers = Higher priorityPriority 0 = Highest priorityPriority 255 = Lowest priorityThe HAL_ function shifts the value left by 4 bits.More from google:// configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY = 5 (raw NVIC value)// With priority group 4: HAL_value = NVIC_value >> 4// So HAL priority should be: 5 >> 4 = 0 (but this rounds to 0)// Actually, for NVIC value 5 to work with Priority Group 4:// You need HAL priority 0 (which gives NVIC value 0)// But FreeRTOS wants NVIC >= 5, so use:HAL_NVIC_SetPriority(EXTI15_10_IRQn, 1, 0); // Gives NVIC value 16// orHAL_NVIC_SetPriority(EXTI15_10_IRQn, 2, 0); // Gives NVIC value 32So this may explain why values like 2 work (because 2 produces actual NVIC priority of 32 or so, which is > the 5 required for an ISR calling FR functions), but it still doesn't explain why a value of 6+ (which is an evenlowerpriority) blows it up.Hmmm, I may have found why 6+ blows it up. In FR port.c they have/* Make PendSV and SysTick the lowest priority interrupts. */portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;and the 2nd one is 15, but this is a "real" 15, not the "HAL 15".Apart from the difference between HAL_NVIC_SetPriority() and NVIC_SetPriority() (the latter of which I never use, and Systick uses some fairly opaque code to set what it calls "priority 15") I do not understand why I see this problem, where HAL_NVIC_SetPriority values 1,2,3,4,5 work and 6+ blows it up.So, for a laugh, I dropped the above paragraph into ClaudeIt came up with the usual supremely confident replybut suggested this:Code:uint32_t systick_priority = NVIC_GetPriority(SysTick_IRQn);uint32_t exti_priority = NVIC_GetPriority(EXTI15_10_IRQn);uint32_t max_syscall = configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY;printf("SysTick NVIC priority: %lu\n", systick_priority);printf("EXTI NVIC priority: %lu\n", exti_priority);printf("FreeRTOS max syscall priority: %lu\n", max_syscall);and the result isSysTick NVIC priority: 15EXTI NVIC priority: 5FreeRTOS max syscall priority: 5Weird, since the EXTI priority is being set with HAL_NVIC_SetPriority(EXTI15_10_IRQn, 5, 0);Now it says "The fact that HAL priority maps 1:1 to NVIC priority suggests your system has no priority grouping enabled."It sounds like lots of people have been up this road before and it found this somewhere online.Next suggestion was this codeCode:HAL_NVIC_SetPriority(EXTI15_10_IRQn, 6, 0);uint32_t nvic_6 = NVIC_GetPriority(EXTI15_10_IRQn);printf("HAL priority 6 gives NVIC: %lu\n", nvic_6);and I get as expected:HAL priority 6 gives NVIC: 6Then I ask: but surely a higher number means a lower priority, so why does 6+ crash. Now he says:You're absolutely right about priority numbering (higher number = lower priority), but you're misunderstanding what configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY means!The Confusing NameconfigLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY is poorly named. It doesn't mean "maximum priority that can call syscalls."It means: "The LOWEST priority (highest number) that can call FreeRTOS APIs"The fact that HAL priority maps 1:1 to NVIC priority suggests your system has no priority grouping enabled.And sure enough the last sentence is right:Code:/* Set Interrupt Group Priority */// This sets 16 pre-emption priority levels and 0 sub priority levels.HAL_NVIC_SetPriorityGrouping(0);// was: (NVIC_PRIORITYGROUP_4) which did the same thing;With Priority Grouping 0:HAL priority directly maps to NVIC register value (1:1)No interrupt can preempt another (except NMI/HardFault)All interrupts essentially have the same "real" prioritySysTick cannot interrupt your EXTI handler.Does this make any sense?

author: tru
author_rank: Regular Contributor
timestamp: September 22, 2025, 10:20:46 am
content: Some of your arguments are incorrect. The HAL priority value is always 1:1 because the value is passed unmodified from the HAL_NVIC_SetPriority() to the CMSIS function __NVIC_SetPriority() - so no HAL manipulation there. Your table of HAL Priority vs Actual NVIC Value is misleading, the bitmapped representation changes according to the group vs sub priority split setting (HAL calls this priority group setting, ARM calls this binary point split).Many of you already know that with Cortex-M, each interrupt has its own 8-bit wide priority level register, but this is split into two bitmap parts, the group priority (higher bits) and sub priority (lower bits). The group priority with higher level can preempt a lower level already executing interrupt. If the group priorities are the same, then the sub priority determines the order in which they are processed.The group vs sub split is determined by the PRIGROUP field of the AIRCR register. The PRIGROUP sets the binary point split, i.e. decides the number of upper and lower bits for group vs sub priority. Note, the number of group priority (2nd last column in the attached table) cannot be 0 so there is always preemption level.HAL by default sets the split as:HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);NVIC_PRIORITYGROUP_4 is a value of 3 so this is PRIGROUP 0b011, which gives 16 preempt levels.I think many are mislead by HAL's suffix numbering, i.e. the macro number is not its value:NVIC_PRIORITYGROUP_0 = 7NVIC_PRIORITYGROUP_1 = 6NVIC_PRIORITYGROUP_2 = 5NVIC_PRIORITYGROUP_3 = 4NVIC_PRIORITYGROUP_4 = 3There is no macro for the value 0, but if you look at the attached table a value of 0b000 gives 128 preempt levels, and not 0 preempt levels that you suggested.I think your problem may be to do with critical section. Perhaps you are calling the interrupt safe FreeRTOS ISR function from within a critical section? This means it would be stuck if your interrupt is lower priority (higher number) than#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5And naturally, setting your interrupt with a higher priority doesn't hang it, because FreeRTOS does not mask higher priorities.A better explanation of FreeRTOS running on Cortex-M Core:https://www.freertos.org/Documentation/02-Kernel/03-Supported-devices/04-Demos/ARM-Cortex/RTOS-Cortex-M3-M4#critical-sections

author: peter-h
author_rank: Super Contributor
timestamp: September 22, 2025, 11:18:12 am
content: QuoteWhat would be a critical section?I am calling xTaskResumeFromISR() from an ISR (priority 5) triggered from a rising edge on PE12.What I have done doesn't appear to do any harm, and I am reluctant to change HAL_NVIC_SetPriorityGrouping(0) back to NVIC_PRIORITYGROUP_4 in case it breaks something.I went to look through the project notes on why the (0) was done and found thisThe sub-priority system is of no real use and does not appear to be used anywhere, whether one calls HAL_NVIC_SetPriorityGrouping() (in main.c) with a value of 0 or with 3 (defined as NVIC_PRIORITYGROUP_4, default in Cube). Both values select the same row hereThese refer to the abovehttps://www.eevblog.com/forum/microcontrollers/does-this-code-need-interrupts-disabled/https://community.st.com/s/question/0D53W000024XLcbSAG/is-nvicprioritygroup4-3-same-in-effect-as-0-32f417?t=1674118144748That was 2.5 years ago...

author: tggzzz
author_rank: Super Contributor
timestamp: September 22, 2025, 11:24:55 am
content: There's a good case to be made that a system design should only have three priorities: normal background task, normal ISR, and panic ISR. Any more than that makesreasoningabout deadlocks/livelocks difficult, and maximum latencies difficult to guarantee. N.B. "measure and hope the worst case has been encountered" and/or "we haven't seen it deadlocked/livelocked" isnota guarantee!Basic system design... Input available and output done generate an interrupt. The normal ISR creates an "even" and deposits that in a FIFO. The background task is an FSM that waits until an event is available in the FIFO, and processes the event (optionally inserting other events into a FIFO). Panic ISR just makes things safe before power disappears.

author: peter-h
author_rank: Super Contributor
timestamp: September 22, 2025, 11:36:11 am
content: I agree, and I write ISRs to be short and fast. Measuring them, most end up under 5us. The PE18 one is 1.5us. But I've always assumed that pre-emption can happen, just not by the RTOS task switch, but that should be right, with a priority of 15.So I think that, in my project, it doesn't make any difference whether you have pre-emption or not, or what the priorities are. A task switch inside an ISR might not be a great idea.I also think that trying to solve issues by juggling RTOS task priorities is a fool's game, because for every one you solve you might create another. But there are cases where one has to do it.If you have FIFOs for serial data then you can probably do everything with tasks running in very low priority.

author: tru
author_rank: Regular Contributor
timestamp: September 22, 2025, 12:31:49 pm
content: Quote from: peter-h on September 22, 2025, 11:18:12 amGood point, I'm not sure myself what those critical sections would be without looking deep into FreeRTOS code, but my guess they are made by synchronization functions such as those belonging to semaphore and mutex. But since your ISR doesn't interrupt anything that makes those calls so that doesn't apply.Your priority grouping table is probably for other Arm cores, specifically for Cortex-M4 see page 234 of PDF from here:https://developer.arm.com/documentation/dui0553/latest/0 and 3 don't select the same rows.

author: peter-h
author_rank: Super Contributor
timestamp: September 22, 2025, 12:41:05 pm
content: There must be something else going on, otherwise why would FR set its Systick priority to 15, which is supposed to be the lowest available?/* The lowest interrupt priority that can be used in a call to a "set priority" function. */#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15/* Make PendSV and SysTick the lowest priority interrupts. */portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI; // ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL )portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI; // ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL )So the stuff about "real" priority 96 or whatever is nonsense. Otherwise why would FR use 15 for Systick?That ARM manual is 277 pages

author: tru
author_rank: Regular Contributor
timestamp: September 22, 2025, 01:19:29 pm
content: Quote from: peter-h on September 20, 2025, 08:30:30 amAlthough, not important to you problem.I think you've found a HAL bug (for non-default priority group splt).The Arm CMSIS set priority function (in core_cm4.h) shifts by the macro __NVIC_PRIO_BITS as you can see:Code:/**\brief Set Interrupt Priority\details Sets the priority of a device specific interrupt or a processor exception.The interrupt number can be positive to specify a device specific interrupt,or negative to specify a processor exception.\param  IRQn Interrupt number.\param  priority Priority to set.\note The priority cannot be set for every processor exception.*/__STATIC_INLINE void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority){if ((int32_t)(IRQn) >= 0){NVIC->IP[((uint32_t)IRQn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);}else{SCB->SHP[(((uint32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);}}I think this macro should be set to something like a function which selects the correct shift according to the PRIGROUP setting, but it is set to a constant 4 in ST's code:https://github.com/STMicroelectronics/cmsis-device-f4/blob/2e1724e592931693ce4dfc43e2fd6b3bc375d6a0/Include/stm32f417xx.hCode:/*** @brief Configuration of the Cortex-M4 Processor and Core Peripherals*/#define __CM4_REV 0x0001U /*!< Core revision r0p1 */#define __MPU_PRESENT 1U /*!< STM32F4XX provides an MPU */#define __NVIC_PRIO_BITS 4U /*!< STM32F4XX uses 4 Bits for the Priority Levels */#define __Vendor_SysTickConfig 0U /*!< Set to 1 if different SysTick Config is used */#define __FPU_PRESENT 1U /*!< FPU present */The shift should be accordingly:if PRIGROUP = 0 then __NVIC_PRIO_BITS = 7if PRIGROUP = 1 then __NVIC_PRIO_BITS = 6if PRIGROUP = 2 then __NVIC_PRIO_BITS = 5if PRIGROUP = 3 then __NVIC_PRIO_BITS = 4if PRIGROUP = 4 then __NVIC_PRIO_BITS = 3if PRIGROUP = 5 then __NVIC_PRIO_BITS = 2if PRIGROUP = 6 then __NVIC_PRIO_BITS = 1if PRIGROUP = 7 then __NVIC_PRIO_BITS = 0

author: tggzzz
author_rank: Super Contributor
timestamp: September 22, 2025, 01:27:29 pm
content: Quote from: peter-h on September 22, 2025, 11:36:11 amPrecisely.Priority inheritance is another trap with tasks with multiple priorities.The perceived benefits of apparently preserving single-thread of execution semantics can be due to a lack of imagination/knowledge of the alternatives.QuoteNot just serial data. Consider multiple FSMs,optionallyeach in their own thread. During execution of an event, if one FSM has to communicate with another FSM then it just puts an event in that FSM's input FIFO.Monitoring/logging the events enables easy and fast understanding of how and why an application has reached its current state.Monitoring queue length enables easy and fast understanding of bottlenecks and slack time.Logging input and output events allows you to demonstrate theotherperson/company is at fault, thus reducing the chance lawyers are required

author: peter-h
author_rank: Super Contributor
timestamp: September 22, 2025, 01:45:12 pm
content: QuoteI wonder if the default of HAL_NVIC_SetPriorityGrouping(4) which probably almost nobody changes (because this stuff is so complicated) means that nobody is affected?Does using HAL_NVIC_SetPriorityGrouping(0) change anything here?The most common context of "HAL" is using Cube MX, which is basically a package pin allocator/configurator and a primitive code-block generator (probably better than Claude, though that isn't saying much) and most people going this route never get into these details.The reason I changed from HAL_NVIC_SetPriorityGrouping(4) to HAL_NVIC_SetPriorityGrouping(0) was probably seeing the noteQuoteThe only case I remember regarding having to tweak interrupt priorities was with serial ints where I was testing RS422 up to 1.8mbps (the highest value settable with 168MHz clock, my APB1/APB2 clocks, and an acceptable error using the 32F4 baud rate generator and its "sort of fractional-n divider") and was getting some errors, which were later eliminated. by setting the UARTs to priority 1.There are many people going around this topic online, and it seems that only four bits are available for the priority, which is why FR uses 15, because there are good reasons for task switching to be at the lowest priority.From my project notes:Interrupt priorityThis is normally set with HAL_NVIC_SetPriority(). The only exception is Systick which uses its own code. We do not use NVIC_SetPriority().We use HAL_NVIC_SetPriorityGrouping(0) (in main.c) which means:0 bits for preemption priority4 bits for sub-priorityThere's full preemption based on the 4-bit group priority. Only the sub-priority field is eliminated (0 bits). You get 16 different preemption levels (0-15).FreeRTOS still enforces the configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY = 5 limit:Values 0-5: Can call FreeRTOS APIsValues 6+: Cannot call FreeRTOS APIsCurrent interrupts are (lowest number is highest priority):TIM6 (set to 1)TIM1 (set to 1)UARTs (set to 1 in hal_msp.c)USB (set to 2 in usbd_conf.c)LCD TE EXTI (set to 5)Systick (set to 15 in port.c - configKERNEL_INTERRUPT_PRIORITY)Note that the above are not listed in order of priority within a given level. For example TIM1 is above TIM6, and the timers are mixed up with UARTs, etc.All ISRs must be kept short, in case of holding up another interrupt of a lower priority. The exception is the USB FLASH write which is ~15ms and hangs up everything…SysTick runs at 1kHz and drives the RTOS task switching.

author: tru
author_rank: Regular Contributor
timestamp: September 22, 2025, 02:23:02 pm
content: Quote from: peter-h on September 22, 2025, 01:45:12 pmIt affects the shift amount and therefore the priority level selected is not as the input.HAL_NVIC_SetPriorityGrouping(0) means that the upper 7 bits of the priority register is assigned for the group priority, so we should shift by 8-7 = 1, example pr = priority register:pr = priority << 1But because we are shifting by 4 all the time it is:pr = priority<< 4I cannot list calculation of all 256 group priority levels, but here is the first 7:With correct shift of 1:Code:When using HAL_NVIC_SetPriorityGrouping(0) the actual priority = upper 7 bitsdesired priority = 0, shift = 0 << 1, pr = 0 (00000000), actual priority = 0desired priority = 1, shift = 1 << 1, pr = 2 (00000010), actual priority = 1desired priority = 2, shift = 2 << 1, pr = 4 (00000100), actual priority = 2desired priority = 3, shift = 3 << 1, pr = 6 (00000110), actual priority = 3desired priority = 4, shift = 4 << 1, pr = 8 (00001000), actual priority = 4desired priority = 5, shift = 5 << 1, pr = 10 (00001010), actual priority = 5desired priority = 6, shift = 6 << 1, pr = 12 (00001100), actual priority = 6desired priority = 7, shift = 7 << 1, pr = 14 (00001110), actual priority = 7With incorrect shift of 4:Code:When using HAL_NVIC_SetPriorityGrouping(0) the actual priority = upper 7 bitsdesired priority = 0, shift = 0 << 4, pr = 0 (00000000), actual priority = 0desired priority = 1, shift = 1 << 4, pr = 16 (00010000), actual priority = 8desired priority = 2, shift = 2 << 4, pr = 32 (00100000), actual priority = 16desired priority = 3, shift = 3 << 4, pr = 48 (00110000), actual priority = 24desired priority = 4, shift = 4 << 4, pr = 64 (01000000), actual priority = 32desired priority = 5, shift = 5 << 4, pr = 80 (01010000), actual priority = 40desired priority = 6, shift = 6 << 4, pr = 96 (01100000), actual priority = 48desired priority = 7, shift = 7 << 4, pr = 112 (01110000), actual priority = 56Perhaps this is still okay, but this shows the actual priority level set is not your desired input priority level.

author: peter-h
author_rank: Super Contributor
timestamp: September 22, 2025, 02:48:40 pm
content: I can see that the actual prioritynumberis irrelevant, so long as e.g. the serial rx interrupt is above some other interrupt which takes a bit longer to run. So there is no difference between two ISRs being set to 1 and 5, or set to 200 and 204But there are two specific points which I am trying to understand:1) FR sets its Systick to 15. This is not done with any HAL function. They set it "directly" using some convoluted code which loads the register directly.2) The FR .h file value configLIBRARY_LOWEST_INTERRUPT_PRIORITY is set to 5 and any ISR whose priority (set withHAL_NVIC_SetPriority) is 6 or a higher value, crashes the system immediately. This suggests that HAL_NVIC_SetPriorityissetting a level corresponding to the way FR sets its "15" level.I did more googling and unsurprisingly went up this hill before, 2.5 years ago:https://community.st.com/t5/stm32-mcus-embedded-software/is-nvic-prioritygroup-4-3-same-in-effect-as-0-32f417/td-p/64826The Pavel guy is smart and probably does understand this stuff.I can also see that if you write ISRs to be very short, the priority hardly matters. The system will still work the same. Maybe that is what is now happening.Finally, in the FR port.c file it states/* Priority grouping: The interrupt controller (NVIC) allows the bitsthat define each interrupt's priority to be split between bits thatdefine the interrupt's pre-emption priority bits and bits that definethe interrupt's sub-priority. For simplicity all bits must be definedto be pre-emption priority bits. The following assertion will fail ifthis is not the case (if some bits represent a sub-priority).If the application only uses CMSIS libraries for interruptconfiguration then the correct setting can be achieved on all Cortex-Mdevices by calling NVIC_SetPriorityGrouping( 0 ); before starting thescheduler. Note however that some vendor specific peripheral librariesassume a non-zero priority group setting, in which cases using a valueof zero will result in unpredictable behaviour. */configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );and this is key: no more preemption (it claims):When the NVIC_PRIORITYGROUP_0 is selected, IRQ preemption is no more possible.The pending IRQ priority will be managed only by the sub priority.Not having pre-emption should produce a more robust system.Code:/*** @brief Sets the priority grouping field (preemption priority and subpriority)* using the required unlock sequence.* @param PriorityGroup The priority grouping bits length.* This parameter can be one of the following values:* @arg NVIC_PRIORITYGROUP_0: 0 bits for preemption priority* 4 bits for subpriority* @arg NVIC_PRIORITYGROUP_1: 1 bits for preemption priority* 3 bits for subpriority* @arg NVIC_PRIORITYGROUP_2: 2 bits for preemption priority* 2 bits for subpriority* @arg NVIC_PRIORITYGROUP_3: 3 bits for preemption priority* 1 bits for subpriority* @arg NVIC_PRIORITYGROUP_4: 4 bits for preemption priority* 0 bits for subpriority* @note When the NVIC_PriorityGroup_0 is selected, IRQ preemption is no more possible.* The pending IRQ priority will be managed only by the subpriority.* @retval None*/void HAL_NVIC_SetPriorityGrouping(uint32_t PriorityGroup){/* Check the parameters */assert_param(IS_NVIC_PRIORITY_GROUP(PriorityGroup));/* Set the PRIGROUP[10:8] bits according to the PriorityGroup parameter value */NVIC_SetPriorityGrouping(PriorityGroup);}

author: SiliconWizard
author_rank: Super Contributor
timestamp: September 22, 2025, 02:49:23 pm
content: Quote from: tggzzz on September 22, 2025, 01:27:29 pmUsing message queues to communicate and synchronize between threads is something that I've used for a while now, and it makes muiltithreading definitely much easier to get right and reason about.

author: mikerj
author_rank: Super Contributor
timestamp: September 22, 2025, 03:28:42 pm
content: Quote from: peter-h on September 20, 2025, 08:30:30 amWith CMSIS you call NVIC_GetPriorityGrouping() then NVIC_EncodePriority() to combine preempt and subpriority into one 8 bit value and then use this value set the combined priority with NVIC_SetPriority(), but the ST HAL_NVIC_SetPriority() function wraps all three CMSIS functions.

author: tru
author_rank: Regular Contributor
timestamp: September 22, 2025, 04:22:42 pm
content: @peterh,The FR comment is misleading with two separate issues under a single comment.First part talks about: NVIC_SetPriorityGrouping( 0 );Yes, value of 0 assigns maximum bits to priority group. Looking at the binary point table for M4, PRIGROUP 0 will assign the max 7-bits to the group priority and 1 bit to sub priority.Then the second part (bit near the end) talks about ST HAL's NVIC_PRIORITYGROUP_0, which is easily confused with above, but this is a separate thing referring to a value of 7:NVIC_PRIORITYGROUP_0 = 7Indeed is correct also, the binary point table for M4, PRIGROUP 7, no bits is assigned for group priority and the total exemption level is 1 (Number of group priorities column), which I guess means no preemption.In your case you've confused 0 with 7. For no preemption you would use NVIC_SetPriorityGrouping( 7 );

author: tru
author_rank: Regular Contributor
timestamp: September 22, 2025, 05:21:36 pm
content: Quote from: mikerj on September 22, 2025, 03:28:42 pmNo, that still will not work correctly because CMSIS NVIC_SetPriority() uses the macro for the shift, and that macro is set as a constant.

author: nctnico
author_rank: Super Contributor
timestamp: September 22, 2025, 05:22:03 pm
content: Quote from: peter-h on September 22, 2025, 11:36:11 amI would design such a system entirely different. An OS is inherently not a realtime system as in being able to meet tight time constraints. The interrupt system OTOH is. Consider the interrupts as your hardware implemented, time slicing OS. So this starts with defining the realtime processes which need to happen inside an interrupt and which processes may take longer to execute. Then sort the priorities of the interrupts. For example: a USB or UART interrupt may occur frequently but it is short, so give this a high priority so it can interrupt a longer running interrupt based process which -for example- does a long calculation or needs to move lots of data around. That will work much better compared to handing everything over to the OS because the overhead of dealing with message queues, FIFOs and task switches will be lower. Keeping interrupts short is one of the dogmas that can bite you in the ass because in many cases it makes things worse. In the end you have X CPU cycles to do Y work. Don't waste X on only moving data around.

author: peter-h
author_rank: Super Contributor
timestamp: September 22, 2025, 05:22:55 pm
content: There is so much crap in the various comments in the source code...What exactly does NVIC_SetPriorityGrouping(0) mean?Am I getting priority 0-15, with Systick being 15, and usable levels, all set via HAL_NVIC_SetPriority, of 1-5, and 6-14 also being usable but not for calling FR functions?Currently I am not using 6-14 and don't need them.I am not going to change back to NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4) in case it breaks something. But what, in theory, would that give me? Apart from dire warnings about FR needing it (which are clearly BS)?The system is rock solid now and has been, in various versions, for years, 24/7/365.The reason I revisited this after 2.5 years is1) Getting that PE12=1 rising edge interrupt working exposed the crash issue with a priority of 5+ (and that now appears understood, once one realises the FR doc grammar is backwards)2) I've been carefully documenting the way the interrupts are configured, for the future.QuoteFair point, but I think IF one can keep ISRs very short (which is mostly easy; the notorious FLASH USB write being the only exception) then this way is fine. The RTOS tasks, about 20 of them, run mostly with very low priorities, which is as it should be.

author: tggzzz
author_rank: Super Contributor
timestamp: September 22, 2025, 06:59:19 pm
content: Quote from: nctnico on September 22, 2025, 05:22:03 pmRealtime constraints don't have to be "tight" (by which I presume you mean low latency). The timing constraints merely have to besatisfiedpredictably. Anything that makes that less likely should be deprecated.Your definition of interrupts as being a timeslicing OS for processes implemented inside ISRs is novel, but at least you stated it explicitly. Fundamentally you are conflating OS task priorities with ISR priorities, which is unnecessary and unhelpful. It will make analysis and prediction of the complete system more difficult.It is worth "wasting cycles" if it makes the overall system timing more predictable.

author: tggzzz
author_rank: Super Contributor
timestamp: September 22, 2025, 07:08:27 pm
content: Quote from: peter-h on September 22, 2025, 05:22:55 pmISRs should indeed be short, so thatthisinterruptandthenextinterrupt can be serviced in a predictably timely manner.Ditto RTOS tasks being low (and ideally equal) priority. Even better if they are all executingsimultaneouslyI'm not aware of the specific FreeRTOS USB Flash Write issue, but if it can be solved in other systems...

author: nctnico
author_rank: Super Contributor
timestamp: September 22, 2025, 07:29:40 pm
content: Quote from: tggzzz on September 22, 2025, 06:59:19 pmBut the problem is that mixing an OS and interrupts makes the timing actually less predictable to the point you can't prove the system will work correctly. Sorting out all the processes, the time they take to do their jobs, their time constraints and their priorities is part of designing embedded software before writing a single line of code. Only then you can get to a system which will work predictable AND meet timing requirements. In many cases you can partition a system in a way the interaction between (time critical) interrupt based processes and OS based (not so time critical) processes have a very minimal amount of interaction.

author: tggzzz
author_rank: Super Contributor
timestamp: September 22, 2025, 07:46:44 pm
content: Quote from: nctnico on September 22, 2025, 07:29:40 pmNot in my experience, nor in that of other people I've worked with.QuoteThat seems to conflict with the architecture in your previous message.The key difference is not between "time critical" and "not so time critical", but in thepredictabilityof thelatencies. If you can'tpredict(and hence guarantee) latencies, then you are simply playing statistics of whether the system will work in in the field.Having said that, a key architectural objective is similar to the one you mention: to match short latencies related to external i/o with the longer latencies allowable with "bulk" processing.In this context a generally useful design pattern is the so-called "half-sync half-async" design pattern. It can be adapted to solve many system implementation objectives.

author: nctnico
author_rank: Super Contributor
timestamp: September 22, 2025, 07:52:12 pm
content: You are not getting the point. The point is: don't make processes which don't need to depend on eachother depend on eachother by designing a system so that processes get in eachother's way. Simplify and optimise instead of blindly making everything square to fit a square hole.Edit: also think about why a typical OS has kernel processes (like device drivers) and userspace processes seperately.

author: peter-h
author_rank: Super Contributor
timestamp: September 23, 2025, 08:17:59 am
content: The 15ms FLASH write I mentioned is not relevant to this discussion. There are threads about it; search for Adesto, 15ms, etc. Basically it was on implementing a USB MSC (removable flash drive) device profile. The host (the PC)writecauses a USB interrupt (the entire STM USB code is interrupt driven) and the 512 byte sector needs to be written inside the ISR. One can store the data somewhere and exit from the ISR quickly (the "right" way) but then the host will send you another 512 bytes right away, and what do you do with that?? The mechanism for returning Busy to the host does exist (it is copied from some "SCSI" scheme) but is not reliable, and it turns out that, for best compatibility reasons, flash sticks just hang in the ISR until the sector is written, never returning any Busy status. In my project, the 15ms hang is fine because the USB MSC write feature is only for rare config uploads or edits.USB MSCreadstake 200us and that is done in the ISR too and 200us is ok, although when I was doing a particular feature which required interrupt latency to be < 10us or so, I had to make the USB interrupt a lower priority, and that solved it. I can't remember what value I used in HAL_NVIC_SetPriorityGrouping() back then. AFAICT (0) also allows pre-emption according to priority, no? This had to be done because anytime you have a USB cable connected to a PC, the PC will perform a read every second or so, triggering that 200us ISR.

author: tggzzz
author_rank: Super Contributor
timestamp: September 23, 2025, 08:23:55 am
content: Quote from: peter-h on September 23, 2025, 08:17:59 amThanks for the overview.Sounds like a classic problem of incorporating a "library" (for want of a better word) that was written to be convenient for its own implementation (and maybe original use), but which contains architectural decisions that cause major problems when it is reused in a different situation.It also sounds like a classic example of the dangers of trying to do everything in an ISR - and that a nice ISR->FIFO->task architecture might have avoided.

author: tru
author_rank: Regular Contributor
timestamp: September 23, 2025, 08:43:15 am
content: Quote from: peter-h on September 23, 2025, 08:17:59 amYes, with (0) you get 128 preemption levels. But with (7) (if MCU supports it) we have only 1 priority level for all interrupts so all at the same priority. Preemption can only interrupt another if it's priority level is higher (i.e. a lower number) which cannot happen in this case.Just some corrections on my side (assuming non-default priority grouping is used)- you are right about the set priority not being 1:1- we cannot fully blame ST code, even the github official CMSIS templates have those macros set to a constant!I've just realised the macro __NVIC_PRIO_BITS is used everywhere in the CMSIS functions so even functions like __NVIC_GetPriority() is affected, meaning it returns back your input priority rather than the actual priority.

author: peter-h
author_rank: Super Contributor
timestamp: September 23, 2025, 08:55:03 am
content: I am not using 7. That was the ST default, no? The default was NVIC_PRIORITYGROUP_4. I changed it to a straight 0. The reason is that it seemed clearer re what it does.The FIFO option on the flash write (if one implemented it that way) still needs returning a Busy status to the USB host, otherwise it will keep sending you more blocks, and I don't think Windows implements it correctly. It also has to work with every other USB Host OS. The flash stick mfgs obviously went up that learning curve, and have decided to do what I did... This crude method works, provided the host USB timeout is > 15ms, which it obviously is (Windows is of the order of 1-2 secs).

author: tru
author_rank: Regular Contributor
timestamp: September 23, 2025, 09:47:23 am
content: No, the default is 3 (the macro NVIC_PRIORITYGROUP_4 is defined with 3).

author: peter-h
author_rank: Super Contributor
timestamp: September 23, 2025, 10:01:26 am
content: Thanks. But is there any practical difference between 3 and 0?Both allow pre-emption.I never managed to work out why the FreeRTOS default was thus set.

author: tru
author_rank: Regular Contributor
timestamp: September 23, 2025, 12:22:33 pm
content: I agree practically typical use no difference, but bear in mind with group priority setting of 0, for instance, due to the incorrect shift of 4, priority settings after 15 rolls over the 8 bit priority register:priority_reg = input_priority << 415 is actual priority 12016 is actual priority 017 is actual priority 818 is actual priority 16etcSo if you use only priorities 0 to 15 is fine, but anything above you'll have to consider the rollover becoming the same priority as another.

author: mikerj
author_rank: Super Contributor
timestamp: September 23, 2025, 05:59:45 pm
content: Quote from: tru on September 22, 2025, 05:21:36 pmClaiming there is a fairly significant bug in NVIC_SetPriority() which would have been in place for ~17 years and no one has noticed is pretty bold!The shift required when writing a priority value to the IP register doesnotdepend on the priority grouping, it's always (8 - __NVIC_PRIO_BITS). You still have the same total number of priority bits, irrespective of the grouping configuration.

author: peter-h
author_rank: Super Contributor
timestamp: September 23, 2025, 07:40:07 pm
content: Here are the two functions. In my Cube IDE 1.14.1 I see about 20 versions of this function, in various .h files for different chips presumably, but this is the one I am running, from core_cm4.hCode:/**\brief Set Interrupt Priority\details Sets the priority of a device specific interrupt or a processor exception.The interrupt number can be positive to specify a device specific interrupt,or negative to specify a processor exception.\param  IRQn Interrupt number.\param  priority Priority to set.\note The priority cannot be set for every processor exception.*/__STATIC_INLINE void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority){if ((int32_t)(IRQn) >= 0){NVIC->IP[((uint32_t)IRQn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);}else{SCB->SHP[(((uint32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);}}/**\brief Get Interrupt Priority\details Reads the priority of a device specific interrupt or a processor exception.The interrupt number can be positive to specify a device specific interrupt,or negative to specify a processor exception.\param  IRQn Interrupt number.\return Interrupt Priority.Value is aligned automatically to the implemented priority bits of the microcontroller.*/__STATIC_INLINE uint32_t __NVIC_GetPriority(IRQn_Type IRQn){if ((int32_t)(IRQn) >= 0){return(((uint32_t)NVIC->IP[((uint32_t)IRQn)] >> (8U - __NVIC_PRIO_BITS)));}else{return(((uint32_t)SCB->SHP[(((uint32_t)IRQn) & 0xFUL)-4UL] >> (8U - __NVIC_PRIO_BITS)));}}

author: tru
author_rank: Regular Contributor
timestamp: September 23, 2025, 09:01:26 pm
content: Quote from: mikerj on September 23, 2025, 05:59:45 pmWell, I'm not making it up, according to the Arm Cortex-M4 user guide (an official doc), it does depend on the grouping configuration.If you look at the attached table, the first column is PRIGROUP value (group configuration) and the second column is the bit assignments depending on the first column. The x represents the number of upper bits that are assigned for the priority 8-bit register. You can clearly see that in each row they are different, therefore you must shift with a different value depending on which row you are using when setting the priority register.The macro __NVIC_PRIO_BITS is this 8 - shift value (i.e. number of x bits), but it is set to a constant 4 in the device template files. This shift is correct only for row four of the attached table (default PRIGROUP setting 3), which has four x's and 8 - 4 = 4 - therefore a shift of 4 to shift your x's into the top part. You find it in your ST project under Drivers/CMSIS/Device/...For example stm32f417xx.h, line 49:Code:/*** @brief Configuration of the Cortex-M4 Processor and Core Peripherals*/#define __CM4_REV 0x0001U /*!< Core revision r0p1 */#define __MPU_PRESENT 1U /*!< STM32F4XX provides an MPU */#define __NVIC_PRIO_BITS 4U /*!< STM32F4XX uses 4 Bits for the Priority Levels */#define __Vendor_SysTickConfig 0U /*!< Set to 1 if different SysTick Config is used */#define __FPU_PRESENT 1U /*!< FPU present

author: abyrvalg
author_rank: Frequent Contributor
timestamp: September 23, 2025, 11:12:19 pm
content: Quote from: peter-h on September 23, 2025, 08:55:03 amFlash stick mfgs just have read the relevant USB MSC spec section saying “NAKs in data phase is the official flow control method”. And you don’t need to stay in ISR to keep the endpoint busy, that happens because there must be some code in the library that makes the EP ready when you exit the ISR. Finding and fixing it would be a more clear solution. We did it like that back in the old days:- sector data rx ISR buffers the data, sets a flag for the main code to start the write and returnswithout rearming the EP to ready- the host tries to send the next sector and gets NAKs, meaning the device is busy- main code does the write and rearms the EP- host sends the next sector successfully, repeating the process

author: peter-h
author_rank: Super Contributor
timestamp: September 24, 2025, 05:24:53 am
content: QuoteSurely the host won't send the next sector until it gets an ACK?There must be more detail. I spent ages back then trying out all sorts of stuff. Posted it all here and then somebody said flash sticks do just that... although to be fair the flash they use tends to write a bit faster, e.g. 4ms, plus they have lots of caching.This is off topic for this FreeRTOS stuff but not entirely because the ability to suspend a task and restart it from an ISR is absolutely relevant if you want to use an RTOS task to perform a "foreground" operation triggered from a USB interrupt.

author: abyrvalg
author_rank: Frequent Contributor
timestamp: September 24, 2025, 04:47:08 pm
content: Sure, it just can’t, that’s a fundamental part of USB itself, a built in flow control mechanism usable by any device class, not just MSC. From host’s perspective a NAKed transfer would hang in “pending, autorepeat in the next frame” state until either a device ACKs it or it times out (don’t worry about this case, the timeout in MSC host drivers is pretty long).Been there, done that almost 20 years ago on AT91SAM7S256, MSC, VCP, no libs. I still have one of those devices, it is alive and shows no problems with modern OSes.What happens exactly in your device during multiple sectors write:- rx EP is ready- host sends a CBW (SCSI Command Block Wrapper packet containing a WRITE cmd, starting sector number, data length).- rx EP stores it to buffer, sends an ACK to the host (immediately, this is an rx acknowledge, not “ready for more” signal), goes into BUSY state and fires a data rx irq- here a fast host could start sending the first portion of data already, the rx EP would reject it with NAKs- a CBW handler code parses the CBW, saves the write parameters, rearms the rx EP to a READY state and returns- host (re)sends the first portion of data- rx EP accepts it (because it was in READY state) with ACK, goes into BUSY state and fires an irq again- a fast host could try sending the next piece of data here, the rx EP would reject it with NAKs- your data write code gets called here- rx EP still NAKs the next data- your data wrire code returns- some code in MSC library rearms the rx EP to READY state, allowing reception of the next data chunkSo if you find who rearms the EP when your ISR code returns, you could remove that and do later when a write finishes outside of the ISR. The rx EP will NAK the next data until this deferred rearm.

author: peter-h
author_rank: Super Contributor
timestamp: September 25, 2025, 09:43:31 am
content: I posted this on the ST forum, where nobody seems any wiserhttps://community.st.com/t5/stm32-mcus-embedded-software/32f417-trying-to-interrupt-from-pe12-rising-edge/td-p/840773/highlight/true/page/2

author: tru
author_rank: Regular Contributor
timestamp: September 25, 2025, 11:12:33 am
content: You got me reading the STM32F417 programming reference PM0214 from:https://www.st.com/en/microcontrollers-microprocessors/stm32f407-417/documentation.htmlJust found out that on STM32F417 (and probably many others) ST only implement the four bits for priority group split setting.You can see the statement on page 215, of Table 47. NVIC_IPRx bit assignment:QuoteST didn't put in the PRIGROUP binary point table in the programming ref, but I took the one from Arm's generic user guide amended with the above and we get the attached table.In the table for ST we can see that PRIGROUP 0 is actually the same as the default PRIGROUP 3. This also explains why there are no macros for PRIGROUP 0 to 2 in the ST HAL headerhttps://github.com/STMicroelectronics/stm32f4xx-hal-driver/blob/master/Inc/stm32f4xx_hal_cortex.h

author: peter-h
author_rank: Super Contributor
timestamp: September 25, 2025, 11:20:21 am
content: Not wishing to claim credit for any insight (I am pretty much clueless here) but isn't what what I posted herehttps://www.eevblog.com/forum/microcontrollers/freertos-and-using-an-isr-to-unsuspend-a-suspended-task-(32f417)/msg6046263/#msg6046263about the values selecting the same row?SoHAL_NVIC_SetPriorityGrouping(0)is the same asHAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4)Clearly loads of people have been up this path before. Like me here in 2023https://community.st.com/t5/stm32-mcus-embedded-software/is-nvic-prioritygroup-4-3-same-in-effect-as-0-32f417/td-p/64826That still leaves us with the mystery around why a priorityvalueof 6 or higher blows up when calling a FreeRTOS function from an ISR with a priority of 5.Digging around the FR file tasks.c, looking at xTaskResumeFromISR() there is this comment [my bold]Quoteand indeed the two functions I am calling from the ISR arexTaskResumeFromISR()portYIELD_FROM_ISR()I wonder if "canbe calledfrom interrupts that have been assigned a priority at or (logically)below the maximum system call interrupt priority"should be "mustbe calledfrom interrupts that have been assigned a priority at or (logically)below the maximum system call interrupt priorityThen I looked up portASSERT_IF_INTERRUPT_PRIORITY_INVALID which is a macro invoking vPortValidateInterruptPriority() which isCode:void vPortValidateInterruptPriority( void ){uint32_t ulCurrentInterrupt;uint8_t ucCurrentPriority;/* Obtain the number of the currently executing interrupt. */__asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) :: "memory" );/* Is the interrupt number a user defined interrupt? */if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER ){/* Look up the interrupt's priority. */ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];/* The following assertion will fail if a service routine (ISR) foran interrupt that has been assigned a priority aboveconfigMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS APIfunction. ISR safe FreeRTOS API functions must *only* be calledfrom interrupts that have been assigned a priority at or belowconfigMAX_SYSCALL_INTERRUPT_PRIORITY.Numerically low interrupt priority numbers represent logically highinterrupt priorities, therefore the priority of the interrupt mustbe set to a value equal to or numerically *higher* thanconfigMAX_SYSCALL_INTERRUPT_PRIORITY.Interrupts thatuse the FreeRTOS API must not be left at theirdefault priority ofzero as that is the highest possible priority,which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY,andtherefore also guaranteed to be invalid.FreeRTOS maintains separate thread and ISR API functions to ensureinterrupt entry is as fast and simple as possible.The following links provide detailed information:http://www.freertos.org/RTOS-Cortex-M3-M4.htmlhttp://www.freertos.org/FAQHelp.html */configASSERT( ucCurrentPriority <= ucMaxSysCallPriority );}/* Priority grouping: The interrupt controller (NVIC) allows the bitsthat define each interrupt's priority to be split between bits thatdefine the interrupt's pre-emption priority bits and bits that definethe interrupt's sub-priority. For simplicity all bits must be definedto be pre-emption priority bits. The following assertion will fail ifthis is not the case (if some bits represent a sub-priority).If the application only uses CMSIS libraries for interruptconfiguration then the correct setting can be achieved on all Cortex-Mdevices by calling NVIC_SetPriorityGrouping( 0 ); before starting thescheduler. Note however that some vendor specific peripheral librariesassume a non-zero priority group setting, in which cases using a valueof zero will result in unpredictable behaviour. */configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );}and configASSERT() is supposed to basically hang the systemCode:#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); for( ;; );}if the current priority is numerically less than configMAX_SYSCALL_INTERRUPT_PRIORITY. Yes what I see is the opposite.

author: tru
author_rank: Regular Contributor
timestamp: September 25, 2025, 01:06:28 pm
content: Agreed, and apologies I wasn't aware of ST's four bits only so thought your table was wrong, and also now having read your other thread (is super long) most of that was already discussed.I am working on a STM32 Nucleo 144 STM32H753ZI, which a bit different from yours, but FreeRTOS should still behave in the same way.I'm not sure if this will help with your problem, I've just setup a simple STM32 Cube IDE project (v1.18.1) to try something like your setup:1. A the push button setup as EXTI and with lowest priority 15.2. Created a task:Code:xTaskCreate(mytask, NULL, configMINIMAL_STACK_SIZE*2, NULL, osPriorityLow, &mytask_handle);3. The task simply counts 1 to 3 every second then suspends:Code:void mytask(void *parameters){for(;;){static int count = 3;if(count == 0){printf("Suspended\n");vTaskSuspend(mytask_handle);count = 3;}else{printf("%i\n", count);count--;}osDelay(1000);}}4. The push button EXTI interrupt (has priority 15) which calls this function back, the code resumes the task when the button is pushed:Code:void BSP_PB_Callback(Button_TypeDef Button){if(Button == BUTTON_USER){HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);BaseType_t xYieldRequired = xTaskResumeFromISR(mytask_handle);portYIELD_FROM_ISR(xYieldRequired);}}On PuTTY serial terminal I see the counting then suspend messages. Pressing the push button resumes the task and I see counting again, so a lower priority (>=5) ISR does work. Perhaps my task is too simple and may break if I add other HAL stuff, but not sure what I can put in there.

author: peter-h
author_rank: Super Contributor
timestamp: September 25, 2025, 01:12:53 pm
content: Does it blow up if you set the ISR to a higher priority, say 3?Try calling some function whose name includes "fromISR":QuoteI am using that together with vTaskSuspend() - see post #1.

author: tru
author_rank: Regular Contributor
timestamp: September 25, 2025, 01:29:35 pm
content: Setting the push button EXTI to priority 3, yes now it blows up!It stops at the FreeRTOS assert (port.c):Code:void vPortValidateInterruptPriority( void ){uint32_t ulCurrentInterrupt;uint8_t ucCurrentPriority;/* Obtain the number of the currently executing interrupt. */__asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) :: "memory" );/* Is the interrupt number a user defined interrupt? */if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER ){/* Look up the interrupt's priority. */ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];/* The following assertion will fail if a service routine (ISR) foran interrupt that has been assigned a priority aboveconfigMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS APIfunction. ISR safe FreeRTOS API functions must *only* be calledfrom interrupts that have been assigned a priority at or belowconfigMAX_SYSCALL_INTERRUPT_PRIORITY.Numerically low interrupt priority numbers represent logically highinterrupt priorities, therefore the priority of the interrupt mustbe set to a value equal to or numerically *higher* thanconfigMAX_SYSCALL_INTERRUPT_PRIORITY.Interrupts thatuse the FreeRTOS API must not be left at theirdefault priority ofzero as that is the highest possible priority,which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY,andtherefore also guaranteed to be invalid.FreeRTOS maintains separate thread and ISR API functions to ensureinterrupt entry is as fast and simple as possible.The following links provide detailed information:http://www.freertos.org/RTOS-Cortex-M3-M4.htmlhttp://www.freertos.org/FAQHelp.html */configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );}...From the debug I see the variables are as follows:ucCurrentPriority = 48ucMaxSysCallPriority = 80

author: peter-h
author_rank: Super Contributor
timestamp: September 25, 2025, 01:35:25 pm
content: Yes; 48 is actually 3 supplied to the set priority call.<<<< 4I edited my last post while you were trying itSee if you can try thishttps://www.eevblog.com/forum/microcontrollers/freertos-and-using-an-isr-to-unsuspend-a-suspended-task-(32f417)/msg6049095/#msg6049095

author: peter-h
author_rank: Super Contributor
timestamp: September 28, 2025, 08:01:56 pm
content: I am bumping this in case anybody wants to test the suspend/unsuspend-from-ISR operation, and verify the interrupt priority apparently working backwards from the FreeRTOS doc.