In ri5cy documentation, it says that :
[§12.1 Interrupts] Interrupts can only be enabled/disabled on a global basis and not individually. It is assumed that there is an
event/interrupt controller outside of the core that performs masking and buffering of the interrupt lines. The global
interrupt enable is done via the CSR register MSTATUS.
but actually, there is nothing in the MSTATUS register § about this, the only thing close is:
[§MSTATUS.MIE] "Machine Interrupt Enable: If you want to enable interrupt handling in your exception handler, set the Interrupt Enable MIE to 1’b1 inside your handler code"
ok, you can enable interrupt in your exception handler but how to enable/disable globally interrupts?
Setting/Clearing MSTATUS.MIE does not en/disable globally interrupts (IRQ are always on, even if MSTATUS.MIE = 0)
So I think there is an error in the ri5cy implementation of the riscv specs,
for instance, for cv32e40x, globally interrupts en/disable is done - at core level - through the MIE CSR, so when MIE = 0xFFFFFFFF all irqs are enabled and when MIE = 0 are irqs are disabled.
Could I disable irqs globally with ri5y?
I thought about using the event controller:
to disable: saving the IER and setting it to 0
to re-enable: setting back the IER to the previous saved value
but this very looks like tinkering...
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 a piece of code where there is:
disable_irq(irq_clk);
local_irq_save(flags);
I found that the disable_irq() disables a specific interrupt, on the other hand local_irq_save() disables all the interrupt.
So I wonder the meaning of the above code.
This makes sense, because interrupts are disabled at different levels.
disable_irq(irq_clk);
This code disables (masks) interrupt in interrupt controller. If you have disabled interrupt at this level, the interrupt wouldn't be passed to internal interrupt controller pipeline. It would not be prioritized, it would not be routed to the destination CPU.
local_irq_save(flags);
This code disables all interrupts at the level of CPU IRQ interface. Interrupts are passed to CPU IRQ interface after they have passed priority & routing pipeline of the interrupt controller and have been asserted to the CPU.
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.
I am working with a very custom and not public Secure IC which has ARM Cortex M3 core.
In case of hw security violation, this IC triggers an NMI interrupt so it is fine, I am doing whatever I need for violation.
But It always enters into NMI Handler again and again when a violation is occurred.
We probably need to clear interrupt pending flag not sure but it should be cleaned directly.
Because SCB->ICSR bit31 says that "entering the handler clears this bit to 0".
I also tried to clear pending flag using NVIC_ClearPendingIRQ() but it does not accept negative IRQ values while NMI is -14.
I tried to set manually NVIC->ICPR[0] = (1 << 2); like as manufacturer examples (but manufacturer example resets device in NMI handler which is different case) but it does not work.
It is custom IC and custom external event which triggers generic Cortex M NMI interrupt and can be a specific case to IC but is there any limitation for NMI like "you can not clear NMI pending flag and you have to reset it bla bla"?
Thank you
The NMI is acting just like any other interrupt here.
From the Cortex-M Generic Device User Guide:
For a level-sensitive interrupt, when the processor returns from the ISR, the NVIC samples the interrupt signal. If the signal is
asserted, the state of the interrupt changes to pending, which might
cause the processor to immediately re-enter the ISR. Otherwise, the
state of the interrupt changes to inactive.
For a pulse interrupt, the NVIC continues to monitor the interrupt signal, and if this is pulsed the state of the interrupt changes to
pending and active. In this case, when the processor returns from the
ISR the state of the interrupt changes to pending, which might cause
the processor to immediately re-enter the ISR.
What this is saying is that unless you clear the hardware state which is generating the interrupt request, the interrupt will pend again.
Clearing the interrupt pending state only allows you to disable an IRQ if the request has already been cleared.
For details on how your secure device operates, you need to speak to your vendor. They may be unhappy about you discussing their product here...
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.