Author Topic: Timer Interrupts with STM32  (Read 27244 times)

0 Members and 1 Guest are viewing this topic.

Offline Udayan SinhaTopic starter

  • Regular Contributor
  • *
  • Posts: 71
Timer Interrupts with STM32
« on: November 15, 2015, 01:10:45 pm »
I am new to ARM MCUs and I have been trying to find my way around the peripherals using STM's HAL library and STM32Cube. I am having trouble in getting interrupts to work. Here, I'm trying to toggle an LED (onboard LD4 LED) on the STM32L100 Discovery Board by using a timer interrupt. The LED should be toggled every time the interrupt routine is run.
But all I get is that the LED just stays on forever (which means the interrupt routine runs just once). I don't think it's a problem with the timer settings since I managed to run the timer fine without interrupts. I am assuming I have not initialized the interrupts properly and I can't figure where I went wrong. Any help would be appreciated. My main.c source code is attached below.

Line-95: main()
Line-148: Clock settings
Line-396: Timer Initialization routine
Line-456: GPIO Initialization routine
Line-485: Timer interrupt routine

There are initialization functions for various other peripherals in the source file but I'm not using any of them right now. Jut timer and GPIO.
 

Offline Kalvin

  • Super Contributor
  • ***
  • Posts: 2145
  • Country: fi
  • Embedded SW/HW.
Re: Timer Interrupts with STM32
« Reply #1 on: November 15, 2015, 02:59:51 pm »
Take a look at this: http://en.radzio.dxp.pl/stm32vldiscovery/lesson4,blinking,with,timer,interrupts.html

Maybe you will spot the two basic errors in your interrupt handler code.
 

Offline Yansi

  • Super Contributor
  • ***
  • Posts: 3893
  • Country: 00
  • STM32, STM8, AVR, 8051
Re: Timer Interrupts with STM32
« Reply #2 on: November 15, 2015, 03:04:39 pm »
Lol a Delay routine inside an interrupt. What a nonsense. Don't do that!! That's a way to hell.

The Delay function uses internally the SysTick interrupt, so you HAVE TO set the two interrupts correct priorities to work. Otherwise you will get stuck inside the Delay function waiting for SysTick interrupt which will never come, because of wrong priorities set.

Also, you shoueld usually clear the interrupt pending flag in the peripheral, otherwise the interrupt will keep going again and again.
 

Offline Udayan SinhaTopic starter

  • Regular Contributor
  • *
  • Posts: 71
Re: Timer Interrupts with STM32
« Reply #3 on: November 15, 2015, 03:13:31 pm »
Lol a Delay routine inside an interrupt. What a nonsense. Don't do that!! That's a way to hell.

The Delay function uses internally the SysTick interrupt, so you HAVE TO set the two interrupts correct priorities to work. Otherwise you will get stuck inside the Delay function waiting for SysTick interrupt which will never come, because of wrong priorities set.

Also, you shoueld usually clear the interrupt pending flag in the peripheral, otherwise the interrupt will keep going again and again.

I know that it's nonsense. I was just testing if I'm doing my code correct. It's not a code for something real. I didn't know that HAL_Delay() use SysTick however  |O
Maybe I'll just add a loop-based delay then. Thanks  :-+
 

Offline Udayan SinhaTopic starter

  • Regular Contributor
  • *
  • Posts: 71
Re: Timer Interrupts with STM32
« Reply #4 on: November 15, 2015, 03:17:38 pm »
Take a look at this: http://en.radzio.dxp.pl/stm32vldiscovery/lesson4,blinking,with,timer,interrupts.html

Maybe you will spot the two basic errors in your interrupt handler code.

So I have to clear the flag manually, that's the first error. What's the other? I'm not using any other timers so I don't need to check if it's for timer-3 or not right?  :-//
 

Offline Yansi

  • Super Contributor
  • ***
  • Posts: 3893
  • Country: 00
  • STM32, STM8, AVR, 8051
Re: Timer Interrupts with STM32
« Reply #5 on: November 15, 2015, 04:07:00 pm »
Udayan Sinha, just my personal suggestion for you: You seem quite smart and it should be better for you, to learn these MCUs from scratch. Why? Because i think it's better to spend effort to actualy learn it, instead of reverse engineering the Cube crap lib package you got with it.

You can play with the MCU registers directly, it's no problem. Setting a timer needs only tweaking a few registers. Nothing complicated. Setting up a clock and PLL for the MCU is also simple using the registers. (Only people who do know nothing about says it is complicated. it's not!).


Also hard to make any suggestions here. Tha HAL rubbish is so bloated, one must sped a real effort to make it do something.

To make timer produce interrupt, simply set CEN bit (start it running) and set the corresponding interrupt bit. Also don't forget to enable the IRQ channel in NVIC!!!
You can use the CMSIS functions for that. Easy.
 

Offline Brutte

  • Frequent Contributor
  • **
  • Posts: 614
Re: Timer Interrupts with STM32
« Reply #6 on: November 15, 2015, 04:31:55 pm »
Quote
Only people who do know nothing about says it is complicated. it's not!
I know something and I says it is complicated.  >:D Keep away from a clock tree for now. Leave a default 2MHz clock, won't change much for blinking a LED.
As for bare bit-banging, I'd prefer STM32L1xx_StdPeripheral library. At least it comes with tested examples.
 

Offline Yansi

  • Super Contributor
  • ***
  • Posts: 3893
  • Country: 00
  • STM32, STM8, AVR, 8051
Re: Timer Interrupts with STM32
« Reply #7 on: November 15, 2015, 04:56:06 pm »
Oh, I haven't noticed this is an L1 device line. Cube/HAL shit is absolutely useless for lowpower stuff. You rather learn how to use bitbanding if you want to make some real low power stuff. (Not bitbanging, but really bitbanding). Some libs use it, most not. Also most programmers are not aware of this nice feature. No Cube/HAL shall be involved in low power applications! Any clock cycle counts into the power consuption.
 

Offline Kalvin

  • Super Contributor
  • ***
  • Posts: 2145
  • Country: fi
  • Embedded SW/HW.
Re: Timer Interrupts with STM32
« Reply #8 on: November 15, 2015, 05:09:41 pm »
Take a look at this: http://en.radzio.dxp.pl/stm32vldiscovery/lesson4,blinking,with,timer,interrupts.html

Maybe you will spot the two basic errors in your interrupt handler code.

So I have to clear the flag manually, that's the first error. What's the other? I'm not using any other timers so I don't need to check if it's for timer-3 or not right?  :-//

The delay ;)
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: Timer Interrupts with STM32
« Reply #9 on: November 15, 2015, 05:24:06 pm »
Quote
But all I get is that the LED just stays on forever (which means the interrupt routine runs just once).

Good news and bad news: the good news is that there are quite a few ST software engineers here. So your chance of getting some help from them is high. Uncalled for inflamatory remarks removed by moderator. User is on his final warning before his account is stuck where the sun does not shine on a permanent basis. You have been given more than your fair chance.
Quote
My main.c source code is attached below.

Your code relies on the HAL libraries, which are bad even by the low ST quality. You will need to make a decision as to if you wish to continue to down that path, risking getting very little help outside of ST (and very little quality help from ST). Or going directly to the registers (as Kalvin's link).

My approach is somewhat in between: modulized code that can use either the standard peripheral libraries or your own register version, should you decide to go down that path.

Two routines are involved, for a STM32F0:
Code: [Select]
/initialize the timer
//timer set to
void tmr3_init(uint16_t ps, uint16_t period) {
TIM_TimeBaseInitTypeDef tmr;

//set clock to TIM3
RCC_APB1PeriphClockCmd(RCC_TIMx, ENABLE);

//timer basestructure 24mhz/(0+1)/(0+1) ~ 2,72mS (655353/24000000)s for full period
tmr.TIM_Prescaler = ps-1 ;
tmr.TIM_CounterMode = TIM_CounterMode_Up; //can be TIM_CounterMode_Up or TIM_CounterMode_Down
tmr.TIM_Period = period-1; //set the period
tmr.TIM_ClockDivision = TIM_CKD_DIV1;
tmr.TIM_RepetitionCounter = /*period-1*/0; //counter runs in repetition
TIM_TimeBaseInit(TIMx, &tmr); //initialize the timer

/* TIM IT enable */
//TIM_ITConfig(TIMx, TIM_IT_Update, ENABLE);

//reset isr ptr
/*_tmr*/_isr_ptr = /*_tmr3_*/empty_handler;

//enable the timer
TIM_Cmd(TIMx, ENABLE);
}

//install user handler
void tmr3_act(void (*isr_ptr)(void)) {
NVIC_InitTypeDef NVIC_InitStructure;

/* TIM IT enable */
TIM_ITConfig(TIMx, TIM_IT_Update, ENABLE);

//enable tim2 irq
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //tim3 irq
//NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //0-15
NVIC_InitStructure.NVIC_IRQChannelPriority = 1; //0-15
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure); //enable timer irq

/*_tmr*/_isr_ptr = isr_ptr;

}

//timer 3 interrupt
void TIM3_IRQHandler(void){

//if interrupt happens the do this
//if(TIM_GetITStatus(TIMx, TIM_IT_Update) != RESET){
if (TIMx->SR & TIM_IT_Update) {
//clear interrupt and start counting again to get precise freq
//TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
/* Clear the IT pending Bit */
TIMx->SR = (uint16_t)~TIM_IT_Update; //for speed reasons. bit is rc_w0
/*_tmr*/_isr_ptr(); //IO_FLP(LED_PORT, LED2);
}
}

in  your application, you call
Code: [Select]
  tmr3_init(TMR_PS_100x, TMR_1ms); //set the tmr3 to trigger every 100ms

you then install a user handle for the isr:
Code: [Select]
  tmr3_act(my_tmr3_isr); //install my tmr3 isr

my_tmr3_isr() is the function that you want to call whenever the isr is triggered.

Porting it to a STM32L requires minimum changes.

You will see that the isr portion of the code utilizes direct register access, much like the page Kalvin linked too - the code that utilizes the standard peripheral library is commented out. The initialization portion of the code utilizes only the standard peripheral library, but it can be easily replaced by a functional equivalent version that goes to the registers directly.

Hope it helps.
« Last Edit: November 15, 2015, 05:55:23 pm by Simon »
================================
https://dannyelectronics.wordpress.com/
 

Offline neslekkim

  • Super Contributor
  • ***
  • Posts: 1305
  • Country: no
Re: Timer Interrupts with STM32
« Reply #10 on: November 15, 2015, 09:48:11 pm »
Quote
Uncalled for inflamatory remarks removed by moderator. User is on his final warning before his account is stuck where the sun does not shine on a permanent basis. You have been given more than your fair chance.

I wish the moderators on these forums also could look at the contributions dannyf gives, I can handle some "inflamatory remarks" from time to time, the amount of insight he have provided have been very valuable many times as how I see it.
 
The following users thanked this post: Manx

Offline richardman

  • Frequent Contributor
  • **
  • Posts: 427
  • Country: us
Re: Timer Interrupts with STM32
« Reply #11 on: November 15, 2015, 09:51:42 pm »
This is how you write a COMPLETE program to blink an LED with JumpStart API https://c4everyone.com/index.php/technologies/jumpstart-api:

Code: [Select]
int main(void)
    {
    Setup();

    porta.MakeOutput(LED_PIN, OSPEED_LOW);

    while (1)
        {
        porta.Set(LED_PIN);
        DelayTenth(5);
        porta.Clear(LED_PIN);
        DelaySecs(1);
        }
    return 0;
    }

static void Setup(void)
    {
    jsapi_clock.SetSystemClock(16, 0, false, 84, 5);
    jsapi_cortex_core.SysTick_Timer(SYSTICK_MILLISECOND);
    }


This call:
Code: [Select]
jsapi_clock.SetSystemClock(16, 0, false, 84, 5);
set the PLL to 84 MHz from the 16MHz HSI (this is an STM32F401).
« Last Edit: November 15, 2015, 09:53:57 pm by richardman »
// richard http://imagecraft.com/
JumpStart C++ for Cortex (compiler/IDE/debugger): the fastest easiest way to get productive on Cortex-M.
Smart.IO: phone App for embedded systems with no app or wireless coding
 

Offline Simon

  • Global Moderator
  • *****
  • Posts: 17816
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: Timer Interrupts with STM32
« Reply #12 on: November 15, 2015, 10:09:45 pm »
Quote
Uncalled for inflamatory remarks removed by moderator. User is on his final warning before his account is stuck where the sun does not shine on a permanent basis. You have been given more than your fair chance.

I wish the moderators on these forums also could look at the contributions dannyf gives, I can handle some "inflamatory remarks" from time to time, the amount of insight he have provided have been very valuable many times as how I see it.

I don't care how much he helps and contributes, it does not help me as a moderator or the feeling on the forum and it sets a bad example, remember "bored at work". He has done enough shit stirring in the past to warrant permanent banning so unless Dave has views to the contrary one more sarky comment and he's out! We have had enough collateral from Dannyf for a lifetime thank you!
 

Offline Udayan SinhaTopic starter

  • Regular Contributor
  • *
  • Posts: 71
Re: Timer Interrupts with STM32
« Reply #13 on: November 16, 2015, 10:11:03 pm »
Take a look at this: http://en.radzio.dxp.pl/stm32vldiscovery/lesson4,blinking,with,timer,interrupts.html

Maybe you will spot the two basic errors in your interrupt handler code.

Thanks Kalvin and everyone else for your suggestions and help. As Kalvin (and a few others) pointed out, I had screwed up the interrupt routine by not clearing the interrupt flag (I had misread somewhere that this happens automatically in the HAL documentation).

So this was my final interrupt routine:

void TIM3_IRQHandler(void)
{
   //if more than 1 timer is used with interrupts enabled, we have to manually check which interrupt flag has been set
   //use __HAL_TIM_GET_FLAG in this case
   HAL_GPIO_TogglePin(GPIOC, LD4_Pin);       //toggle LD4
       delay_ms(250);            //wait 250 ms
   __HAL_TIM_CLEAR_FLAG(&htim3, TIM_FLAG_UPDATE);            //clear interrupt flag
}

I also replaced the HAL_Delay() with a loop-based version of my own (thanks to Yansi for pointing out that HAL_Delay() uses SysTick; I figured I won't use it anymore since it could create more problems in the future). As a safeguard, I did fix the priorities for both Timer-3 & SysTick as well.
Thanks a lot guys  :-+  :popcorn:
 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: Timer Interrupts with STM32
« Reply #14 on: November 17, 2015, 11:48:15 am »
Thanks Kalvin and everyone else for your suggestions and help. As Kalvin (and a few others) pointed out, I had screwed up the interrupt routine by not clearing the interrupt flag (I had misread somewhere that this happens automatically in the HAL documentation).

You probably did not misread, the HAL can clear the interrupt flag for you, but it must have a chance to do it.
Since you are writing your own TIM3 IRQ handler, the HAL IRQ handling for the timer is never invoked.
The routine in HAL (I did not check the specific one for L1xx, but they are all similar) will call a callback function you can define according to the specific interrupt (e.g. period, output compare etc.), but it must be invoked inside the IRQ handler:
Code: [Select]
void TIM3_IRQHandler(void)
{
  HAL_TIM_IRQHandler(htim3)
}
in your case.
Your code seems generated by CubeMX, if you had specified that TIM3 would use interrupt this would have happened automatically (and you'd have learned less!), and you'd be left with filling in:
Code: [Select]
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
// Your code here
}

Is it worth doing it your way or the HAL way?
In this case, writing your own handler seems simpler, in others (when coping with several different kinds of interrupts) one would end up writing something quite similar to what is already in the HAL (check flags, dispatch and clear) so, provided the HAL is already in use...why not?

Another note: why keep the busy loop delay inside the handler, now that everything is working?
With a reasonable prescaler and period, one can get almost any rate from the timer, and any duty cycle using the PWM/OC capabilities.
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline Udayan SinhaTopic starter

  • Regular Contributor
  • *
  • Posts: 71
Re: Timer Interrupts with STM32
« Reply #15 on: November 17, 2015, 07:13:33 pm »
Thanks Kalvin and everyone else for your suggestions and help. As Kalvin (and a few others) pointed out, I had screwed up the interrupt routine by not clearing the interrupt flag (I had misread somewhere that this happens automatically in the HAL documentation).

You probably did not misread, the HAL can clear the interrupt flag for you, but it must have a chance to do it.
Since you are writing your own TIM3 IRQ handler, the HAL IRQ handling for the timer is never invoked.
The routine in HAL (I did not check the specific one for L1xx, but they are all similar) will call a callback function you can define according to the specific interrupt (e.g. period, output compare etc.), but it must be invoked inside the IRQ handler:
Code: [Select]
void TIM3_IRQHandler(void)
{
  HAL_TIM_IRQHandler(htim3)
}
in your case.
Your code seems generated by CubeMX, if you had specified that TIM3 would use interrupt this would have happened automatically (and you'd have learned less!), and you'd be left with filling in:
Code: [Select]
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
// Your code here
}

Is it worth doing it your way or the HAL way?
In this case, writing your own handler seems simpler, in others (when coping with several different kinds of interrupts) one would end up writing something quite similar to what is already in the HAL (check flags, dispatch and clear) so, provided the HAL is already in use...why not?

Another note: why keep the busy loop delay inside the handler, now that everything is working?
With a reasonable prescaler and period, one can get almost any rate from the timer, and any duty cycle using the PWM/OC capabilities.

I tried with HAL_TIM_PeriodElapsedCallback() initially, but it didn't work. Do you mean to say that we can configure in STM32Cube if we want to use interrupts for a peripheral or not? I don't remember seeing any such setting  :-//
As for the loop delay, like I mentioned in a previous post, it was just for testing to see if everything works fine. If I did not use the delay, I would be merely dimming my LED with a PWM signal; my LED was already very bright so I couldn't really tell the difference much. Or i may just have bad eyesight  :-DD

 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf