From d0bc42796b1fce183f2bb5ddfdde05bd7c9f6b18 Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Wed, 10 Jul 2024 16:01:16 +0100 Subject: [PATCH] rp2/clocks_extra: Update runtime_clocks_init based on new pico-sdk. Signed-off-by: Damien George --- ports/rp2/CMakeLists.txt | 3 +- ports/rp2/clocks_extra.c | 70 +++++++++++++++++++++++++++++++--------- ports/rp2/clocks_extra.h | 2 +- ports/rp2/modmachine.c | 2 +- 4 files changed, 59 insertions(+), 18 deletions(-) diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index 0d5b10f337..40672a8b31 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -181,6 +181,7 @@ set(PICO_SDK_COMPONENTS cmsis_core hardware_adc hardware_base + hardware_boot_lock hardware_clocks hardware_dma hardware_flash @@ -487,7 +488,7 @@ target_compile_options(${MICROPY_TARGET} PRIVATE target_link_options(${MICROPY_TARGET} PRIVATE -Wl,--defsym=__micropy_c_heap_size__=${MICROPY_C_HEAP_SIZE} -Wl,--wrap=dcd_event_handler - -Wl,--wrap=clocks_init + -Wl,--wrap=runtime_init_clocks ) # Apply optimisations to performance-critical source code. diff --git a/ports/rp2/clocks_extra.c b/ports/rp2/clocks_extra.c index e2c97962cb..73def24b80 100644 --- a/ports/rp2/clocks_extra.c +++ b/ports/rp2/clocks_extra.c @@ -13,22 +13,36 @@ #include "hardware/xosc.h" #include "hardware/irq.h" #include "hardware/gpio.h" +#include "hardware/ticks.h" +#if PICO_RP2040 +// The RTC clock frequency is 48MHz divided by power of 2 (to ensure an integer +// division ratio will be used in the clocks block). A divisor of 1024 generates +// an RTC clock tick of 46875Hz. This frequency is relatively close to the +// customary 32 or 32.768kHz 'slow clock' crystals and provides good timing resolution. #define RTC_CLOCK_FREQ_HZ (USB_CLK_KHZ * KHZ / 1024) +#endif -// Wrap the SDK's clocks_init() function to save code size -void __wrap_clocks_init(void) { - clocks_init_optional_usb(true); +static void start_all_ticks(void) { + uint32_t cycles = clock_get_hz(clk_ref) / MHZ; + // Note RP2040 has a single tick generator in the watchdog which serves + // watchdog, system timer and M0+ SysTick; The tick generator is clocked from clk_ref + // but is now adapted by the hardware_ticks library for compatibility with RP2350 + // npte: hardware_ticks library now provides an adapter for RP2040 + + for (int i = 0; i < (int)TICK_COUNT; ++i) { + tick_start((tick_gen_num_t)i, cycles); + } } -// Copy of clocks_init() from pico-sdk, with USB +// Wrap the SDK's clocks_init() function to save code size +void __wrap_runtime_init_clocks(void) { + runtime_init_clocks_optional_usb(true); +} + +// Copy of runtime_init_clocks() from pico-sdk, with USB // PLL and clock init made optional (for light sleep wakeup). -void clocks_init_optional_usb(bool init_usb) { - // Start tick in watchdog, the argument is in 'cycles per microsecond' i.e. MHz - watchdog_start_tick(XOSC_KHZ / KHZ); - - // Modification: removed FPGA check here - +void runtime_init_clocks_optional_usb(bool init_usb) { // Disable resus that may be enabled from previous software clocks_hw->resus.ctrl = 0; @@ -46,14 +60,26 @@ void clocks_init_optional_usb(bool init_usb) { } /// \tag::pll_init[] - pll_init(pll_sys, PLL_COMMON_REFDIV, PLL_SYS_VCO_FREQ_KHZ * KHZ, PLL_SYS_POSTDIV1, PLL_SYS_POSTDIV2); + pll_init(pll_sys, PLL_COMMON_REFDIV, PLL_SYS_VCO_FREQ_HZ, PLL_SYS_POSTDIV1, PLL_SYS_POSTDIV2); if (init_usb) { - pll_init(pll_usb, PLL_COMMON_REFDIV, PLL_USB_VCO_FREQ_KHZ * KHZ, PLL_USB_POSTDIV1, PLL_USB_POSTDIV2); + pll_init(pll_usb, PLL_COMMON_REFDIV, PLL_USB_VCO_FREQ_HZ, PLL_USB_POSTDIV1, PLL_USB_POSTDIV2); } /// \end::pll_init[] // Configure clocks - // CLK_REF = XOSC (usually) 12MHz / 1 = 12MHz + + // todo amy, what is this N1,2,4 meant to mean? + // RP2040 CLK_REF = XOSC (usually) 12MHz / 1 = 12MHz + // RP2350 CLK_REF = XOSC (XOSC_MHZ) / N (1,2,4) = 12MHz + + // clk_ref aux select is 0 because: + // + // - RP2040: no aux mux on clk_ref, so this field is don't-care. + // + // - RP2350: there is an aux mux, but we are selecting one of the + // non-aux inputs to the glitchless mux, so the aux select doesn't + // matter. The value of 0 here happens to be the sys PLL. + clock_configure(clk_ref, CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC, 0, // No aux mux @@ -85,18 +111,32 @@ void clocks_init_optional_usb(bool init_usb) { USB_CLK_KHZ * KHZ, USB_CLK_KHZ * KHZ); + #if HAS_RP2040_RTC // CLK RTC = PLL USB 48MHz / 1024 = 46875Hz clock_configure(clk_rtc, 0, // No GLMUX CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB, USB_CLK_KHZ * KHZ, RTC_CLOCK_FREQ_HZ); + #endif - // CLK PERI = clk_sys. Used as reference clock for Peripherals. No dividers so just select and enable - // Normally choose clk_sys or clk_usb + // CLK PERI = clk_sys. Used as reference clock for UART and SPI serial. clock_configure(clk_peri, 0, CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS, SYS_CLK_KHZ * KHZ, SYS_CLK_KHZ * KHZ); + + #if PICO_RP2350 + // CLK_HSTX = clk_sys. Transmit bit clock for the HSTX peripheral. + clock_configure(clk_hstx, + 0, + CLOCKS_CLK_HSTX_CTRL_AUXSRC_VALUE_CLK_SYS, + SYS_CLK_KHZ * KHZ, + SYS_CLK_KHZ * KHZ); + #endif + + // Finally, all clocks are configured so start the ticks + // The ticks use clk_ref so now that is configured we can start them + start_all_ticks(); } diff --git a/ports/rp2/clocks_extra.h b/ports/rp2/clocks_extra.h index 40f77f53bd..7d630e5088 100644 --- a/ports/rp2/clocks_extra.h +++ b/ports/rp2/clocks_extra.h @@ -28,6 +28,6 @@ #include "hardware/clocks.h" -void clocks_init_optional_usb(bool init_usb); +void runtime_init_clocks_optional_usb(bool init_usb); #endif // MICROPY_INCLUDED_RP2_CLOCKS_EXTRA_H diff --git a/ports/rp2/modmachine.c b/ports/rp2/modmachine.c index 798078faf6..2faf0bc6f8 100644 --- a/ports/rp2/modmachine.c +++ b/ports/rp2/modmachine.c @@ -259,7 +259,7 @@ static void mp_machine_lightsleep(size_t n_args, const mp_obj_t *args) { rosc_hw->ctrl = ROSC_CTRL_ENABLE_VALUE_ENABLE << ROSC_CTRL_ENABLE_LSB; // Bring back all clocks. - clocks_init_optional_usb(disable_usb); + runtime_init_clocks_optional_usb(disable_usb); MICROPY_END_ATOMIC_SECTION(my_interrupts); }