@web-font-path: "roboto-debian.css";
Loading...
Searching...
No Matches
clocks.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#ifndef _HARDWARE_CLOCKS_H
8#define _HARDWARE_CLOCKS_H
9
10#include "pico.h"
11#include "hardware/structs/clocks.h"
12
13#ifdef __cplusplus
14extern "C" {
15#endif
16
138
139#define KHZ 1000
140#define MHZ 1000000
141
142// \tag::pll_settings[]
143// There are two PLLs in RP-series microcontrollers:
144// 1. The 'SYS PLL' generates the system clock, the frequency is defined by `SYS_CLK_KHZ`.
145// 2. The 'USB PLL' generates the USB clock, the frequency is defined by `USB_CLK_KHZ`.
146//
147// The two PLLs use the crystal oscillator output directly as their reference frequency input; the PLLs reference
148// frequency cannot be reduced by the dividers present in the clocks block. The crystal frequency is defined by `XOSC_HZ` (or
149// `XOSC_KHZ` or `XOSC_MHZ`).
150//
151// The system's default definitions are correct for the above frequencies with a 12MHz
152// crystal frequency. If different frequencies are required, these must be defined in
153// the board configuration file together with the revised PLL settings
154// Use `vcocalc.py` to check and calculate new PLL settings if you change any of these frequencies.
155//
156// Default PLL configuration RP2040:
157// REF FBDIV VCO POSTDIV
158// PLL SYS: 12 / 1 = 12MHz * 125 = 1500MHz / 6 / 2 = 125MHz
159// PLL USB: 12 / 1 = 12MHz * 100 = 1200MHz / 5 / 5 = 48MHz
160//
161// Default PLL configuration RP2350:
162// REF FBDIV VCO POSTDIV
163// PLL SYS: 12 / 1 = 12MHz * 125 = 1500MHz / 5 / 2 = 150MHz
164// PLL USB: 12 / 1 = 12MHz * 100 = 1200MHz / 5 / 5 = 48MHz
165// \end::pll_settings[]
166
167#ifndef PLL_COMMON_REFDIV
168// backwards compatibility, but now deprecated
169#define PLL_COMMON_REFDIV 1
170#endif
171
172// PICO_CONFIG: PLL_SYS_REFDIV, PLL reference divider setting for PLL_SYS, type=int, default=1, advanced=true, group=hardware_clocks
173#ifndef PLL_SYS_REFDIV
174// backwards compatibility with deprecated PLL_COMMON_REFDIV
175#ifdef PLL_COMMON_REFDIV
176#define PLL_SYS_REFDIV PLL_COMMON_REFDIV
177#else
178#define PLL_SYS_REFDIV 1
179#endif
180#endif
181
182#ifndef PLL_SYS_VCO_FREQ_HZ
183// For backwards compatibility define PLL_SYS_VCO_FREQ_HZ if PLL_SYS_VCO_FREQ_KHZ is defined
184#ifdef PLL_SYS_VCO_FREQ_KHZ
185#define PLL_SYS_VCO_FREQ_HZ (PLL_SYS_VCO_FREQ_KHZ * KHZ)
186#endif
187#endif
188
189#if (SYS_CLK_HZ == 125 * MHZ || SYS_CLK_HZ == 150 * MHZ) && (XOSC_HZ == 12 * MHZ) && (PLL_SYS_REFDIV == 1)
190// PLL settings for standard 125/150 MHz system clock.
191// PICO_CONFIG: PLL_SYS_VCO_FREQ_HZ, System clock PLL frequency, type=int, default=(1500 * MHZ), advanced=true, group=hardware_clocks
192#ifndef PLL_SYS_VCO_FREQ_HZ
193#define PLL_SYS_VCO_FREQ_HZ (1500 * MHZ)
194#endif
195// PICO_CONFIG: PLL_SYS_POSTDIV1, System clock PLL post divider 1 setting, type=int, default=6 on RP2040 or 5 on RP2350, advanced=true, group=hardware_clocks
196#ifndef PLL_SYS_POSTDIV1
197#if SYS_CLK_HZ == 125 * MHZ
198#define PLL_SYS_POSTDIV1 6
199#else
200#define PLL_SYS_POSTDIV1 5
201#endif
202#endif
203// PICO_CONFIG: PLL_SYS_POSTDIV2, System clock PLL post divider 2 setting, type=int, default=2, advanced=true, group=hardware_clocks
204#ifndef PLL_SYS_POSTDIV2
205#define PLL_SYS_POSTDIV2 2
206#endif
207#endif // SYS_CLK_KHZ == 125000 && XOSC_KHZ == 12000 && PLL_COMMON_REFDIV == 1
208
209#if PICO_RP2040 && (SYS_CLK_HZ == 200 * MHZ) && (XOSC_HZ == 12 * MHZ) && (PLL_SYS_REFDIV == 1)
210// PICO_CONFIG: SYS_CLK_VREG_VOLTAGE_AUTO_ADJUST, Should the regulator voltage be adjusted above SYS_CLK_VREG_VOLTAGE_MIN when initializing the clocks, type=bool, default=0, advanced=true, group=hardware_clocks
211#ifndef SYS_CLK_VREG_VOLTAGE_AUTO_ADJUST
212#define SYS_CLK_VREG_VOLTAGE_AUTO_ADJUST 1
213#endif
214// PICO_CONFIG: SYS_CLK_VREG_VOLTAGE_MIN, minimum voltage (see VREG_VOLTAGE_x_xx) for the voltage regulator to be ensured during clock initialization if SYS_CLK_VREG_VOLTAGE_AUTO_ADJUST is 1, type=int, advanced=true, group=hardware_clocks
215#if SYS_CLK_VREG_VOLTAGE_AUTO_ADJUST && !defined(SYS_CLK_VREG_VOLTAGE_MIN)
216#define SYS_CLK_VREG_VOLTAGE_MIN VREG_VOLTAGE_1_15
217#endif
218// PLL settings for fast 200 MHz system clock on RP2040
219#ifndef PLL_SYS_VCO_FREQ_HZ
220#define PLL_SYS_VCO_FREQ_HZ (1200 * MHZ)
221#endif
222#ifndef PLL_SYS_POSTDIV1
223#define PLL_SYS_POSTDIV1 6
224#endif
225#ifndef PLL_SYS_POSTDIV2
226#define PLL_SYS_POSTDIV2 1
227#endif
228#else
229#ifndef SYS_CLK_VREG_VOLTAGE_AUTO_ADJUST
230#define SYS_CLK_VREG_VOLTAGE_AUTO_ADJUST 0
231#endif
232#endif // PICO_RP2040 && SYS_CLK_KHZ == 200000 && XOSC_KHZ == 12000 && PLL_COMMON_REFDIV == 1
233
234// PICO_CONFIG: SYS_CLK_VREG_VOLTAGE_AUTO_ADJUST_DELAY_US, Number of microseconds to wait after updating regulator voltage due to SYS_CLK_VREG_VOLTAGE_MIN to allow voltage to settle, type=int, default=1000, advanced=true, group=hardware_clocks
235#ifndef SYS_CLK_VREG_VOLTAGE_AUTO_ADJUST_DELAY_US
236#define SYS_CLK_VREG_VOLTAGE_AUTO_ADJUST_DELAY_US 1000
237#endif
238
239#if !defined(PLL_SYS_VCO_FREQ_HZ) || !defined(PLL_SYS_POSTDIV1) || !defined(PLL_SYS_POSTDIV2)
240#error PLL_SYS_VCO_FREQ_HZ, PLL_SYS_POSTDIV1 and PLL_SYS_POSTDIV2 must all be specified when using custom clock setup
241#endif
242
243// PICO_CONFIG: PLL_USB_REFDIV, PLL reference divider setting for PLL_USB, type=int, default=1, advanced=true, group=hardware_clocks
244#ifndef PLL_USB_REFDIV
245// backwards compatibility with deprecated PLL_COMMON_REFDIV
246#ifdef PLL_COMMON_REFDIV
247#define PLL_USB_REFDIV PLL_COMMON_REFDIV
248#else
249#define PLL_USB_REFDIV 1
250#endif
251#endif
252
253#ifndef PLL_USB_VCO_FREQ_HZ
254// For backwards compatibility define PLL_USB_VCO_FREQ_HZ if PLL_USB_VCO_FREQ_KHZ is defined
255#ifdef PLL_USB_VCO_FREQ_KHZ
256#define PLL_USB_VCO_FREQ_HZ (PLL_USB_VCO_FREQ_KHZ * KHZ)
257#endif
258#endif
259
260#if (USB_CLK_HZ == 48 * MHZ) && (XOSC_HZ == 12 * MHZ) && (PLL_USB_REFDIV == 1)
261// PLL settings for a USB clock of 48MHz.
262// PICO_CONFIG: PLL_USB_VCO_FREQ_HZ, USB clock PLL frequency, type=int, default=(1200 * MHZ), advanced=true, group=hardware_clocks
263#ifndef PLL_USB_VCO_FREQ_HZ
264#define PLL_USB_VCO_FREQ_HZ (1200 * MHZ)
265#endif
266// PICO_CONFIG: PLL_USB_POSTDIV1, USB clock PLL post divider 1 setting, type=int, default=5, advanced=true, group=hardware_clocks
267#ifndef PLL_USB_POSTDIV1
268#define PLL_USB_POSTDIV1 5
269#endif
270// PICO_CONFIG: PLL_USB_POSTDIV2, USB clock PLL post divider 2 setting, type=int, default=5, advanced=true, group=hardware_clocks
271#ifndef PLL_USB_POSTDIV2
272#define PLL_USB_POSTDIV2 5
273#endif
274#endif // USB_CLK_HZ == 48000000 && XOSC_HZ == 12000000 && PLL_COMMON_REFDIV == 1
275#if !defined(PLL_USB_VCO_FREQ_HZ) || !defined(PLL_USB_POSTDIV1) || !defined(PLL_USB_POSTDIV2)
276#error PLL_USB_VCO_FREQ_HZ, PLL_USB_POSTDIV1 and PLL_USB_POSTDIV2 must all be specified when using custom clock setup.
277#endif
278
279// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_HARDWARE_CLOCKS, Enable/disable assertions in the hardware_clocks module, type=bool, default=0, group=hardware_clocks
280#ifndef PARAM_ASSERTIONS_ENABLED_HARDWARE_CLOCKS
281#ifdef PARAM_ASSERTIONS_ENABLED_CLOCKS // backwards compatibility with SDK < 2.0.0
282#define PARAM_ASSERTIONS_ENABLED_HARDWARE_CLOCKS PARAM_ASSERTIONS_ENABLED_CLOCKS
283#else
284#define PARAM_ASSERTIONS_ENABLED_HARDWARE_CLOCKS 0
285#endif
286#endif
287
288 // PICO_CONFIG: PICO_CLOCK_GPIO_CLKDIV_ROUND_NEAREST, True if floating point GPIO clock divisors should be rounded to the nearest possible clock divisor rather than rounding down, type=bool, default=PICO_CLKDIV_ROUND_NEAREST, group=hardware_clocks
289#ifndef PICO_CLOCK_GPIO_CLKDIV_ROUND_NEAREST
290#define PICO_CLOCK_GPIO_CLKDIV_ROUND_NEAREST PICO_CLKDIV_ROUND_NEAREST
291#endif
292
293typedef clock_num_t clock_handle_t;
294
319bool clock_configure(clock_handle_t clock, uint32_t src, uint32_t auxsrc, uint32_t src_freq, uint32_t freq);
320
331void clock_configure_undivided(clock_handle_t clock, uint32_t src, uint32_t auxsrc, uint32_t src_freq);
332
344void clock_configure_int_divider(clock_handle_t clock, uint32_t src, uint32_t auxsrc, uint32_t src_freq, uint32_t int_divider);
345
351void clock_stop(clock_handle_t clock);
352
359uint32_t clock_get_hz(clock_handle_t clock);
360
367uint32_t frequency_count_khz(uint src);
368
374void clock_set_reported_hz(clock_handle_t clock, uint hz);
375
377static inline float frequency_count_mhz(uint src) {
378 return ((float) (frequency_count_khz(src))) / KHZ;
379}
381
387typedef void (*resus_callback_t)(void);
388
397void clocks_enable_resus(resus_callback_t resus_callback);
398
419void clock_gpio_init_int_frac16(uint gpio, uint src, uint32_t div_int, uint16_t div_frac16);
420
441static inline void clock_gpio_init_int_frac8(uint gpio, uint src, uint32_t div_int, uint8_t div_frac8) {
442 return clock_gpio_init_int_frac16(gpio, src, div_int, (uint16_t)(div_frac8 << 8u));
443}
444
445// backwards compatibility
446static inline void clock_gpio_init_int_frac(uint gpio, uint src, uint32_t div_int, uint8_t div_frac8) {
447 return clock_gpio_init_int_frac8(gpio, src, div_int, div_frac8);
448}
449
468static inline void clock_gpio_init(uint gpio, uint src, float div)
469{
470 uint div_int = (uint)div;
471 const int frac_bit_count = REG_FIELD_WIDTH(CLOCKS_CLK_GPOUT0_DIV_FRAC);
472#if PICO_CLOCK_GPIO_CLKDIV_ROUND_NEAREST
473 div += 0.5f / (1 << frac_bit_count); // round to the nearest fraction
474#endif
475#if REG_FIELD_WIDTH(CLOCKS_CLK_GPOUT0_DIV_FRAC) == 16
476 uint16_t frac = (uint16_t)((div - (float)div_int) * (1u << frac_bit_count));
477 clock_gpio_init_int_frac16(gpio, src, div_int, frac);
478#elif REG_FIELD_WIDTH(CLOCKS_CLK_GPOUT0_DIV_FRAC) == 8
479 uint8_t frac = (uint8_t)((div - (float)div_int) * (1u << frac_bit_count));
480 clock_gpio_init_int_frac8(gpio, src, div_int, frac);
481#else
482#error unsupported number of fractional bits
483#endif
484}
485
494bool clock_configure_gpin(clock_handle_t clock, uint gpio, uint32_t src_freq, uint32_t freq);
495
501void set_sys_clock_48mhz(void);
502
512void set_sys_clock_pll(uint32_t vco_freq, uint post_div1, uint post_div2);
513
523bool check_sys_clock_hz(uint32_t freq_hz, uint *vco_freq_out, uint *post_div1_out, uint *post_div2_out);
524
534bool check_sys_clock_khz(uint32_t freq_khz, uint *vco_freq_out, uint *post_div1_out, uint *post_div2_out);
535
547static inline bool set_sys_clock_hz(uint32_t freq_hz, bool required) {
548 uint vco, postdiv1, postdiv2;
549 if (check_sys_clock_hz(freq_hz, &vco, &postdiv1, &postdiv2)) {
550 set_sys_clock_pll(vco, postdiv1, postdiv2);
551 return true;
552 } else if (required) {
553 panic("System clock of %u Hz cannot be exactly achieved", freq_hz);
554 }
555 return false;
556}
557
569static inline bool set_sys_clock_khz(uint32_t freq_khz, bool required) {
570 uint vco, postdiv1, postdiv2;
571 if (check_sys_clock_khz(freq_khz, &vco, &postdiv1, &postdiv2)) {
572 set_sys_clock_pll(vco, postdiv1, postdiv2);
573 return true;
574 } else if (required) {
575 panic("System clock of %u kHz cannot be exactly achieved", freq_khz);
576 }
577 return false;
578}
579
580#define GPIO_TO_GPOUT_CLOCK_HANDLE_RP2040(gpio, default_clk_handle) \
581 ((gpio) == 21 ? clk_gpout0 : \
582 ((gpio) == 23 ? clk_gpout1 : \
583 ((gpio) == 24 ? clk_gpout2 : \
584 ((gpio) == 25 ? clk_gpout3 : \
585 (default_clk_handle)))))
586
587#define GPIO_TO_GPOUT_CLOCK_HANDLE_RP2350(gpio, default_clk_handle) \
588 ((gpio) == 13 ? clk_gpout0 : \
589 ((gpio) == 15 ? clk_gpout1 : \
590 (GPIO_TO_GPOUT_CLOCK_HANDLE_RP2040(gpio, default_clk_handle))))
591
600#ifndef GPIO_TO_GPOUT_CLOCK_HANDLE
601#if PICO_RP2040
602#define GPIO_TO_GPOUT_CLOCK_HANDLE GPIO_TO_GPOUT_CLOCK_HANDLE_RP2040
603#else
604#define GPIO_TO_GPOUT_CLOCK_HANDLE GPIO_TO_GPOUT_CLOCK_HANDLE_RP2350
605#endif
606#endif
607
613static inline clock_handle_t gpio_to_gpout_clock_handle(uint gpio, clock_handle_t default_clk_handle) {
614 return GPIO_TO_GPOUT_CLOCK_HANDLE(gpio, ({invalid_params_if(HARDWARE_CLOCKS, true); default_clk_handle;}));
615}
616#ifdef __cplusplus
617}
618#endif
619
620#endif
void clock_configure_int_divider(clock_handle_t clock, uint32_t src, uint32_t auxsrc, uint32_t src_freq, uint32_t int_divider)
Configure the specified clock to use the undivided input source.
Definition clocks.c:126
static void clock_gpio_init_int_frac8(uint gpio, uint src, uint32_t div_int, uint8_t div_frac8)
Output an optionally divided clock to the specified gpio pin.
Definition clocks.h:441
static bool set_sys_clock_hz(uint32_t freq_hz, bool required)
Attempt to set a system clock frequency in hz.
Definition clocks.h:547
void clock_stop(clock_handle_t clock)
Stop the specified clock.
Definition clocks.c:33
void set_sys_clock_pll(uint32_t vco_freq, uint post_div1, uint post_div2)
Initialise the system clock.
Definition clocks.c:367
#define GPIO_TO_GPOUT_CLOCK_HANDLE
Returns the GPOUT clock number associated with a particular GPIO if there is one, or default_clk_hand...
Definition clocks.h:602
bool clock_configure(clock_handle_t clock, uint32_t src, uint32_t auxsrc, uint32_t src_freq, uint32_t freq)
Configure the specified clock with automatic clock divisor setup.
Definition clocks.c:98
void(* resus_callback_t)(void)
Resus callback function type.
Definition clocks.h:387
void clocks_enable_resus(resus_callback_t resus_callback)
Enable the resus function. Restarts clk_sys if it is accidentally stopped.
Definition clocks.c:221
void clock_configure_undivided(clock_handle_t clock, uint32_t src, uint32_t auxsrc, uint32_t src_freq)
Configure the specified clock to use the undivided input source.
Definition clocks.c:130
static void clock_gpio_init(uint gpio, uint src, float div)
Output an optionally divided clock to the specified gpio pin.
Definition clocks.h:468
bool check_sys_clock_khz(uint32_t freq_khz, uint *vco_freq_out, uint *post_div1_out, uint *post_div2_out)
Check if a given system clock frequency is valid/attainable.
Definition clocks.c:425
void set_sys_clock_48mhz(void)
Initialise the system clock to 48MHz.
Definition clocks.c:333
void clock_set_reported_hz(clock_handle_t clock, uint hz)
Set the "current frequency" of the clock as reported by clock_get_hz without actually changing the cl...
Definition clocks.c:142
uint32_t clock_get_hz(clock_handle_t clock)
Get the current frequency of the specified clock.
Definition clocks.c:137
void clock_gpio_init_int_frac16(uint gpio, uint src, uint32_t div_int, uint16_t div_frac16)
Output an optionally divided clock to the specified gpio pin.
Definition clocks.c:245
static bool set_sys_clock_khz(uint32_t freq_khz, bool required)
Attempt to set a system clock frequency in khz.
Definition clocks.h:569
static clock_handle_t gpio_to_gpout_clock_handle(uint gpio, clock_handle_t default_clk_handle)
return the associated GPOUT clock for a given GPIO if any
Definition clocks.h:613
bool clock_configure_gpin(clock_handle_t clock, uint gpio, uint32_t src_freq, uint32_t freq)
Configure a clock to come from a gpio input.
Definition clocks.c:300
enum clock_num_rp2040 clock_num_t
Clock numbers on RP2040 (used as typedef clock_num_t).
uint32_t frequency_count_khz(uint src)
Measure a clocks frequency using the Frequency counter.
Definition clocks.c:147
bool check_sys_clock_hz(uint32_t freq_hz, uint *vco_freq_out, uint *post_div1_out, uint *post_div2_out)
Check if a given system clock frequency is valid/attainable.
Definition clocks.c:404
void panic(const char *fmt,...)
Displays a panic message and halts execution.
Definition panic.c:64