Timing - TeensyUser/doc GitHub Wiki
wip (luni)
Libraries
IntervalTimer
IntervalTimer uses interrupts to call a function at a precise timing interval.
TeensyTimerTool
Low level access to the timers
Teensy 3.x timers
PIT- Periodic Interval Timer
4 independent 32bit timer modules. Each module has its own IRQ
FTM & TPM - Flex Timer Module
Number of FTM/TPM modules and number of channels per module depends on the Model -> add table
Teensy 4.x timers
TMR (QUAD)
4 TMR modules, each module contains 4 independent timers which share one IRQ
Here a simple example showing how to use channel 2 from TMR module 3 to generate a periodic interrupt.
IMXRT_TMR_t& module = IMXRT_TMR3;
IMXRT_TMR_CH_t& channel = module.CH[2];
void ISR(){
channel.CSCTRL &= ~TMR_CSCTRL_TCF1; // we do not need to check if channel flag is set since we disabled all other channels
digitalToggleFast(LED_BUILTIN);
asm volatile("dsb");
}
void TMR_start(u_int16_t reload)
{
for (unsigned i = 0; i < 4; i++) module.CH[i].CTRL = 0x0000; // disable all channels
attachInterruptVector(IRQ_QTIMER3, ISR); // attach ISR to module interrupt (note: ISR must handle all 4 channels)
NVIC_ENABLE_IRQ(IRQ_QTIMER3);
channel.LOAD = 0x0000; // load on compare -> 0
channel.COMP1 = reload; // comapare values
channel.CMPLD1 = reload;
channel.CNTR = 0x0000; // set counter to zero
channel.CSCTRL |= TMR_CSCTRL_TCF1EN; // enable interrupt
channel.CTRL = TMR_CTRL_CM(1) | TMR_CTRL_PCS(0b1111) | TMR_CTRL_LENGTH; // start timer using prescaler: 7->1/128; internal clock source
}
void setup(){
pinMode(LED_BUILTIN, OUTPUT);
TMR_start(0xFFFF); // max reload value
}
void loop(){
}
Please note that the TMR timer modules are also used for PWM generation. Using them will disable PWM on the corresponding pins.
PIT - Periodic interval timer)
One timer module with four independent 32bit channels. All channels share one ISR
GPT - General purpose timer
Two timer modules with one 32bit channel per module.
Here a simple example how to use GPT1 for a 1us (microsecond) timer witch toggles the pin 23 on the Teensy 4.1.
void GPT1_GPT_IRQHANDLER(void)
{
GPT1_SR = GPT_SR_OF1;
digitalToogleFast(23);
// GPIO6_DR_TOGGLE = (1 << 25); // even faster.....
asm volatile("dsb");
}
int main(void)
{
pinMode(23, OUTPUT);
uint32_t us = 1;
CCM_CCGR1 |= CCM_CCGR1_GPT(CCM_CCGR_ON); //enable clock for General Purpose Timer 1
GPT1_CR = 0;
GPT1_PR = 0;
GPT1_SR = 0x3F; // clear all prior status
GPT1_IR = GPT_IR_OF1IE; // enable GPT1 COMPARE 1 Interrupt
GPT1_CR = GPT_CR_EN | GPT_CR_CLKSRC(1); // sets timer clock to 24 MHz (Teensy 4)
GPT1_OCR1 = 24000000 / 1000000 * us - 1 ; // set compare value
attachInterruptVector(IRQ_GPT1, GPT1_GPT_IRQHANDLER);
NVIC_SET_PRIORITY(IRQ_GPT1, 0);
NVIC_ENABLE_IRQ(IRQ_GPT1);
for(;;)
{
}
}
Important in this example is the use of asm volatile("dsb")
at the end of the ISR. Without that, the ISR will finish before the interrupt flag (first commend in the ISR) is cleared and the ISR will be called again, immediatly after leaving it. The result on the oscilloscope is, the pin goes down after ~60ns and not after 1us as expected.