Question will be deleted shortly. Made a stupid mistake,these IRQs are supposed to be triggered by buttons. I meant to ask why don't they fire on their own automatically.
Interrupt handlers are not triggered. That's a book code
for the most part. Board based on : stm32f411RE Nucleo.
The code is meant for f429 but form my research it looks like it should be
fine.
Edit:
Adding this line makes it fire, but only once:
EXTI->SWIER = EXTI_SWIER_SWIER0|EXTI_SWIER_SWIER2;
So I need to reset a flag for this somehow.
But why the original hardware interrupts do not trigger.
int main(void)
{
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN;
RCC->APB2ENR = RCC_APB2ENR_SYSCFGEN;
__DSB();
GPIOA->MODER |= GPIO_MODER_MODE5_0;
GPIOB->PUPDR |= GPIO_PUPDR_PUPD2_0;
SYSCFG->EXTICR[0] = SYSCFG_EXTICR1_EXTI0_PB | SYSCFG_EXTICR1_EXTI2_PB ;
EXTI->FTSR = EXTI_FTSR_TR2;
EXTI->RTSR = EXTI_RTSR_TR0;
EXTI->IMR = EXTI_IMR_MR0 | EXTI_IMR_MR2;
NVIC_EnableIRQ(EXTI0_IRQn);
NVIC_EnableIRQ(EXTI2_IRQn);
while (1);
}
/* main */
void EXTI0_IRQHandler(void)
{
if ( EXTI->PR & EXTI_PR_PR0)
{
EXTI->PR = EXTI_PR_PR0;
GPIOA->ODR ^= GPIO_ODR_OD5; }
}
void EXTI2_IRQHandler(void)
{
if ( EXTI->PR & EXTI_PR_PR2)
{
EXTI->PR = EXTI_PR_PR2;
GPIOA->ODR ^= GPIO_ODR_OD5;
}
}
You also have to clear the pending IRQ in the NVIC, something like
NVIC_ClearPendingIRQ(EXTI0_IRQn);
In addition, you need to make sure the interrupt vector table have the correct entries for your handlers. Usually the interrupt vector table is in the startup file, but it depends on your system.
Related
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
I am trying to program my bluePill to blink an LED at the PB11 pin while echoing whats being send over the serial port UART1.
as far as my knowledge, Interrupts allows us to run the programme we want and while running it if any flag triggered an interrupt signal the program the control will be diverted to run the interrupt service routine while the original program is running, am I correct here?
So, I'm trying to keep the Green LED blinking and when I type anything on the serial port the red LED blinks while the green is blinking and the blue led must be always turned on unless data is being sent.
Problem 1:
The green led never blinks!
Problem 2:
Whenever sending letters or numbers through Arduino serial monitor the received echo is always 2 letters out of the entire send letters, also the echo is always on the same line, I mean not not on a newline
so typing Hello and pressing enter yields He and when typing hi there and pressing enter the it just adds the first two letters like so Hehi , why?
my code is
/* ********************** Project Description ***********************
STM32f103xx BluePill Board
PB10 = Green LED
PB11 = Blue LED (To be toggled)
PB0 = Red LED (PWM OUTPUT Controlling the Brightness)
PB9 = Push Button for toggling the state of the blue LED
PA0 = Potentiomater Pin (Analog Input)
USART1 Activated and Sends the Voltage of PA0 to the user1
*/
#include "stm32f1xx.h" // Include the MCU header
#include <stdbool.h> // Boolean Library header
#include <stdint.h>
// Prototypes:
void UART1_Init(void); //Enable UART1 on PA9(Tx) & PA10(Rx).
void portsEnable(void); //Enable Clock for desired MCU Ports.
void delay(uint32_t delay); //Intuduce Delays.
void pinsConfig(void); //Configure the used pins.
// Defines and Macros
int main(void)
{
// Inintialization:
portsEnable();
pinsConfig();
UART1_Init(); // Enable USART1 & interrupts # 8Mhz clock Speed only # 9600Bps
while(1)
{
// ******** Blink The green LED ***********************
GPIOB->BSRR = GPIO_BSRR_BS11;
delay(100000);
GPIOB->BSRR = GPIO_BSRR_BR11;
delay(100000);
} // End of while loop
} // End main() loop
// ************** Function Implimentation *****************************
void UART1_Init(void) // Initiallize USART1
{
// Reset Setting (8bit, one stop bit, no parity)
// Enable clock for UART1 First after already enabling the PortA clock
RCC->APB2ENR |= RCC_APB2ENR_USART1EN; // Enable Clock to the USART1 Module
// Pin Configuration for the USART1 Peripheral where Tx(PA9) = AF Push-Pull and Rx = Input Floating
// Setting Tx (PA9) Pin
GPIOA->CRH |= ((1<<4) | (1<<5)); // Set PA9 to Output 50Mhz Mode
GPIOA->CRH &= ~(1<<6); // Configure it to be an AF push-pull
GPIOA->CRH |= (1<<7); // Same as above^
// Setting Rx (PA10) pin
// Nothing to be set as the reset value makes it an input pin with floating configuration
// Set the Baud-Rate
USART1->BRR = 0x341; //# 8Mhz, USARTDIV = 8Mhz/(16*9600) = 52.083 -> 52=0x34 and 0.083 * 16 = 1.328 = 1 which is 0x1
// Enable Interrupts for the USART1 Module:
// A peripheral can generates a flag at a certain event, this flag can trigger an interrupt signal but first the certain event interrupt must be enabled and the peripheral interrupt as well and the global interrupts.
USART1->CR1 |= USART_CR1_TXEIE | USART_CR1_RXNEIE; // Enable the Transmit Data Register Empty Interrupt register and data received interrupt
// Enable the Tx, Rx, USART1 as a whole block
USART1->CR1 |= (USART_CR1_RE | USART_CR1_TE | USART_CR1_UE);
// Enable the USART1 Global interrupt on NVIC "Nested Vectored Interrupt controller" side. The NVIC is the interrupt processing unit in the MCU.
NVIC_EnableIRQ(USART1_IRQn); // This function's name can't be changed!
}
// This is a global interrupt service routine, any flag from the USART1 will lead to the same ISR, to distinguesh which is which we check the the flags and if one is set then this what caused the interrupt
void USART1_IRQHandler(void) // This function's name must be the same as it's defined in the main libraries
{
// Check if we are here because we Received Data or simply the "RXNE flag is set".
if(USART1->SR & USART_SR_RXNE) // If Rx is Not Empty, or if we received Data, The USART1->SR register is going to change as it is controlled by the hardwart and we compare it to the value of the register USART_SR_RXNE which indicates a 1 at bit5
{
char temp = USART1->DR; // Read the 8bit data received fron the data register into a char called temp
USART1->DR = temp; // Put the same data in the data register to be resent again, here the data registers are clled shadow registers they are not the same registers from the hardware prospective but from programming prospective we use the same registers
while(!(USART1->SR & USART_SR_TC))
{
// Wait while the transmission completes and indicate the waiting process by flashing the RED led indicating data being sent.
GPIOB->BSRR = GPIO_BSRR_BR10; // When not ready to accept more data (e.g. while transmitting data process) turn of the Blue LED
GPIOB->BSRR = GPIO_BSRR_BS1;
delay(10000);
GPIOB->BSRR = GPIO_BSRR_BR1;
}
}
// Check if we are here because the TXEIE is set "OR the Transmit complete" meaning we are ready to accept more data to transmit
if(USART1->SR & USART_SR_TXE)
{
// Handle transmit complete here: (Blink an LED)
GPIOB->BSRR = GPIO_BSRR_BS10; // When Ready to accept more data
}
else
{
GPIOB->BSRR = GPIO_BSRR_BR10; // When not ready to accept more data (e.g. while transmitting data process)
}
}
void portsEnable(void) /* Enable PortA and PortB */
{
// Enable clock for Ports (A & B) on "APB2" Bus.
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // Enable PortA Clock
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; // Enable PortB Clock
}
void pinsConfig(void) //Configure the used pins.
{
//Set pin "PB1" as output push-pull (Red LED)
GPIOB->CRL |= ((1<<4) | (1<<5)); //Set Pin to Output 50Mhz max speed
GPIOB->CRL &= ~((1<<6) | (1<<7)); //Configure Pin as Push-Pull
//Set Pin "PB9" as Input Pulled-Up (Push Button Pin)
GPIOB->CRH &= ~(1<<6); //Set PB9 to input "pullup|pulldown"
GPIOB->CRH |= (1<<7);
GPIOB->ODR |= (1<<9); //Set PB9 input pin as Pull-up pin.
//Set pin "PB10" as output push-pull (Blue LED)
GPIOB->CRH |= ((1<<9) | (1<<8)); //Set Pin to Output 50Mhz max speed
GPIOB->CRH &= ~((1<<11) | (1<<10)); //Configure Pin as Push-Pull
//Set pin "PB11" as output push-pull (Green LED)
GPIOB->CRH |= ((1<<12) | (1<<13)); //Set Pin to Output 50Mhz max speed
GPIOB->CRH &= ~((1<<14) | (1<<15)); //Configure Pin as Push-Pull
//Set pin PA0 as Analog input
GPIOA->CRL &= ~((1<<0) | (1<<1)); // Make sure the Mode registers are 00 for input
GPIOA->CRL &= ~((1<<2) | (1<<3)); // Set the CNF registers to 00 for input analog
} // End PinsConfig()
void delay(uint32_t delay) /* Psudo-delay in Milliseconds */
{
for(uint32_t i = 0; i <= delay; i++)
{
// Looping to delay!
}
}
Maybe below link is helpful for you:
stm32 dead lock
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.
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.
I have the STM32F0DISCOVERY Board with the STM32F051R8T6 microcontroller. I am trying to communicate to the PC using USART.
Sending data from the board to the PC works fine with my putChar() function.
Receiving data sent from the PC to the board with my getChar() function is not working properly. The problem is that the RXNE flag (Read Data Register Not Empty) is not being set. However I have seen using the debugger in Keil uVision4 that the data is indeed in RDR (Receive Data Register).
I have tried running it without debugging, just in case the debugger was reading the RDR register before my program could read the RXNE flag and it's still not working.
This is my code:
#include <STM32F0xx.h>
uint8_t data;
int main (void) {
RCC->AHBENR |= (1UL<<17); // PortA clock enable
GPIOA->MODER &= ~((3UL<<2*2)|(3UL<<2*3));
GPIOA->MODER |= ((2UL<<2*2)|(2UL<<2*3)); // Alt func on PA2, PA3
GPIOA->AFR[0] &= ~((15UL<<4*2)|(15UL<<4*2));
GPIOA->AFR[0] |= (( 1UL<<4*2)|( 1UL<<4*3)); // Alt func 1 on PA2, PA3
RCC->APB1ENR |= (1UL<<17); // USART clock enable
USART2->BRR = 5000; // Baud rate 48 000 000 / BRR -> 9600
USART2->CR1 |= (1UL<<0); // Enable USART
while (1) {
data = getChar();
if (data!=0xFF) {
putChar(data);
}
}
}
Here is the putChar() function that works properly.
void putChar (uint8_t data) {
USART2->CR1 |= (1UL<<3); // Transmitter enable
USART2->TDR = data;
while ((USART2->ISR|(1UL<<7))==(1UL<<7)); // Wait until sent
}
Here is the getChar() function that is not working and keeps returning 0xFF.
uint8_t getChar (void) {
USART2->CR1 |= (1UL<<2); // Receiver enable
if ((USART2->ISR|(1UL<<5))==(1UL<<5)) { // Check RXNE to see if there is data
return USART2->RDR;
} else {
return 0xFF;
}
}
You are not correctly checking the RXNE bit. This line of your code is wrong:
if ((USART2->ISR|(1UL<<5))==(1UL<<5)) {
You need to use an AND instead of an OR. This will allow you to mask correctly and check if the bit is set. Use this instead:
if ((USART2->ISR&(1UL<<5))==(1UL<<5)) {
In this you are checking the default state of the bit.
Check it and put your code in else if the data is there if no data then it goes in if condition.
if ((USART2->ISR&(1UL<<5))==(1UL<<5)) {
} else {
/***** operations *****/
}