Skip to content

rp2/main.c: Set the default clock frequency at boot. #13718

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 20, 2024

Conversation

robert-hh
Copy link
Contributor

As a side effect, the peripheral clock will be set to 48Mhz and both UART and I2C baud rates will not be affected any more by CPU speed changes using machine.freq().

With the change the UART baud rate range is 50 to 3_000_000. That is a somewhat breaking change since baud rates beyond 3MBaud are not supported any more.

Addresses the discussion #13679.

ports/rp2/main.c Outdated
@@ -223,6 +227,12 @@ int main(int argc, char **argv) {
soft_timer_deinit();
gc_sweep_all();
mp_deinit();
// Reset the MCU frequency
set_sys_clock_khz(125000, false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure it should reset the frequency on soft reset. Soft reset is about resetting all the Python state, whereas it's best to leave a lot of the hardware state as-is. Eg the WiFi is still connected. Eg on stm32 the frequency is not reset on soft reset.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The intention here is to have the device at the same state as when entering the for (;;) { loop. If code e.g. in boot.py and main.py changes the frequency, it will still do it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other discussion which is open in the forum is, whether the peripheral clock should be set to 48MHz. Or should it better follow the CPU freq change. That can be implemented as well by changing the code for machine.freq(). My preference was for the more conservative and less surprising state, but others missed the high speed options.

@Gadgetoid
Copy link
Contributor

Could this possibly also include some accommodation for #8208

I'd very much like a board config option to change that default, please!

@robert-hh robert-hh force-pushed the rp2_clock_init branch 2 times, most recently from e5a8965 to af7470a Compare March 7, 2024 15:09
Copy link

github-actions bot commented Jun 1, 2024

Code size report:

   bare-arm:    +0 +0.000% 
minimal x86:    +0 +0.000% 
   unix x64:    +0 +0.000% standard
      stm32:    +0 +0.000% PYBV10
     mimxrt:    +0 +0.000% TEENSY40
        rp2:  +136 +0.015% RPI_PICO_W
       samd:    +0 +0.000% ADAFRUIT_ITSYBITSY_M4_EXPRESS

@robert-hh
Copy link
Contributor Author

@dpgeorge I dropped resetting the clock at soft reboot. Only at cold boot the clock it set to have the side effect of changing the peripheral frequency to 48MHz.

@robert-hh robert-hh changed the title rp2/main.c: Set the default clock frequency at boot and soft reset. rp2/main.c: Set the default clock frequency at boot. Jun 5, 2024
// 0,
// CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS,
// SYS_CLK_KHZ * KHZ,
// SYS_CLK_KHZ * KHZ);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what this commented-out code is aiming to do. When set_sys_clock_khz() is called, does that update the PERI clock or not?

Copy link
Contributor Author

@robert-hh robert-hh Jul 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The whole change is about the inconsistency, that when machine.freq() is called to change the frequency, then PERI clock is set to 48 MHz as result of calling set_sys_clock_khz(). The change I suggested would set PERI clock always to 48MHz. Then, changing the CPU frequency would not affect e.g. the UART or PWM settings, at the penalty of limiting the peripherals baud rates.

This commented code is about the alternative suggestion to set PERI clock always to the CPU clock. Then there would be changes to the baud rates of the peripherals when changing the CPU clock, but at known rates. I added that code here just to recall it,

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I understand more.

So without this PR (ie current master), what is the value of PERI at start up, is it the system clock, or system clock divided by some factor?

Note that machine.freq() takes multiple arguments to specify the frequency of the buses (see eg stm32 port). So maybe it's a good idea to allow the user to specify the PERI clock as the second (optional) argument to machine.freq()? Something like:

machine.freq(sys, peri=48000000)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the moment the PERI freq at boot is the system clock 125Mhz and it will be set to 48Mhz when calling machine.freq(n).

Note that machine.freq() takes multiple arguments to specify the frequency of the buses (see eg stm32 port).

Actually, the stm32 port lost this feature with commit 7d39db2. machine.freq() takes just 1 argument.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed machine.freq() to have a second boolean type agrument. If set to False or omitted, the peripheral frequency will be 48MHz, which is the default value now at boot. If set to True, the peripheral frequency is the same as the MCU. The clock section for the peripheral clock has no divider. The documentation is wrong. So the peripheral clock can only be one of the other clock sources, like USB clock or SYS clock.
The API could also be changed to accept a frequency instead of a boolean value, with 48_000_000 and the value of the first argument as the permitted values. But then, an error check & message would have to be added.
As a required side change, machine.freq() now accepts up to 4 arguments. I made a separate PR for that 1 char change as well.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The API could also be changed to accept a frequency instead of a boolean value, with 48_000_000 and the value of the first argument as the permitted values. But then, an error check & message would have to be added.

It looks like this is how you ended up implementing it (ie not as a boolean). I think what you did -- specifying a freq -- is the right way to do it. That way is more general, and more consistent with stm32.

But do you think it's better to make the peri frequency a keyword-only argument? That forces the user to be explicit and makes it even more future proof/general. Eg machine.freq(125000000, peri=48000000).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But do you think it's better to make the peri frequency a keyword-only argument? That forces the user to be explicit and makes it even more future proof/general. Eg machine.freq(125000000, peri=48000000).

The Python API is is extmod/modmachine.c. Making peri=xxx a keyword only argument would either require to change that or to move the API back to the rp2 port.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Python API is is extmod/modmachine.c. Making peri=xxx a keyword only argument would either require to change that

Yes, if we want to make this a keyword-only argument, we'd need to change the API in extmod/modmachine.c. We can do that if we think it's the best option. All other ports can remain as they are (stm32 accepting 4 positional args, all other ports accepting 1 positional arg).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not know if it the best option, and it's a larger change. The STM32 port does not have the keywords.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, let's leave it as a positional argument.

@robert-hh robert-hh force-pushed the rp2_clock_init branch 2 times, most recently from f35c4a9 to c8e4511 Compare July 6, 2024 11:03
Copy link

codecov bot commented Jul 6, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 98.43%. Comparing base (55b2720) to head (4b3e419).

Additional details and impacted files
@@           Coverage Diff           @@
##           master   #13718   +/-   ##
=======================================
  Coverage   98.43%   98.43%           
=======================================
  Files         161      161           
  Lines       21281    21281           
=======================================
  Hits        20948    20948           
  Misses        333      333           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@robert-hh robert-hh force-pushed the rp2_clock_init branch 2 times, most recently from 9b2a6a9 to 7c53d70 Compare July 8, 2024 11:35
mp_obj_new_int(mp_hal_get_cpu_freq()),
mp_obj_new_int(clock_get_hz(clk_peri)),
};
return mp_obj_new_tuple(MP_ARRAY_SIZE(tuple), tuple);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning a 2-tuple here is a big breaking change... not sure how to handle this. My suggestion for now is to just retain the old behaviour here (ie just return the CPU freq), and we can work out how to query the peri frequency in the future (if anyone ever needs it).

(I know stm32 returns a tuple, but a lot of code will be written already for rp2 that expects this to return a single integer.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keeping the old behavior is easy. That's why it's a separate commit.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for removing the additional commit (and returning just a single int).

As a side effect, the peripheral clock will be set to 48Mhz and both UART
and I2C will not be affected by CPu speed changed using `machine.freq()`.

With the change the UART baud rate range is 50 to 3_000_000.

Signed-off-by: robert-hh <robert@hammelrath.com>
By default, the peripheral clock for UART and SPI is set to 48 MHz and will
not be affected by the MCU clock change.  This can be changed by a second
argument to `machine.freq(freq, peripheral_freq)`.  The second argument
must be either 48 MHz or identical with the first argument.

Note that UART and SPI baud rates may have to be re-configured after
changing the MCU clock.

Signed-off-by: robert-hh <robert@hammelrath.com>
@dpgeorge dpgeorge merged commit 7270b87 into micropython:master Aug 20, 2024
9 checks passed
@dpgeorge
Copy link
Member

Could this possibly also include some accommodation for #8208

I'd very much like a board config option to change that default, please!

@Gadgetoid that was not done in this PR (a config option for default CPU freq). That should be pretty easy to do, but someone needs to do it 😄

@robert-hh
Copy link
Contributor Author

Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy