Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 6 of 6

Thread: IntervalTimer/ISR question

  1. #1

    IntervalTimer/ISR question

    I know the ISR must run quickly and have tried to make them small. I have some code running, currently, and do not have consistent run times. My guess is I am trying to do too much in the ISR. Can someone give be some guidance on dos and dont's in the ISR? Paul's example shows this
    Code:
    void blinkLED(void) {
      if (ledState == LOW) {
        ledState = HIGH;
        blinkCount = blinkCount + 1;  // increase when LED turns on
      } else {
        ledState = LOW;
      }
      digitalWrite(ledPin, ledState);
    }
    I notice he uses digitalWrite in the ISR. I thought this may be 'too long'. Also, the 'microseconds' argument for the timer, is it an unsigned long? Not clear form the page, but I am guessing it is.

    I am cascading 2 timers in my ISRs. When one elapses, I start another one. Is this too much to do in the ISR? Also, I am writing pins, stopping timers starting timers and such. Is this too much? What this code does is shove a solenoid to one side then reverses. I trigger the coil form the main code and start a timer to time the pulse (stopPulse). When this elapses, I start another timer (drainTimer). when it elapses, I run the first timer again. What I have noticed is that the times when we watch the solenoid with high speed video are not consistent. Sometimes it is close to what we have set as variables in code, other times it is slow.

    Mine are:
    Code:
    int32_t drainTime = 10;       // ms
    int32_t actuationTime = 50; // ms
    
    void stopPulse(void) {     // when this pulse timer expires, stop pulse
      pulseTimer.end();                  // turn timer off
      digitalWriteFast(motInA, LOW);  // turn off drive pins
      digitalWriteFast(motInB, LOW);
        if (runFlag && solFlag){           // if we are running and the solenoid is open start a timer
        drainTimer.begin(drainer, (unsigned long) drainTime*1000);
        }
    }
    
    void drainer(void) {
      drainTimer.end();
      digitalWriteFast(motInB, HIGH);  
      solFlag = LOW;
      pulseTimer.begin(stopPulse, (unsigned long) actuationTime*1000);    // start timer to run in microseconds 
      startTime = millis();                                                                   // variable for use in the code
    }
    Thanks for the help.

    Keith

  2. #2
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany NRW
    Posts
    5,679
    Are the times constant ? 10 and 50ms ?
    If yes, there's no need for two timers. Just use one: Count to 5 (5 interrupts) for "actuation" and 1 for "drain". Don't start and stop the timers.

    But, on the other hand, 10ms are a lot of time for a teensy.
    I'd think that the problem is somewhere else.. you know that communication like USB or Serial (or "Systick") use Interrupts, too ?

  3. #3
    Junior Member
    Join Date
    Sep 2016
    Posts
    4
    hey, i am having the same problem, i want to use ISR with TIMER.. from the avr world the TIMER0_COMPA_vect
    i am having a problem compiling..i read through the forums and didnt get a suitable answer. hope you can help me here.

    void init(void){
    TIMSKO = 2; //turn on timer 0 comp match ISR
    OCROA = 125; //set compare register to 250 time ticks
    TCCROA = 0b00000010; //turn on clear on match
    TCCROB = 0b00000011; //clock prescaler to 64

    // init is called in void setup..



    ISR (TIMER0_COMPA_vect){
    if (sample_time>0){
    sample_time--;
    else{
    sample_time = TOUCHING_SAMPLE_PERIOD;
    I2C_GET_SAMPLE = true;
    }
    }
    }
    }

    void loop(){
    if (I2C_GET_SAMPLE){
    //do some work
    }
    }
    i know that teensy uses the masks TIMSK0 and OCIE0A, so OCROA would be replaced by OCIE0A.. but the flags differ (TIFR0,OCF0A)..
    do you know any way to get ISR with TIMER to get to work together as the code i presented? (the avr code worked on avr microcontroller).
    thanks in advance

  4. #4
    Senior Member
    Join Date
    Jan 2013
    Posts
    843
    digitalWriteFast is extremely fast, it's normally only 2 instructions. There is no issue with using it in interrupts.

    IntervalTimer is no thread safe. This means if IntervalTimer is used in one place, an interrupt occurs and you try to allocate / deallocate / start / stop a timer in the ISR, unpredictable things can happen.

    You should expect that most library code is not thread safe and calling it from inside an ISR is problematic. Even if things seem to work correctly, you may get occasional strange behavior or Teensy may hang.

    Quote Originally Posted by keithg View Post
    Also, the 'microseconds' argument for the timer, is it an unsigned long? Not clear form the page, but I am guessing it is.
    Microseconds are used. IntervalTimer is using the PIT timers which have 32-bit counters running at FBUS (usually 36MHz, 48MHz or 60MHz depending on the Teensy and selected CPU frequency). At 48MHz, you have a maximum interval of 89s.

    Did you read the warning about "Interrupt Context Issues"? Your 'drainTime' and 'actuationTime' are not volatile and updating them may or may not work correctly. The same thing may apply to your other variables (you haven't included the declarations).

    @tipikosh:
    Post a new thread. Having 2 unrelated discussions here will just be confusing. When you do, include your Teensy version.

  5. #5
    Your 'drainTime' and 'actuationTime' are not volatile and updating them may or may not work correctly.
    Actually, those are only changed when the program is not running. They are not dynamic variables. Do I still need to declare them as volatile even though they do not change?

    I am using a teensy3.2. I am a noob on interrupts and timers. I have an interrupt which is triggered by an external sensor which starts this sequence of timers. I have seen the teensy lock up and the complications of having these timers plus an interrupt may be causing what I was seeing. If I cannot start a timer from another timer, how should one have timers scheduled after one another? Is the 'best way' to just flip a boolean in the ISR and allow the timers to be started and stopped from the main code?

    Basic program: My external sensor interrupts and increments a volatile variable, I copy this volatile into a global variable in the main code then start the timer sequence: Pulse (write pin hi),Stop Pulse (write pin low), Wait, Pulse(write pin high), Stop Pulse (write pin low). This sequence repeats when the next interrupt increments the volatile variable. I am also writing to an SD card and also an I2C connected display. It was this variability in operation time that I was trying to solve by using timers. That SPI and I2C also use timers, could this be the cause of my erratic activation times?

    Keith

  6. #6
    I was able to resolve my issues by putting only a boolean variable in the ISRs and all other activities in the main code in an if statement for when the flag is set.

    To speed up the SD card and i2c writes, I tidied the individual peripheral commands (lcd.write... write.file) by first writing all the characters to a string variable then sending that single string at one go to the individual device. Also, I schedule sending the peripheral data after I have completed the sequence and not during the timing of everything.

    Thanks for the help!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •