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

Thread: Problems Synchronizing an Interval Timer to a PWM on a Teensy 4

  1. #1
    Junior Member
    Join Date
    Jul 2013
    Posts
    19

    Problems Synchronizing an Interval Timer to a PWM on a Teensy 4

    For some reason, when I set up the interval timer, I am only getting it to fire once. The code I am trying to update for use with the T4 already works on T3.2, T3.5, and T3.6 with minor timing tweaks between them, but not yet on the T4. The new program is an update my Commodore 6581 (SID) player.

    https://forum.pjrc.com/threads/42587...?highlight=SID

    I need a 1MHz clock and a timed chip select that lines up with the clock's rising edge and doesn't "walk" away from the clock between SID writes. That looks like the following:

    Click image for larger version. 

Name:	IMG_2569.JPG 
Views:	4 
Size:	120.9 KB 
ID:	17667

    The code needed to do this on previous Teensys is this:

    Code:
    #define CLK 4
    #define CS1 3
    #define NOP __asm__("nop\n\t")
    
    
    
    volatile long timetonext;
    volatile byte dataavailable;
    volatile unsigned long cycles_per_us;
    
    static inline void delayCycles(uint32_t cycles)
    { // MIN return in 7 cycles NEAR 20 cycles it gives wait +/- 2 cycles - with sketch timing overhead
      uint32_t begin = ARM_DWT_CYCCNT - 12; // Overhead Factor for execution
      while (ARM_DWT_CYCCNT - begin < cycles) ; // wait
    }
    
      
    IntervalTimer myTimer;
    
    void setup() {
      Serial.begin(115200);
      pinMode(CLK, OUTPUT);
      digitalWrite(CLK, HIGH);
      pinMode(CS1, OUTPUT);
      digitalWrite(CS1, HIGH);
    
    
      analogWriteFrequency(CLK, 1000000);               // set clock frequency to 1MHz
      analogWriteResolution(5);                         // PWM resolution
      analogWrite(CLK, 15);                             // PWM dutycycle
    
    
      myTimer.begin(DATA, 10);
      //myTimer.priority(64);
      cycles_per_us = F_BUS_ACTUAL / 1000000;
    }
    
    FASTRUN void loop() {                               
       while (1) {
        timetonext = 3;                                  //Change this to vary the number of CLK pulses between CS1 pulses                                   
        dataavailable = 1;
        PIT_LDVAL0 = timetonext * cycles_per_us - 1;     // reset the PIT timer in myTimer to the delay until the next write
        while (dataavailable == 1) {}                    // wait for myTimer to fire interrupt
      }
    }
    
    FASTRUN void DATA(void)
    {
      if (dataavailable >= 1) {
     
        digitalWriteFast(CS1, LOW);
    
        // 200ns Pulse on Teensy 4 @ 600MHz
        delayCycles(45);
     
        dataavailable = 0;
        digitalWriteFast(CS1, HIGH);
      }
    }
    The variable "timetonext" is the number of microseconds to wait before firing the interrupt and can be any number between 0 and 65535. I used PIT_LDVAL0 to change the start of the timer on the fly and it worked very well. Also, don't worry if the chip select doesn't line up with the clock in the example since that can be fixed with different amounts of delayCycles either in the interrupt routine or the main routine.

    Any ideas?

    David

  2. #2
    Senior Member+ manitou's Avatar
    Join Date
    Jan 2013
    Posts
    2,232
    Repeating what was noted in https://forum.pjrc.com/threads/57609...l=1#post216399
    One problem you have is using F_BUS_ACTUAL. The PIT timer for T4 IntervalTimer runs at 24MHz, not F_BUS_ACTUAL. Also if you are not running 1.48-beta1, the first PIT channel you get for IntervalTimer is channel 2, so you need to use PIT_LDVAL2.
    To avoid explicit register usage note that the IntervalTimer has a method myTimer.update(micros).

    If you want a 200ns pulse on CS1, then you want delayCycles(120).

    FASTRUN has no effect on T4 since the T4 startup code copies all of the program's FLASH to RAM.
    Last edited by manitou; 09-22-2019 at 05:51 PM.

  3. #3
    Junior Member
    Join Date
    Jul 2013
    Posts
    19
    Quote Originally Posted by manitou View Post
    Manitou, thanks for your help!

    Quote Originally Posted by manitou View Post
    If you want a 200ns pulse on CS1, then you want delayCycles(120).
    This was the issue... delayCycles(25) does NOT result in a 42ns pulse at pin 3. 25 looks more like 4-5ns, 60 only looks like 20ns, and 130 does look like 200ns. I was measuring this at a testpoint after it is level shifted by an NTE74HC139 decoder and a 5ns input pulse is effectively filtered out. I should have measured at the Teensy pin and I would have seen that it was only a blip.

    Quote Originally Posted by manitou View Post
    To avoid explicit register usage note that the IntervalTimer has a method myTimer.update(micros).
    I've checked this on the other Teensys and using myTimer.update(micros) took longer than the explicit register write. Sometimes, I need timetonext=1 and this doesn't work on T4 without the explicit call. timetonext=2 does work, though.

    Quote Originally Posted by manitou View Post
    FASTRUN has no effect on T4 since the T4 startup code copies all of the program's FLASH to RAM.
    Noted and removed.

    I can now get a waveform with timetonext=3 that repeats like the one above. There is one new issue I see, though. When I restart the Teensy4 repeatedly, I do not get the same phase relationship between the PWM and the interval timer every time. I assume they are running off different clock domains with different startup characteristics. Is there any way to make them use the same clock and thus always start with the same relationship?

    David

Posting Permissions

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