diff --git a/src/rp2_common/hardware_clocks/clocks.c b/src/rp2_common/hardware_clocks/clocks.c index 2d41c73d2..d1bbff861 100644 --- a/src/rp2_common/hardware_clocks/clocks.c +++ b/src/rp2_common/hardware_clocks/clocks.c @@ -123,6 +123,26 @@ 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); +#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); + // 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..7602f2bdd 100644 --- a/src/rp2_common/hardware_clocks/include/hardware/clocks.h +++ b/src/rp2_common/hardware_clocks/include/hardware/clocks.h @@ -318,6 +318,31 @@ 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 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 + * \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 *