-
Notifications
You must be signed in to change notification settings - Fork 5
Timing
wip (luni)
IntervalTimer uses interrupts to call a function at a precise timing interval.
4 independent 32bit timer modules. Each module has its own IRQ
Number of FTM/TPM modules and number of channels per module depends on the Model -> add table
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.
One timer module with four independent 32bit channels. All channels share one ISR
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.
Teensy is a PJRC trademark. Notes here are for reference and will typically refer to the ARM variants unless noted.