ppotts wrote on Friday, January 29, 2016:
Thank you for taking the time to explain. If you are willing to take a little longer I think I am just about there. I have read that document you linked to yet again. This must be the fifth time… I also read this: http://embeddedgurus.com/state-space/2014/02/cutting-through-the-confusion-with-arm-cortex-m-interrupt-priorities/
I think there is further confusion due not only to the reversed counting of priorities, but to the use of a subset of bits that is shifted towards the high bits.
So,
In my build, __NVIC_PRIO_BITS is 4
configLIBRARY_LOWEST_INTERRUPT_PRIORITY is 0xF
configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY is 0x1
I take this to mean that 1 is the next-to-highest priority (not numerically highest, but logically highest).
The document says “The RTOS interrupt nesting scheme splits the available interrupt priorities into two groups - those that will get masked by RTOS critical sections, and those that are never masked by RTOS critical sections and are therefore always enabled. The configMAX_SYSCALL_INTERRUPT_PRIORITY setting in FreeRTOSConfig.h defines the boundary between the two groups.”
However, I don’t find this to be perfectly clear. “Defines the boundary” could be read as either “this value and logically higher values are not masked,” or “values logically higher than this value are not masked.” So I am not clear whether priority 1 can be masked by FreeRTOS critical sections.
There are two more macros, configKERNEL_INTERRUPT_PRIORITY and configMAX_SYSCALL_INTERRUPT_PRIORITY that are based on the previous two macros but take into account the number of priority bits, to shift them into the high bits.
So in this case configKERNEL_INTERRUPT_PRIORITY becomes 0xF << 4 = 0xF0
That should be the logically lowest priority ready to put into BASEPRI
The other one is configMAX_SYSCALL_INTERRUPT_PRIORITY and that turns into 1 << 4 = 0x10
That should be the logically next-to-highest priority ready to put into BASEPRI
Trying to figure out the actual priority used for the system clock is buried under more layers of macros. It looks like my port defines #define portNVIC_SYSTICK_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL )
Which should mean that is 0xF0000000
It looks like that is formatted to be placed in portNVIC_SYSPRI2_REG
That is defined as ( * ( ( volatile uint32_t * ) 0xe000ed20 ) ) but I don’t find that address in any of the chip headers so I’m not certain what that is, but I’ll take it as a given that the lowest available priority setting is assigned to the system tick.
But I’m still unclear on why taskENTER_CRITICAL could not disable that. We seem to have a chain of definitions, taskENTER_CRITICAL -> portENTER_CRITICAL -> vPortEnterCritical() which calls portDISABLE_INTERRUPTS -> vPortRaiseBASEPRI -> which sets BASEPRI to configMAX_SYSCALL_INTERRUPT_PRIORITY which is 0x10 (next-to-highest logical priority, shifted into the high bits).
That should have blocked the timer tick, which has the the lowest logical priority, right? (But it did not seem to in my case, because disabling the timer tick fixed the crash problem, while calling taskENTER_CRITICAL only did not).
You wrote “No, it disables everything with the priority 0x10 and lower. Remember,
on the ARM Cortex-M, the lower the numeric priority the higher the
logical priority. So, setting BASEPRI to 0x10 does not disable
interrupt priority 0 (or 1, 2, etc.) because those priorities have a
lower numeric value and therefore a HIGHER logical priority. This is
why it is so confusing for people.”
But I think putting 0x10 in BASEPRI should allow interrupts with numeric priority 0 and disable interrupts with numeric priority 1 or greater (lower logical priority). (Remember, the bits are shifted up by 4).
If that is not the case… then it seems like the port is not defining things sensibly, with its definitions of configKERNEL_INTERRUPT_PRIORITY and configMAX_SYSCALL_INTERRUPT_PRIORITY, because using those values would never disable any of the actual 16 interrupt priority levels used on this chip? I think if that was the case, the port would not work right.
Thanks for any clarification.