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

Thread: Teensy 3.6 maximum pin toggle rate

  1. #1
    Junior Member
    Join Date
    Sep 2015
    Location
    Brooklyn
    Posts
    9

    Teensy 3.6 maximum pin toggle rate

    Hello all, I'm hoping to generate a 54MHz clock signal from a Teensy 3.6

    I've looked into "fast" ways to set and clear ports, etc, and am currently running this very simple program:
    Code:
    #define ap 5
    void setup() {
      pinMode(ap, OUTPUT);
    }
    
    void loop() {
      while (1) {
        digitalWriteFast(ap, HIGH);
        digitalWriteFast(ap, LOW);
      }
    }
    ...however, this produces a square wave with an asymmetrical waveform / a non-50/50 duty cycle, and the wave is only at around 2.5MHz.
    I'm compiling with "CPU Speed" at 240MHz and "Optimize" set to "Fastest". I don't understand why, but if I compile at "240MHz" and "Smallest Code", I get a 10MHz waveform that erratically (about 1 in 4 times) sticks in the "on" position for a clock cycle or two...

    I'm sorry if I've missed something obvious - I'd be very grateful for anyone's opinion/debug/advice-to-just-use-a-clock-generator...

    Thank you,

    AKA

  2. #2
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    9,062
    From another post : another option is to use the bitband toggle macro like this :: *portToggleRegister(LEDPIN) = 1;

    It won't be faster - but it should be symmetric at least

  3. #3
    Senior Member
    Join Date
    Jan 2013
    Posts
    843
    Quote Originally Posted by defragster View Post
    From another post : another option is to use the bitband toggle macro like this :: *portToggleRegister(LEDPIN) = 1;

    It won't be faster - but it should be symmetric at least
    It's slower. The port toggle register access does a bus read and a bus write for a total of 4 CPU clock cycles. An unrolled digitalWriteFast executes in 1 CPU clock cycle (it uses the port set / clear register).

    The posted loop should run in 4-6 clock cycles per iteration (with loop counter it uses 6), using the portToggleRegister() would take 8.

    \\

    The IO pins are by default configured with slew rate limiting. You want to disable that. You may be able to overclock FBUS to 96 MHz, which may allow you to use PWM to get a 48MHz signal. Maybe, you can even push things to 108 = 54 * 2.

    In any case, you will be at the slew rate limits and you won't get anything that looks like a square wave.

    Is your measurement equipment actually good enough? If it doesn't have enough bandwidth, you will see a 'funny' frequency.
    Last edited by tni; 05-27-2017 at 02:19 PM.

  4. #4
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    5,068
    Thanks TNI,

    good information to know about writing to the registers GPIOx_PTOR is slower than writing to the registers: GPIOx_PCOR and GPIOx_PSOR.

    Did not see anything in reference about the timings, but have no doubt it is true.

  5. #5
    Senior Member
    Join Date
    Jan 2013
    Posts
    843
    Quote Originally Posted by KurtE View Post
    good information to know about writing to the registers GPIOx_PTOR is slower than writing to the registers: GPIOx_PCOR and GPIOx_PSOR.
    Actually not. I was just verifying that everything was exactly the same. portToggleRegister() returns the bit-band version of the register - that takes 4 clocks. GPIOx_PTOR is as fast as GPIOx_PCOR / GPIOx_PSOR and can in the best case take a single clock cycle.

  6. #6
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    9,062
    AKA - you should try that on your scope to check the speed and the symmetry and see if it gets rid of the 'stick' problem.

    Setting fast slew rate for the pin ::#define ap 5 ?

    Were I/O changes tied to F_BUS or not? Change F_BUS here: I:\arduino-1.8.1\hardware\teensy\avr\cores\teensy3\kinetis.h
    #if (F_CPU == 240000000)
    #define F_PLL 240000000
    #ifndef F_BUS
    #define F_BUS 60000000
    //#define F_BUS 80000000 // uncomment these to try peripheral overclocking
    //#define F_BUS 120000000 // all the usual overclocking caveats apply...
    #endif
    #define F_MEM 30000000

  7. #7
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,323

  8. #8
    Junior Member
    Join Date
    Sep 2015
    Location
    Brooklyn
    Posts
    9
    Thanks to everyone for their quick and helpful replies!

    My scope's bandwidth is 100MHz, so I wasn't as worried about the sine-not-square nature of the wave as much as I was worried about the "gaps" in the pulse train. I hadn't realized my scope's bandwidth might be at issue there as well.

    Unfortunately I'm on a short deadline trying to get something crazy to work (generating FPD-Link III video signal for an automotive display - I need a 60MHz pixel clock), so I left the 3.6 on the bench yesterday while I looked into RasPi solutions.

    I'll be sure to update here if I get any further with the 3.6. Thanks again for the quick help!

    AKA

  9. #9
    Quote Originally Posted by AKA View Post
    Thanks to everyone for their quick and helpful replies!

    My scope's bandwidth is 100MHz, so I wasn't as worried about the sine-not-square nature of the wave as much as I was worried about the "gaps" in the pulse train. I hadn't realized my scope's bandwidth might be at issue there as well.

    Unfortunately I'm on a short deadline trying to get something crazy to work (generating FPD-Link III video signal for an automotive display - I need a 60MHz pixel clock), so I left the 3.6 on the bench yesterday while I looked into RasPi solutions.

    I'll be sure to update here if I get any further with the 3.6. Thanks again for the quick help!

    AKA
    Just a quick note for future readers:

    How to clear up the lopsided timing and see exactly how fast you can go: Take the 'while' loop and all of its contents, and put it at the end of setup() - and have nothing in loop(). It won't be 100% perfect, but that huge gap will go away.

    To get closer to perfect, cli(); before the 'while' loop starts.

    Mind you, doing so will make your Teensy blast that pin as fast as it can. You may see that the signal doest get to rise all the way because there isn't enough time (try a pair of delayMicroseconds(10); first, after a HIGH and then after a LOW, to see if that improves the situation) But, you may have trouble trying to talk to it again (like, to load a new sketch!) In those cases, when it seems unwilling to receive an upload, even after pressing the Program Mode button, switch to a different USB port and then try the upload.

Posting Permissions

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