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

Thread: What peripherals are affected by the undocumented 24 MHz OSC circuit on Teensy 4.0?

  1. #1
    Junior Member
    Join Date
    Aug 2019
    Posts
    13

    What peripherals are affected by the undocumented 24 MHz OSC circuit on Teensy 4.0?

    From Teensyduino's cores/teensy4/startup.c:

    Code:
     // ARM SysTick is used for most Ardiuno timing functions, delay(), millis(),
     // micros().  SysTick can run from either the ARM core clock, or from an
     // "external" clock.  NXP documents it as "24 MHz XTALOSC can be the external
     // clock source of SYSTICK" (RT1052 ref manual, rev 1, page 411).  However,
     // NXP actually hid an undocumented divide-by-240 circuit in the hardware, so
     // the external clock is really 100 kHz.  We use this clock rather than the
     // ARM clock, to allow SysTick to maintain correct timing even when we change
     // the ARM clock to run at different speeds.
     #define SYSTICK_EXT_FREQ 100000
    I'm curious how this was even discovered, but more to the point I'd like to know why SysTick seems to be the only affected peripheral if this circuit sits in the hardware.

    For example, same file, in void ResetHandler(void), the PIT/GPT and UART clock muxes are configured to use this same 24 MHz XTALOSC without divisors:

    Code:
         // Configure clocks
         // TODO: make sure all affected peripherals are turned off!
         // PIT & GPT timers to run from 24 MHz clock (independent of CPU speed)
         CCM_CSCMR1 = (CCM_CSCMR1 & ~CCM_CSCMR1_PERCLK_PODF(0x3F)) | CCM_CSCMR1_PERCLK_CLK_SEL;
         // UARTs run from 24 MHz clock (works if PLL3 off or bypassed)
         CCM_CSCDR1 = (CCM_CSCDR1 & ~CCM_CSCDR1_UART_CLK_PODF(0x3F)) | CCM_CSCDR1_UART_CLK_SEL;
    And then in cores/teensy4/HardwareSerial.cpp the UART devices assume a bus frequency of 24 MHz (not 100 kHz) to compute an appropriate divisor and over-sample rate:

    Code:
     #define UART_CLOCK 24000000
    ...
     void HardwareSerial::begin(uint32_t baud, uint16_t format)
     {
         //printf("HardwareSerial begin\n");
         float base = (float)UART_CLOCK / (float)baud;
         float besterr = 1e20;
         int bestdiv = 1;
         int bestosr = 4;
         for (int osr=4; osr <= 32; osr++) {
             float div = base / (float)osr;
             int divint = (int)(div + 0.5f);
             if (divint < 1) divint = 1;
             else if (divint > 8191) divint = 8191;
             float err = ((float)divint - div) / div;
             if (err < 0.0f) err = -err;
             if (err <= besterr) {
                 besterr = err;
                 bestdiv = divint;
                 bestosr = osr;
             }
         }
    Obviously the UARTs work quite well on Teensy 4.0, so what gives? Why can SysTick and UART both use the same external 24 MHz OSC, yet only one of them has to account for this divide-by-240 circuit?

  2. #2
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    7,904
    Sorry I am not really sure what you are asking and what information you are trying to understand.


    Note: I have not done much of anything with the SYSTICK code other than use results so not much help there, maybe others who have played with it will chime in.

    As for the timers used by sub-systems.

    They are controlled by the CCM module. See the CCM Clock Tree, in my version of manual about page 1016 and and which clock is used and which dividers are by settings in a few registers.
    As you mentioned the PIT/GPT timers run off of 24mhz clock as we currently set the CCM_CSCMR1_PERCLK_CLK_SEL,

    I have a Pull Request from awhile ago that for example allowed us to change that and have the IntervalTimer run at a faster speed.
    That is if a sketch did: CCM_CSCMR1 &= ~CCM_CSCMR1_PERCLK_CLK_SEL;
    Those clocks would run at the same speed as ADC/XBAR or ARM Core Clock / value in CBCDR(IPG_PODF) setting (default to 4). So 600mhz the timers would run at 150mhz.
    Again not sure if this will be incorporated or not. But @luni has timer library that does handle the different settings.

    Again Hardware Serial, currently is assuming the CCM_CSCDR1_UART_CLK_SEL,
    It started out that way, when Paul first started the core. When I did the Hardware Serial class code I just used it. It could be enhanced to make it more flexible, by having it also read
    the appropriate CCM settings and compute the the appropriate BAUD rate conversions. I believe the other option was to use the pll3_sw_clk which unless in bypass (CCM_PLL3_BYP) will be 480mhz / 6 = 80mhz (and of course we could divide this again by the CSCDR1(UART_CLK_PODR) which defaults to 1...

    As for what other things can run off of the 24mhz clock, again look the the Clock Tree and you will see lots of gates showing as one option OSC...

    Not sure if this helps or not.

  3. #3
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    23,030
    Quote Originally Posted by ardnew View Post
    I'm curious how this was even discovered
    When I first tried using Systick (about 2 years ago, on the 1052 chip, months before we started the Teensy 4 beta test) is was pretty obviously running much slower than expected when configured for the "external" clock. At the time very little of the core library code was written, so it took quite a bit of testing to figure out the ratio was a fixed divide by 240.

    Since then, NXP has updated their documentation. This now appears in the reference manual.

    Click image for larger version. 

Name:	sc.png 
Views:	9 
Size:	157.6 KB 
ID:	22165

    I wanted to run Systick from the external clock so we could (maybe) someday have consistent Arduino timing functions even if the CPU clock speed is dynamically changed. Sadly, NXP didn't give us a glitchless mux for the peripheral clock, so work on seamless dynamic clock scaling hasn't happened. But that's still a dream of mine... to someday have really nice support for dynamically changing the clock speed at runtime. That's why I put so much effort into using the Systick external clock.


    Obviously the UARTs work quite well on Teensy 4.0, so what gives? Why can SysTick and UART both use the same external 24 MHz OSC, yet only one of them has to account for this divide-by-240 circuit?
    This clock divider is only for Systick. At the time, NXP didn't document anything about Systick. They still have very little about it, since it's technically part of the M7 core they license from ARM. It's fully documented in ARM's architecture reference manual, except that the source of the "external" clock is vendor defined and it not even strictly required to be implemented.

    All the other peripherals which NXP documents as getting the 24 MHz oscillator clock (when configured to do so) do indeed get 24 MHz.

  4. #4
    Junior Member
    Join Date
    Aug 2019
    Posts
    13
    Quote Originally Posted by PaulStoffregen View Post
    Since then, NXP has updated their documentation. This now appears in the reference manual.
    This must come from the 1052 documentation you mention in the comment.

    Quote Originally Posted by PaulStoffregen View Post
    At the time, NXP didn't document anything about Systick.
    The current 1062 reference manual (IMXRT1060RM Rev.2 12/2019) still contains precisely 0 instances of the term "SysTick" across 3437 pages!

    Quote Originally Posted by PaulStoffregen View Post
    That's why I put so much effort into using the Systick external clock.
    I can see a lot of effort has also been put into scaling the core clock to a given frequency with uint32_t set_arm_clock(uint32_t frequency) -- even if we can't yet take advantage of it. NXP's own 1062 SDK has no such generalized functionality as this routine, very nice!

    Quote Originally Posted by PaulStoffregen View Post
    All the other peripherals which NXP documents as getting the 24 MHz oscillator clock (when configured to do so) do indeed get 24 MHz.

    Perfect, exactly what I was asking. Thanks a bunch for all the insight.

  5. #5
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    7,904
    Quote Originally Posted by ardnew View Post
    The current 1062 reference manual (IMXRT1060RM Rev.2 12/2019) still contains precisely 0 instances of the term "SysTick" across 3437 pages!
    Mine does, in the exact section that Paul mentioned: 13.3.2.1 (Page 986)

  6. #6
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    23,030
    Quote Originally Posted by ardnew View Post
    The current 1062 reference manual (IMXRT1060RM Rev.2 12/2019) still contains precisely 0 instances of the term "SysTick" across 3437 pages!
    Maybe your search was case sensitive? It appears on page 986 in all caps. You can see "SYSTICK" appears twice in the 13.3.2.1 screen grab I posted on msg #3 above.

    But as I mentioned earlier, SysTick is part of the ARM Cortex-M7 which NXP licenses from ARM. If you want the details, ARM's document number is "DDI0403E" (Google with that number to get the PDF). Turn to page 676 for the detailed SysTick documentation.

  7. #7
    Junior Member
    Join Date
    Aug 2019
    Posts
    13
    Ah, indeed my mistake, I was searching case-sensitive (and assumed the screenshot was from the 1052 manual referenced in the source code).

    Thanks again guys

Posting Permissions

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