Skip to content

Commit 6a53ff3

Browse files
Wren6991kilograham
authored andcommitted
Add example of detaching peripheral clock and varying system clock
1 parent 49d1514 commit 6a53ff3

File tree

3 files changed

+99
-0
lines changed

3 files changed

+99
-0
lines changed

clocks/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
if (NOT PICO_NO_HARDWARE)
2+
add_subdirectory(detached_clk_peri)
23
add_subdirectory(hello_48MHz)
34
add_subdirectory(hello_gpout)
45
add_subdirectory(hello_resus)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
add_executable(clocks_detached_clk_peri
2+
detached_clk_peri.c
3+
)
4+
5+
# Pull in our pico_stdlib which pulls in commonly used features
6+
target_link_libraries(clocks_detached_clk_peri pico_stdlib)
7+
8+
# create map/bin/hex file etc.
9+
pico_add_extra_outputs(clocks_detached_clk_peri)
10+
11+
# add url via pico_set_program_url
12+
example_auto_set_url(clocks_detached_clk_peri)
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
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

Comments
 (0)