GPIO Level Triggered Understanding - arm

I have recently started working on GPIO Interrupts both edge triggered as well as level triggered. I implemented edge triggered and that seems to be working fine, but for level triggered interrupts, I am a little confuzed.
Suppose, I pull the pin low for initial state and configure the pin as High level triggered Interrupt. So, if I will now connect Vcc to my pin, I will receive an interrupt. That's fine. My question is now if I keep my Vcc continuously connected to this pin, should the interrupts keep on coming or should it trigger only once?
Note: I have cleared the pending interrupt in Gpio Handler Interrupt routine.
In case any good reference document is available, please provide the link also, I want to dig deeper into it. Thanks

should the interrupts keep on coming or should it trigger only once?
This is generally the main trait of level-triggered interrupts: As soon as the input line is on trigger level and the interrupt flag is clear, an interrupt is triggered.
So if your GPIO line is constantly at trigger level, the interrupt will trigger initially - And as soon as you clear the interrupt flag in the ISR, the interrupt will trigger again - Probably not very useful, but depending on what you want. In such a system, your code will continuously execute the ISR and nothing else.

Related

need to use delay in a interrupt function using an STM32F4

so i'm using an STM32F4 based bare bone board (Black Pill) to run a program for my project
i m using the STM32CubeIDE for code generating
Current Overtime cases explanatory
the figure you just saw, is a graph i made simply on paint to explain the post
my project revolve around inductance load protection against short circuits, (doesn't matter but just clarification)
i m using interrupts, where the first interrupt triggers once the current reaches a reference 1 value
second interrupt triggers once the if reaches Value Reference 1
since current noises can't be filtered in my case, I have to avoid the triggering of instruction of int 2
there for I put a delay that is a bit bigger then the noise period (about 100ns)
if delay ended and int trigger is still on (high) , shut down the system (change the output)
if delay ended and int trigger is off (low), keep the system running (keep initial output)
this is the code i came up with so far
enter code here
I believe what you're looking for is a "Timer" and some interrupt handling magic. I will expand a little.
If your interrupt is OFF (in NVIC only, the rest is configured), but an interrupt triggering event occurred, the interrupt will NOT fire (obviously). But if you enable the interrupt in NVIC after that, it will fire immediately.
Example:
You set up a GPIO as input, you setup EXTI (external interrupt) and SYSCFG (binding port to EXTI), basically, you make a rising edge interrupt
In NVIC the corresponding interrupt is OFF
Rising edge happens on GPIO, immediately goes back down to LOW
You enable an interrupt in NVIC
Interrupt fires (even if the input never had a rising edge after NVIC interrupt was turned on)
My idea is the following.
In the interrupt 1 handler, you do 2 things.
Disable interrupt 2 in NVIC
Launch a delay via Timer with interrupt.
When interrupt 1 fires, it immediately disables interrupt 2 and enables timer. The timer eventually fires its own interrupt, where it enables interrupt 2 in NVIC. If interrupt 2 event happened, the interrupt 2 handler will be called immediately. If not, interrupt 2 will not fire.
During all this waiting your MCU is free to do whatever it wants, full interrupt implementation.

How do I reset the STM32 HAL UART driver (HAL) state?

I know one can enable a UART receive interrupt using
HAL_UART_Receive_IT(&huart2, (uint8_t *)rx_buffer, expectedNumberOfBytes)
But once started how does one stop it, "manually"?
We can disable the UART interrupt using HAL_NVIC_DisableIRQ() (ex: HAL_NVIC_DisableIRQ(USART1_IRQn)). This will prevent it from raising an interrupt, but the state set by the function HAL_UART_Receive_IT which is HAL_UART_STATE_BUSY_RX needs to be set back to HAL_UART_STATE_READY for the uart handle to go back to a state that can accept a new HAL_UART_Receive_IT() call.
Question
How do I reset the state of the UART interrupt if I wish to disable a Rx interrupt after some time?
Stack Overflow questions do not address how to reset the state; I have referred to these questions:
Disabling interrupt in interrupt handler STM32F407
https://electronics.stackexchange.com/questions/100073/stm32-usart-rx-interrupts
I could use USART_ClearITPendingBit() or USART_ITConfig() but these are defined as private functions by STM's HAL library. So should I use them?
How [do I] reset the state of the UART interrupt if [I] wish to disable a Rx interrupt after some time[?]
(See it's usage in "stm32f4xx_hal_uart.c", for example.)
The huart->RxState member of a uart handle struct is really only used internally by the HAL library when doing things such as HAL_UART_Receive(), HAL_UART_Receive_IT(), HAL_UART_Receive_DMA(), (and many other internal functions like this), etc. If you manually implement your own interrupt-based and ring-buffer-based UART Tx and Rx calls, however, which is the preferred way to do it, this member is completely meaningless and it doesn't matter what you do with it, as it is used only inside HAL library function calls and HAL ISR handlers (neither of which you have to use), and really has nothing to do with the register-level interrupts and things directly.
By digging around the source code in stm32f4xx_hal_uart.c (for example), however, here are a couple valid options you can use:
1. How to reset huart->RxState to HAL_UART_STATE_READY:
Call HAL_UART_Init(). By inspecting its source code, you'll see it calls huart->RxState= HAL_UART_STATE_READY; before returning.
Just manually set huart->RxState = HAL_UART_STATE_READY; So long as you know you have properly stopped the interrupt-based receive in the middle of its processing, this is perfectly valid.
Let's take this further, however.
Imagine you are using UART7 on an STM32F4. Therefore, in your stm32f4xx_it.c interrupt handler file, you'll see the following code auto-generated by STM32CubeMX:
/**
* #brief This function handles UART7 global interrupt.
*/
void UART7_IRQHandler(void)
{
/* USER CODE BEGIN UART7_IRQn 0 */
/* USER CODE END UART7_IRQn 0 */
HAL_UART_IRQHandler(&huart7);
/* USER CODE BEGIN UART7_IRQn 1 */
/* USER CODE END UART7_IRQn 1 */
}
Let's go over some layers of disabling/enabling interrupts.
2. From broadest to narrowest scope, here are several ways to disable/enable the USART Rx interrupt:
You can disable/enable ALL interrupts, including this UART7_IRQHandler(), using these ARM-core CMSIS calls:
__disable_irq();
__enable_irq();
Source: https://stm32f4-discovery.net/2015/06/how-to-properly-enabledisable-interrupts-in-arm-cortex-m/
So, you could do the following to disable the interrupt, reset the RxState, and then start up the interrupt-based receive again when ready:
__disable_irq();
huart7->RxState= HAL_UART_STATE_READY;
__enable_irq();
HAL_UART_Receive_IT(&huart7, (uint8_t *)rx_buffer, expectedNumberOfBytes);
You can disable/enable ONLY the UART7_IRQHandler() interrupts (all 10 types of uart7 interrupts connected to this interrupt vector, including Tx-related, Rx-related, error-related, etc), using these STM32 HAL calls:
HAL_NVIC_DisableIRQ(UART7_IRQn);
HAL_NVIC_EnableIRQ(UART7_IRQn);
Then, do the same as just above except use these calls to disable/enable the interrupts instead.
If you dig down into the implementation of HAL_UART_IRQHandler(), however, which is called by UART7_IRQHandler(), you'll see that it only calls the interrupt-based receive handler, UART_Receive_IT(), if both the USART_SR_RXNE bit ("Receive Not Empty", inside the USART Status Register) and the USART_CR1_RXNEIE bit ("Receive Not Empty Interrupt Enable", inside the USART Control Register 1), are both set. The RXNE bit is set whenever a byte comes in, and is cleared whenever you read the data register or write a zero to it. The interrupt-enable bit is something you have full control over to disable this UART receive interrupt, and if you clear this bit manually, you will disable the receive interrupt withOUT disabling any other type of interrupt associated with this USART. This is the best way to do it, as there are 10 interrupt sources associated with this UART. In other words, clearing this bit not only causes the check inside HAL_UART_IRQHandler() to fail, but it also prevents the receive interrupt from happening in the first place! Refer to the Reference Manual RM0090 Rev 16, for example:
p969:
p1009:
p1011:
p1015:
p1013:
So, to disable/enable the USART Receive Not Empty interrupt only, do the following. Refer to the Control Register (USART_CR1) on p1013, shown just above.
// Disable the USART Receive Not Empty interrupt
CLEAR_BIT(huart7.Instance.CR1, USART_CR1_RXNEIE);
// Enable the USART Receive Not Empty interrupt
SET_BIT(huart7.Instance.CR1, USART_CR1_RXNEIE);
Now, you could do the following to disable the USART Receive interrupt, reset the HAL RxState, and then start up the interrupt-based receive again when ready:
CLEAR_BIT(huart7.Instance.CR1, USART_CR1_RXNEIE);
huart7->RxState= HAL_UART_STATE_READY;
SET_BIT(huart7.Instance.CR1, USART_CR1_RXNEIE); // This call isn't actually necessary, as this bit is set inside `HAL_UART_Receive_IT()` as well
HAL_UART_Receive_IT(&huart7, (uint8_t *)rx_buffer, expectedNumberOfBytes);
3. How to (awkwardly) use HAL_UART_Receive_IT() for continual interrupt-based receiving.
TODO
4. Why HAL_UART_Receive_IT() really isn't a very useful function after-all.
TODO
5. How to manually configure your own interrupt-based UART Tx and Rx ISRs and functions.
TODO
You can use HAL_UART_Abort_IT.
Most UARTs clear any pending Receive interrupt when the program reads from the holding register. So my answer would be: simply read the data register after disabling interrupts, and ignore the result.
I haven't had a chance to try this on my STM32 yet, but...
There is a function static void UART_EndRxTransfer(UART_HandleTypeDef *huart)
in the HAL library that does the following:
Disable RXNE, PE and ERR interrupts
restore huart->RxState to Ready
I found that function in the stm32f7xx_hal_uart.c file. However, it is defined as static, so I just copied over the definition into the file where I used it. It might be a bit hacky but it worked for me.

The right way to clear an interrupt flag on STM32

I'm developping a bare-metal project on a STM32L4 and I'm starting from an existing code base.
The ISRs have been implemented the following way:
read interrupt status in the peripheral to know what event(s) provoked the interrupt
do something
clear the flags that have read at the beginning.
Is it the right way to clear the flag ? Shouldn't the flags be cleared at the very beginning of the ISR ? My understanding is that, if the same peripheral event is happening a second time during step 2, it will not provoke a second IRQ so it would be lost. On the other hand if you clear the flag as soon as you can, this second event would pulse the interrupt whose state in the CPU would change to "pending and active": a second IRQ would happen.
PS: From STM32 Processor Programming Manual I read: "STM32 interrupts are both level-sensitive and pulse-sensitive".
Definitely at the beginning (unless you have special reasons in the program logic) as some time is needed the for actual write to the flag clear register to propagate through the buses.
If you decide for some reason to put it at the end of the interrupt you should leave some instructions, place the barrier instruction or read back the register before the interrupt routine return to make sure that the clear operation has propagated across the buses. Otherwise you may have a "phantom" duplicate routine calls.

ARM Cortex M NonMaskable Interrupt is NonClearable also?

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...

Cortex: NVIC, please demostrate how to make it level or edge detects by software

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.

Resources