I have a problem with set-up interruption flag in AVR AT90S2313. Normally interruption is setting-up through hardware counter. I want to setting this flag in programming way when I want (at the specific moment). I'm writing all code in C:
SEI(); //enable globall interupt
TIMSK | = (1<<TOIE1); //enable interrupt from timer 1
TIFR | = (1<<TOV1); //enable interruption (setting bit) - IT DOESN"T WORKS!
So, in the last line it should be programming interruption but nothing is happening and I don't know why. Any idea? Thanks in advance.
TIFR registers are special in that writing a 1 to a bit sets it to 0.
Edit in response to a comment:
You shouldn't be doing anything with the register as far as I can tell from what little information you have supplied. That is, don't try to use the interrupt mechanism to run the handler. At the point in your code where you want to trigger the interrupt, just call the handler yourself. You may also want to be adjusting the enable bits or clearing flags at the same time -- I don't know what you are trying to do.
If you want the handler to run as if it were acting in response to an interrupt, then you will want to disabled interrupts first. The usual way to do this is
void function_to_trigger_handler()
{
uint8_t sreg = SREG;
cli();
my_interrupt_handler();
SREG = sreg;
}
Related
I am writing code with the STM323 ide and using the STM32f303re nucleo board. I configured pin PA7 as an interrupt, however it does not have its own interrupt handler like previous development boards i've worked with.
As you can see, this one interrupt handler handles interrupts from pins 9-5, thus if any of these pins are triggered they will call the same interrupt. I need to be able to perform different functions depending on which pin is triggered. Is there a way to know which specific pin was causing the interrupt?
You can use EXTI_GetITStatus, to check which line causing interrupt.
/* Handle PA7 interrupt */
void EXTI9_5_IRQHandler(void) {
/* Make sure that interrupt flag is set */
if (EXTI_GetITStatus(EXTI_Line7) != RESET) {
/* Do your stuff when PA7 is changed */
/* Clear interrupt flag */
EXTI_ClearITPendingBit(EXTI_Line7);
}
}
Do not forget to clear flag after.
For the cases when multiple pins share an interrupt, when the interrupt fires, you need to check what pin specifically caused an interrupt. Unlike pin 1 interrupt, where the interrupt itself means it was pin 1 and you can process it right away, in this case an interrupt means "it's either pin 5, or 6, or 7, or 8, or 9", so in the ISR you need to check "was it pin 5? or 6?..."
I think it's a good opportunity to look directly into the registers of EXTI peripheral.
If you open the reference manual of your MCU on page 299, section 14.3.6, you can see this EXTI_PR1 register holds pending bits for lines 0..31. Those bits are marked as rc_w1, which from the start of the document means (reference manual, page 46):
read/clear (rc_w1)
Software can read as well as clear this bit by writing 1. Writing ‘0’
has no effect on the bit value.
So the logic is the following: if an interrupt of lines 5..9 occurred, you need to check what bit specifically in that register is set to 1, and then you write 1 there to reset it. This will clear the flag.
void EXTI9_5_IRQHandler(void)
{
if(EXTI_PR1 & (1U<<5U)) //check if it's line 5, returns 0 if PR5 is 0, otherwise returns non-zero, which is true
{
EXTI_PR1 |= (1U<<5U); //write 1 to that bit to clear it so interrupt doesn't fire again once ISR is finished
do_stuff_if_it's_pin5();
}
}
Alternatively, instead of 1U<<5U you should be able to use EXTI_PR1_PR5, so the code would look a little easier to read, like this:
void EXTI9_5_IRQHandler(void)
{
if(EXTI_PR1 & EXTI_PR1_PR5) //check if it's line 5, returns 0 if PR5 is 0, otherwise returns non-zero, which is true
{
EXTI_PR1 |= EXTI_PR1_PR5; //write 1 to that bit to clear it so interrupt doesn't fire again once ISR is finished
do_stuff_if_it's_pin5();
}
}
This is what the functions provided by #Lime7 do behind the scenes, I suspect (can't check, but it makes logical sense).
I don't have that microcontroller to test it, but it should work.
Other answers already covered the interrupt flags. I'm going to add some info regarding CubeMX and HAL, since it looks like you are using them.
When you enable a GPIO interrupt in CubeMX, the code generator adds a line in the appropriate IRQ handler function. When multiple interrupts are enabled, the generated code looks like so (comments removed):
void EXTI9_5_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_5);
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_6);
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_7);
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_8);
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_9);
}
The HAL_GPIO_EXTI_IRQHandler() function checks the interrupt status for the given pin and calls HAL_GPIO_EXTI_Callback() function if the flag is set.
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);
}
}
In the HAL flow, you don't typically write code directly in the IRQ handler, but implement the HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) function. The pin that triggered the interrupt is provided as a parameter for your convenience.
Hi I'm using STM32G070 nucleo board and I was trying to learn how to use UART with interrupts. I made a simple led blinking program in the main and in the interrupt handler there is a simple echo program. The echo works fine but the led blinking never starts.
Below is my code:
//while loop for led blinking
while(1)
{
GPIOA->BSRR |= (GPIO_BSRR_BS5);
//delaySys is a blocking delay function that takes milli seconds as input
delaySys(1000);
GPIOA->BSRR &=~(GPIO_BSRR_BS5);
GPIOA->BSRR |= (GPIO_BSRR_BR5);
delaySys(1000);
}
Next is my interrupt handler
void USART2_IRQHandler()
{
if((USART2->ISR) & (USART_ISR_RXNE_RXFNE))
{
USART2->TDR = USART2->RDR;
while(!((USART2->ISR) & (USART_ISR_TC)))
;
NVIC_ClearPendingIRQ(USART2_IRQn);
}
if(((USART2->ISR) & (USART_ISR_TXE_TXFNF)))
{
//TRANSMISSION COMPLETE
}
}
If you expect a subsequent stream of bytes from the UART, it might sometimes be justified to hang in the ISR and poll, until you got the expected amount. However, the rest of the program will hang up and wait while you do.
You shouldn't need to call NVIC_ClearPendingIRQ from inside the ISR, because the flag causing the interrupt should be cleared automatically, typically by reading it followed by a data register access or such. Check the UART part of the manual for register descriptions.
A better but more complex way to deal with UART rx interrupts without stalling is to use DMA. I think most STM32 should have support for this, but I'm not sure.
Looking at your blinking code however, it's problematic:
// light up 1000ms
GPIOA->BSRR |= (GPIO_BSRR_BS5);
delaySys(1000);
// lights off
GPIOA->BSRR &=~(GPIO_BSRR_BS5);
// light up some other LED? NOTE: BR5 not BS5
GPIOA->BSRR |= (GPIO_BSRR_BR5);
delaySys(1000);
This can do one of two things:
If GPIO_BSRR_BS5 and GPIO_BSRR_BR5 are the same bit masks, then it lits up the LED approximately 1000ms and turns it off for approximately 50-100ns. The LED stays lit around 99.99% of the time.
If GPIO_BSRR_BS5 and GPIO_BSRR_BR5 are different bit masks, then one LED will blink with 1000ms duty cycle and another stay lit 100% of the time.
Okay I did fix the problem somehow. I had enabled the interrupt for tx before but when I have disabled it, everything works fine. Seems like Tx was sending an interrupt request and was competing with main.
I have several interrupts in the system, including TC capture, external interrupts and ADC conversion interrupts. There's one vector in particular that, when executed, will prevent ANY vector from executing even after the reti() instruction.
The TCB2 Capture interrupt vector (Vector 25) is the only vector in the system that stops everything leading to a WDT reset.
Global Interrupt Flag is 1, and the INTFLAGS for the activated interrupts get set correctly when an interrupt occurs. But no vector is executed.
This applies for all interrupts.
I've tried changing the vector a little, making sure the reti() instruction is present and making sure the vector table didn't change.
I also already made sure the code kept executing normally after the reti(). The only thing that seems not to work are vectors.
volatile uint8_t new_input_regs = 0x00;
/*[Other code, including other vectors without this issue]*/
void __vector_25() {
new_input_regs = PORTD_IN; //Get PORTD input values
TCB2_CTRLA &= ~(0x01); //Clear TC enable and flags
TCB2_INTFLAGS = 0xFF;
asm("WDR"); //Reset the WD timer
event_type = EVENT_INPUT_INTERRUPT; //Set the event
reti();
}
After this executes, all interrupts stop working until reset (This also causes a Watchdog Reset eventually due to no interrupts executing).
More info about the register and vector table here: https://imgur.com/a/SpLKrgT
Thanks to the comment, i've noticed the ISRs were too optimized, even skipping retis and merging vectors in one single block of assemble with no returns. The default vector functions (Like __vector_25() used above) do not work as expected, leading to un-terminated ISRs and missing reti() even when manually written. This lead to completely unexpected behaviour.
I've changed the vector definition to ISR(_VECTOR(25)) and removed reti() at the end of functions. Interrupts have resumed working as they should.
Thanks for the help.
I have a problem with my STM32F103C8T6 microcontroller. I am using (as an exercise) external interrupts to toggle on/off a led, by pressing an external switch wich in turn is connected to PC13. I am using StdPeriph Library.
When the chip has programmed, nothing happens. On the contrary, when I am using the debugger (debug in Coocox), the chip is working fine. I can not figure out where is the problem.
Can you help me please?
Here is my code.
#include<stm32f10x.h>
#include<stm32f10x_rcc.h>
#include<stm32f10x_gpio.h>
#include<stm32f10x_exti.h>
#include<misc.h>
typedef enum{
on,
off
}state;
state led=on;
int main(void){
// enable clocks
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
// uncomment to disable/remap JTAG pins
GPIO_PinRemapConfig(GPIO_Remap_SWJ_NoJTRST,ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
// configure PC13 as input
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_2MHz;
GPIO_Init(GPIOC,&GPIO_InitStructure);
// configure PB8 as led output
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_2MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
// connect PC13 to EXTI controller
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource13);
// enable and configure EXTI controller
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line=EXTI_Line13;
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd=ENABLE;
EXTI_Init(&EXTI_InitStructure);
// enable IRQ
NVIC_EnableIRQ(EXTI15_10_IRQn);
NVIC_SetPriorityGrouping(NVIC_PriorityGroup_2);
// Configure NVIC
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=EXTI15_10_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;
NVIC_Init(&NVIC_InitStructure);
// switch on led
GPIO_WriteBit(GPIOB,GPIO_Pin_8,Bit_SET);
while(1);
return 0;
}
void EXTI15_10_IRQHandler(void){
// clear pending bit
if(EXTI_GetITStatus(EXTI_Line13)!=RESET){
EXTI_ClearITPendingBit(EXTI_Line13);
}
if(led==off){
GPIO_WriteBit(GPIOB,GPIO_Pin_8,Bit_SET);
led=on;
}else{
GPIO_WriteBit(GPIOB,GPIO_Pin_8,Bit_RESET);
led=off;
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t * file,uint32_t line){
/* Infinite loop */
while (1);
}
#endif
I had this issue as well. I'm using a STM32F030.
The problem for me was not having the SYSCFG clock enabled, which is bit 0 of RCC APB2ENR register. I'm guessing this setting is enabled in debug, so that the software can debug? Otherwise the clock is disabled!
I finally found this by looking into the STM32F1 reference manual, which is slightly more comprehensive.
It is generally a very bad idea to use external interrupts for the buttons and keys. You should use the timer interrupt instead.
You can see simple implementation of the key in the timer interrupt (click, double click, long click events supported) here : https://www.diymat.co.uk/arm-three-function-click-double-and-long-click-button-library-timer-interrupt-driven/
I don't have knowledge about the mentioned controller, but I worked on STM32L4 series controllers. In STM32L4 push button is connected to the PC13 pin. I observed gpio debouncing when pressing the push button. In your EXTI15_10_IRQHandler() implement debouncing logic. Make sure the interrupt is reaching this function for only once per button press. May be the debugger is slowing down the processor(cpu running in lower frequency compared to free run) and you are getting the interrupts properly.
Do you use different build config for debug? If so, try making the led variable volatile and see if it helps.
If not: add some delay loop, i.e. voliatile unsigned i; for (i=0; i < 50000u; ++i); after clearing the EXTI bit in the ISR. This is generally a bad pratcice to use blocking delays in the interrupt service (if it's ever a good practice...) but might be helpful to see if it is related to debuncing not done properly. If it helps, then debouncing the switch is the most likely problem.
EDIT: consider using bit-banding (if possible) to access the output port, then you could do sth like bind_band_led_port ^= 1;, but that's just a side note.
i am trying to setup an UART interrupt to trigger when a character is entered on the UART screen. The thing is the way i have set it up it seems that the interrupt triggers when transmitting and receiving. I have read the data sheet and it doesnt really say if it can be done and how. Its just says that a interrupt for serial port is avaiable.
This is how i have set up the uart
S0CON = 0x50;
PCON |= 0x80; /* Double Baud rate */
ADCON0 |= 0x80; /* Use baudrate generator */
S0RELL = 0xCC; /* Baudrate = 9614 Baud # 16Mhz */
S0RELH = 0x03;
TI0 = 1; /* Ready to transmit */
ES0 =1;
Does anyone possibly have any idea how this can be accomplished??
I am using Keil compiler and the Infineon C509
Datasheet **link fixed
Thank you
Unfortunately, it doesn't look like you'll be able to do what you want cleanly. Taking a look at the user manual--the data sheet is typically insufficient for this type of problem--check out Figure 7.4. The send and receive interrupt flags set by hardware for channel 0, TI0 and RI0, both trigger the default serial communication interrupt, and it doesn't appear that either can be disabled.
There might be other options, but I'd consider one of the following:
Polling (vs. using any interrupts for the UART)
Use the interrupt as you have it working, but check first thing in your serial comms interrupt that RI0 is set and if it's not, exit immediately. (Just make sure there's not any kind of timing problem with respect to this and clearing the receive flag to make sure you don't have any potential for dropping a byte.)
Link to C509-L user manual (not sure how long it'll persist): Infineon product site