diff --git a/clock_setup.c b/clock_setup.c deleted file mode 100644 index 6f40c17..0000000 --- a/clock_setup.c +++ /dev/null @@ -1,92 +0,0 @@ -/* this function was salvaged from pico-bootrom/bootrom/bootrom_main.c */ - -/** - * Copyright (c) 2021 Raspberry Pi (Trading) Ltd. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include - -// USB bootloader requires clk_sys and clk_usb at 48 MHz. For this to work, -// xosc must be running at 12 MHz. It is possible that: -// -// - No crystal is present (and XI may not be properly grounded) -// - xosc output is much greater than 12 MHz -// -// In this case we *must* leave clk_sys in a safe state, and ideally, never -// return from this function. This is because boards which are not designed to -// use USB will still enter the USB bootcode when booted with a blank flash. - -void _usb_clock_setup(void) { - // First make absolutely sure clk_ref is running: needed for resuscitate, - // and to run clk_sys while configuring sys PLL. Assume that rosc is not - // configured to run faster than clk_sys max (as this is officially out of - // spec) - // If user previously configured clk_ref to a different source (e.g. - // GPINx), then halted that source, the glitchless mux can't switch away - // from the dead source-- nothing we can do about this here. - rosc_hw->ctrl = ROSC_CTRL_ENABLE_VALUE_ENABLE << ROSC_CTRL_ENABLE_LSB; - hw_clear_bits(&clocks_hw->clk[clk_ref].ctrl, CLOCKS_CLK_REF_CTRL_SRC_BITS); - - // Resuscitate logic will switch clk_sys to clk_ref if it is inadvertently stopped - clocks_hw->resus.ctrl = - CLOCKS_CLK_SYS_RESUS_CTRL_ENABLE_BITS | - (CLOCKS_CLK_SYS_RESUS_CTRL_TIMEOUT_RESET - << CLOCKS_CLK_SYS_RESUS_CTRL_TIMEOUT_LSB); - - // Resetting PLL regs or changing XOSC range can glitch output, so switch - // clk_sys away before touching. Not worried about clk_usb as USB is held - // in reset. - hw_clear_bits(&clocks_hw->clk[clk_sys].ctrl, CLOCKS_CLK_SYS_CTRL_SRC_BITS); - while (!(clocks_hw->clk[clk_sys].selected & 1u)); - // rosc can not (while following spec) run faster than clk_sys max, so - // it's safe now to clear dividers in clkslices. - clocks_hw->clk[clk_sys].div = 0x100; // int 1 frac 0 - clocks_hw->clk[clk_usb].div = 0x100; - - // Try to get the crystal running. If no crystal is present, XI should be - // grounded, so STABLE counter will never complete. Poor designs might - // leave XI floating, in which case we may eventually drop through... in - // this case we rely on PLL not locking, and/or resuscitate counter. - // - // Don't touch range setting: user would only have changed if crystal - // needs it, and running crystal out of range can produce glitchy output. - // Note writing a "bad" value (non-aax) to RANGE has no effect. - xosc_hw->ctrl = XOSC_CTRL_ENABLE_VALUE_ENABLE << XOSC_CTRL_ENABLE_LSB; - while (!(xosc_hw->status & XOSC_STATUS_STABLE_BITS)); - - // Sys PLL setup: - // - VCO freq 1200 MHz, so feedback divisor of 100. Range is 400 MHz to 1.6 GHz - // - Postdiv1 of 5, down to 240 MHz (appnote recommends postdiv1 >= postdiv2) - // - Postdiv2 of 5, down to 48 MHz - // - // Total postdiv of 25 means that too-fast xtal will push VCO out of - // lockable range *before* clk_sys goes out of closure (factor of 1.88) - hw_set_bits(&resets_hw->reset, RESETS_RESET_PLL_SYS_BITS); - hw_clear_bits(&resets_hw->reset, RESETS_RESET_PLL_SYS_BITS); - while (!(resets_hw->reset_done & RESETS_RESET_DONE_PLL_SYS_BITS)); - pll_sys_hw->cs = 1u << PLL_CS_REFDIV_LSB; - pll_sys_hw->fbdiv_int = 100; - pll_sys_hw->prim = - (5u << PLL_PRIM_POSTDIV1_LSB) | - (5u << PLL_PRIM_POSTDIV2_LSB); - - // Power up VCO, wait for lock - hw_clear_bits(&pll_sys_hw->pwr, PLL_PWR_PD_BITS | PLL_PWR_VCOPD_BITS); - while (!(pll_sys_hw->cs & PLL_CS_LOCK_BITS)); - - // Power up post-dividers, which ungates PLL final output - hw_clear_bits(&pll_sys_hw->pwr, PLL_PWR_POSTDIVPD_BITS); - - // Glitchy switch of clk_usb, clk_sys aux to sys PLL output. - clocks_hw->clk[clk_sys].ctrl = 0; - clocks_hw->clk[clk_usb].ctrl = - CLOCKS_CLK_USB_CTRL_ENABLE_BITS | - (CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS - << CLOCKS_CLK_USB_CTRL_AUXSRC_LSB); - - // Glitchless switch of clk_sys to aux source (sys PLL) - hw_set_bits(&clocks_hw->clk[clk_sys].ctrl, CLOCKS_CLK_SYS_CTRL_SRC_BITS); - while (!(clocks_hw->clk[clk_sys].selected & 0x2u)); -} diff --git a/myboard.c b/myboard.c index 960c2ed..b895335 100644 --- a/myboard.c +++ b/myboard.c @@ -26,16 +26,90 @@ #include "tusb.h" #include +#include "hardware/pll.h" + /* This is a more streamlined alternative to the current pico-sdk based TinyUSB board support package. Sticking to C and avoiding all that C++ yields a much smaller executable. */ -void _usb_clock_setup(void); /* clock initialization routine borrowed from pico-bootrom */ +/* overhaul of clock_configure() from pico-sdk to use much less memory */ +bool simple_clock_configure(enum clock_index clk_index, uint32_t src, uint32_t auxsrc, bool glitchless) +{ + const uint32_t div = 0x100; /* always 1:1 ratio */ + + clock_hw_t *clock = &clocks_hw->clk[clk_index]; + + // If increasing divisor, set divisor before source. Otherwise set source + // before divisor. This avoids a momentary overspeed when e.g. switching + // to a faster source and increasing divisor to compensate. + if (div > clock->div) + clock->div = div; + + // If switching a glitchless slice (ref or sys) to an aux source, switch + // away from aux *first* to avoid passing glitches when changing aux mux. + // Assume (!!!) glitchless source 0 is no faster than the aux source. + if (glitchless) + { + hw_clear_bits(&clock->ctrl, CLOCKS_CLK_REF_CTRL_SRC_BITS); + while (!(clock->selected & 1u)); + } + // If no glitchless mux, cleanly stop the clock to avoid glitches + // propagating when changing aux mux. Note it would be a really bad idea + // to do this on one of the glitchless clocks (clk_sys, clk_ref). + else + { + hw_clear_bits(&clock->ctrl, CLOCKS_CLK_GPOUT0_CTRL_ENABLE_BITS); + } + + // Set aux mux first, and then glitchless mux if this clock has one + hw_write_masked(&clock->ctrl, + (auxsrc << CLOCKS_CLK_SYS_CTRL_AUXSRC_LSB), + CLOCKS_CLK_SYS_CTRL_AUXSRC_BITS + ); + + if (glitchless) + { + hw_write_masked(&clock->ctrl, + src << CLOCKS_CLK_REF_CTRL_SRC_LSB, + CLOCKS_CLK_REF_CTRL_SRC_BITS + ); + while (!(clock->selected & (1u << src))); + } + + hw_set_bits(&clock->ctrl, CLOCKS_CLK_GPOUT0_CTRL_ENABLE_BITS); + + // Now that the source is configured, we can trust that the user-supplied + // divisor is a safe value. + clock->div = div; + + return true; +} + +static void usb_clock_init(void) +{ + hw_set_bits(&resets_hw->reset, RESETS_RESET_PLL_USB_BITS); + hw_clear_bits(&resets_hw->reset, RESETS_RESET_PLL_USB_BITS); + while (~resets_hw->reset_done & RESETS_RESET_PLL_USB_BITS); + + pll_init(pll_usb_hw, 1, 480 * 1000000, 5, 2); + + // CLK SYS = PLL USB (48MHz) / 1 = 48MHz + simple_clock_configure(clk_sys, + CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX, + CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB, + true); + + // CLK USB = PLL USB (48MHz) / 1 = 48MHz + simple_clock_configure(clk_usb, + 0, // No GLMUX + CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB, + false); +} void board_init(void) { - _usb_clock_setup(); + usb_clock_init(); } void irq_set_exclusive_handler(unsigned int num, void *handler) {} diff --git a/pico-debug.hzp b/pico-debug.hzp index 7a4428e..0d812e4 100644 --- a/pico-debug.hzp +++ b/pico-debug.hzp @@ -15,12 +15,12 @@ - + diff --git a/usb_descriptors.c b/usb_descriptors.c index 19e6b47..d981b3a 100644 --- a/usb_descriptors.c +++ b/usb_descriptors.c @@ -23,7 +23,7 @@ tusb_desc_device_t const desc_device = /* using Dapper Miser CMSIS-DAP VID:PID */ .idVendor = 0x1209, .idProduct = 0x2488, - .bcdDevice = 0x1001, + .bcdDevice = 0x1002, .iManufacturer = 0, .iProduct = STRID_PRODUCT,