Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 21 of 21

Thread: Interrupts not always served on Teensy 3.1

  1. #1
    Junior Member
    Join Date
    May 2015
    Location
    Germany
    Posts
    13

    Interrupts not always served on Teensy 3.1

    I'm testing the Interrupt reponse times for Teensy 2.0 and Teensy 3.1 in preparation of a new project. Doing this, I wrote a very simple program, which activates an interrupt if an external event happens, and simply toggles an output line once the interrupt arrives. Th eocde is attached. Th eexternal event is genearted by a pulse generator, which fires a 200 ns pulse each ms. With Teensy 2.0 this works fine, besides some jitter, since the timer interrupt is still enabled. With Teens 3.1, this does not work reliable, saying that only about every third interrupt it catched. The behabiour does not depend on the lelngt of the pulse (1 tried it up to 10 Ás) or the frequency of the pulses. Does someona have any clue what is to be changed?

    --------------- Code -----------

    void setup()
    {
    // Initialize the digital pin as an output.

    pinMode(10, OUTPUT);
    pinMode(2, INPUT);
    attachInterrupt(2, flagIsr, RISING);

    }

    volatile int intarrived = 1;

    void loop()
    {
    // Main code loop

    while (intarrived) {
    }
    digitalWrite(10, HIGH);
    delayMicroseconds(5);
    digitalWrite(10, LOW);
    intarrived = 1;
    }

    /// --------------------------
    /// Custom ISR Routine
    /// --------------------------
    void flagIsr()
    {
    intarrived = 0;
    digitalWrite(10, HIGH);
    digitalWrite(10, LOW);
    }

  2. #2
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,380
    Just a question... The HIGH/LOW seems to happen twice, once in the loop and once in the isr routine. Is that intended? Why?

    That looks like the loop makes Pin10 blink all the time with a 5us on-time as long as no interrupt occurs, but when one occurs, there will be one single shorter(?) blink. digitalWrite() is relatively slow. Why not use digitalWriteFast()?

  3. #3
    Junior Member
    Join Date
    May 2015
    Location
    Germany
    Posts
    13
    Hello Tehermingenieur, thanks for the reply.

    a) There are intentionally two pulses, one to see how fast the ISR receives the signal, and the second to see how fast the main loop is notified.
    b) There is the tiny 'while (intarrived) {}' loop (negative logic, sorry) which blocks the main program from running. And when there is not input pulse, there is no output pulse. As said, it works fine with Teensy 2.0 (or Arduino x), but not with Teensy 3.1.
    c) Thanks for the hint to digitalWriteFast(). Where is that documentet?
    Best Regards

  4. #4
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    8,319
    I saw the digitalWriteFast() - like most else - on the forum and I ended up with this handy tool to toggle a pin:
    Code:
    #define qBlink() (digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN) ))
    Also to paste code use the "#" on advanced or hit the 'Quote Bubble' button and change QUOTE to CODE on both ends to preserve indentation.

    I'm wondering if it is somehow running too fast? put a 'delayMicroseconds(1);' or 'yield();' in your empty 'while (intarrived)'.

    Try a compile at 24mHz - it should have no trouble keeping up if a T2 can do it.

    Add this to setup: 'pinMode(LED_BUILTIN, OUTPUT);' then call above qBlink() between the HIGH&LOW writes in the flagIst() and watch for the LED to glow or blink steadily at lower freq.

  5. #5
    Senior Member+ manitou's Avatar
    Join Date
    Jan 2013
    Posts
    1,914
    FYI, earlier thread on interrupt latency
    https://forum.pjrc.com/threads/23266...errupt-latency
    using systick to count cycles in and out of ISR
    Last edited by manitou; 05-30-2015 at 10:42 AM.

  6. #6
    Junior Member
    Join Date
    May 2015
    Location
    Germany
    Posts
    13
    Hello all, the problem disappeared. I cannot say it was solved, so it's a little bit strange. The first reliable operation was trying to reduce clock speed. But then it worked at every clock speed. Thank you all for your suggestions. I learned a few new tricks. The hint about digitalFastWrite was helpful. About digitalFastWrite(): A code sequence like:

    while (1) {
    digitalWriteFast(pin, HIGH);
    digitalWriteFast(pin, LOW);
    }

    does not always produce a square output. if it does, the frequency at 96 MHz clock is like 6.5 MHz. With my test code above, the shortest pulse detected is like 25 ns. The only thing to add for this first feasibility run is temporily switching of the timer interrupt.

  7. #7
    Junior Member
    Join Date
    May 2015
    Location
    Germany
    Posts
    13

    More on timings

    I shoudl add, that I played around with generatung suqare waves as inicated above, Two observations, which the 'Senior' in this form probably know:

    digitalreadFast() (and its counterpart) generate the equivalent Assembler statement, when called with constant parameters. so:

    digitalWriteFast(10, HIGH); is equivalent to CORE_PIN10_PORTSET = CORE_PIN10_BITMASK;

    but much better readable. This short loop gave the fastest square wave at 96 MHZ I could produce:

    while (1) {
    digitalWriteFast(10, HIGH);
    __asm__ volatile("DSB");
    digitalWriteFast(10, LOW);
    }


    Without the __asm__ volatile("DSB"); instruction, the output would not go high the full way up. Cycle time is 73 ns (7 Clocks)
    Regards

  8. #8
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    8,319
    Faster? - is it more squared? If not optimized away there should always be a jump
    Code:
    FASTRUN
    void BlinkForever()
    {
      goto OnEntry;
    OffNow:
      digitalWriteFast(10, LOW);
      // __asm__ volatile("DSB");
      goto OnNow;
    OnEntry:
      goto OffNow;
    OnNow:
      digitalWriteFast(10, HIGH);
      // __asm__ volatile("DSB");
      goto OffNow;
    }

  9. #9
    Junior Member
    Join Date
    May 2015
    Location
    Germany
    Posts
    13
    Hello defragster, thank you for your commets. I tested that. The square wave of my code above has no 50% duty cycle, and yes, you see the rise/fall times. The initial code you suggest has a cycle time of 52 ns (like 5 clock cycles), and 60% durty cycle. I added a load to the output (330Ohm) to get an almost full voltage swing. I did no further testign on the influence of the probe tip. When I uncomment the __asm__ statements, I get a full level swing w/o load(as expected). But even then, no 50% duty cycle. The duty cycle is 60% high, 40% low, period of 100ns. If I drop the __asm__ Statement after setting the output HIGH, the durty cycle is 40%, and the period 73ns. All in 96MHz/optimized settings of Teensuino.
    Best Regards

  10. #10
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    8,319
    Something optimized or not symmetric in the goto/jumps.

    This using the qBlink should more easily give uniform cycles and you can adjust the duty. You'd not have periodic oddity if you disabled interrupts.

    Code:
    #define qBlink10() (digitalWriteFast(10, !digitalReadFast(10) ))
    
    {
      while (1)   {
        qBlink10();
        delayMicroseconds(500000);
      }
    }

  11. #11
    Junior Member
    Join Date
    May 2015
    Location
    Germany
    Posts
    13
    Hello defragster,
    obviously you are mostly about the uniform cycles. Without the delayMicroseconds call, I'll get a 53% duty cycle and 375ns cycle time, iwth the difference between high and low cycle being 22 ns or about 2 clock cycles. The rise/fall times are 8ns vs. 7.5 ns, so it does not look like an 'analog' reason for the difference. A look into the datasheets may explain the reason. But besides that, I do not care about the duty cycle. The aspect I was looking for was a) the elapsed time between an external event and the ISR to be notified, and b) the elapsed in after which the main program is notified or some other event can be triggered. The fast loop was just a test in between, whether interrupts were detected bot not flagged. During a ISR, the main program loop would halted, and that would cause a longer negative or positive pulse.. And BTW, I have temporarily switched off the SysTick timer, which is the only interrupt source present for this test. But for the other, the hint to digitalFastWrite() was very helpful.
    Best Regards

  12. #12
    Junior Member
    Join Date
    May 2015
    Location
    Germany
    Posts
    13
    Sorry, the first sentence should read: "obviously you are right about the uniform cycles."

  13. #13
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    8,319
    Maybe putting the qBlink() on the LED_BUILTIN (or another pin) in the ISR rather than overloading pin 10 - back in your first example.

    T3.1 Speed is catching you somewhere. The transition High>Low happens really fast - more so with digitalFastWrite. The qBlink() toggle will cut the change freq in half and allow settling before the next change. You have a good way of seeing the freq and duty cycle so that alone should show if you are missing interrupts, or missing the indications you are seeing them.

    I've not done a lot with interrupts here but PJRC warning that it gets complex fast may be hiding something.

  14. #14
    Junior Member
    Join Date
    May 2015
    Location
    Germany
    Posts
    13

    Output switching speed

    Hello defragster,
    the missing intterupt problem is solved. It was just a wrong setting of the pulse generator, which I used to trigger the interrupt. The level was too low, and it was lat at night,so I did not see it at once. But looking for the reason strarted this good discussion over switching timing. This morning, I started to compare the data sheet with the setting in the pins_teensy.c file, and found, that pinMode() sets a slow slew rate. Once I changed it, the slew rate improved. I have attached the two figures for your loop (cycle 375ns) and my fastest loop (cycle 52ns). With fast slew rate, the issue of the output not touching the low level disappeared too. The pictures show a slew rate of about 2 ns. The probe has a tip capacitance of 14 pf, and the measuring set-up has a rise time of 2 ns, so the device my be faster. If you wonder what the change is:

    Change line 791 in pins_teensy.c from:
    *config = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1);
    to
    *config = PORT_PCR_DSE | PORT_PCR_MUX(1);
    The SRE bit must be 0 for fast slew rate, but the code sets it to 1 for slow slew rate.
    Regards
    Attached Thumbnails Attached Thumbnails Click image for larger version. 

Name:	Cycle 52ns.jpg 
Views:	147 
Size:	111.7 KB 
ID:	4397   Click image for larger version. 

Name:	Cycle 375ns.jpg 
Views:	170 
Size:	111.0 KB 
ID:	4398  


  15. #15
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    8,319
    Glad you got a reason and a fix. Thx for the update.

  16. #16
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    19,914
    Hmmm... maybe the website needs some updates about how to get fast signals. The pages were written back in the AVR-only days, when you just couldn't make a pin toggle faster than 8 MHz.

  17. #17
    Senior Member
    Join Date
    Oct 2012
    Location
    Portland OR
    Posts
    593

    T3.1 fast slew rate: SRE=0 changes 7 ns risetime to sub-ns

    Until reading this, I didn't realize the pins were configured to be slow. I went into C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy3 and changed two files, core_pins.h and pins_teensy.c as a rude hack to add:
    Code:
    void pinModeFast(uint8_t pin, uint8_t mode); // for high drive strength (fast slew rate)
    
    void pinModeFast(uint8_t pin, uint8_t mode)
    {
    	volatile uint32_t *config;
    
    	if (pin >= CORE_NUM_DIGITAL) return;
    	config = portConfigRegister(pin);
    
    	if (mode == OUTPUT) {
    #ifdef KINETISK
    		*portModeRegister(pin) = 1;
    #else
    		*portModeRegister(pin) |= digitalPinToBitMask(pin); // TODO: atomic
    #endif
    		*config = PORT_PCR_DSE | PORT_PCR_MUX(1); // SRE bit = 0 for fast slew rate
    	} else {
    #ifdef KINETISK
    		*portModeRegister(pin) = 0;
    #else
    		*portModeRegister(pin) &= ~digitalPinToBitMask(pin);
    #endif
    		if (mode == INPUT) {
    			*config = PORT_PCR_MUX(1);
    		} else {
    			*config = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; // pullup
    		}
    	}
    }
    and tried this code:
    Code:
    const int LED1 = 0;  // output pin
    
    void setup() {
      pinModeFast(LED1, OUTPUT); // high slew rate setting
    }
    
    void loop() {
      digitalWriteFast(LED1, HIGH); 
      delayMicroseconds(10); 
      digitalWriteFast(LED1, LOW); 
      delayMicroseconds(10); 
    }
    Previously, when using the normal pinMode() call I got 7 ns risetime. With the high slew rate enabled I get sub-nanosecond risetimes, maybe around 0.85 ns but my 500 MHz scope/probe is not accurate at those levels. At any rate, it is quite a difference.

    "Before" (default slew rate)Click image for larger version. 

Name:	2015-06-08_08.49_Scope.jpg 
Views:	166 
Size:	105.7 KB 
ID:	4466 "After" (fast slew rate)Click image for larger version. 

Name:	2015-06-09%u00252B09.07.46.jpg 
Views:	177 
Size:	99.9 KB 
ID:	4464
    short ground wire probeClick image for larger version. 

Name:	2015-06-09%u00252B09.10.11.jpg 
Views:	179 
Size:	81.4 KB 
ID:	4465
    Last edited by defragster; 09-12-2018 at 04:07 AM. Reason: before/after scope photo

  18. #18
    Junior Member
    Join Date
    May 2015
    Location
    Germany
    Posts
    13
    Hi JBeale,
    thanks for the update. I did not expect any further comments on that any more. I had assume that the transition times were faster, but with my scope & probe that fastest I could get was 2ns, which is the limit of that combination. The data sheet tells 6 ns, regardless of the mode set. So the data sheet may be wrong in that perspective. What I wanted to find out was a set-up, where an input signal would cause an output signal after a programmable delay. So ISR response times USING the teensuino environment is an issue. The best I could get at the moment is a delay range from 2Ás to about 90 sec with about 20 ns resolution and 50 ns jitter, using the PIT units. At the moment. I try to figure out whether the PDB or Flex-Timer could be used instead. It looks like the PDB can be triggered itself externally, but I did not find a physical output signal, amd even if the signal exists in the die, it might not be routed to a pin of the CPU package, and that might not be routed to a pin of teensy.
    I have coworkers which would always go to bare bone assembly code for these kind of tasks. But I want to set up a little framework which is well maintained, uses a high level language and can be used with little training. And for that, teensy 3.1 and Teensuino + Arduino seems to be perfect. Who ever want to go bare bone, can still do that.
    The only issue if have with teensy 3.1 is the flimsy USB connector. I fear that it will not survive in the lab for long. For integration into another board, which is anyhow required for an analog circuit, simple soldering pads would be better. Then I could add a type B connector.

  19. #19
    Junior Member
    Join Date
    Jan 2016
    Location
    Minot, ND, USA
    Posts
    10
    Quote Originally Posted by JBeale View Post
    Until reading this, I didn't realize the pins were configured to be slow. I went into C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy3 and changed two files, core_pins.h and pins_teensy.c as a rude hack to add:
    ....<snip>...
    *config = PORT_PCR_DSE | PORT_PCR_MUX(1); // SRE bit = 0 for fast slew rate
    Nice...
    This little hack was the difference between an LCD running with the Teensy 3.2 @ 48Mhz and 120Mhz.
    I couldn't get pinModeFast() to work, so I copied the line above into core_pins.h above and commented out the original.
    Works like a champ.

  20. #20
    Senior Member
    Join Date
    Jun 2013
    Location
    So. Calif
    Posts
    2,828
    Assembly language isn't the solution.

    Relying on an interrupt latency of less than about 5 microseconds is imprudent in most any processor.
    The ARM NVIC can be used to let interrupt handler A interrupt (preempt) handler B. But resorting to that means that there is some handler x that is badly written. Or the functional allocation to software should have been to hardware, due to speeds.

  21. #21
    Senior Member
    Join Date
    Oct 2012
    Location
    Portland OR
    Posts
    593
    NOTE: my original code block for pinModeFast is missing a close bracket } at the end, somehow missed it in a cut-and-paste, sorry about that!

    <edit>: added close bracket }
    Last edited by defragster; 09-12-2018 at 04:11 AM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •