Timer 1 cycle problems

Status
Not open for further replies.

RobinK

Member
Hello,

I'm trying to get Timer1 running as I want it. I'm using PIT but the frequency of the timer seems to be too slow. Does someone know on what frequency the Bus Clock runs?
I'm trying to get an interrupt every 31.25ns (3 cycles at 96MHz).

Code:
char CLKout = 2;

void setup() {
  pinMode(CLKout, OUTPUT);
  
  SIM_SCGC6 |= SIM_SCGC6_PIT;
  PIT_MCR = 0x00;
  NVIC_ENABLE_IRQ(IRQ_PIT_CH1);
  
  PIT_LDVAL1 = 0x00000002; // setup Timer 1 for 3 cycles
  PIT_TCTRL1 |= 0x00000003; // enable Timer 1 interrupts (TIE = 1) & start Timer 1 (TEN = 0)
}

void pit1_isr(void){
    digitalWrite(CLKout,!digitalRead(CLKout));
    PIT_TFLG1 = 0;
}

void loop() {
}

with this code I only get 716kHz at the output instead of 32MHz.

Thanks a lot for your help!
 
Does someone know on what frequency the Bus Clock runs?

When F_CPU is 96 MHz, F_BUS defaults to 48 MHz.

Look in kinetis.h for details.

I'm trying to get an interrupt every 31.25ns (3 cycles at 96MHz).

That's never going to work. The ARM processor takes at least a dozen cycles just to enter interrupt mode, and likely more if your function isn't in 1-cycle RAM with FASTRUN.
 
The absolute maximum Teensy 3.2 can handle is about 3'400'000 pulses per second (6'800'000 interrupts).

"PIT_TFLG1 = 0;" doesn't clear the interrupt, it remains asserted. You need to do "PIT_TFLG1 = 1;".

digitalWrite is extremely slow. Use digitalWriteFast instead. For the fastest possible pin toggling, you need to use the port toggle register. E.g.:

Code:
const uint8_t out_pin = 12;
#define OUT_PIN_PTOR GPIOC_PTOR
#define OUT_PIN_BMASK CORE_PIN12_BITMASK

void pit1_isr(void){
    PIT_TFLG1 = 1;
    OUT_PIN_PTOR = OUT_PIN_BMASK;
}

Even then, you will have a lot of jitter. Interrupt latency is variable by several clock cycles and various libraries disable interrupts.
 
Last edited:
The absolute maximum Teensy 3.2 can handle is about 6'800'000 interrupts per second.
Where did you get that figure?

i have a sketch that uses systick to count cycles into and out of isr. For T3.1 i get 46 ticks in, 25 ticks out, so that's 71/96 = 0.74 us/ interrupt, or about 1.35 million/sec.
 
Last edited:
Where did you get that figure?

i have a sketch that uses systick to count cycles into and out of isr. For T3.1 i get 46 ticks in, 25 ticks out, so that's 71/96 = 0.74 us/ interrupt, or about 1.35 million/sec.
Your measurement methodology has too much overhead. Can you post your sketch?

Code:
const uint8_t out_pin = 12;
#define OUT_PIN_PTOR GPIOC_PTOR
#define OUT_PIN_BMASK CORE_PIN12_BITMASK

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

    SIM_SCGC6 |= SIM_SCGC6_PIT;
    PIT_MCR = 0x00;
    NVIC_ENABLE_IRQ(IRQ_PIT_CH1);
    PIT_LDVAL1 = 1; // count to 1
    PIT_TCTRL1 |= 0x00000003; // enable Timer 1 interrupts (TIE = 1) & start Timer 1 (TEN = 0)
}

void pit1_isr(void){
    OUT_PIN_PTOR = OUT_PIN_BMASK;
    PIT_TFLG1 = 1;
}

void loop() {}
Teensy 3.2 running at 96MHz. 'FASTRUN' doesn't really make a difference. A second Teensy is used for pulse counting.
 
Your measurement methodology has too much overhead. Can you post your sketch?

Yep, it's that "too much overhead" that I am trying to measure. :)
sketch at https://github.com/manitou48/teensy3/blob/master/isrperf.ino
T3.1 results are for FASTISR where i hack the core PORTC ISR to go directly to my sketch isr
anecdotal results from various MCUs at https://github.com/manitou48/DUEZoo/blob/master/isrperf.txt

I can do better. if i PWM @2mhz into attachInterrupt isr (not FASTISR) i count 1819499 ticks/sec in the isr. If PWM is faster than 2mhz, then sketch hangs (all CPU cycles consumed in ISR)

EDIT: with FASTISR (direct PORTC ISR) and T3.2@120mhz and PWM at 2.5mhz, I get 5 million interrupts/sec, 400 ns in ISR toggling pin 12. 400/8.3333 is 24 cycles. With default ISR, 46 cycles.

Cortex M4 architecture manual says 12 cycles entry latency, and 10 cycles exit latency, assuming lazy stacking for float.
 
Last edited:
There are two big differences. My code will trigger the use of interrupt chaining, reducing interrupt overhead quite a bit.

Your measurements also have overhead for the GPIO toggle instructions, GPIO bus latency, the wait loop and reading the systick counter.
 
In doing some PIT tests, i revisited this post and tni's sketch in post #5. With the scope attached to pin 12, i noticed that pin 12 frequency was same as PIT frequency when PIT_LDVAL1 = 59, BUT pin 12 frequency should be half of PIT. So i think the ISR is firing twice. The FIX is to reset PIT_TFLG1 in the ISR before doing the toggle,.

In that configuration, with T3.2@120mhz and PIT_LDVAL1=1, the pin 12 frequency is 2.5 mhz, implying that max PIT ISR rate is 5 million interrupts/sec. ISR duration is 200 ns or 24 cycles with F_CPU 120mhz.
 
Status
Not open for further replies.
Back
Top