|
| 1 | +/** |
| 2 | + * Copyright (c) 2021 Raspberry Pi (Trading) Ltd. |
| 3 | + * |
| 4 | + * SPDX-License-Identifier: BSD-3-Clause |
| 5 | + */ |
| 6 | + |
| 7 | +// By default, clk_peri (which drives the serial parts of SPI and UART) is |
| 8 | +// attached directly to clk_sys, so varies if the system clock is scaled up |
| 9 | +// and down. clk_peri has a multiplexer (though no divider) which allows it to |
| 10 | +// be attached to other sources. |
| 11 | +// |
| 12 | +// If set_sys_clock_khz is called (here setting the system clock to 133 MHz), |
| 13 | +// this automatically attaches clk_peri to the USB PLL, which by default we run |
| 14 | +// at 48 MHz. As long as you call this *before* configuring your UART etc, the |
| 15 | +// UART baud rate will then not be affected by subsequent changes to clk_sys. |
| 16 | +// |
| 17 | +// However, dropping clk_peri to 48 MHz limits the maximum serial frequencies |
| 18 | +// that can be attained by UART and particularly SPI. This example shows how |
| 19 | +// clk_peri can be attached directly to the system PLL, and the clk_sys |
| 20 | +// divider can then be varied to scale the system (CPUs, DMA, bus fabric etc) |
| 21 | +// frequency up and down whilst keeping clk_peri at a constant 133 MHz. |
| 22 | +// |
| 23 | +// The complete list of clock sources available on clk_peri can be found in |
| 24 | +// hardware/regs/clocks.h: |
| 25 | +// |
| 26 | +// Field : CLOCKS_CLK_PERI_CTRL_AUXSRC |
| 27 | +// 0x0 -> clk_sys |
| 28 | +// 0x1 -> clksrc_pll_sys |
| 29 | +// 0x2 -> clksrc_pll_usb |
| 30 | +// 0x3 -> rosc_clksrc_ph |
| 31 | +// 0x4 -> xosc_clksrc |
| 32 | +// 0x5 -> clksrc_gpin0 |
| 33 | +// 0x6 -> clksrc_gpin1 |
| 34 | + |
| 35 | +#include <stdio.h> |
| 36 | +#include "pico/stdlib.h" |
| 37 | +#include "hardware/clocks.h" |
| 38 | + |
| 39 | +#define PLL_SYS_KHZ (133 * 1000) |
| 40 | + |
| 41 | +int main() { |
| 42 | + // Set the system frequency to 133 MHz. vco_calc.py from the SDK tells us |
| 43 | + // this is exactly attainable at the PLL from a 12 MHz crystal: FBDIV = |
| 44 | + // 133 (so VCO of 1596 MHz), PD1 = 6, PD2 = 2. This function will set the |
| 45 | + // system PLL to 133 MHz and set the clk_sys divisor to 1. |
| 46 | + set_sys_clock_khz(PLL_SYS_KHZ, true); |
| 47 | + |
| 48 | + // The previous line automatically detached clk_peri from clk_sys, and |
| 49 | + // attached it to pll_usb, so that clk_peri won't be disturbed by future |
| 50 | + // changes to system clock or system PLL. If we need higher clk_peri |
| 51 | + // frequencies, we can attach clk_peri directly back to system PLL (no |
| 52 | + // divider available) and then use the clk_sys divider to scale clk_sys |
| 53 | + // independently of clk_peri. |
| 54 | + clock_configure( |
| 55 | + clk_peri, |
| 56 | + 0, // No glitchless mux |
| 57 | + CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS, // System PLL on AUX mux |
| 58 | + PLL_SYS_KHZ * 1000, // Input frequency |
| 59 | + PLL_SYS_KHZ * 1000 // Output (must be same as no divider) |
| 60 | + ); |
| 61 | + |
| 62 | + // The serial clock won't vary from this point onward, so we can configure |
| 63 | + // the UART etc. |
| 64 | + stdio_init_all(); |
| 65 | + |
| 66 | + puts("Peripheral clock is attached directly to system PLL."); |
| 67 | + puts("We can vary the system clock divisor while printing from the UART:"); |
| 68 | + |
| 69 | + for (uint div = 1; div <= 10; ++div) { |
| 70 | + printf("Setting system clock divisor to %u\n", div); |
| 71 | + clock_configure( |
| 72 | + clk_sys, |
| 73 | + CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX, |
| 74 | + CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS, |
| 75 | + PLL_SYS_KHZ, |
| 76 | + PLL_SYS_KHZ / div |
| 77 | + ); |
| 78 | + printf("Measuring system clock with frequency counter:"); |
| 79 | + // Note that the numbering of frequency counter sources is not the |
| 80 | + // same as the numbering of clock slice register blocks. (If we passed |
| 81 | + // the clk_sys enum here we would actually end up measuring XOSC.) |
| 82 | + printf("%u kHz\n", frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_SYS)); |
| 83 | + } |
| 84 | + return 0; |
| 85 | +} |
| 86 | + |
0 commit comments