Call function by interrupt, just once, x microseconds from now

I'm hoping there might be a way to do this, but an evening of googling and experimenting hasn't led me to the answer yet...

I want to set a "timeout", to cause a function to be called a set number of microseconds from now.

I've found numerous instructions and libraries for calling a function repeatedly every x microseconds, and some for calling a function x milliseconds from now, but x microseconds from now seems quite elusive.

Any clues would be greatly appreciated!

Blink without delay, with "micros()" instead of "millis()" ?

I've found numerous instructions and libraries for calling a function repeatedly every x microseconds, and some for calling a function x milliseconds from now, but x microseconds from now seems quite elusive.

Once the interrupt service routine is called, set the conditions to call it again to never.

Thanks for the responses.

AWOL, I'm needing to do an actual interrupt rather than simply a delay, in order to continue executing other code while waiting for the interrupt to happen.

PaulS, good suggestion. I experimented with the Timer1 and Timer3 libraries, which allow for repeated interrupts at microsecond resolution, and attempted switching them off after the first interrupt.

This behaved fairly well in my simple test sketch, but attempting to do this in my more complicated main project oddly caused Timer1 and Timer3's behaviour to become quite erratic in this context. Experienced interrupt wait-times could vary by well over 100%. This main project did not use any other interrupts - just a lot of loops and dynamic memory management - I wasn't expecting this to affect the timing of interrupts.

I've also experimented with FlexiTimer2, but its delay times could vary by over 100uS even in a simple setting, and unfortunately I need more resolution than that.

Does anyone have any other ideas for triggering microsecond-precise interrupts?

Put a 555 on one of the interrupt pins.

Problem is, I need to vary the amount of time before the interrupt. I really have to do it with code.

I’m not quite following this yet, are you saying that you want some code to set something in motion that will cause an interrupt in NuS?


Rob

Yes, that's right. I just figured it out though, by modifying some code which was intended for a different purpose.

This helpful guy made a library for getting a super-accurate clock reading in half-microseconds. http://electricrcaircraftguy.blogspot.co.nz/2014/02/Timer2Counter-more-precise-Arduino-micros-function.html#.Uz18SfmSxAc

It works using "timer2", and a part of this process is receiving an interrupt every 128uS. Arduino knows to do this every 128uS by keeping a count in a variable called TCNT2. The trick is, by manipulating TCNT2's value, one can control the precise instant at which these interrupts occur - theoretically down to half-microsecond resolution, and from playing around with it, it seems to be that accurate.

By writing a little additional code, I was able to create a function to set up an interrupt to occur, just once, after x microseconds. X can be any number 0 or greater - it can be a lot bigger than 128 too. Here's a snippet, if anyone's interested - this has to be added to the library linked to above (and in the case of the ISR function, replace its equivalent in the library):

volatile boolean fancyInterruptsOn = false;
void (*fancyInterruptFunction)();
volatile unsigned int waitCycles = 0;

// Call this function to set the interrupt
void setT2Interrupt(int microseconds, void (*interruptFunction)()) {
  int newMicroseconds = microseconds % 128;
  waitCycles = (microseconds - newMicroseconds) / 128;
  TCNT2 = 255 - newMicroseconds * 2;
  fancyInterruptsOn = true;
  fancyInterruptFunction = interruptFunction;
}

// This will be triggered every 128uS by the Arduino - except we're going to manipulate it to not quite do so
ISR(TIMER2_OVF_vect)
{
  if (fancyInterruptsOn) {
    if (waitCycles > 0) waitCycles--;
    else {
      fancyInterruptFunction(); // Call the function we wanted called at the set time
      fancyInterruptsOn = false;
    }
  }
}

I must be missing something here, but I fail to see why interrupts, timers, libraries, etc. are needed just to call a function n microseconds from now. Indeed the micros() function only has resolution of 4µs, so maybe that is not good enough. But interrupt latency time is on the order of a few microseconds so I don't see sub-microsecond precision happening anyway.

I have something like this in my code. It turns an LED on for a set amount of time after an particular event happens. Here’s the appropriate snippets:

#define ADC_REF_MVOLTS 1100UL
#define VOLTAGE_DIVIDER 11
#define ADC_TO_MV_CORRECTION (ADC_REF_MVOLTS*VOLTAGE_DIVIDER/1024)

const byte overload_led_pin = A1;

volatile byte overload_flag = 0;
unsigned long overload_on_delay = 250;
unsigned long overload_timestamp = 0;

void setup()
{
  pinMode( overload_led_pin, OUTPUT );
  digitalWrite( overload_led_pin, LOW);
  
  init_freerunning_ADC();
  delay( 10 ); // To let internal reference settle
  start_ADC_conversions();
  // Delay to some conversions happen
  delay( 100 );

}

void loop()
{
  unsigned long t_now_ms = millis();

  if( overload_flag )
  {
    overload_flag = 0;
    overload_timestamp = t_now_ms;
    digitalWrite( overload_led_pin, HIGH );
  }
  if( t_now_ms - overload_timestamp > overload_on_delay )
  {
    digitalWrite( overload_led_pin, LOW );
  }
}

ISR(ADC_vect)
{
  int result = ADC;
  result = result - 512;

  //.... 

  if( abs(result) > 5500/ADC_TO_MV_CORRECTION )
  {
    overload_flag = 1;
  }
}

void init_freerunning_ADC()
{
  ADCSRA =  _BV(ADEN) |  // ADC enable
            _BV(ADATE) | // ADC Auto Trigger Enable
            _BV(ADIE) | // ADC Interrupt Enable
            0x06;        // /64 prescaler, ADC does approx. 
                          // 19,200 conversions per second.
         
  ADCSRB = 0; // Set ADC to Freerunning mode.
  
  ADMUX = (0x3<<6) | // 1.1 V Reference
          0;          // Channel 0
}

void init_Arduino_ADC()
{
  ADCSRA = _BV(ADEN) |
          0x07; // /128 Prescaler
            
}

void start_ADC_conversions()
{
  ADCSRA |= _BV(ADSC);
}

My ISR, the ADC_vect in this case, sets the overload flag when I particular condition happens. My loop function, when it detects the overload flag, turns an LED on for a set period of time, then turns it off.

As it is written my code will continually turn off the LED after the timeout period, so you’ll need to make a modification to only call the function once if you want to use my code.