From 6728e7ec9fe9bfe0cd73e6a8fde307d388f2484a Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Fri, 7 Feb 2025 14:25:52 +0000 Subject: [PATCH 1/2] Add clock_configure_mhz Trades off accuracy (only gets to +/- 1MHz) for reduced code size as it doesn't need 64 bit division --- src/rp2_common/hardware_clocks/clocks.c | 14 ++++++++++++++ .../hardware_clocks/include/hardware/clocks.h | 16 ++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/rp2_common/hardware_clocks/clocks.c b/src/rp2_common/hardware_clocks/clocks.c index 2d41c73d2..8b6375365 100644 --- a/src/rp2_common/hardware_clocks/clocks.c +++ b/src/rp2_common/hardware_clocks/clocks.c @@ -123,6 +123,20 @@ bool clock_configure(clock_handle_t clock, uint32_t src, uint32_t auxsrc, uint32 return true; } +bool clock_configure_mhz(clock_handle_t clock, uint32_t src, uint32_t auxsrc, uint16_t src_freq_mhz, uint16_t freq_mhz) { + assert(src_freq_mhz >= freq_mhz); + + if (freq_mhz > src_freq_mhz) + return false; + + uint32_t div = (uint32_t)((((uint32_t) src_freq_mhz) << CLOCKS_CLK_GPOUT0_DIV_INT_LSB) / freq_mhz); + uint32_t actual_freq = (uint32_t) ((((uint32_t) src_freq_mhz) << CLOCKS_CLK_GPOUT0_DIV_INT_LSB) / div) * MHZ; + + clock_configure_internal(clock, src, auxsrc, actual_freq, div); + // Store the configured frequency + return true; +} + void clock_configure_int_divider(clock_handle_t clock, uint32_t src, uint32_t auxsrc, uint32_t src_freq, uint32_t int_divider) { clock_configure_internal(clock, src, auxsrc, src_freq / int_divider, int_divider << CLOCKS_CLK_GPOUT0_DIV_INT_LSB); } diff --git a/src/rp2_common/hardware_clocks/include/hardware/clocks.h b/src/rp2_common/hardware_clocks/include/hardware/clocks.h index 68f4b1a50..342cc841a 100644 --- a/src/rp2_common/hardware_clocks/include/hardware/clocks.h +++ b/src/rp2_common/hardware_clocks/include/hardware/clocks.h @@ -318,6 +318,22 @@ typedef clock_num_t clock_handle_t; */ bool clock_configure(clock_handle_t clock, uint32_t src, uint32_t auxsrc, uint32_t src_freq, uint32_t freq); +/*! \brief Configure the specified clock to +/- 1MHz + * \ingroup hardware_clocks + * + * This function differs from clock_configure in that it does not configure the clocks as accurately, + * but therefore doesn't need to bring in 64-bit division functions, reducing the code size. + * + * See the tables in the description for details on the possible values for clock sources. + * + * \param clock The clock to configure + * \param src The main clock source, can be 0. + * \param auxsrc The auxiliary clock source, which depends on which clock is being set. Can be 0 + * \param src_freq_mhz Frequency of the input clock source in MHz + * \param freq_mhz Requested frequency in MHz + */ +bool clock_configure_mhz(clock_handle_t clock, uint32_t src, uint32_t auxsrc, uint16_t src_freq_mhz, uint16_t freq_mhz); + /*! \brief Configure the specified clock to use the undivided input source * \ingroup hardware_clocks * From 4a9584ba07faf07552f23651deaf07e4c42fd85f Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Mon, 24 Feb 2025 16:18:45 +0000 Subject: [PATCH 2/2] Review fixup Fixup for dividers 1.0-2.0 on RP2040 Improve docs --- src/rp2_common/hardware_clocks/clocks.c | 6 ++++++ .../hardware_clocks/include/hardware/clocks.h | 11 ++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/rp2_common/hardware_clocks/clocks.c b/src/rp2_common/hardware_clocks/clocks.c index 8b6375365..d1bbff861 100644 --- a/src/rp2_common/hardware_clocks/clocks.c +++ b/src/rp2_common/hardware_clocks/clocks.c @@ -130,6 +130,12 @@ bool clock_configure_mhz(clock_handle_t clock, uint32_t src, uint32_t auxsrc, ui return false; uint32_t div = (uint32_t)((((uint32_t) src_freq_mhz) << CLOCKS_CLK_GPOUT0_DIV_INT_LSB) / freq_mhz); +#if PICO_RP2040 + // on RP2040 only clock divider of 1, or >= 2 are supported + if (div < (2u << CLOCKS_CLK_GPOUT0_DIV_INT_LSB)) { + div = (1u << CLOCKS_CLK_GPOUT0_DIV_INT_LSB); + } +#endif uint32_t actual_freq = (uint32_t) ((((uint32_t) src_freq_mhz) << CLOCKS_CLK_GPOUT0_DIV_INT_LSB) / div) * MHZ; clock_configure_internal(clock, src, auxsrc, actual_freq, div); diff --git a/src/rp2_common/hardware_clocks/include/hardware/clocks.h b/src/rp2_common/hardware_clocks/include/hardware/clocks.h index 342cc841a..7602f2bdd 100644 --- a/src/rp2_common/hardware_clocks/include/hardware/clocks.h +++ b/src/rp2_common/hardware_clocks/include/hardware/clocks.h @@ -322,8 +322,17 @@ bool clock_configure(clock_handle_t clock, uint32_t src, uint32_t auxsrc, uint32 * \ingroup hardware_clocks * * This function differs from clock_configure in that it does not configure the clocks as accurately, - * but therefore doesn't need to bring in 64-bit division functions, reducing the code size. + * but therefore doesn't need to bring in 64-bit division functions, reducing the code size if 64-bit + * division is not otherwise used by the application. * + * \if rp2350_specific + * Note: The RP2350 clock hardware supports divisors from 1.0->65536.0 in steps of 1/65536 + * + * \endif + * \if rp2040_specific + * Note: The RP2040 clock hardware only supports divisors of exactly 1.0 or 2.0->16777216.0 in steps of 1/256 + * \endif + * * See the tables in the description for details on the possible values for clock sources. * * \param clock The clock to configure