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

Thread: IntervalTimer is not precise

  1. #1
    Junior Member
    Join Date
    Feb 2015
    Posts
    1

    IntervalTimer is not precise

    Hello,

    I am a newbie and I'd like to ask for a piece of advice.

    I am trying to play a binary sequence at a sample rate of 32768 Hz.
    Manual says that IntervalTimer is for precise timing control, so I tried to use it.
    In the example code below the sequence {1 0 1} is repeated once a second.
    This is just to simplify illustration: in real application I need to play long MLS (M-sequence).

    Code:
    int pin = 9; // output pin
    int L = 3;   // length of sequence
    boolean seq[3] = {1 0 1}; // sequence to be played
    int Fs = 32768; // sampling rate
    
    IntervalTimer t;
    
    volatile int ind = 0;
    
    void next_digit(){
      if (ind<L){
        digitalWrite(pin,seq[ind]);
      }
      else if (ind<=Fs){
        digitalWrite(pin,0);
      }
      else{ 
        ind=-1;
      }
      ind++;  
    }
    
    void setup() {
      pinMode(pin, OUTPUT);
      t.begin(next_digit,1./Fs);
    }
    
    
    void loop() {
    }
    In a perfect world I'd expect to see at output pin a signal looking like this:
    Click image for larger version. 

Name:	ideal.jpg 
Views:	136 
Size:	31.4 KB 
ID:	3444
    I checked the real life output by connecting oscilloscpope to the ouput pin and recording waveform a few times.
    What I saw is like this:
    Click image for larger version. 

Name:	real.jpg 
Views:	138 
Size:	39.9 KB 
ID:	3445
    And here is zoom of the zone around the first drop:
    Click image for larger version. 

Name:	real_zoom.jpg 
Views:	133 
Size:	47.2 KB 
ID:	3446
    As one can see, sometimes timing is off up to about 3 us which is 10% of my sampling period and is not acceptable.

    Am I doing something wrong?
    How can I get more precise timing?

    Thank you!

  2. #2
    Senior Member
    Join Date
    Jan 2015
    Location
    SF Bay Area
    Posts
    255
    I think you can raise the interrupt priority. the default is 128. you can try a lower value.

  3. #3
    Senior Member
    Join Date
    Apr 2013
    Posts
    1,853
    Gave it a go then and for what it's worth t.priority(number); with lower numbers does reduce the jitter but doesn't suppress it fully, though may start conflicting with other timing critical functions depending on what the remaining code does.

    In terms of being able to stream data with high precision I'm thinking the next step is to utilise one of the hardware FIFOs to allow data to be lined up and reducing the CPU impact to just coming back often enough to keep the buffer full. The default serial ports will insist on a start bit and character gaps, unsure if this is configurable. An alternative would be to look at the OCTO library which uses DMA clocked from a PWM out to achieve a custom bit chain out which I think would be the 'right' way to achieve this, but suspecting the coding overhead for that would be non trivial.

    You could also do similar thing with hardware by using a high precision oscillator clocking shift register. Use one pin to interrupt the code, with an ISR that outputs the next bit to the shift register. Possibly with a very small delay in there to ensure you don't toggle the output while the shift register is clocking.

    hopefully tweaking the interrupt priority gets you 'close enough' to real time. without needing the more adventurous options above. Was surprised by the amount of jitter since 3us is quite a lot of commands running in something with an empty loop.

  4. #4
    Senior Member
    Join Date
    Jan 2013
    Location
    San Francisco Bay Area
    Posts
    641
    I would check that your sample rate is an exact multiple of the clock. I forget, but I think the clock is not a power of 2.
    This was discussed early on with the IntervalTimer. See if you can go back and find that thread. I would do it by ticks of the clock, and see what that looks like.

  5. #5
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    19,248
    Did you try the priority function? If you don't raise the priority, your interval interrupt can be blocked by others.

    Some code temporarily disables all interrupts. No matter what the priority, if your program is causing such code to run, it'll delay the interval interrupt.

    If you need low-jitter waveforms, the PWM hardware (eg, analogWrite & analogWriteFrequency) is the best way.

    If you need the ADC to sample on a precise schedule, the triggering it with a hardware timer is the best way. Trying to run code to do it will always add some jitter.

  6. #6
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    19,248
    I'm trying to reproduce this problem, but the code you posted does not even compile. This line is a syntax error, missing commas.

    Code:
    boolean seq[3] = {1 0 1}; // sequence to be played
    Even when I fix that, I still get no output.

    This line is obviously wrong:

    Code:
      t.begin(next_digit,1./Fs);
    The interval is specified in microseconds, and Fs is 32768. IntervalTimer can not implement a 30.5 picosecond interval!

    If you'd like me to investigate, please post the actual code you're running on Teensy. It must be a complete program I can copy into Arduino and run on a board here, to reproduce the problem you're seeing.

  7. #7
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    19,248
    I modified the code to this:

    Code:
      t.begin(next_digit, 1000000.0/Fs);
    Then I set my scope to 5 us/div, 30 us delay from rising edge trigger, and infinite persistence. I let it run for a few minutes. I got this:

    Click image for larger version. 

Name:	file.png 
Views:	146 
Size:	25.4 KB 
ID:	3496
    (click for full size)

    Again, I can't reproduce the problem.

    My guess is you tested with a very different program, which was probably generating quite a lot of other interrupt activity, with interrupts having a higher (lower numerical setting) priority than the IntervalTimer object you're using, which defaults to 128 if you don't use the priority() function.

  8. #8
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    19,248
    I did even more experimenting. After observing for longer times, I did see the Systick interrupt cause the waveform to jitter by about 1 microsecond.

    Writing to the SCB_SHPR3 register to lower the Systick priority, and of course IntervalTimer's priority function to make it the highest proirity, solves that.

    But still quite a bit of jitter happens. I managed to solve most of it by using FASTRUN on the interrupt routine, and replacing digitalWrite() with digitalWriteFast(). When executing code from flash memory, the timing can vary, because the flash is slow and the timing depends on whatever is in the small cache memory between the flash and processor. The RAM runs without any delays.

    There's still a jitter of approx 40 ns, which I believe corresponds to 4 processor cycles at 96 MHz. I still can't figure out exactly what's causing that...

    Anyway, here's a copy of the code with the lowest IntervalTimer to digitalWrite jitter.

    Code:
    #define PIN  9   // output pin
    
    int L = 3;   // length of sequence
    boolean seq[3] = {1, 0, 1}; // sequence to be played
    int Fs = 32768; // sampling rate
    
    IntervalTimer t;
    
    volatile int ind = 0;
    
    FASTRUN void next_digit(){
      if (ind<L){
        digitalWriteFast(PIN, seq[ind]);
      }
      else if (ind<=Fs) {
        digitalWriteFast(PIN, 0);
      }
      else {
        ind=-1;
      }
      ind++;  
    }
    
    void setup() {
      SCB_SHPR3 = 0x20200000;  // Systick = priority 32 (defaults to zero)
      pinMode(PIN, OUTPUT);
      t.priority(0);
      t.begin(next_digit, 1000000.0/Fs);
      t.priority(0);
    }
    
    
    void loop() {
    }
    Edit: Here's what I see with this code. Notice the time scale is only 20 ns/div

    Click image for larger version. 

Name:	file-2.png 
Views:	198 
Size:	22.5 KB 
ID:	3497
    Last edited by PaulStoffregen; 02-07-2015 at 05:26 PM.

  9. #9
    Senior Member
    Join Date
    Oct 2014
    Posts
    153
    Well, as it turns out, the teensy 3.2 is duplication the code nicely. It compares to the original handset really well..

Posting Permissions

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