Does HAL_NVIC_SetPendingIRQ call the ISR to execute? - stm32

I am really new to STM32 world so I came across this while reading:
void HAL_NVIC_SetPendingIRQ(IRQn_Type IRQn);
This will cause the interrupt to fire, as it would be generated by the hardware. A distinctive feature
of Cortex-M processors it that it is possible to programmatically fire an interrupt inside the ISR
routine of another interrupt.
I got this from the book Mastering STM32 (by Carmine Noviello page 208). From this I have understood that If we set this pending bit even from the main function, then the interrupt is generated.
So to try this out, I have written this code:
while (1)
{
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET);
for(int i = 0; i <10000000; i++);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET);
for(int i = 0; i <10000000; i++);
HAL_NVIC_SetPendingIRQ(EXTI0_IRQn);
}
}
along with this call back function
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_PIN){
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_15);
}
I have programmed GPIO_PIN_0 as source of interrupt and when I press the push button connected to PA0 the Interrupt works perfectly i.e. ISR is executed. To my surprice HAL_NVIC_SetPendingIRQ function doesn't generate interrupt. I don't understand why?
More Info:
I am using STM32F411VET6 DISCO board
I am using STM32CubeIDE to program the board

Thank you #Tagli. I have found the function HAL_GPIO_EXTI_IRQHandler inside stm32f4xx_hal_gpio.c file. Defalult definition was like this:
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
/* EXTI line interrupt detected */
if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
HAL_GPIO_EXTI_Callback(GPIO_Pin);
}
}
I got why the GPIO was not being toggled. It was the same reason you have commented above.
I have modified to prove it.
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
/* EXTI line interrupt detected */
HAL_GPIO_EXTI_Callback(GPIO_Pin);
if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
HAL_GPIO_EXTI_Callback(GPIO_Pin);
}
}
Now the callback function is called when the HAL_NVIC_SetPendingIRQ(EXTI0_IRQn); is being called

Related

STM32L4A6 - ISR is processed twice

Issue
I have an input signal that shall trigger an interrupt. The ISR then shall toggle an output pin 24 times.
Having it set up stright forward I am facing the issue that the ISR is executed twice.
System
IDE: STM32CubeIDE v1.10.0
uC: STM32L4A6 (NUCLEO-L4A6ZG)
Pin config:
PC12 (DATA_READY_NEG_EDGE) = External interrupt, falling edge (externally pulled down with 100k and 100n)
PC11 (ADC_SPI_CLK) = Output
Code
The auto code generator pulls out the following code
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
/* EXTI line interrupt detected */
if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != 0x00u)
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
HAL_GPIO_EXTI_Callback(GPIO_Pin);
}
}
The callback function looks like this (but I don't think that this is part of the issue):
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == DATA_READY_NEG_EDGE_Pin) // INT Source is pin PC12
{
HAL_GPIO_TogglePin(LED_RED_GPIO_Port, LED_RED_Pin); // Toggle LED
for (int var = 0; var < 24; ++var)
{
HAL_GPIO_TogglePin(ADC_SPI_CLK_GPIO_Port, ADC_SPI_CLK_Pin);
HAL_GPIO_TogglePin(ADC_SPI_CLK_GPIO_Port, ADC_SPI_CLK_Pin);
}
}
}
This way the interrupt is falsely triggered twice.
Interchange the sequence of "CLEAR" and "Callback" function call in the IRQHandler, the ISR is correctly only called once. But this is a hack and every time I generate the code it is reverted again, so for sure not a solution.
What issue do I have and what could be the workaround?
Thx for any support!

STM32 HAL I2C Slave Interrupts Stop Working

I'm working with an STM32 (STM32F030K6TX) with the HAL Library. The STM32 functions as a slave device, all events are triggered by interrupts by events from the master MCU (Jetson Nano), interrupting the main loop running on the STM32. Upon resetting the device, the I2C works for a period of time, fulfilling several I2C requests before it stops working. When this happens the interrupts stop firing on the STM32 and all I2C reads/writes from the master MCU time out. The main loop is still active.
I noticed the HAL_I2C_GetError(&hi2c1) = HAL_I2C_ERROR_AF after these events. I tried to see if I could disable and re-enable the I2C to fix the interrupts, but it does not work. The code restores the state of the I2C to listening and clears the errors, but the interrupts still do not fire.
Does anyone know what might be the cause of these errors, and/or logic that can restore the I2C to a good state if this occurs?
MX_DMA_Init();
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_ADC_Init();
MX_I2C1_Init();
MX_TIM3_Init();
MX_DMA_Init();
MX_TIM14_Init();
/* USER CODE BEGIN 2 */
if(HAL_I2C_EnableListen_IT(&hi2c1) != HAL_OK)
{
/* Transfer error in reception process */
Error_Handler();
}
transferState = 0;
while (1)
{
// 2) Respond to I2C Requests
if (transferState == 1) {
transferState = 2;
if (transferDirection == I2C_DIRECTION_TRANSMIT) {
// Receive a message from the Jetson, it's telling us to do something!
HAL_StatusTypeDef receiveState = HAL_I2C_Slave_Seq_Receive_DMA(&hi2c1, (uint8_t *)jetsonRequestRX, RXBUFFERSIZE, I2C_FIRST_AND_LAST_FRAME);
if(receiveState != HAL_OK)
{
Error_Handler();
}
} else {
// State is listen. This request fails... why?
if(HAL_I2C_Slave_Seq_Transmit_DMA(&hi2c1, (uint8_t *)jetsonTransmitPos, TXBUFFERSIZE, I2C_FIRST_AND_LAST_FRAME) != HAL_OK)
{
Error_Handler();
}
reset_calibration();
}
}
// This code attempts to detect the error condition and fix the I2C interrupts, but does not work
else if (transferState == 0) {
if (HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF) {
HAL_I2C_DeInit(&hi2c1);
HAL_I2C_Init(&hi2c1);
if(HAL_I2C_EnableListen_IT(&hi2c1) != HAL_OK)
{
/* Transfer error in reception process */
Error_Handler();
}
}
}
// *** ... Main loop ...
}
/* USER CODE BEGIN 4 */
void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *i2cHandle) {
transferState = 0;
}
void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *i2cHandle) {
jetsonRequest[0] = jetsonRequestRX[0];
jetsonRequest[1] = jetsonRequestRX[1];
transferState = 0;
}
void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c)
{
/* restart listening for master requests */
if(HAL_I2C_EnableListen_IT(&hi2c1) != HAL_OK)
{
Error_Handler();
}
}
void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode)
{
UNUSED(AddrMatchCode);
if(transferState == 0) {
transferState = 1;
transferDirection = TransferDirection;
}
}
the slave and listen hal is not very robust nor simple to use
i had use it very rarely and with hard time always
i remenber the hal handle do have some internal state or alike that went wrong in rare or unexpected error or if you rd/Wr less data than initaly expected or you don't do "right" (wjat they expect you) on the callback.
In this case it wan't restart operating correctly until state it's not hacked.
Try hanlding all hal error callback to see if their'ss any error thrown before it get screwd.
I don't have the f/W working in slave mode right now with me to help more :/

Stm32F4 ADC Analog watchdog interrupt doesnt work

Currently I am working on ADC analog watchdog,I want to write a interrupt code for Analog watchdog.I adjusted analog watchdog via reference manual of stm32f4xx and ı started ADC with dma and Analog watchdog timer for interrupt.But when ı run code interrupt doesnt work.What is the problem?
My ADC and DMA Configurations
void adc_ayar()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
ADC_InitStruct.ADC_Resolution=ADC_Resolution_12b;
ADC_InitStruct.ADC_ScanConvMode=ENABLE;
ADC_InitStruct.ADC_ExternalTrigConvEdge=ADC_ExternalTrigConvEdge_None;
ADC_InitStruct.ADC_ExternalTrigConv=0;
ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;
ADC_InitStruct.ADC_ContinuousConvMode=ENABLE;
ADC_InitStruct.ADC_NbrOfConversion=bufferlength;
ADC_Init(ADC1,&ADC_InitStruct);
ADC_CommonInitStruct.ADC_DMAAccessMode=ADC_DMAAccessMode_Disabled;
ADC_CommonInitStruct.ADC_Mode=ADC_Mode_Independent;
ADC_CommonInitStruct.ADC_Prescaler=ADC_Prescaler_Div4;
ADC_CommonInitStruct.ADC_TwoSamplingDelay=ADC_TwoSamplingDelay_20Cycles;
ADC_CommonInit(&ADC_CommonInitStruct);
ADC_Init(ADC1,&ADC_InitStruct);
ADC_ITConfig(ADC1,ADC_IT_AWD,ENABLE);
ADC_Cmd(ADC1,ENABLE);
ADC_DMACmd(ADC1,ENABLE);
ADC_DMARequestAfterLastTransferCmd(ADC1,ENABLE);
ADC1->CR1|=1<<6|1<<23;
ADC_AnalogWatchdogSingleChannelConfig(ADC1,ADC_Channel_0);
ADC_AnalogWatchdogThresholdsConfig(ADC1,2500,300);
ADC_AnalogWatchdogCmd(ADC1,ADC_AnalogWatchdog_SingleRegEnable);
ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_3Cycles);
ADC_ITConfig(ADC1,ADC_IT_AWD,ENABLE);
}
void dma_ayar()
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
DMA_DeInit(DMA2_Stream0);
DMA_InitStruct.DMA_Channel=DMA_Channel_0;
DMA_InitStruct.DMA_Priority=DMA_Priority_VeryHigh;
DMA_InitStruct.DMA_DIR=DMA_DIR_PeripheralToMemory;
DMA_InitStruct.DMA_PeripheralBaseAddr=(uint32_t) & ADC1->DR;
DMA_InitStruct.DMA_Memory0BaseAddr=(uint32_t) & adc_value;
DMA_InitStruct.DMA_BufferSize=2;
DMA_InitStruct.DMA_FIFOMode=DMA_FIFOMode_Enable;
DMA_InitStruct.DMA_FIFOThreshold=DMA_FIFOThreshold_Full;
DMA_InitStruct.DMA_MemoryBurst=DMA_MemoryBurst_Single;
DMA_InitStruct.DMA_PeripheralBurst=DMA_PeripheralBurst_Single;
DMA_InitStruct.DMA_Mode=DMA_Mode_Circular;
DMA_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;
DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;
DMA_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
DMA_Init(DMA2_Stream0,&DMA_InitStruct);
DMA_Cmd(DMA2_Stream0,ENABLE);
}
ADC interrupt code
void ADC_IRQHandler()
{
if(ADC_GetITStatus(ADC1,ADC_IT_AWD))
{
sayac++;
GPIO_ToggleBits(GPIOD,GPIO_Pin_12|GPIO_Pin_13);
ADC_ClearITPendingBit(ADC1,ADC_IT_AWD);
}
}
If I have well understand what you want to do, you should use
void HAL_ADC_LevelOutOfWindowCallback(ADC_HandleTypeDef *hadc)
instead of
void ADC_IRQHandler()

STM32F103 | libopencm3 | GPIO toggle using interrupt issue

So, I am trying to toggle a LED based on an interrupt from a button.
Ideally the when the button is pressed the LED should toggle i.e. switch on if its off and vice versa. But when I execute this code it toggles and returns to its original state.
Expected Result:
LED OFF » Button pressed » LED ON
Practical Result:
LED OFF » Button pressed » LED ON » LED OFF
I have added a delay for debouncing so bouncing is out of the picture. Also the GPIO's ODR is set in the ISR when the button is pressed so how is it getting cleared while exiting the ISR?
I would really appreciate your help! Thank you.
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/exti.h>
#include <libopencm3/cm3/nvic.h>
#define LEDPIN (GPIO13)
static void exti_setup(void)
{
/* Enable GPIOA and AFIO clock. */
rcc_periph_clock_enable(RCC_GPIOB);
rcc_periph_clock_enable(RCC_AFIO);
/* Enable EXTI0 interrupt. */
nvic_enable_irq(NVIC_EXTI15_10_IRQ);
/* Set GPIO12 (in GPIO port B) to input */
gpio_set_mode(GPIOB, GPIO_MODE_INPUT,GPIO_CNF_INPUT_FLOAT, GPIO12);
/* Configure the EXTI subsystem. */
exti_select_source(EXTI12,GPIOB);
exti_set_trigger(EXTI12, EXTI_TRIGGER_BOTH);
exti_enable_request(EXTI12);
}
static void gpio_setup(void)
{
/* Enable clock for GPIO port C */
rcc_periph_clock_enable(RCC_GPIOC);
/* Set LEDPIN (in GPIO port C) as opendrain output */
gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, LEDPIN);
}
void delay(){
int i;
for (i = 0; i < 1000000; i++)
{
__asm__("nop");
}
}
void handler(){
delay();
gpio_toggle(GPIOC, GPIO13);
}
int main(void)
{
gpio_setup();
exti_setup();
while (1) {
__asm__("nop");
}
return 0;
}
void exti15_10_isr()
{
exti_reset_request(EXTI12);
handler();
}
Not open drain but push-pull
Butttons should not use EXTI as it makes debouncing more complicated, often floods the uC with interrupts, Use timer interrupt instead to read the key and debounce.
As #dev_eng rightly pointed out the issue was the interrupt being configured as both RISING/FALLING edge.
Configuring it with single EDGE that is either RISING or FALLING solved my problem.

Using signal() inside handler function

I have taken this example from GNU library. And I wonder why they call signal() function twice, first time in main() when setting up the signal handler and second time inside handler function itself.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
/* This flag controls termination of the main loop. */
volatile sig_atomic_t keep_going = 1;
/* The signal handler just clears the flag and re-enables itself. */
void
catch_alarm (int sig)
{
keep_going = 0;
signal (sig, catch_alarm);
}
void
do_stuff (void)
{
puts ("Doing stuff while waiting for alarm....");
}
int
main (void)
{
/* Establish a handler for SIGALRM signals. */
signal (SIGALRM, catch_alarm);
/* Set an alarm to go off in a little while. */
alarm (2);
/* Check the flag once in a while to see when to quit. */
while (keep_going)
do_stuff ();
return EXIT_SUCCESS;
}
Now my code...
void createTimer(long freq_nanosec)
{
timer_t timerid;
struct sigevent sev;
struct itimerspec timerint;
struct sigaction saction;
/* Establish handler for timer signal */
saction.sa_flags = 0;
saction.sa_handler = OnTimer;
sigemptyset(&saction.sa_mask);
sigaddset (&saction.sa_mask, SIGIO);
if (sigaction(SIGALRM, &saction, NULL) == -1) error("sigaction");
else printf("OnTimer handler created\n");
/* Create real time signal */
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIGALRM;
sev.sigev_value.sival_ptr = &timerid;
if (timer_create(CLOCKID, &sev, &timerid) == -1) error("timer_create");
else printf("timer ID is 0x%lx\n", (long) timerid);
/* Arm the timer */
timerint.it_value.tv_sec = timerint.it_interval.tv_sec =
freq_nanosec / 1000000000;
timerint.it_value.tv_nsec = timerint.it_interval.tv_nsec =
freq_nanosec % 1000000000;
if (timer_settime(timerid, 0, &timerint, NULL) == -1)
error("timer_settime");
else printf("Timer armed\n");
}
From the man page for signal, we see that when a signal arrives:
first either the disposition is reset to SIG_DFL, or the signal is blocked (see Portability below), and then handler is called with argument signum.
So after the signal arrives, further signals will revert to default behavior. In your sample code, the handler is choosing to re-set the signal handler so further signals will be handled in the same manner as the first.
This is noted in the comment for the function catch_alarm in the code you found.
There are two popular versions of signal, which differ in whether the disposition of a signal is reset to the default when the handler is called, and whether a signal is blocked for the duration of its handler's execution.
The standard says those two behaviors are implementation-defined. The first code sample
void
catch_alarm (int sig)
{
keep_going = 0;
signal (sig, catch_alarm);
}
is assuming that the implementation may reset the signal disposition to the default when the handler is called. That's like calling signal(sig, SIG_DFL) in the first line of the handler. You almost never want that, because the next time a SIGALRM signal comes in, the default action is for the program to be killed. So the handler calls signal(sig, catch_alarm) to re-establish itself as the handler.
Your second code sample
saction.sa_flags = 0;
saction.sa_handler = OnTimer;
sigemptyset(&saction.sa_mask);
sigaddset (&saction.sa_mask, SIGIO);
if (sigaction(SIGALRM, &saction, NULL) == -1) error("sigaction");
uses sigaction, which is generally preferred over signal because you can specify exactly the behavior you want. The standard says
new applications should use sigaction() rather than signal().
When .sa_flags has the SA_RESETHAND flag on, the disposition of the signal is reset to the default when the handler starts, just like in (one version of) signal.
But in your case, that flag is off because you set .sa_flags to 0, so you don't need to write any code to re-establish the handler.