Is there any way to disable all irq from Cortex M3 MCU except one ?
My issue is that I have a system running several kinds of irq with various priority levels and I want to disable all irq except one in a particular state.
I know I can disable all irq by using "__disable_irq()" instruction but I can't enable one irq after calling this instruction if I didn't call "__enable_irq()" before.
Thanks for your help,
Regards
Use the BASEPRI register to disable all interrupts below the specified priority level.
This is a core register, described in the Cortex-M3 Programming Manual.
CMSIS provides the __get_BASEPRI() and __set_BASEPRI() functions to manipulate its value.
Note that bits 7-4 are used, the priority value must be shifted left by 4. To disable all interrupts with priority 1 or lower, use
__set_BASEPRI(1 << 4);
and to enable all, set it to 0
__set_BASEPRI(0);
You should of course set interrupt priorities accordingly, ensuring that no other interrupt has priority 0.
Other than by disabling all the enabled interrupts you don't want, no.
__disable_irq() is implemented as CPSID I, which turns off all exceptions which can have a priority set (those configured in the NVIC), it achieves this by changing the PRIMASK register (setting bit 0) within the CPU. There is no way to tell this to only enable a specific interrupt.
Related
From what I understand, the interrupts are enabled by using the below approach :
The steps 1) through 9) are followed in a general EXTI programming.
There are two sides for enabling and clearing the interrupt :
Peripheral Side : gets enabled by SYSCFG, EXTI blocks and also cleared in the pending register EXTI_PR once interrupt is encountered.
Processor Side : NVIC->ISER to enable. But in spite of NVIC->ICPR being there I don't see that it's being used to clear the processor side for pending register. Why?
Are there any peripheral side interrupt generators too which also don't have any pending register that required to be cleared?
Any document which explains these also would be greatly appreciated.
It is the same with all other peripheral registers. The clear path is not important from the programmer point of view. The important is information how to clear the bit.
Clear the bit you need to clear bit EXTI PR register.
Clearing sometimes happen indirectly (for example by reading the data register in some communication registers). Some peripherals have special registers only for clearing the pending bit. Example: DMA
Everything is in the Reference Manual.
Clearing the flag in the peripheral register deasserts the interrupt line coming to NVIC form peripheral.
I have started using ARM Cortex M0+ for GPIO Interrupts. I want to disable nesting feature from ARM Interrupts. Is there any way to do it.? I know by default, nesting is enabled in ARM, I want to disable it.
ARM Cortex-M0/M0+ do not support interrupt priority grouping into preemption priority(nestable) and sub-priority (non-nestable) available on the M3/M4/M7 for example.
If you wish to prevent interrupt nesting; it would be necessary to either;
set all interrupts to the same priority, or
disable and re-enable interrupts on entry and exit to all handlers.
The first of these options is the simplest, but gives no control over execution order (which seldom matters for asynchronous events, but may lead to non-deterministic behaviour and timing). The second does not actually prevent nesting, but does allow nesting only before the lower-priority interrupt has disabled the interrupts - before it has started processing the actual event. The result is behaviour similar to that of sub-priorities available on Cortex-M3 etc.
Is it a feature of Cortex-M series MCUs to be able to wake from a low power mode (sleep or deepsleep or other MCU specific modes) with interrupts configured but disabled?
The mechanism for entering the low power mode is executing WFI instruction.
The MCUs I have used from STM and Renesas, wake from the low power mode via an interrupt if the interrupt is configured correctly and even if all interrupts are disabled via the cpsid instruction.
I am trying to determine is this is what I should expect on all Cortex M series based MCUs or just specific to certain MCU vendors.
Every ARM Cortex-M will work this way as long as you use PRIMASK to disable ALL interrupts. This is what __disable_irq() from CMSIS does. According to the docs, raising priority with BASEPRI will not cause an interrupt with insufficient priority to wake the chip.
See here - http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/BABFEFIG.html
Operation
WFI is a hint instruction that suspends execution until one of the following events occurs:
a non-masked interrupt occurs and is taken
an interrupt masked by PRIMASK becomes pending
a Debug Entry request.
Context
on i.MX6Quad board, when the system running, I found that Core3 can not deal with any interrupt.
view the GIC interface registers by Trace32, the GICC_RPR is always 0, which means the highest priority event is running, so it explain the uppon question: lower priority event cannot be processed.
Question
I have insert a instruction : write 0 to GICC_EOI , which can change GICC_RPR to idle priority(0xFF), but it doesn't work, keep 0.
Goal
I want to do priority drop and deactivate success.
References
gic arch specf : 3.2.1 Priority drop and interrupt deactivation
Priority drop is the drop in the Running priority that occurs on a valid write > to an EOIR, either the
GICC_EOIR or the GICC_AEOIR.
On priority drop, the running priority is reduced from the priority of the
interrupt referenced by the
EOIR write to either
Writing Zero to EOI does not help. When an interrupt fires, you have to read GICC_IAR register. The value you get is the interrupt number that fired. If you are in legacy mode, you have to write this interrupt number to EOI to retire this interrupt. If you are in priority drop mode, writing this number to EOI decreases the priority, writing the same value to DI will retire the interrupt (check GICC_CTLR to confirm your mode). Hope this clears up the confusion with RPR and EOI.
Some pointers to debug your issue:
1. Check the GICD_ITARGET registers to see there are interrupts pointed at CPU3.
2. Ensure the interrupts that you are expecting in CPU3 (if anything specific) is not masked in the distributor
3. Check GICC_PMR for CPU3 to see that the priority is not too high. An interrupt is forwarded from distributor to cpu interface only if its priority is higher than the value in this register
4. Check CPU interface for CPU3 is enabled
5. Check GICD_ISPEND to see if the interrupt in question is pending
NOTE: Be careful when using T32 to debug GIC. T32 works by reading values from registers/memory. This has undesired effects on some GIC registers, for eg GICC_IAR register can only read once to acknowledge the interrupt. Further reads will return spurious interrupt numbers. When T32 is connected and a window is opened to read GICC registers, this will cause an 'orphan' interrupt that no one can take care of. I would suggest putting in logs in the interrupt handling logic to debug issues.
I have read the ARM document about Cortex-M3 (or M0) and it say it can be used as level sensetive or pulse (edge) interrupt within the NVIC controller. The problem that it rather vague on how to do this, if this is done by software.
I fails to see any kind of register within the NVIC or such that control the type of the interrupt (to select edge or level by adjusting the register bits). So something must be done by software within handler but again it vague in this field.
I like to hear anyone having a way to make it edge or level trigger interrupt by software.
Please demonstrate within the handler code (if this control it) that the make it detect for level or pulse.
If this is level detect, I can hold interrupt active and disable by the handler, until restore by external code for which it re-excute the interrupt. This is what I'm trying to do, but it will not work if this is pulse detect type.
Thx
A document that describes how the Cortex-M3 NIVC handles level or edge (pulse) triggered interrupts can be found here:
Cortex-M3 Devices Generic User Guide, 4.2.9. Level-sensitive and pulse interrupts
This may well be the document you refer to in your question. Joseph Yiu's book, "The Definitive Guide to the ARM Cortex-M3" also has a pretty good description.
There is no particular configuration of the NVIC for these two interrupt signal types - it handles either kind. Essentially, when an interrupt is asserted (whterh level-based or edge triggered) the NVIC latches that status in the SETPENDx register. When the ISR for that interrupt is vectored to, the corresponding bit in the ACTIVEx register will be set and the bit in the SETPENDx register will be cleared.
While the interrupt is active, if the interrupt line transitions from inactive to active, the pending bit will be turned on again, and upon return from the current active ISR instance, the interrupt will be handled again. This handles the edge triggered interrupt case.
Also, when the ISR returns (and the NVIC clears the 'active' bit), the NIVC will reexamine the state of the interrupt line - if it's still asserted it will set the pending bit again (even if there hasn't been a a transition from inactive to active). This handles the case where an interrupt is level triggered, and the ISR didn't manage to cause the interrupt to be de-asserted (maybe a second device on a shared IRQ line asserted its interrupt at just the critical moment so there was no time when the interrupt line was inactive).
If this is level detect, I can hold interrupt active and disable by the handler, until restore by external code for which it re-execute the interrupt.
I'm not sure I really understand what you're after here, but I think that you might be able to do what you want using the NVIC's SETENAx and CLRENAx registers to enable/disable the interrupt. These work independently of the pending bits, so an interrupt can be pending (or become pending) even if the interrupt is disabled. So you can hold off handling an interrupt for as long as you want.
If that's not quite enough, also note that you can cause an interrupt to pend via software by simply setting the pending bit in the corresponding SETPENDx register - the CPU will vector to the ISR just as if a hardware interrupt were asserted (assuming the interrupt is enabled in the SETENAx register). you can also use the "Software Trigger Interrupt Register" (STIR) to trigger an interrupt by software.