Forum Rule: Always post complete source code & details to reproduce any issue!
Page 1 of 2 1 2 LastLast
Results 1 to 25 of 30

Thread: Teensy4 IntervalTimer Channels Problem

  1. #1
    Member
    Join Date
    Nov 2018
    Location
    Canada
    Posts
    40

    Teensy4 IntervalTimer Channels Problem

    Just got my T4s this week and I'm putting th T4 through some basic tests. I wrote a very basic IntervalTime sketch using 4 channels of the IntervalTimer and discovered that it will only handle two channels. The other two (any combination of two) are ignored.

    Is this a known problem, or did I blow it somewhere?
    Here is the sketch:

    Update: It should also be noted that the last two instances do return false indicating resources are not available, but I don't understand why this may be happening in such a basic demonstration.

    Code:
    IntervalTimer timer_led1;
    IntervalTimer timer_led2;
    IntervalTimer timer_led3;
    IntervalTimer timer_led4;
    
    const uint8_t led1 = 1;
    const uint8_t led2 = 2;
    const uint8_t led3 = 3;
    const uint8_t led4 = 4;
    
    void toggle( const uint8_t pin ) { digitalWrite( pin, !digitalRead(pin) ); }
    
    void led1_isr() { toggle( led1 ); }
    void led2_isr() { toggle( led2 ); }
    void led3_isr() { toggle( led3 ); }
    void led4_isr() { toggle( led4 ); }
    
    
    //--------------------------------------------------------------------------------------//
    
    void setup()
    {
      pinMode( led1, OUTPUT );
      pinMode( led2, OUTPUT );
      pinMode( led3, OUTPUT );
      pinMode( led4, OUTPUT );
    
      timer_led1.begin( led1_isr, 100000 );
      timer_led2.begin( led2_isr, 250000 );
      timer_led3.begin( led3_isr, 500000 );
      timer_led4.begin( led4_isr, 1000000 );
    }
    
    void loop() {}
    Last edited by quadrupel; 08-25-2019 at 04:55 PM.

  2. #2
    I've observed the same exact behavior.

    I don't see where the other two timers are going (looks like interval timer 0 and 1 are in use or not initialized properly)... or what happens if they are disabled/reassigned but this code makes them available for me:

    Code:
      // clear/make available all PIT timers
      CCM_CCGR1 |= CCM_CCGR1_PIT(CCM_CCGR_ON);
      PIT_MCR = 1;
      PIT_TCTRL0=0;
      PIT_TCTRL1=0;
      PIT_TCTRL2=0;
      PIT_TCTRL3=0;

  3. #3
    I'm also confused by the overloaded methods casting microseconds from long to int in IntervalTimer.h begin(), possibly I don't understand the code but it looks like a bug to me. I use floats for the period in my application so this isn't much of a concern.

  4. #4
    Member
    Join Date
    Nov 2018
    Location
    Canada
    Posts
    40
    hjd, thanks for the update. I'll give your code mods a try and let you know my results.

  5. #5
    Senior Member+ manitou's Avatar
    Join Date
    Jan 2013
    Posts
    2,229
    Strange. for some reason TCTRL0 and TCTRL1 have non-zero values (power on should set them to 0). I haven't yet found where in the core those registers are set. here is my test sketch
    Code:
    #define PRREG(x) Serial.printf(#x" 0x%x\n",x);
    IntervalTimer t1, t2, t3, t4;
    volatile uint32_t t1c, t2c, t3c, t4c;
    
    void t1isr() {
      t1c++;
    }
    void t2isr() {
      t2c++;
    }
    void t3isr() {
      t3c++;
    }
    void t4isr() {
      t4c++;
    }
    void setup() {
      Serial.begin(9600);
      while (!Serial);
      CCM_CCGR1 |= CCM_CCGR1_PIT(CCM_CCGR_ON);
      PRREG(PIT_TCTRL0);
      PRREG(PIT_TCTRL1);
      PRREG(PIT_TCTRL2);
      PRREG(PIT_TCTRL3);
    
     // PIT_MCR = 1;
      PIT_TCTRL0 = 0;
      PIT_TCTRL1 = 0;
      //  PIT_TCTRL2=0;
      //  PIT_TCTRL3=0;
      t1.begin(t1isr, 500000);
      t2.begin(t2isr, 200000);
      t3.begin(t3isr, 100000);
      t4.begin(t4isr, 1000);
    
    
    }
    
    void loop() {
      Serial.printf("%d %d %d %d\n", t1c, t2c, t3c, t4c);
      delay(1000);
    
    }
    I confirm setting TCTRL0 and TCTRL1 to 0 allow all 4 PIT timers to be used in IntervalTimer ... more research required.

    Production T4 (1062) using 1.8.8 1.47 or 1.8.9 1.47

    EDIT: PIT registers should be 0 at power on/reset, but for T4 (1062), regs are
    Code:
    PIT_MCR 0x2
    PIT_TCTRL0 0x1
    PIT_TCTRL1 0x5
    PIT_TCTRL2 0x0
    PIT_TCTRL3 0x0
    PIT_LDVAL0 0xffffffff
    PIT_LDVAL1 0xffffffff
    PIT_LDVAL2 0x0
    PIT_LDVAL3 0x0
    It looks like PIT was configured for 64-bit cycle counting (channel 1 chained to channel 0). I still don't know why regs aren't all 0.

    FWIW, see https://github.com/manitou48/teensy4...t_micros64.ino
    Last edited by manitou; 08-31-2019 at 12:31 PM.

  6. #6
    Senior Member+ manitou's Avatar
    Join Date
    Jan 2013
    Posts
    2,229
    maybe the following is a suitable FIX in hardware/teensy/avr/cores/teensy4/IntervalTimer.cpp
    Code:
    ...
        } else {
            CCM_CCGR1 |= CCM_CCGR1_PIT(CCM_CCGR_ON);
            //__asm__ volatile("nop"); // solves timing problem on Teensy 3.5
            if (PIT_MCR == 2) { 
                // first time, fix POR values
                PIT_TCTRL0 = 0;
                PIT_TCTRL1 = 0;
            }
    ...
    Last edited by manitou; 08-31-2019 at 12:01 PM.

  7. #7
    Quote Originally Posted by hjd View Post
    I'm also confused by the overloaded methods casting microseconds from long to int in IntervalTimer.h begin(), possibly I don't understand the code but it looks like a bug to me. I use floats for the period in my application so this isn't much of a concern.
    Never mind...

    I always assumed int's were forced to 16bit for "Arduino" compatibility. I see both int and long are both 32bit, learn something new every day.

  8. #8
    Member
    Join Date
    Nov 2018
    Location
    Canada
    Posts
    40
    manitou, ran your test sketch. Interesting observation about TCTRL0, and TCTRL1. Added your 'fix' to IntervalTimer and now my test sketch runs all four timers. Thank you for all your help.

  9. #9
    Senior Member+ manitou's Avatar
    Join Date
    Jan 2013
    Posts
    2,229
    latest observation: In setup() I printed out the TCTRLx registers on T4B1 (beta 1052), and all values are 0. (1.8.8 1.47-beta1)

    Hardware or software ?? i'll test with NXP EVKB boards and mbed or SDK ....

  10. #10
    Member
    Join Date
    Nov 2018
    Location
    Canada
    Posts
    40
    hjd, I've been working with Teensy for almost a year now and I'm still learning new stuff every day. I should have moved to the Teensy platform years ago. Have fun.

  11. #11
    Member
    Join Date
    Nov 2018
    Location
    Canada
    Posts
    40
    Quote Originally Posted by manitou View Post
    latest observation: In setup() I printed out the TCTRLx registers on T4B1 (beta 1052), and all values are 0. (1.8.8 1.47-beta1)

    Hardware or software ?? i'll test with NXP EVKB boards and mbed or SDK ....
    Looking forward to your observations...

  12. #12
    Member
    Join Date
    Nov 2018
    Location
    Canada
    Posts
    40
    Quote Originally Posted by manitou View Post
    latest observation: In setup() I printed out the TCTRLx registers on T4B1 (beta 1052), and all values are 0. (1.8.8 1.47-beta1)

    Hardware or software ?? i'll test with NXP EVKB boards and mbed or SDK ....
    manitou,
    Out of curiosity, I created a class to play around with PIT. It's a very basic version of IntervalTimer, but I can get all 4 channels running without having to anything funny. The code snippet below shows the class constructor with the normal PIT initialization and then the addChannel method simply creates the PIT channel as you'd suspect. I didn't include the pit_isr as it is identical to the one in IntervalTimer. This may help in any investigation into the IntervalTimer behaviour.

    Code:
    Timer::Timer()
    {
    	CCM_CCGR1 |= CCM_CCGR1_PIT(CCM_CCGR_ON);
    	PIT_MCR = 1;
    }
    
    bool Timer::addChannel( void (*f)(), const uint32_t us )
    {
    	if (channel_index > 3) return false;
    
    	IMXRT_PIT_CHANNEL_t *channel = IMXRT_PIT_CHANNELS + channel_index;
    	pit_event[channel_index] = f;
    
    	constexpr uint8_t PIT_TIE = 0x2;
    	constexpr uint8_t PIT_TEN = 0x1;
    
    	channel->LDVAL = (F_BUS_ACTUAL / 1000000) * us - 1;
    	channel->TCTRL = PIT_TIE;
    	channel->TCTRL |= PIT_TEN;
    	channel->TFLG = 1;
    
    	attachInterruptVector(IRQ_PIT, &_pit_isr);
    	NVIC_ENABLE_IRQ(IRQ_PIT);
    
    	channel_index++;
    	return true;
    }

  13. #13
    Senior Member+ manitou's Avatar
    Join Date
    Jan 2013
    Posts
    2,229
    Quote Originally Posted by manitou View Post
    latest observation: In setup() I printed out the TCTRLx registers on T4B1 (beta 1052), and all values are 0. (1.8.8 1.47-beta1)

    Hardware or software ?? i'll test with NXP EVKB boards and mbed or SDK ....
    Inconclusive results for NXP eval boards. The mbed core uses the PIT timer for us_ticker() with EVKB 1052 eval board, and with the 1062 eval board the NXP SDK is using the PIT for microseconds(). So it will require messing with core files to see initial values of PIT registers -- may or may not pursue that...

  14. #14
    Out of curiosity, I created a class to play around with PIT. It's a very basic version of IntervalTimer, but I can get all 4 channels running without having to anything funny.
    The IntervalTimer class uses each timers TCTRL flag to indicate if a given PIT timer is in use so interval timers can be allocated/deallocated in any order as needed. At startup all four TCTRL should be set to 0 (as an "available" flag) but for some reason the first two are not.

  15. #15
    Quote Originally Posted by quadrupel View Post
    hjd, I've been working with Teensy for almost a year now and I'm still learning new stuff every day. I should have moved to the Teensy platform years ago. Have fun.
    I've been working with a mix of 8-bit AVR, Teensy's, ESP's, STM32 in Arduino for quite a while. Since the same code runs on all of these I developed a kind of protective amnesia WRT int's I think.

  16. #16
    Member
    Join Date
    Nov 2018
    Location
    Canada
    Posts
    40
    Quote Originally Posted by hjd View Post
    The IntervalTimer class uses each timers TCTRL flag to indicate if a given PIT timer is in use so interval timers can be allocated/deallocated in any order as needed. At startup all four TCTRL should be set to 0 (as an "available" flag) but for some reason the first two are not.
    In the IntervalTimer code, I created a constructor that initializes the PIT timer and I cleared TCTRCL0 and TCTRL1 to 0. manitou indicated that only those first two flags were not being cleared. In the beginCycles() method, I commented out 'CCM_CCGR1 |= CCM_CCGR1_PIT(CCM_CCGR_ON)' and 'PIT_MCR = 1' as they are now in the constructor as shown in the code snippet below. manitou's fix was removed. All four timers function correctly.

    I created a local version of the IntervalTimer named Interval_Timer so as not to interfere with the Teensy4 core version

    Code:
    constexpr Interval_Timer() 
    {
    	CCM_CCGR1 |= CCM_CCGR1_PIT(CCM_CCGR_ON);
    	PIT_TCTRL0 = 0;
      	PIT_TCTRL1 = 0;
    	PIT_MCR = 1;
    }
    Last edited by quadrupel; 08-29-2019 at 07:22 PM. Reason: Update

  17. #17
    Senior Member+ manitou's Avatar
    Join Date
    Jan 2013
    Posts
    2,229
    Quote Originally Posted by manitou View Post
    Inconclusive results for NXP eval boards. The mbed core uses the PIT timer for us_ticker() with EVKB 1052 eval board, and with the 1062 eval board the NXP SDK is using the PIT for microseconds(). So it will require messing with core files to see initial values of PIT registers -- may or may not pursue that...
    Latest observation of 1052 and 1062 with NXP SDK (MCUXpresso IDE). A PIT timer example on the 1052 has all TCTRL and LDVAL values 0. On the 1062 eval board, the PIT example starts with channels 0 and 1 TCTRL at 1 and 5, and the channel 0 and 1 LDVALs as 0xffffffff -- just like the T4B1 and T4. So maybe the default hardware POR values are different for the 1062? Unless both Teensy and NXP bootloader are some how using the PIT timer channels 0 and 1 chained for a 64-bit timer ....

  18. #18
    Member
    Join Date
    Nov 2018
    Location
    Canada
    Posts
    40
    Thanks for keeping me informed. It would seem you've encountered quite the rabbit hole. I've been reading Ch. 52 of the Ref. Manual, trying to get a better understanding of PIT, but I also need a better understanding of the Teensy4 core as well.

  19. #19
    Senior Member+ manitou's Avatar
    Join Date
    Jan 2013
    Posts
    2,229
    A feature?

    Though 1052 and 1062 both have PIT "lifetime" timer capability (chained channel 0 and 1), only the 1062 is configured to start the lifetime timer as soon as PIT is enabled in CCM_CCGR1. So if startup.c enabled PIT in CCGR1, then the PIT would have a running timer of how long the core has been running (in 24mhz cycles).

    so maybe a better fix is in startup.c, enable PIT, clear all of PIT registers, then disable (optional?) PIT in CCGR1, then IntervalTimer lib would work with all 4 channels.

  20. #20
    Member
    Join Date
    Nov 2018
    Location
    Canada
    Posts
    40
    Quote Originally Posted by manitou View Post
    A feature?

    Though 1052 and 1062 both have PIT "lifetime" timer capability (chained channel 0 and 1), only the 1062 is configured to start the lifetime timer as soon as PIT is enabled in CCM_CCGR1. So if startup.c enabled PIT in CCGR1, then the PIT would have a running timer of how long the core has been running (in 24mhz cycles).

    so maybe a better fix is in startup.c, enable PIT, clear all of PIT registers, then disable (optional?) PIT in CCGR1, then IntervalTimer lib would work with all 4 channels.
    Installed the patch below into Teensy4 core startup.c file's ResetHandler() function. Ran my IntervalTimer test previously posted on this thread and all 4 channels behave correctly.
    Code:
    // manitou suggested PIT fix 
      CCM_CCGR1 |= CCM_CCGR1_PIT(CCM_CCGR_ON);
      PIT_TCTRL0 = 0;
      PIT_TCTRL1 = 0;
      PIT_TCTRL2 = 0;
      PIT_TCTRL3 = 0;
      CCM_CCGR1 |= CCM_CCGR1_PIT(CCM_CCGR_OFF);

  21. #21
    Even after just digging into T4 (have has a 3.6 but never got the “round-to-it” to begin learning. The higher price of the 3.6 kept me out of the game, but going forward the T4 is only slightly more than Pololu AStar 32u4 boards.... so have become a def Teensy convert. ��

    Quote Originally Posted by quadrupel View Post
    hjd, I've been working with Teensy for almost a year now and I'm still learning new stuff every day. I should have moved to the Teensy platform years ago. Have fun.

  22. #22
    Senior Member+ manitou's Avatar
    Join Date
    Jan 2013
    Posts
    2,229
    Quote Originally Posted by quadrupel View Post
    Installed the patch below into Teensy4 core startup.c file's ResetHandler() function. Ran my IntervalTimer test previously posted on this thread and all 4 channels behave correctly.
    Code:
    // manitou suggested PIT fix 
      CCM_CCGR1 |= CCM_CCGR1_PIT(CCM_CCGR_ON);
      PIT_TCTRL0 = 0;
      PIT_TCTRL1 = 0;
      PIT_TCTRL2 = 0;
      PIT_TCTRL3 = 0;
      CCM_CCGR1 |= CCM_CCGR1_PIT(CCM_CCGR_OFF);
    I think to disable the PIT you need to clear the bits
    Code:
    // manitou suggested PIT fix 
      CCM_CCGR1 |= CCM_CCGR1_PIT(CCM_CCGR_ON);
      PIT_TCTRL0 = 0;
      PIT_TCTRL1 = 0;
      PIT_TCTRL2 = 0;
      PIT_TCTRL3 = 0;
      CCM_CCGR1 &= ~CCM_CCGR1_PIT(CCM_CCGR_ON);   //optional
    Last edited by manitou; 09-07-2019 at 11:54 PM.

  23. #23
    Member
    Join Date
    Nov 2018
    Location
    Canada
    Posts
    40
    Manitou, thanks for the update.

  24. #24

    awesome forum

    Yes - I totally agree! New T4 user been on just a week or so - just beginning to see the depth that is here.

    Quote Originally Posted by quadrupel View Post
    hjd, I've been working with Teensy for almost a year now and I'm still learning new stuff every day. I should have moved to the Teensy platform years ago. Have fun.

  25. #25
    @Quadrupel - where did you insert the startup patch in startup.c - that is a VERY busy file - don't want to break it. Also - I'm keeping a copy of the original..

Posting Permissions

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