other way to access teensy timers?

Status
Not open for further replies.

so999

Member
Hello,
I have a Teensy 3.2 board and I would like to know if there is a possibility to produce a pwm signal with a period not being a multiple of microseconds. For example I would need a signal with a frequency of 289.3519Hz. This would be produced with a period of 3456 microseconds. But if I change the period with only one microsecond the resulted frequency is 289.2682Hz. The difference between these frequencies is too large (0.0837Hz). In arduino uno I was able to obtain a much smaller difference between these frequencies (about 0.0003Hz), simply incrementing an output compare register of a timer. But I can’t use arduino as it is too slow. So is there a different way to access the hardware timers to get fractional periods of microseconds?
Sorin
 
Using the correct settings of analogWriteFrequency() and analogWriteResolution(), a Teensy 3.2 might reach a granularity of 20.8ns (1/48MHz), a Teensy 3.6 even 16.7ns.

You should study the source code of these functions in the Teensyduino core files and the FTM chapter of the MK20DX256 reference manual. This gives you the needed insight.
 
This?: reading teensy/td_pulse.html

There is :
Code:
    void setup() {
      analogWriteResolution(12);  // analogWrite value 0 to 4095, or 4096 for high
    }

Setting that to 16 bit resolution should cover the desired frequency and allow this to give best resolution:
Code:
Teensy LC & 3.x support the analogWriteFrequency(pin, frequency) function to easily configure the PWM. 
    void setup() {
      analogWriteFrequency(4, 375000); // Teensy 3.0 pin 3 also changes to 375 kHz

    }
…
Teensyduino 1.23 and later accept a floating point number with analogWriteFrequency(), so you can set precise low frequencies for optimized PWM resolution.
 
Thank you very much!

I didn’t find the code source for analogWriteFrequency() and analogWriteResolution(). As I understand these functions are based on the flex timer modules and for Teensy 3.2 there are 3 FTM’s. This means that I can run simultaneously 3 independent PWM signales. Am I correct?

I browsed a bit the MK20DX256 manual but it is not that simple (for me). I found some formulas for frequency and resolution but I don’t how to use them, what modes of operation are used etc. It seems that I have a lot to study. So could you please tell me how can I calculate the period/frequency granularity for a specific resolution and frequency range?

Another problem: I need to count the pwm pulses. I already made some tests attaching an interrupt to the same used pwm pin to detect the rising edge. It seems to work, but I would like to know if this method is reliable at higher frequencies.
 
The source code for analogWrite() is in hardware/teensy/avr/cores/teensy3/pins_teensy.c
https://github.com/PaulStoffregen/cores/blob/master/teensy3/pins_teensy.c
For the T3.2 you will see
Code:
    #define FTM0_CH0_PIN 22
    #define FTM0_CH1_PIN 23
    #define FTM0_CH2_PIN  9
    #define FTM0_CH3_PIN 10
    #define FTM0_CH4_PIN  6
    #define FTM0_CH5_PIN 20
    #define FTM0_CH6_PIN 21
    #define FTM0_CH7_PIN  5
    #define FTM1_CH0_PIN  3
    #define FTM1_CH1_PIN  4
    #define FTM2_CH0_PIN 32
    #define FTM2_CH1_PIN 25
So there are 3 FTM timers (max frequency is F_BUS/2). FTM0 has 8 channels so you could have 8 different duty cycles for the FTM0 frequency which is selected by a prescaler (PS) and the 16-bit MOD value (see FTM chapter in reference manual https://www.pjrc.com/teensy/datasheets.html)

counting pulses with attachInterrupt() is probably effective up to a 1 or 2 mhz pulse rate, much higher than that and CPU is totally consumed handling interrupts. Alternatives are FreqCount or FreqMeasure library https://www.pjrc.com/teensy/td_libs_FreqCount.html

With T3.2@96mhz (F_BUS 48 mhz), then to get a PWM of 289.3519Hz, you need prescale of 4 (F_BUS/4/MOD). MOD of 41472 would yield
12000000/41472 = 289.351851 Hz. (T3.2 crystal is probably accurate to 18 ppm).

FTM0_MOD = ((F_BUS >> prescale) / frequency) - 1;

analogWriteFrequency(23,289.3519);
results in FTM0_SC = 0x8A and FTM0_MOD = 0xA1FF (= 41472-1)
 
Last edited:
Awesome! Thank you so much!

It is the same formula as in fast pwm mode for atmega328. But I saw in the code that mod is a bit different:
mod = (float)(ftmClock >> prescale) / frequency - 0.5f; Why is subtracted 0.5 and not 1?

For my frequency I will get a period granularity of 0.083 usec and if I would overclock the board at 120mhz, I would obtain 0.067 usec. This is excellent and similar with what I get on arduino, because at arduino the clock is slower, but I don’t have to use a prescaler, so the value for mod is about the same.

Thank you again.
 
Awesome! Thank you so much!

It is the same formula as in fast pwm mode for atmega328. But I saw in the code that mod is a bit different:
mod = (float)(ftmClock >> prescale) / frequency - 0.5f; Why is subtracted 0.5 and not 1?

For my frequency I will get a period granularity of 0.083 usec and if I would overclock the board at 120mhz, I would obtain 0.067 usec. This is excellent and similar with what I get on arduino, because at arduino the clock is slower, but I don’t have to use a prescaler, so the value for mod is about the same.

Thank you again.

Subtracting 0.5 is basically subtracting 1 as you would expect and adding 0.5 to minimize rounding errors.
 
FTM0_SC = 0x8A means:

- FTM counter has overflowed.
- Disable TOF interrupts. Use software polling.
- FTM counter operates in Up Counting mode.
- System clock
- Prescaler = 4

??
 
Status
Not open for further replies.
Back
Top