One shot timer

Status
Not open for further replies.

slomobile

Well-known member
When you answer, please specify which Teensy versions your answer can apply to.

How to immediately schedule an output pin to flip in X uS from now. X can be from 400 - 2800uS(microseconds).
sub 1uS resolution preferred, but 4uS resolution of micros() would be acceptable.

The general case might use delay, or constantly check elapsedMicros(), but I am interested in scheduling an interrupt to occur or use peripherals because I cannot guarantee acceptable loop times.

This project has further constraints.
The scheduling task above must be non blocking and happen quickly within the ISR of a pin change falling interrupt.
Other things that must happen within that same ISR:
Immediately set output pin High,
compute X = constrain(time since previousRising + offset[+/- 400 - 2800uS])
Offset is a frequently changing value based on data received via serial.
I would like to avoid turning off interrupts at any point if at all possible.
Each input pin has a corresponding output pin. Input Capture seems like the right way to go but Im not clear on how to use it, and ...
This same process is happening on a minimum of 4 other pins at the same time.
The better solution maximizes the number of pins I can do this on.
It is highly likely that some input pins will trigger simultaneously but have different offset values, thus different output timing.
This sketch uses PulsePosition library to read input PPM stream at the same time, so the scheduling approach must be compatible.
Edit: I forgot to mention, this one shot timer/interrupt scheduling task comes up about every 10mS on each pin and they are semi regular. Their clocks do creep.
 
Last edited:

Looks promising but both libs use ftm0 and conflict. I've filed an issue against PulsePosition a while ago suggesting ability to select which ftm is used. Any guidance there, or generally how to write libraries which select alt peripheral numbers? PulsePosition rarely requires more than 1 input and 1 output making the other FTMs the better default choice. Since PulsePosition requires mods for Teensy 4 anyway, perhaps that feature could be worked in as well?

Trying the example DelayChain and adding #include <PulsePosition.h> result in

In function `ftm0_isr':
/arduino-1.8.9/hardware/teensy/avr/libraries/PulsePosition/PulsePosition.cpp:267: multiple definition of `ftm0_isr'
/tmp/arduino_build_145602/libraries/TeensyDelay/TeensyDelay.cpp.o:/arduino-1.8.9/libraries/TeensyDelay/src/TeensyDelay.cpp:74: first defined here
/arduino-1.8.9/hardware/tools/arm/bin/../lib/gcc/arm-none-eabi/5.4.1/../../../../arm-none-eabi/bin/ld: Disabling relaxation: it will not work with multiple definitions
collect2: error: ld returned 1 exit status
 
Last edited:
Looked at this again - TeensyDelay looks like it could be handy. Will be nice working with T_4.

As far as the TIMER used - I scanned the github and it indicates this :: If you want to change the timer used by TeensyDelay please edit line 22 in the file config.h according to the description given in the file.
 
I saw that note. Unfortunately I need every available channel for TeensyDelay and only 2 channels for PulsePosition. At least I can try to use TeensyDelay as a model to modify a local copy of PulsePosition.

Edit:Nevermind. I thought FTM0 was the only one with 8 channels, but FTM3 does as well. It compiles now.

Code:
// D: Default, X: available
//
//      TIMER           | Channels|        Timer is available for           |
//                      |         | T-LC | T3.0 |  T3.1 | T3.2 | T3.5 | T3.6|
//----------------------|---------|------|------|-------|------|------|-----|
#define TIMER_FTM0 1  //|   8     |      |  D   |   D   |  D   |  D   |  D  |
#define TIMER_FTM1 2  //|   2     |      |  X   |   X   |  X   |  X   |  X  |
#define TIMER_FTM2 3  //|   2     |      |      |   X   |  X   |  X   |  X  |
#define TIMER_FTM3 4  //|   8     |      |      |       |      |  X   |  X  |
#define TIMER_TPM0 5  //|   6     |      |      |       |      |      |     |
#define TIMER_TPM1 6  //|   2     |      |      |       |      |      |  X  |
#define TIMER_TPM2 7  //|   2     |      |      |       |      |      |  X  |
#define TIMER_DEFAULT -1

// If you need a special timer, please replace "TIMER_DEFAULT" by a timer from the list above
#define USE_TIMER TIMER_FTM3
 
Last edited:
Glad that it works.

sub 1uS resolution preferred, but 4uS resolution of micros() would be acceptable.

Just to make sure: Did you see the possibility to manually set the prescaler in line 23 of the config? Setting this to small values gives you a sub µs resolution. However, a smaller resolution will also reduce the maximum delay time (16 bit timer)
 
I did see that! It turned out that having micros() elapsedMicros() and 1uS resolution from TeensyDelay was so convenient that the code practically wrote itself. If I need to go back and refactor with a shorter time base it will be a pain I'd rather avoid. So fingers crossed when hardware arrives it will work good enough as is. But if I need a bit more resolution, its great to know at least the TeensyDelay portion will be an easy edit away.

Edit: Is there any way to use more than 8 channels with the library? The more channels I can use per teensy, the fewer teensies I need.
 
Last edited:
Is there any way to use more than 8 channels with the library? The more channels I can use per teensy, the fewer teensies I need.

There are always ways to do things :)

Originally, the library was designed to use one of the FTMs only -> only one TeensyDelay object would ever exist -> Having a class doesn't make sense -> I implemented it using a namespace instead of a static class ( Info: https://stackoverflow.com/a/14361552/1842762). Changing the library to a class based design (one object per FTM) is certainly possible but will be some work. But, since I need to adapt the lib to T4.0 anyway I can have a look into this as well.

For a quick workaround I simply made a copy of the library (changed names etc to TeensyDelay2, *zip attached) so that you can use each with its own FTM in parallel (you can of course extend that scheme for all FTMs you want to use). Here the usage (lib attached).

Code:
#include "Arduino.h"
#include "TeensyDelay.h"
#include "TeensyDelay2.h"

void delayCallbackTimer1()
{
  Serial.println("Timer1");
}

void delayCallbackTimer2()
{
  Serial.println("Timer2");
}

void setup()
{
  pinMode(LED_BUILTIN,OUTPUT);

  TeensyDelay::begin();
  TeensyDelay2::begin();

  TeensyDelay::addDelayChannel(delayCallbackTimer1);
  TeensyDelay2::addDelayChannel(delayCallbackTimer2);
}

void loop()
{
  TeensyDelay::trigger(100);
  TeensyDelay2::trigger(110);

  digitalWriteFast(LED_BUILTIN,!digitalReadFast(LED_BUILTIN));
  delay(500);
}
 

Attachments

  • TeensyDelay2.zip
    234.4 KB · Views: 72
There are always ways to do things :)

That was awesome! Exactly what I needed, quickly, and a model for how to solve the same problem with other libraries. Thanks for tackling this, good luck with the Teensy 4 port. Mine will be here sometime this week, looking forward to see what it can do.
 
Status
Not open for further replies.
Back
Top