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

Thread: attachInterruptVector() with Teensy 4.0

  1. #1
    Junior Member
    Join Date
    Nov 2019
    Posts
    3

    attachInterruptVector() with Teensy 4.0

    Hi

    I need to use the attachInterruptVector() to be able to capture a digital signal with a max. freq of 10 MHz with the superfast Teensy 4.0. The normally used (and easy to use) attachInterrupt has a too big delay between the signal change and the start of the interrupt routine.
    After reading and searching in this forum, I realized why the attachInterrupt() is slower and that I need to use the attachInterruptVector(). I also once had to make that with an Arduino / ATmega32u4, but the Teensy 4.0 / IMXRT1060RM is at a completely different level...

    I've found a post with a similar topic and tried to adapt it to my project (see last post): https://forum.pjrc.com/threads/57717...le-question-T4

    That is my code, but sadly it doesn't work:
    Code:
    void change() {
     //do something extremely fast
      GPIO9_ISR = 0x08; // clear the IRQ
      asm("dsb");
    }
    
    void setup() {
      pinMode(2, INPUT); // connected to EMC_04
      pinMode(5, INPUT); // connected to EMC_08
      attachInterruptVector(IRQ_GPIO6789, &change);
      NVIC_ENABLE_IRQ(IRQ_GPIO6789);
      GPIO9_GDIR &= ~0x08;
      GPIO9_EDGE_SEL = 0x08;
      GPIO9_ISR = 0xffff;
      //attachInterrupt(digitalPinToInterrupt(2), change, CHANGE); // works, but "slow"
      //attachInterrupt(digitalPinToInterrupt(5), change, CHANGE); // works, but "slow"
    }
    
    void loop() {
      // do something else
    }
    It compiles perfectly, but no interrupt occurs. Tested at 600 MHz/Fast settings. For sure I did something wrong...

    Can you please help me?

    Thanks,
    Stephan

  2. #2
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    5,755
    I don't see anywhere where you are enabling the interrupt? That is the IMR register and probably maybe need to setup ICR1 and/or ICR2 depending on which pin...

  3. #3
    Junior Member
    Join Date
    Nov 2019
    Posts
    3
    Hi KurteE

    Thank you for your answer. I'm in general confused about those thousands of registers available, so any help is appreciated!
    I'll try to find the mentioned registers in the manual of the chip and will write back if I was successful or not. I think I'll need some time for it...

  4. #4
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,848
    Double check these 2 lines?

    Quote Originally Posted by hitz_s View Post
    Code:
      GPIO9_GDIR &= ~0x08;
      GPIO9_EDGE_SEL = 0x08;
    You're using either pin 2 (bit 4 in GPIO9) or pin 5 (bit 8 in GPIO9), but this manipulates bit 3.

    Maybe you meant this?

    Code:
      GPIO9_GDIR &= ~(1<<8);
      GPIO9_EDGE_SEL = (1<<8);
    Likewise with writing to GPIO9_ISR within your interrupt.

  5. #5
    Senior Member
    Join Date
    May 2015
    Location
    USA
    Posts
    306
    If you don't have other things to do, polling is faster than an interrupt.

  6. #6
    Junior Member
    Join Date
    Nov 2019
    Posts
    3
    Thank you very much for your help, Paul and jonr!

    I've finally found a working solution, this is my code right now:
    Code:
    uint8_t encA = 0;
    uint8_t encB = 0;
    uint8_t oldOutA = 0;
    uint8_t oldOutB = 0;
    uint8_t oldEncA = 0;
    uint8_t oldEncB = 0;
    
    FASTRUN void pin_isr() {
      uint8_t encA = digitalReadFast(2);
      uint8_t encB = digitalReadFast(5);
      if ((encA ^ oldEncA) | (encB ^ oldEncB)) { // step happened
        uint8_t dir = (encA ^ oldEncB); // set direction
        uint8_t outA = !(dir ^ oldOutB); //set out A
        oldOutB = dir ^ oldOutA; // set out B
        oldOutA = outA;
        digitalWriteFast(14, oldOutA); // write output signal A
        digitalWriteFast(22, oldOutB); // write output signal B
        oldEncA = encA;
        oldEncB = encB;
      }
      GPIO9_ISR = ((1<<4) | (1<<8)); // clear the IRQ
      asm("dsb");
    }
    
    void setup() {
      
      attachInterruptVector(IRQ_GPIO6789, &pin_isr);
      NVIC_ENABLE_IRQ(IRQ_GPIO6789);
      GPIO9_GDIR &= ~((1<<4) | (1<<8)); // Set as Input (0 = input)
      GPIO9_EDGE_SEL = ((1<<4) | (1<<8)); // Edge  select register, overrides ICR register, p.1034
      //GPIO9_ICR1 = 0x00; // not needed because of EDGE_SEL register
      GPIO9_IMR = ((1<<4) | (1<<8)); // Interrupt mask register, p.1032
      GPIO9_ISR = ((1<<4) | (1<<8)); // Interrupt status register, p. 1033
    
      pinMode(14, OUTPUT); // connected to AD_B1_02
      IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_02 = 0b11011111; // Max speed, fast slew rate, drive strength R0/3, p. 662ff
      
      pinMode(22, OUTPUT); // connected to AD_B1_08
      IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_08 = 0b11011111; // p. 674ff
    
      while (1) {}
      
    }
    
    void loop() {
    }
    Inside the ISR, I calculate something small and then, if needed, toggle an output. I now measured the delay between the change of the input signal and the change in the output signal:


    • Constantly polling two inputs (see code below): Delay between 65ns and 100ns (All interrupts disabled with cli(), 1.008 GHz clock freq., fastest option)
    • Interrupt methode: Delay usually 74ns, but if another interrupt occurs up to 134ns (1.08 GHz clock freq., fastest option). With another interrupt I mean an interrupt, which I didn't configure, but still happens (USB connection?). If someone knows which interrupt(s) it could be and how I can disable it, that would already be helpful.


    So polling can be a little bit faster (65ns instead of 74ns), but varies continuously. The interrupt methode is very stable at 74ns, as long as no other (unwanted) interrupt occurs.
    To conclude, if I can not "accelerate" one of the methods, I won't be able to catch an external signal at 10 MHz. But I still learned something and I'm still impressed about the speed of the Teensy 4.0!

    This is the polling version:
    Code:
    #define PIN_A_IN 2
    #define PIN_B_IN 5
    #define PIN_A_OUT 22 // 22 = AD_B1_08
    #define PIN_B_OUT 14 // 14 = AD_B1_02
    
    void setup() {
      pinMode(PIN_A_OUT, OUTPUT);
      pinMode(PIN_B_OUT, OUTPUT);
      IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_02 = 0b11011111;
      IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_08 = 0b11011111;
      prog();
    }
    
    void loop() { // too slow
    }
    
    FASTRUN void prog() {
      uint8_t oldOutA = 0;
      uint8_t oldOutB = 0;
      uint8_t oldEncA = 0;
      uint8_t oldEncB = 0;
      cli();
      while (1) {
        uint8_t encA = digitalReadFast(PIN_A_IN);
        uint8_t encB = digitalReadFast(PIN_B_IN);
        if ((encA ^ oldEncA) | (encB ^ oldEncB)) { // step happened
          uint8_t dir = (encA ^ oldEncB); // set direction
          uint8_t outA = !(dir ^ oldOutB); //set out A
          oldOutB = dir ^ oldOutA; // set out B
          digitalWriteFast(PIN_A_OUT, outA); // write output signal A
          digitalWriteFast(PIN_B_OUT, oldOutB); // write output signal B
          oldOutA = outA;
          oldEncA = encA;
          oldEncB = encB;
        }
      }
    }

  7. #7
    Senior Member
    Join Date
    May 2015
    Location
    USA
    Posts
    306
    You could tighten up that polling code to be a little faster. I think a reliable < 50 ns is possible.

    > if I can not "accelerate" one of the methods, I won't be able to catch an external signal at 10 MHz

    The teensy 4.0 has hardware for input capture with time stamp. This works for some applications.
    Last edited by jonr; 12-02-2019 at 03:21 PM.

Posting Permissions

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