Teensy 4.0 Interrupt missing using TeensyTimerTool and Serial.print

andreobi

Member
Hi

I discovered the following situation:
- There is an interrupt missing, when I combine a "1" micro second interrupt and a Serial.print. Take a look at the picture.
- with the delay it is possible to move the position.
- taking out the print command all interrupts show up

I downloaded: https://github.com/luni64/TeensyTimerTool
using PeriodicTimer t1(PIT);

Compliling for: Teensy 4.0, 600MHz, fast
- the frequency and option have no influence

I'm convinced the problem is somewhere in the timer or print lib. Unfourtuntely I have no clue how to fix that.



Andre
 

Attachments

  • SCR07.PNG
    SCR07.PNG
    46.3 KB · Views: 32
  • I2C_Sniffer_Teensy40.ino
    5.4 KB · Views: 31
just to see ...Change:
Code:
volatile uint16_t  writeIdx;
 // ...
void loop() {
  cli();
  int16_t widx = (int16_t)writeIdx;
  sei();
//...

to, this since it is already volatile, and 32 bit copies are atomic:
Code:
volatile uint32_t  writeIdx;
 // ...
void loop() {
  //cli();
  int32_t widx = writeIdx;
  //sei();
//...

Disabling interrupts might be causing trouble?

Also if really provably a problem perhaps a variation of:
Code:
FASTRUN void captureData() {
  digitalWriteFast(MONITOR_OUT1, HIGH);

// just for testing - enough time for scope detect
    delayNanoseconds(500);

  digitalWriteFast(MONITOR_OUT1, LOW);
}
 
I just tried your hints
- taking out the cli and sei has no influence on the situation but is basicly a good hint
- the scope capture is with peek detect and 100 MHz bandwidth and digital 300MHz so I don't believe it is a measureing problem

an additional delay of a 100ns in the interrupt roution like
...
delayNanoseconds(100);
digitalWriteFast(MONITOR_OUT1, LOW);

brings up even more missing interrupts.

I also shorten the longest path through the interrupt, because it must not be done in the interrupt
idleCnt =0;
if (bitDetect){
bitDetect =false;
if (bitMask){
if (bitValue){
byteValue |= bitMask;
}
bitMask >>=1;
}else{
uint8_t state = S_IDLE_DETECT;
if (bitValue){
state |= S_ACK;
}
// if (!(streamState & S_ADDRESS)){
// if (byteValue & 0x01){
// byteRwAdr = S_R_W;
// }
// byteValue >>=1;
// }
// state |= byteRwAdr;
// byteRwAdr |= S_ADDRESS;
uint16_t idx = writeIdx;
stateBuffer[idx] = streamState = state;
// stateBuffer[idx] = state;
// streamState = state | byteRwAdr;
valueBuffer[idx++] = byteValue;
if (idx >= BUFFER_SIZE){
idx =0;
}
writeIdx = idx;

bitMask =0x80;
byteValue = 0;
}
}

unfortunately with no positive effect on the problem.
 
Just a guess without testing: Per default the PIT runs at 24MHz only. This can generate some relatively large bus sync waiting times. So 1MHz interrupt rate together with your relatively large code in the ISR might simply be too high? Can you use one of the TMRs instead? They run at 150Mhz which should reduce the effect. If this doesn't help I can have a closer look later today.
 
Thanks, it is a good advise to use the TMR source. It runs now without glitches.

I assume it has something to do with the IO structure using the timer and serial port.

As a "nice" sideeffect now I have to define 2000 kHz to get a 1 us interrupt.

Sofar I would say thank you for the hints and major problme solved.

Andre
 
Thanks, it is a good advise to use the TMR source. It runs now without glitches.
I assume it has something to do with the IO structure using the timer and serial port.

Probably not. Due to the architecture of the chip the internal busses need some time to sync data. This adds some waiting time at the end of the ISR. The larger the difference of the frequency of the CPU to that of the peripheral, the longer this may take. If the ISR time plus the waiting time gets longer than the time between two interrupts you can run into issues.

By default the PIT runs at 24MHz the TMRs at 150MHz. You can also switch the PIT to 150MHz in the config file if you want to give it a try.


As a "nice" sideeffect now I have to define 2000 kHz to get a 1 us interrupt.
Actually that should not happen. It should give you 2MHz interrupt frequency. Can you post a minimal example showing that effect?
 
Basicly I changed the serial output to Serial1 for easier pin access.
I set the interrupt timing to 1000kHz. CPU 600MHz, and PeriodicTimer t1(TMR3);
on the snapshot you can see that the interrrupt (yellow) schifts when the start bit of the uart happens, but this must be in a specific timeposition of the interrupt, so it won't shift always.

I'll simplify the code on Wednesday.
 

Attachments

  • SCR08.PNG
    SCR08.PNG
    57.8 KB · Views: 31
My assumption is: the serial interrupt is preparing the next byte to send ( this seems to take upto 530ns) and the timer interrupt happend in that time. So the timer interrupt handling is delayed. If the delay is to huge it will show up as a missing interrupt.

The other topic is the time, a typical period is 1.71 us.
 
I just tried your hints
- taking out the cli and sei has no influence on the situation but is basicly a good hint
- the scope capture is with peek detect and 100 MHz bandwidth and digital 300MHz so I don't believe it is a measureing problem

an additional delay of a 100ns in the interrupt roution like
...
delayNanoseconds(100);
digitalWriteFast(MONITOR_OUT1, LOW);

brings up even more missing interrupts.

I also shorten the longest path through the interrupt, because it must not be done in the interrupt
...

unfortunately with no positive effect on the problem.

@luni got you to a solution!

But what the suggestion in post #2 was : replace ALL _isr code with just the indicated lines, not ADD the delay.

At 1 MHz there are less than 600 cycles available - and then adding in the details on bus timing etc ... the guess was the _isr() was being serviced when the next one triggered and was missed.
 
My assumption is: the serial interrupt is preparing the next byte to send ( this seems to take upto 530ns) and the timer interrupt happend in that time. So the timer interrupt handling is delayed. If the delay is to huge it will show up as a missing interrupt.
Makes sense. Did you try increasing the priority of the timer interrupt?

The other topic is the time, a typical period is 1.71 us.

Also makes sense. If you look at the TimerTool config file you see that the TMR runs with the default prescaler of 128. (see here: https://github.com/luni64/TeensyTim...d32c95b98dc083790/src/defaultConfig.h#L42-L58)

With this setting you get:
1/150MHz * 128 = 0.853µs per timer tick. Your 1MHz setting ends up in a timer overflow setting of two ticks -> 2 * 0.853µs = 1,71µs

Set the prescaler to PSC_1 to get a better granularity at high frequencies (1/150MHz = 6.66ns)
 
I think I got a solution for me

- I changed to timer GTP1, it is muche more pecise for higher frequency
- and I also lift up the interrupt priority, so the timer comes ahead the serial communication
 
Back
Top