Multiple PWM outputs with different frequencies - timer issues

Status
Not open for further replies.

Snowtoad

Member
Hello,
I'm working on a project which involves flashing 3 LEDs at different, precisely defined frequencies, and with different duty cycles.
It is my understanding that Teensy 3.1 has 3 timers (0, 1 and 2) which means I can indeed achieve PWM signals with 3 different frequencies, using analogWriteFrequency(pin, frequency) - this allows setting precise frequency, not just integer multiple of base frequency, correct?

However I also need to control 2 motors (most likely using PWM) and probably will also need to use timer-sensitive functions such as millis()

It probably doesn't matter too much if the motor driving PWM frequency changes as long as it's still reasonably high, but not ideal.

is there some way I can have all these things working together without causing issues? Possibly use some manual approach to Motor speed control or LED flash frequency, to leave a timer intact for millis() etc?
Is there another timer I'm missing which could help?

The LED PWM frequency would be in range 10Hz - 1kHz

Thanks for any advice!
 
Last edited:
It is my understanding that Teensy 3.1 has 3 timers (0, 1 and 2) which means I can indeed achieve PWM signals with 3 different frequencies, using analogWriteFrequency(pin, frequency) - this allows setting precise frequency, not just integer multiple of base frequency, correct?

Correct.

But the 3 timers for PWM pins are called FTM0, FTM1 and FTM2. On Teensy 3.1, the timers have names, not just numbers.

However I also need to control 2 motors (most likely using PWM) and probably will also need to use timer-sensitive functions such as millis()

Good news, Teensy 3.1 has a total of 12 hardware timers. The millis() timing is from the SysTick timer, which is separate from FTM0, FTM1 and FTM2.

Almost nothing touches SysTick, so unlike normal Arduino where you lose millis() accuracy when you start using up more timers, on Teensy 3.1 you pretty much always get relaible millis(). While you can try to use SysTick, it really should be your last resort. The other 11 timers give you so much awesome capability.

is there some way I can have all these things working together without causing issues? Possibly use some manual approach to Motor speed control or LED flash frequency, to leave a timer intact for millis() etc?
Is there another timer I'm missing which could help?

You could use the FrequencyTimer2 library. On 8 bit AVR, it uses timer2 or timer4 (on chips lacking timer2). On Teensy 3.1, it uses the CMT timer, which is completely separate from SysTick, FTM0, FTM1 and FTM2. It's not really PWM,and it has a lower base frequency (as I recall, about 8 MHz), but maybe that would be useful?

There are 4 interval timers (called PIT0, PIT1, PIT2, PIT3) which are accessed from the IntervalTimer object. You can use these to run an interrupt which toggles a pin. It won't be as perfect as hardware PWM. You can raise the interrupt priority and go to other lengths to reduce the jitter from software delays.

If you use the tone() function, it uses one of the interval timers. Many of the timer-based Arduino libraries (but not manipulating a pin with the timer) that have been ported to Teensy use one of the interval timers. This allows MANY combinations of libraries that would ordinarily conflict on Arduino to work nicely together on Teensy 3.1. If you're going to use lots of libraries, it's best not to use up all 4 interval timers.

There are 3 more hardware timers, called LPTMR, PDB and RTC. The RTC only works if you add a 32.768 kHz crystal, and it's mostly useful for keeping track of date & time of day.

The Servo library uses either PDB (default on Teensy 3.1) or LPTMP (default on Teensy LC, which lacks the PDB timer) to create waveforms. If you want to explore using either of those timers, the Servo code would be the place to look for example code to get started.

- this allows setting precise frequency, not just integer multiple of base frequency, correct?
...
The LED PWM frequency would be in range 10Hz - 1kHz

The FTM type timers use an integer division of the bus clock. The integer is 16 bits. There's also a prescaler, 1, 2, 4, 8, etc.

When Teensy runs at 48 or 96 MHz, the bus clock is 48 MHz. So you can get exactly 1 kHz (48 MHz / 48000). The next step lower is 999.979 Hz (48 MHz / 48001), and then 999.958 Hz (48 MHz / 48002), and so on. That's pretty fine grain resolution, but it's not continuous. The hardware can only create frequencies that are integer division of 48 MHz.
 
Thanks for the comprehensive response Paul!

Correct.

Good news, Teensy 3.1 has a total of 12 hardware timers. The millis() timing is from the SysTick timer, which is separate from FTM0, FTM1 and FTM2.

Great to hear!



There are 4 interval timers (called PIT0, PIT1, PIT2, PIT3) which are accessed from the IntervalTimer object. You can use these to run an interrupt which toggles a pin. It won't be as perfect as hardware PWM. You can raise the interrupt priority and go to other lengths to reduce the jitter from software delays.

The Servo library uses either PDB (default on Teensy 3.1) or LPTMP (default on Teensy LC, which lacks the PDB timer) to create waveforms. If you want to explore using either of those timers, the Servo code would be the place to look for example code to get started.

So would it maybe be best to use the FTM timers for LED flashing with precise frequency adjustment with analogWriteFrequency(pin, freq) , and maybe PDB for motor speed control?

The FTM type timers use an integer division of the bus clock. The integer is 16 bits. There's also a prescaler, 1, 2, 4, 8, etc.

When Teensy runs at 48 or 96 MHz, the bus clock is 48 MHz. So you can get exactly 1 kHz (48 MHz / 48000). The next step lower is 999.979 Hz (48 MHz / 48001), and then 999.958 Hz (48 MHz / 48002), and so on. That's pretty fine grain resolution, but it's not continuous. The hardware can only create frequencies that are integer division of 48 MHz.
[/QUOTE]
Yeah that's fine, it doesn't need to be continuous, that resolution is sufficient.
Does the analogWriteFrequency(pin, freq) function mentioned here: https://www.pjrc.com/teensy/td_pulse.html automatically calculate and use the required divisor to obtain the desired frequency?
 
So would it maybe be best to use the FTM timers for LED flashing with precise frequency adjustment with analogWriteFrequency(pin, freq) , and maybe PDB for motor speed control?

I'd say the most accurate answer, from only the info given, would be "it depends".

Probably the easiest path would involve using analogWriteFrequency and FrequencyTimer2, so I'd try the easy way first... before exploring harder ways that require digging into how the hardware timers actually work.


Does the analogWriteFrequency(pin, freq) function mentioned here: https://www.pjrc.com/teensy/td_pulse.html automatically calculate and use the required divisor to obtain the desired frequency?

Yes, analogWriteFrequency() will automatically start using the prescaler as you go to lower frequencies that can't be created without it.
 
I'd say the most accurate answer, from only the info given, would be "it depends".

Probably the easiest path would involve using analogWriteFrequency and FrequencyTimer2, so I'd try the easy way first... before exploring harder ways that require digging into how the hardware timers actually work.

You mean one or the other? They'd be mutually exclusive right?
analogWriteFrequency seems like it would do the job well.
Yes, analogWriteFrequency() will automatically start using the prescaler as you go to lower frequencies that can't be created without it.

For motor control, looking at the servo page, it doesn't show details for Teensy 3.1 in the table.

https://www.pjrc.com/teensy/td_libs_Servo.html

Would Servo or PWMServo be more appropriate to control speed of standard DC motor? Do you know which pins etc they use for Teensy 3.1?

Thanks
 
Also one more quick question..
I want to measure frequency of two input signals (using IR sensor to measure rotational frequency of something)

This library looks like it would work fine:
https://www.pjrc.com/teensy/td_libs_FreqMeasure.html
But seems to only have one frequency input.
What would I need to do to independently measure two frequency inputs?
Which timer does FreqMeasure() use? would it be affected by the changing PWM timer frequencies?


Thanks!
 
Last edited:
The FreqMeasure uses Pin3 which is one of the two FTM1 channels. Thus using that library would affect PWM on pins 3 and 4. Nothing else.
Unfortunately, nobody has yet taken the time to extend the FreqMeasure library for using multiple pins and/or timers, which is a pity since the demands here are recurring.
 
The FreqMeasure uses Pin3 which is one of the two FTM1 channels. Thus using that library would affect PWM on pins 3 and 4. Nothing else.
Unfortunately, nobody has yet taken the time to extend the FreqMeasure library for using multiple pins and/or timers, which is a pity since the demands here are recurring.
Great, looks like I might have to just do it manually using interrupts and counters/timers.. That would work out ok for reasonable accuracy?
 
The FreqMeasure uses Pin3 which is one of the two FTM1 channels. Thus using that library would affect PWM on pins 3 and 4. Nothing else.
Unfortunately, nobody has yet taken the time to extend the FreqMeasure library for using multiple pins and/or timers, which is a pity since the demands here are recurring.

Its open source... you could do it !
 
I'm hesitating... Actually I'm working on other parts of my project, always hoping that someone would advance on the FreqMeasure thing in the meantime. But if I'll see no advancement in the next lets say 4 weeks, I'll most probably attack it.

My "problem" is that Paul insists strongly on respecting Arduino conventions (almost nothing in the class constructors, everything done in the begin() function, using asynchronous read() and available() functions) while I personally prefer working mostly event based, using callback functions or passing sometimes pointers to global variables (similar to a signal bus structure in a circuit) which would be updated i.e. after a capture event, so that other classes see the new value as soon as they are triggered without explicit reading. So, my loop() is always empty, everything is triggered by events, interrupts and callbacks.

I would have to "violate" myself when creating a library in the Arduino style...
 
Last edited:
Great, looks like I might have to just do it manually using interrupts and counters/timers.. That would work out ok for reasonable accuracy?

That depends on your definition of "reasonable", and also to some degree the number of other libraries using interrupts. You can improve the performance and resilience to other libraries somewhat by using higher priority for the pin interrupt. But it's never going to be as good as FreqMeasure, which is pretty much perfect (within the single-cycle resolution of the bus clock).
 
I would have to "violate" myself when creating a library in the Arduino style...

You can use any style you like for your own project. Likewise, you can use a complex style for a library you release yourself, hopefully with a distinctive name so people can tell it's different from the existing library.

But if you want your library to be widely used by the huge Arduino community, you really do need to go to the extra effort to craft a simple but effective Arduino-style API. Sometimes that requires a lot of extra work. Believe me, I do know!

The microcontroller world is filled with overly complex sample code. Often the complexity is just a way of pushing responsibility for more challenging parts of the overall design back onto the user. Sometimes that complexity comes in the form of interrupt-based callbacks, which are seductive in their promise of high performance, but ultimately very hard to use correctly due to thread safety issues in shared data structures. Arduino is so popular because of the extra effort to make thing simple to learn and use.
 
That depends on your definition of "reasonable", and also to some degree the number of other libraries using interrupts. You can improve the performance and resilience to other libraries somewhat by using higher priority for the pin interrupt. But it's never going to be as good as FreqMeasure, which is pretty much perfect (within the single-cycle resolution of the bus clock).

I would be interested in using FreqMeasure but as mentioned earlier, I need to change the PWM frequency of the 3 FTM timers, so this would mess with it? I also need to measure 2 channels of frequency signals. Changing the single measurement pin on FreqMeasure would probably be easy, but making it able to handle 2 channels at once, like 2 instances of the same function, would require significantly more work I believe...
 
One more thing Paul, the pin diagram for Teensy doesn't specify that PWM works on pins 25 and 32, but I assume it does?
Thanks
edit: nevermind, the diagram I was looking at didn't specify it, but I've found another that does
 
Paul, can you comment on which timers are used by Arduino functions or other libraries in the 32u4 Teensy?
 
Status
Not open for further replies.
Back
Top