cancel
Showing results for 
Search instead for 
Did you mean: 

Enabling and disabling CCR interrupts on a running timer.

JSven.9
Associate II

Hello all.

I am trying to set up a continuously running timer to use to set of interrupts at specific counts of the timer. So the user of this thing would say "setAlarm(n)" and at timer=n an interrupt goes off. But I also want interrupts for the ccr to be off when no alarm is set.

The end use case is a bit more complicated, I try to use the 32bit timer to emulate a 64bit timer and use the overflow interrupt to increment an "extra" 32 bit word. So the ISR is a bit complicated.

The ISR currently looks like this:

uint32_t hw = counter_high_word;
  
  if (tim->SR & 0x1 ) { /* This indicates and update event (overflow?) */
    /* TODO: Not 100% certain this is definitely an overflow. Couldn't it
       be other "events"?  */
    uint32_t sr = tim->SR;
    sr &= 0x1 & STM32_TIM_DIER_IRQ_MASK;
    tim->SR = ~sr; /* clear update event flag */
 
 
    counter_high_word++;
 
    if (alarm.active) {
      if (counter_high_word == alarm.alarm_time >> 32) {
     	tim->CCR[0] = (uint32_t)alarm.alarm_time;
    	tim->DIER |= 0x2; /* activate interrupt on ccr channel 1 */
      }
    }
  }
 
  if (tim->SR & 0x2) {
    uint32_t low_word;
    uint32_t high_word;
    Time time;
    
    uint32_t sr = tim->SR;
    sr &= 0x2 & STM32_TIM_DIER_IRQ_MASK;
    tim->SR = ~sr; /* clear ccr event flag */
 
 
    tim->DIER &= ~0x2; /* disable interrupt on ccr channel 1 */
 
    low_word = tim->CNT;
    time = hw;
    time <<= 32;
    time |= low_word;
    
    svm_msg_t msg;
    msg.sender_id = SYS_TIME_SENDER_ID;
    msg.timestamp = time; 
    msg.data = 0xDEADBEEF;
    msg.msg_type = 0;
 
    osalSysLockFromISR(); 
    interop->send_message(interop, msg); /* check for error */
    osalSysUnlockFromISR();  
 
    alarm.active = false;
  }
 

There are some parts of this that uses mailboxes from chibios. But this is inconsequential to the issue, i believe.

The ISR has two different modes. Either there was an overflow and we we increment the "high word", then we check if there is an alarm set in the next 32bit low-word window. if you put that low word into CCR and activate interrupts.

The code that sets an alarm looks like this.

 high_word = counter_high_word;
 if (high_word == alarm.alarm_time >> 32) {
    tim->CCR[0] = absolute; /* low 32 bits */
    tim->DIER |= 0x2; /* enable interrups on CCR[0] */
 } else {
    tim->DIER &= ~0x2;
 }

if the alarm is within the current 32 bit low-word window. write the low word to CCR and activate interrupts for that CCR. if the alarm is not in the window, then interrupts for CCR is disabled.

I cannot seem to get the disabling of the CCR interrupt to work. Do you need to do something to make that piece of configuration stick. I do not want to stop the timer or restart it or anything like that. The timer should be free running that is essential to the application.

So what I want to learn is, if I do tim->DIER &= ~0x2 should interrupts be immediately disabled? or is there need for some kind of memory barrier or some other means of telling the TIM to make this configuration "stick". Or am I totally confused about enabling and disabling interrupts on CCR at all.

Thank you all and have a great day!

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Guru

You can modify DIER while the timer is running. The CCRxIF flags still get set, but they won't trigger the interrupt.

> if (tim->SR & 0x2) {

What is probably happening is that since your interrupt still gets called in the update event, and you check the CCRxIF flags in the interrupt, you are interpreting this as the CCRx event triggering the ISR, which is not the case. You should modify the handler to read CCRxIE as well as CCRxIF.

On the second point: if you want to generate an update event but not trigger interrupts, disable interrupts, generate the event, clear the flag, then re-enable interrupts. Or disable the update interrupt enable flag temporarily.

I didn't look into your program logic much. There are certainly simpler ways to implement a 64-bit counter. One of which would be to use the update event to increment a different timer. Note that reading from a 64-bit counter will not be atomic and must be done correctly.

If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

5 REPLIES 5
LCE
Principal

Can't find it in the ref manual, but in my application I seemingly need to stop the timer to change the DIER.

Simple solution:

keep the interrupt active, add another variable to ignore the interrupt when not needed

JSven.9
Associate II

I am guessing now, but Imagine writing a manual update event on the timer... Maybe that would do it.

tim->EGR = 0x1;

But, I don't want to do that as I guess that would fire off an update event interrupt as well and I use those to increment the high word. so every time switching between interrupts on and off I would get an extra 1 added.. If setting EGR has the desired effect that is 😉 (it may be useful for other applications in that case?)

Thank you very much. That is a way to consider definitely. Thanks!

TDK
Guru

You can modify DIER while the timer is running. The CCRxIF flags still get set, but they won't trigger the interrupt.

> if (tim->SR & 0x2) {

What is probably happening is that since your interrupt still gets called in the update event, and you check the CCRxIF flags in the interrupt, you are interpreting this as the CCRx event triggering the ISR, which is not the case. You should modify the handler to read CCRxIE as well as CCRxIF.

On the second point: if you want to generate an update event but not trigger interrupts, disable interrupts, generate the event, clear the flag, then re-enable interrupts. Or disable the update interrupt enable flag temporarily.

I didn't look into your program logic much. There are certainly simpler ways to implement a 64-bit counter. One of which would be to use the update event to increment a different timer. Note that reading from a 64-bit counter will not be atomic and must be done correctly.

If you feel a post has answered your question, please click "Accept as Solution".

Thanks a lot. This feels spot on to me!

Right. I am vaguely aware that that one can link up timers like that. These timers are complicated though! so small steps for me 😉

Have a great evening