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

Thread: Teensy4 PWM interrupt config

  1. #1

    Teensy4 PWM interrupt config

    I am setting up PWM output on a digital pin. I want an interrupt to fire on the falling edge of the PWM output. At present, I can't get both the interrupt and the PWM configured simultaneously: If I call attachinterrupt, the square wave output stops. Was I crazy thinking you can throw an interrupt on an output pin or is this just a config error?

    Here's the basic code:

    analogWriteResolution(11);
    pinMode(22,OUTPUT);
    analogWrite(22,1024);
    analogWriteFrequency(22,40000);
    attachInterrupt(digitalPinToInterrupt(22),PIN_22_I SR,FALLING);

  2. #2
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    7,469
    Sorry in advance for these ramblings But maybe something might work.

    Both of these things are trying to use this pin in two different ways. Driven by Timer and trying to get interrupt like it was an IO pin.
    Looking at the data associated with this pin: 23 4A1 A9 RX1 3:9 MCL1 1.25 AD-B1_09

    There may be some straight forward ways of getting the interrupt like you tried not sure if that exact way would do it. You might try doing the attach before you do the AnalogWrite stuff to see if maybe the interrupt data will persist. I have my doubts.

    If not and if I were playing, I would try things like:
    Code:
    22	4A0	A8			TX1			3:08		1.24	AD_B1_08
    From my document P497 shows all of the things this pin does with the different MUX_MODES

    and likewise sources in cores\teensy4\pwm.c, I See that this PWM is done by FLEXPWM4_PWMA01
    Code:
    {1, M(4, 0), 1, 1},  // FlexPWM4_0_A  22  // AD_B1_08
    So this pin uses the FlexPWM timer system to do the PWM. So after the PWM is hooked up I might try experimenting with setting up an interrupt through the timer and see if they worked together.
    Looking at imxrt.h I see there is an interrupt vector:
    Code:
            IRQ_FLEXPWM4_0 =        147,
    So wonder what would happen if I set up an interruptVector for this one, like a few libraries do, like: FreqMeasureMulti
    You would need to do all of the normal things like enable enable the interrupt and the like.
    The data that this is on Timer Module 4, SubModule 0, and Pin A

    I would then look at the timers registers, probably, then look at the INTEN register associated with this pin.
    Something like IMXRT_FLEXPWM4.SM[0].INTEN
    And look to see if either the CAPTURE A0 or A1 work... Maybe not as I think these are mainly for Input Capture and not OUTPUT

    AND if that did not work. (very possible ) I would wonder if maybe I could hack up something using XBAR and ???
    Again I don't know what I would try to map the XBAR in of

    Again I don't know if if it would work to map something like one of:
    Code:
    #define XBARA1_IN_FLEXPWM4_PWM1_OUT_TRIG0 52
    #define XBARA1_IN_FLEXPWM4_PWM1_OUT_TRIG1 52
    #define XBARA1_IN_FLEXPWM4_PWM2_OUT_TRIG0 53
    #define XBARA1_IN_FLEXPWM4_PWM2_OUT_TRIG1 53
    #define XBARA1_IN_FLEXPWM4_PWM3_OUT_TRIG0 54
    #define XBARA1_IN_FLEXPWM4_PWM3_OUT_TRIG1 54
    #define XBARA1_IN_FLEXPWM4_PWM4_OUT_TRIG0 55
    #define XBARA1_IN_FLEXPWM4_PWM4_OUT_TRIG1 55
    To something else that I can get an interrupt on. It could be possible...

    But depending on my needs, I would probably simply try to connect up pin 22 to some unused IO pin and the set the interrupt on that pin... But I know that is cheating.

    Again sorry for these ramblings (brain dump) of things I might try if I really needed this to work.

  3. #3
    Setting up PWM on an unused IO pin and setting an interrupt on another is exactly what I'm doing presently. This is super lame since its using up an extra pin...but it works.

    I'm primarily wanting interrupts off PWM output so I can easily match the exact frequency config of another Teensy 4. I only really use the output of the interrupt pin for a diagnostic...so its fine if I don't get output, but the interrupt still fires. I would prefer to just use a timer interrupt directly, but the configuration for that may not perfectly match what analogwritefrequency is doing...same gig with IntervalTimer.


    It seems like there has to be a good way for me to just use the timers directly

  4. #4
    Senior Member+ manitou's Avatar
    Join Date
    Jan 2013
    Posts
    2,575
    Quote Originally Posted by kdharbert View Post
    It seems like there has to be a good way for me to just use the timers directly
    The T4 PWM timers can interrupt on period start and on "falling edge of the PWM output". Here is a simple sketch using flexpwm (ref ch 55) on T4 pin 8. Pin 13 is toggled on the falling PWM edge in the isr.
    Code:
    // PWM on pin8, flexpwm timer PWM1_A3
    #define MMASK (1<<3)   // module mask 3 for PWM1_A3
    
    volatile uint32_t ticks;
    void pwm1_3_isr() {
      FLEXPWM1_SM3STS = FLEXPWM_SMSTS_CMPF(1 << 3); //clear VAL3 cmp
      GPIO7_DR_TOGGLE = 1 << 3; //fast GPIO 13 toggle
      ticks++;
      asm volatile ("dsb");
    }
    void setup() {
      pinMode(13, OUTPUT);
      analogWriteFrequency(8, 1000);
      analogWrite(8, 64);
      // set up ISR on falling edge, duty cycle compare match
      FLEXPWM1_MCTRL |= FLEXPWM_MCTRL_CLDOK(MMASK);  // stop timer
      attachInterruptVector(IRQ_FLEXPWM1_3, pwm1_3_isr);
      FLEXPWM1_SM3STS =  FLEXPWM_SMSTS_CMPF(1 << 3); // clear
      FLEXPWM1_SM3INTEN = FLEXPWM_SMINTEN_CMPIE(1 << 3) ; // enable compare interrupt
      NVIC_ENABLE_IRQ(IRQ_FLEXPWM1_3);
      analogWrite(8, 64); // restart
    }
    
    void loop() {
      static int prev = 0;
      Serial.printf("%d ticks %d\n", ticks - prev, ticks);
      prev = ticks;
      delay(1000);
    }
    Here is scope image of PWM on pin 8 (yellow, 25% duty) and pin 13 toggle (blue).
    Click image for larger version. 

Name:	t4pwmcmp.png 
Views:	18 
Size:	34.6 KB 
ID:	21073
    You can see pin 13 toggles on the falling edge of the PWM. When you zoom in with the scope, you can measure the ISR latency at 56 ns.
    Click image for larger version. 

Name:	t4pwmisr.png 
Views:	25 
Size:	41.0 KB 
ID:	21077
    Using attachInterrupt() with pin 8 jumpered to pin 12, the ISR latency is 109 ns
    Last edited by manitou; 07-25-2020 at 09:57 AM.

  5. #5
    I got this working on pin4 \ PWM2.0. Thanks for the code.
    With this working, you can quite simply implement PFM on a single pin when combined with the techniques in this thread:
    https://forum.pjrc.com/threads/61793...head-questions

    Teensy4 has 16 timers, so you can quite simply implement PFM on 16 independent pins with very little overhead. Pretty neat I think.

  6. #6
    Thanks again for this code. How can I modify it to get an interrupt on both edges and rising edges only?

  7. #7
    Senior Member+ manitou's Avatar
    Join Date
    Jan 2013
    Posts
    2,575
    Quote Originally Posted by kdharbert View Post
    Thanks again for this code. How can I modify it to get an interrupt on both edges and rising edges only?
    ? "both" and "only" seem mutually exclusive?? any how, you can enable interrupt on both edges of the PWM. There is only one ISR for the interrupt so you will need to check the status flag (FLEXPWM1_SM3STS) to determine which interrupt fired. Read Ch 55 of reference manual.
    Code:
    ...
    void pwm1_3_isr() {
      if (FLEXPWM1_SM3STS & FLEXPWM_SMSTS_CMPF(1 << 3)) {
        FLEXPWM1_SM3STS = FLEXPWM_SMSTS_CMPF(1 << 3); //clear VAL3 cmp
        GPIO7_DR_TOGGLE = 1 << 3; //fast GPIO 13 toggle
      }
      if (FLEXPWM1_SM3STS & FLEXPWM_SMSTS_RF) {
        FLEXPWM1_SM3STS = FLEXPWM_SMSTS_RF; // reload clear
      }
      ticks++;
      asm volatile ("dsb");
    }
    ...
      attachInterruptVector(IRQ_FLEXPWM1_3, pwm1_3_isr);
      FLEXPWM1_SM3STS =  FLEXPWM_SMSTS_CMPF(1 << 3) | FLEXPWM_SMSTS_RF; // clear
      FLEXPWM1_SM3INTEN = FLEXPWM_SMINTEN_CMPIE(1 << 3) | FLEXPWM_SMINTEN_RIE ; // enable interrupts
      NVIC_ENABLE_IRQ(IRQ_FLEXPWM1_3);
    ...

  8. #8
    Bad sentence. I have code for FALLING. I need code for CHANGE and RISING configs individually, not in tandem.

  9. #9
    Senior Member+ manitou's Avatar
    Join Date
    Jan 2013
    Posts
    2,575
    Quote Originally Posted by kdharbert View Post
    Bad sentence. I have code for FALLING. I need code for CHANGE and RISING configs individually, not in tandem.
    Hmmm, the ISR function in post #7 does all three. ISR is equivalent to CHANGE, then in the ISR you check the status flag to see if you have rising (RF) or falling (CMPF).

  10. #10
    Ahhh, I see. Wonderful. Thank you!

Posting Permissions

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