pixelmatix / SmartMatrix

SmartMatrix Library for Teensy 3, Teensy 4, and ESP32
http://docs.pixelmatix.com/SmartMatrix
611 stars 161 forks source link

Teensy 4: Default FlexIO clock configuration is invalid #156

Open ardnew opened 2 years ago

ardnew commented 2 years ago

In the Teensy 4 sources, the code that initializes the FLEXIO2 peripheral configures an invalid clock setting according to the IMXRT1062 reference manual. I'm curious if this setting is intentional and is actually being accepted, or if its code that has just always been there and hasn't really been verified.

The code in question is from MatrixTeensy4Hub75Refresh_Impl.h:

template <int refreshDepth, int matrixWidth, int matrixHeight, unsigned char panelType, uint32_t optionFlags>
FLASHMEM void SmartMatrixRefreshT4<refreshDepth, matrixWidth, matrixHeight, panelType, optionFlags>::hardwareSetup() {
    // ...

    // Configure FlexIO clock source
    // FlexIO clock is independent from CPU and bus clocks (not affected by CPU overclocking)
    pFlex->setClockSettings(3, 0, 0); // 480 MHz PLL3_SW_CLK clock

    // ...
}

The problem is with the two clock dividers, given the 480 MHz PLL3_SW_CLK mux selection. A value of 0 means a divider of 1, so altogether this is attempting to configure FLEXIO2 clock root as: 480MHz / (1 * 1) = 480MHz.

However, according to the i.MX RT1060 Processor Reference Manual, Rev. 2, 12/2019, Table 14-5. System Clock Frequency Values, page 1032, the maximum clock frequency for all three FlexIO peripherals is 120 MHz (FLEXIO2 and FLEXIO3 share the same clock source):

flexio-maxfreq

This means the minimum allowable dividers — with 480 MHz source clock frequency — must have a product no less than 4, so they must be either 1 * 4 or 2 * 2. The code could thus be changed to:

    // Configure FlexIO clock source (120 MHz)
    // FlexIO clock is independent from CPU and bus clocks (not affected by CPU overclocking)
    pFlex->setClockSettings(3, 1, 1); // 480 MHz PLL3_SW_CLK clock, CLK_PRED=2, CLK_PODF=2

The original FlexIO driver from KurtE, as noted in its comments, makes no attempt to verify the given clock settings, so it will happily try to use invalid settings.

embedded-creations commented 2 years ago

@easone do you have any thoughts on this?

easone commented 2 years ago

The FlexIO peripheral seems to run happily with a 480 MHz clock as far as I can tell. From my testing, increasing the FlexIO clock increases the speed at which the shifters trigger when data is copied into their buffers, which reduces delays and improves display speed slightly. I guess the manual lists a conservative maximum speed for FlexIO and it can actually be overclocked.

I will say that the 480 MHz clock doesn't seem to work perfectly with the CPU speed below 600 MHz. Some other folks have had issues as documented here: https://forum.pjrc.com/threads/67815-FlexIO-quot-Extra-quot-clock-cycle-on-8080-parallel-setup

I don't know whether a lower FlexIO clock speed would enable running the CPU slower but it seems possible... If for some reason you wanted to reduce the FlexIO clock speed, you would need to adjust the timing constants in the MatrixHardware header accordingly.

easone commented 2 years ago

Just confirmed that reducing the FlexIO clock speed from 480 to 240 MHz works as expected and allows the CPU speed to be reduced as low as 396 MHz. Apart from some low power application, I don't see why this provides any benefit...

For posterity: to use the 240 MHz clock speed, make the following changes:

ardnew commented 2 years ago

I think by you comparing the behavior of FlexIO timers relative to how they behave when configured with a valid clock (per RM) is a legitimate test, verifying it is indeed using the 480 MHz its configured with. You verified this with FLEXIO2 only? Curious then where the 120 MHz comes from — perhaps one of the FlexIO functional modes, or maybe one of the possible input trigger sources, or its outputs, are the bottleneck?

I discovered the 120 MHz limitation by using NXP's MCUXpresso SDK (Eclipse IDE) while trying to configure a project equivalent to the settings used in this repo. Their "Clocks" configuration tool refuses to accept — in every way I know to try — the FlexIO PRED/PODF prescalars equal 1; or, if you hardcode any value greater than 120 MHz as a FlexIO clock root, it will flag it as an error and refuse to generate code for you. Pretty helpful tool, huh? 👎🏻

I am intending to mimic much of this project in terms of its DMA-driven FlexIO config, so I too will try using a 480 MHz clock and hope for the best.

Anyway, thanks for verifying this on a real device @easone. Sounds like this issue can probably be closed.

ardnew commented 2 years ago

Also, considering this project is using a completely undocumented extra FlexIO shifter, it really shouldn't be surprising that the FlexIO clock roots are capable of a greater-than-documented frequency...

easone commented 2 years ago

There are many things undocumented about FlexIO, unfortunately. For example if you read the FLEXIO2_PARAM register after enabling FlexIO2, the value stored there indicates that there are 8 timers and 8 shifters on the chip rather than 4 as stated in the manual. As far as I'm aware, the extra four shifters function normally in most respects, except I think they cannot be used with DMA. It was a bit of a happy accident to discover that we could use this for SmartMatrix addressing.