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.
Related
Summary:
An ISR necessarily causes its own trigger pin to toggle randomly multiple times. These toggles (during the ISR) should be ignored, but aren't, and result in another interrupt to be set as pending and get executed afterwards.
I have a serial bit-bang device that I read via an interrupt. Device has a data pin and a "clock" pin. Data pin is HIGH by default. When the device is ready to be read, it pulls this data pin LOW. After this falling edge, each pulse on the "clock" pin shifts one bit out to the data pin.
An interrupt triggers on the falling edge of the data pin, and ISR bangs 24 bits of data out of the same data pin. Therefore, additional random falling edges on the data pin causes another interrupt to be set as pending. Which triggers immediately after the actual ISR has returned, resulting two consecutive interrupts being run per one "real" interrupt.
I have tried multiple ways to disable interrupts and/or clear pending interrupts, none of which seem to have any effect whatsoever. I suspect that this is because manipulating interrupt related registers is not allowed/or ignored in an ISR.
The device is Atmel ATSAMD21. (ARM Cortex M0+). Code is built under Atmel Studio with optimisation level -Og.I am okay with using ASF and/or SAM libraries/definitions, ARM CMSIS or baremetal register manipulation. Whichever happens to work.
Here is what I tried so far:
void interrupt_cb ( void )
{
// Trying to disable interrupts
// Executed at the beginning of the ISR
NVIC_DisableIRQ(EIC_IRQn);
ext_irq_disable( <pin> );
__disable_irq();
// body
// < code that results in same pin >
// < that the interrupt is triggered >
// < to be toggled randomly. >
// Trying to clear pending interrupts
// Executed just before the ISR returns.
NVIC_ClearPendingIRQ( EIC_IRQn );
NVIC->ICPR[0] |= 4; //probably same as the above
EIC->INTENCLR.bit.EXTINT2 = 1;
}
Or a combination of these commands.
I am currently making some additions to some code for a STM32F3 MCU that I did not write. Part of what the product will do is blink LEDs at 1Hz while testing until the MCU determines if the test is pass or fail.
The previous writer of this code implemented two delays; one that is a for loop based off the clock rate, the other off a timer interrupt. The first delay gets called like this
MsDelay(1000); //Provides approx a one second delay via a for loop
The other like this
Wait(x,y); //x indicates the timer channel, y is delay in milliseconds
The "wait(x,y)" function goes through a clock tick check and some incrementing to implement this delay.
The problem I'm having is in the LED blinking I talked about earlier. To test this function, in the ISR for the test, I call
Set_Led(1,1); //Turns LED1 ON
Wait(1,1000); //Wait one second
Set_Led(2,1); //Turns LED2 ON
However, there is not a one second delay between the LEDs turning on. However, if I call,
Set_Led(1,1); //Turns LED1 ON
MsDelay(1000); //Wait one second
Set_Led(2,1); //Turns LED2 ON
There is a one second delay. I am not very familiar with the differences of blocking vs non-blocking delays other than blocking takes all processing power away from other peripherals. Should there not be a pause between the LEDs turning when using the non-blocking delay? Thank You.
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'm struggling to get tickless support working for our xmega256a3 port of FreeRTOS. Looking around, trying to understand under the hood better, I was surprised to see the following line in vTaskStepTick():
configASSERT( xTicksToJump <= xNextTaskUnblockTime );
I don't have configASSERT turned on, but I would think that if I did, that would be raising issues regularly. xTicksToJump is a delta time, but xNextTaskUnblockTime, if I read the code correctly, is an absolute tick time? Did I get that wrong?
My sleep function, patterned after the documentation example looks like this:
static uint16_t TickPeriod;
void sleepXmega(portTickType expectedIdleTime)
{
TickPeriod = RTC.PER; // note the period being used for ticking on the RTC so we can restore it when we wake up
cli(); // no interrupts while we put ourselves to bed
SLEEP_CTRL = SLEEP_SMODE_PSAVE_gc | SLEEP_SEN_bm; // enable sleepability
setRTCforSleep(); // reconfigure the RTC for sleeping
while (RTC.STATUS & RTC_SYNCBUSY_bm);
RTC.COMP = expectedIdleTime - 4; // set the RTC.COMP to be a little shorter than our idle time, seems to be about a 4 tick overhead
while (RTC.STATUS & RTC_SYNCBUSY_bm);
sei(); // need the interrupt to wake us
cpu_sleep(); // lights out
cli(); // disable interrupts while we rub the sleep out of our eyes
while (RTC.STATUS & RTC_SYNCBUSY_bm);
SLEEP.CTRL &= (~SLEEP_SEN_bm); // Disable Sleep
vTaskStepTick(RTC.CNT); // note how long we were really asleep for
setRTCforTick(TickPeriod); // repurpose RTC back to its original use for ISR tick generation
sei(); // back to our normal interruptable self
}
If anyone sees an obvious problem there, I would love to hear it. The behavior it demonstrates is kind of interesting. For testing, I'm running a simple task loop that delays 2000ms, and then simply toggles a pin I can watch on my scope. Adding some printf's to my function there, it will do the first one correctly, but after I exit it, it immediately reenters, but with a near 65535 value. Which it dutifully waits out, and then gets the next one correct again, and then wrong (long) again, alternating back and forth.
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;
}