Unwanted ISR call from timer ??

Post here first, or if you can't find a relevant section!
Post Reply
picclock
Posts: 20
Joined: Sat Aug 14, 2021 8:21 am

Unwanted ISR call from timer ??

Post by picclock »

Simple timer setup is resulting in an ISR call before time period elapsed. Timer is instantiated, pause(d), setOverflow value written, Interrupt attached, and resumed. The ISR is called immediately (1 second delay shows LED illuminated before ISR turns it off).

Not sure how to proceed. Either the timer needs clearing or resetting, or the ISR flag needs clearing prior to attachinterrupt.

Any assistance much appreciated.

Best Regards

picclock

//stm32f4011 target
#define pin PC13
HardwareTimer *GTim = new HardwareTimer(TIM1);

void ISR(void)// Toggle pin.
{
digitalWrite(pin, !digitalRead(pin));
GTim->pause();
}
void setup()
{ // configure Led pin
digitalWrite(pin, LOW); //High=Blue LED off
pinMode(pin, OUTPUT);
delay(1000); //to show lamp is on
GTim->pause();
GTim->setOverflow((5000*1000), MICROSEC_FORMAT); // period 5000mS
GTim->attachInterrupt(ISR);
GTim->resume();
}
void loop()
{
}
ozcar
Posts: 143
Joined: Wed Apr 29, 2020 9:07 pm
Answers: 5

Re: Unwanted ISR call from timer ??

Post by ozcar »

I took your code and tried it on a F401RE Nucleo, initially just changing the LED pin definition.

The ISR does seem to be called "too soon", but not immediately. I added a couple of statements to store micros() value at GTim->resume() and then subtract that from micros() in the ISR, and the ISR was called a bit less than 800 microseconds later. I also note that if I leave the timer running, the LED seems to blink at the correct rate after that.

I think this is related to the fact that updates to some of the timer registers are (or optionally may be) buffered, and only take effect when the update event occurs. This is to prevent getting unpredictable timings that could occur if the updates were not synchronised with what is happening in the timer.

So, GTim->setOverflow() has to calculate new values for ARR and PSC, but those values only take effect when the next update event occurs (which triggers entry to the ISR for the first time).

To check this I did this:

Code: Select all

...
  GTim->setOverflow((5000*1000), MICROSEC_FORMAT); // period 5000mS
  GTim->refresh(); 
  GTim->attachInterrupt(ISR);
...
And now the ISR gets called for the first time very close to 5,000,000 microseconds after the GTim->resume().
picclock
Posts: 20
Joined: Sat Aug 14, 2021 8:21 am

Re: Unwanted ISR call from timer ??

Post by picclock »

@ozcar
Thankyou for that, it now works perfectly :D .
I had spent some time trying to figure it out, but the timers on the STM32F's are a bit complex for me. I've never come across the "refresh()" procedure?? command before, but it works a treat.

Many Thanks

Best Regards

picclock
ozcar
Posts: 143
Joined: Wed Apr 29, 2020 9:07 pm
Answers: 5

Re: Unwanted ISR call from timer ??

Post by ozcar »

I also was not aware of the existence of refresh() until yesterday. When I first realised what was happening, I tried directly setting the UG flag in the timer EGR register. Then I spotted refresh() in the HarwareTimer documentation and so tried using that instead. Today I checked HardwareTimer.c, and yes, it looks like all refresh() does is to set the UG flag.

However, I notice the following in a comment there: "@note Refresh() can only be called after a 1st call to resume() to be sure timer is initialised.", and that is not where I inserted it. You can't just move refresh() down to after the resume(), in fact that will make the ISR get called even sooner! That is because when refresh() sets the UG flag, the resulting update event causes the ISR to be called.

I then also tried doing in the order:

Code: Select all

...
  GTim->setOverflow((5000*1000), MICROSEC_FORMAT); // period 5000mS
  GTim->resume();
  GTim->refresh();
  GTim->attachInterrupt(ISR);
...
That also worked for me, but somehow I don't feel so comfortable about that. I would probably just leave it the way I suggested yesterday, unless you are worried that some future change to HardwareTimer could cause you some trouble for not following the advice in that note in the code.

I can't help thinking that perhaps the HardwareTimer setOverflow() could handle things a bit better by automatically doing the refresh if the timer is not actually running when you call it.

Maybe somebody from ST could comment on this?
ABOSTM
Posts: 60
Joined: Wed Jan 08, 2020 8:40 am
Answers: 7

Re: Unwanted ISR call from timer ??

Post by ABOSTM »

Hi @ozcar,
All your analysis is true, and adding refresh() before resume() is an appropriate solution.
What is wrong, is the comment in the code you mentioned, it is no more fully appropriate since introduction of Pull Request https://github.com/stm32duino/Arduino_C ... 2/pull/806

The appropriate comment should now be something like
"@note Refresh() can only be called after timer has been initialized, either by calling setup() function or thanks to constructor with TIM instance parameter ."
I will update the comment.

Note: an alternative solution would be to call setPreloadEnable(false); in order to disable the preload feature (the buffer)

I can't help thinking that perhaps the HardwareTimer setOverflow() could handle things a bit better by automatically doing the refresh if the timer is not actually running when you call it
Yes, that could be a good improvement, I will consider it, thanks.
ag123
Posts: 1653
Joined: Thu Dec 19, 2019 5:30 am
Answers: 24

Re: Unwanted ISR call from timer ??

Post by ag123 »

just 2 cents, i'm somewhat got used to an idiom with timers

Code: Select all

void setup() {
Timer->pause();
Timer->setOverflow( dur);
Timer->setCaptureCompare(ch, ticks);
Timer->attachInterrupt(fn);
Timer->refresh();
Timer->resume();
}
If a missed period isn't all that important e.g. in a PWM situation or timer call back situation. I'd place my attach interrupt before refresh().
I found that there are situations where I want the interrupt to fire pretty much immediately in the first cycle, such as to initialize something.
And this actually helps. If I need the timer to fire only on schedule, then perhaps attachInterrupt() is more appropriate after refresh.
ozcar
Posts: 143
Joined: Wed Apr 29, 2020 9:07 pm
Answers: 5

Re: Unwanted ISR call from timer ??

Post by ozcar »

Thanks for your response.
ABOSTM wrote: Wed May 18, 2022 8:21 am
Note: an alternative solution would be to call setPreloadEnable(false); in order to disable the preload feature (the buffer)
I tried inserting that just before the call to setOverflow() and I can see that it turns off ARPE in CR1, so that the change to ARR takes effect straight away, but the ISR still gets called way too soon, because the update to PSC is still delayed until the update event. As far as I know there is no equivalent flag to stop updates to PSC from being buffered?
ABOSTM
Posts: 60
Joined: Wed Jan 08, 2020 8:40 am
Answers: 7

Re: Unwanted ISR call from timer ??

Post by ABOSTM »

@ozcar Right, I missed the PSC.

I pushed the Pull Request to take into account register update immediately when Timer is not running.
https://github.com/stm32duino/Arduino_C ... /pull/1721
Post Reply

Return to “General discussion”