We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
Hello,
I am using STM32F407ZGT6 Cortex-M4 microcontroller. I am interested in changing the priority of a certain interrupt while servicing the same interrupt. Is that possible?
More elaborately, lets say I have an interrupt which has a priority of 4. The interrupt has arrived and I am currently in the ISR servicing that interrupt. After running a certain code (in the ISR), I want to run the remaining code (in the ISR) to run at higher priority (say 2). And when I was about to leave the ISR, I again change its priority to 4. Is this possible?
Currently, I have achieved this by calling a higher priority interrupt inside the lower priority interrupt.
Thanking in anticipation for your time and help.
I think you can use __set_BASEPRI(priority) for this.
Try having a look at the "Can I prevent my interrupt handlers from being interrupted" article at the ARM Information Center.
Although written or Cortex-M3, it also applied to Cortex-M4.
...Searching with Google also gives you this article, which is good reading.
Until I studied the mechanism of interrupts profiles Cortex-M, interrupts can be configured and manipulated under any circumstances and will respond appropriately as the most suitable for the processor time.
The exchange of priority in my view does not seem to be a good practice run when the interruption itself, despite being allowed, I see as a violation of the responsibilities in structuring your code, so signal through the recorder BASEPRI / PRIMASK or its function in C is the best choice.
The article below can give you some useful information to complement.
Cutting Through the Confusion with ARM Cortex-M Interrupt Priorities
adnan.ashraf could you mark responses as 'correct' or 'helpful' as and when please so that contributors can get their fair share of points? Thanks!
Many thanks for the response.
Well, I think I was unable to properly explain the issue.
Let's suppose I have following ISRs:
IRQHandler_0
{
// priority = 0 (highest priority)
}
IRQHandler_1
// priority = 1
IRQHandler_2
// priority = 2
IRQHandler_3
// priority = 3
IRQHandler_4
// priority = 4
Code A // needs to run at priority 4
Code B // needs to run at priority 2
I am asking, is this possible that I can change the priority while in IRQHandler_4 and run a certain part at higher priority (say 2). Please note that when running the higher priority code (Code B) in the IRQHandler_4, higher priorities interrupts (such as 0 and 1) should be able to pre-empt the IRQHandler_4 and come back to Code B with the same higher priority of 2. But when running Code B, lower priority interrupts (such as 2, 3, 4) should not be able to pre-empt Code B.
BASEPRI / PRIMASK registers prevent other low priority exceptions. I don't think, they will be useful in my case.
Well, when I would do as follows.
Before entering the "Code A", I do not interfere in the priority of the current interrupt.
Before entering the "Code B", I change the current interrupt priority to 2.
Have you tried it? what happened?
Thanks for your detailed reply. It seems to me that you are misinterpreting that higher priority values mean higher priorities. Please note that low priority values represent higher priorities (which means 0 is the highest priority here). Please correct me if I am wrong.
So, I am trying to change the priority level of a running interrupt to a higher priority.
Thanks!!
Thanks for your reply.
I've not tried it yet, I am interested in knowing the definite answer. However, I achieved the same by calling a higher priority interrupt inside a lower priority interrupt.
(Sorry for the confusion, I've cleaned up this reply)
I think the article Re: Changing interrupt priority to prevent nesting may be what you're looking for.
You've probably already read A Beginner’s Guide on Interrupt Latency - and Interrupt Latency of the ARM® Cortex®-M processors - but if not, it's an excellent article.
But if you still want to change the priority level in the middle of your interrupt, I believe it's possible.
Typically you would only use an approach like this in a multitasking environment or with very simple high-speed applications.
You could use a svc handler and make the svc handler modify the priority, then call the svc handler from within your interrupt...
...or you could set the priority level of the svc handler to a higher priority, then do a svcall and place the critical section inside your svc handler.
I think both jyiu and chrisshore may have some valuable input on this.
> BASEPRI / PRIMASK registers prevent other low priority exceptions. I don't think, they will be useful in my case.
Wouldn't changing the priority also prevent other low priority exceptions as well ?
As far as I understood it, this is how the priority mechanism actually works (but I may be wrong).
Have you tried ...
Code A
dump contents of BASEPRI
execute SVC, which has priority 2
SVC
... (try making a short test-program, which does nothing except from the above and trigger IRQHandler_4 once only.
-So using __set_BASEPRI(priority) for setting / restoring it inside the interrupt would have the same effect; you should not have to call/trigger a higher priority interrupt manually.
Thanks for the reply!
I am still unable to understand why I need to use BASEPRI. Because SVC has a priority higher than IRQHanlder_4, so the SVC interrupt will easily pre-empt the IRQHandler_4 and I don't need to change BASEPRI. Please correct me if I am wrong.
Any ways, the idea of using SVC is as similar as I am already achieving by calling a higher priority (software) interrupt inside IRQHandler_4. Please correct me if I am wrong.
Many thanks for your time and help!
jyiu Can I've a definite answer please!
Many thanks!!
I simply practically implemented the following code:
Change IRQHandler_4 to higher priority 2
Change back IRQHandler_4 to lower priority 4
And it runs perfectly. Code A runs at lower priority 4 and Code B at higher priority 2.
Thus, in ARM Cortex-M4, the interrupt priority can be dynamically changed anywhere, even inside the interrupt handler (which is servicing the interrupt)
Sorry for delay of my reply.
Glad to know that you have find the answer. Yes, Cortex-M3 and Cortex-M4 supports dynamic changing of the priority level.
Please note that this is not supported in ARMv6-M (Cortex-M0/M0+/M1). For ARMv6-M, you should only change the priority level of a interrupt when it is inactive and ideally disable it first, change the priority level, and then reenable it.
Normally we expect users to use BASEPRI to block the lower priority level interrupts.
For example, when you change the priority level of IRQHandler_4 to 2:
NVIC_SetPriority(PORT0_4_IRQn, 0x2);
You can get the same effect by:
__set_BASEPRI(0x2 << (8 - __NVIC_PRIO_BITS));
But at the end of the ISR, when you set the priority level back to 4:
NVIC_SetPriority(PORT0_4_IRQn, 0x4);
If you are using BASEPRI, you should be restoring it to orginal value (e.g. 0). Otherwise it could block other lower priority level interrupts.
for example, your ISR could look like:
void IRQ4_Handler(void)
uint32_t last_basepri;
// Run code A
...
last_basepri = __get_BASEPRI();
// Run code B
__set_BASEPRI(last_basepri);
return;
Comparing between using IRQ priority level and BASEPRI, there is one difference:
The function code using BASEPRI (function_X below) can be used by both an IRQ handler as well as in Thread, and can be shared by multiple IRQ handlers:
void function_X(void)
// Run code B at level 2
Change the priority level of an active IRQ cannot work in Thread (because the IRQ isn't active at that stage), and if the code need to be shared by multiple ISRs, you need to detect which IRQ it is serving to change the right priority level setting.
Hope this helps.
regards,
Joseph
Thanks a lot for the detailed reply. It has cleared up many confusions.