diff --git a/clocks/CMakeLists.txt b/clocks/CMakeLists.txt index 927a8c0..69ba68c 100644 --- a/clocks/CMakeLists.txt +++ b/clocks/CMakeLists.txt @@ -1,4 +1,5 @@ if (NOT PICO_NO_HARDWARE) + add_subdirectory(detached_clk_peri) add_subdirectory(hello_48MHz) add_subdirectory(hello_gpout) add_subdirectory(hello_resus) diff --git a/clocks/detached_clk_peri/CMakeLists.txt b/clocks/detached_clk_peri/CMakeLists.txt new file mode 100644 index 0000000..009643e --- /dev/null +++ b/clocks/detached_clk_peri/CMakeLists.txt @@ -0,0 +1,12 @@ +add_executable(clocks_detached_clk_peri + detached_clk_peri.c + ) + +# Pull in our pico_stdlib which pulls in commonly used features +target_link_libraries(clocks_detached_clk_peri pico_stdlib) + +# create map/bin/hex file etc. +pico_add_extra_outputs(clocks_detached_clk_peri) + +# add url via pico_set_program_url +example_auto_set_url(clocks_detached_clk_peri) \ No newline at end of file diff --git a/clocks/detached_clk_peri/detached_clk_peri.c b/clocks/detached_clk_peri/detached_clk_peri.c new file mode 100644 index 0000000..f6e1411 --- /dev/null +++ b/clocks/detached_clk_peri/detached_clk_peri.c @@ -0,0 +1,86 @@ +/** + * Copyright (c) 2021 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +// By default, clk_peri (which drives the serial parts of SPI and UART) is +// attached directly to clk_sys, so varies if the system clock is scaled up +// and down. clk_peri has a multiplexer (though no divider) which allows it to +// be attached to other sources. +// +// If set_sys_clock_khz is called (here setting the system clock to 133 MHz), +// this automatically attaches clk_peri to the USB PLL, which by default we run +// at 48 MHz. As long as you call this *before* configuring your UART etc, the +// UART baud rate will then not be affected by subsequent changes to clk_sys. +// +// However, dropping clk_peri to 48 MHz limits the maximum serial frequencies +// that can be attained by UART and particularly SPI. This example shows how +// clk_peri can be attached directly to the system PLL, and the clk_sys +// divider can then be varied to scale the system (CPUs, DMA, bus fabric etc) +// frequency up and down whilst keeping clk_peri at a constant 133 MHz. +// +// The complete list of clock sources available on clk_peri can be found in +// hardware/regs/clocks.h: +// +// Field : CLOCKS_CLK_PERI_CTRL_AUXSRC +// 0x0 -> clk_sys +// 0x1 -> clksrc_pll_sys +// 0x2 -> clksrc_pll_usb +// 0x3 -> rosc_clksrc_ph +// 0x4 -> xosc_clksrc +// 0x5 -> clksrc_gpin0 +// 0x6 -> clksrc_gpin1 + +#include +#include "pico/stdlib.h" +#include "hardware/clocks.h" + +#define PLL_SYS_KHZ (133 * 1000) + +int main() { + // Set the system frequency to 133 MHz. vco_calc.py from the SDK tells us + // this is exactly attainable at the PLL from a 12 MHz crystal: FBDIV = + // 133 (so VCO of 1596 MHz), PD1 = 6, PD2 = 2. This function will set the + // system PLL to 133 MHz and set the clk_sys divisor to 1. + set_sys_clock_khz(PLL_SYS_KHZ, true); + + // The previous line automatically detached clk_peri from clk_sys, and + // attached it to pll_usb, so that clk_peri won't be disturbed by future + // changes to system clock or system PLL. If we need higher clk_peri + // frequencies, we can attach clk_peri directly back to system PLL (no + // divider available) and then use the clk_sys divider to scale clk_sys + // independently of clk_peri. + clock_configure( + clk_peri, + 0, // No glitchless mux + CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS, // System PLL on AUX mux + PLL_SYS_KHZ * 1000, // Input frequency + PLL_SYS_KHZ * 1000 // Output (must be same as no divider) + ); + + // The serial clock won't vary from this point onward, so we can configure + // the UART etc. + stdio_init_all(); + + puts("Peripheral clock is attached directly to system PLL."); + puts("We can vary the system clock divisor while printing from the UART:"); + + for (uint div = 1; div <= 10; ++div) { + printf("Setting system clock divisor to %u\n", div); + clock_configure( + clk_sys, + CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX, + CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS, + PLL_SYS_KHZ, + PLL_SYS_KHZ / div + ); + printf("Measuring system clock with frequency counter:"); + // Note that the numbering of frequency counter sources is not the + // same as the numbering of clock slice register blocks. (If we passed + // the clk_sys enum here we would actually end up measuring XOSC.) + printf("%u kHz\n", frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_SYS)); + } + return 0; +} +