@web-font-path: "roboto-debian.css";
v2.2.0 (RP2040)
Loading...
Searching...
No Matches
clocks.h
Go to the documentation of this file.
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _HARDWARE_CLOCKS_H
#define _HARDWARE_CLOCKS_H
#include "pico.h"
#include "hardware/structs/clocks.h"
#ifdef __cplusplus
extern "C" {
#endif
#define KHZ 1000
#define MHZ 1000000
// \tag::pll_settings[]
// There are two PLLs in RP-series microcontrollers:
// 1. The 'SYS PLL' generates the system clock, the frequency is defined by `SYS_CLK_KHZ`.
// 2. The 'USB PLL' generates the USB clock, the frequency is defined by `USB_CLK_KHZ`.
//
// The two PLLs use the crystal oscillator output directly as their reference frequency input; the PLLs reference
// frequency cannot be reduced by the dividers present in the clocks block. The crystal frequency is defined by `XOSC_HZ` (or
// `XOSC_KHZ` or `XOSC_MHZ`).
//
// The system's default definitions are correct for the above frequencies with a 12MHz
// crystal frequency. If different frequencies are required, these must be defined in
// the board configuration file together with the revised PLL settings
// Use `vcocalc.py` to check and calculate new PLL settings if you change any of these frequencies.
//
// Default PLL configuration RP2040:
// REF FBDIV VCO POSTDIV
// PLL SYS: 12 / 1 = 12MHz * 125 = 1500MHz / 6 / 2 = 125MHz
// PLL USB: 12 / 1 = 12MHz * 100 = 1200MHz / 5 / 5 = 48MHz
//
// Default PLL configuration RP2350:
// REF FBDIV VCO POSTDIV
// PLL SYS: 12 / 1 = 12MHz * 125 = 1500MHz / 5 / 2 = 150MHz
// PLL USB: 12 / 1 = 12MHz * 100 = 1200MHz / 5 / 5 = 48MHz
// \end::pll_settings[]
#ifndef PLL_COMMON_REFDIV
// backwards compatibility, but now deprecated
#define PLL_COMMON_REFDIV 1
#endif
// PICO_CONFIG: PLL_SYS_REFDIV, PLL reference divider setting for PLL_SYS, type=int, default=1, advanced=true, group=hardware_clocks
#ifndef PLL_SYS_REFDIV
// backwards compatibility with deprecated PLL_COMMON_REFDIV
#ifdef PLL_COMMON_REFDIV
#define PLL_SYS_REFDIV PLL_COMMON_REFDIV
#else
#define PLL_SYS_REFDIV 1
#endif
#endif
#ifndef PLL_SYS_VCO_FREQ_HZ
// For backwards compatibility define PLL_SYS_VCO_FREQ_HZ if PLL_SYS_VCO_FREQ_KHZ is defined
#ifdef PLL_SYS_VCO_FREQ_KHZ
#define PLL_SYS_VCO_FREQ_HZ (PLL_SYS_VCO_FREQ_KHZ * KHZ)
#endif
#endif
#if (SYS_CLK_HZ == 125 * MHZ || SYS_CLK_HZ == 150 * MHZ) && (XOSC_HZ == 12 * MHZ) && (PLL_SYS_REFDIV == 1)
// PLL settings for standard 125/150 MHz system clock.
// PICO_CONFIG: PLL_SYS_VCO_FREQ_HZ, System clock PLL frequency, type=int, default=(1500 * MHZ), advanced=true, group=hardware_clocks
#ifndef PLL_SYS_VCO_FREQ_HZ
#define PLL_SYS_VCO_FREQ_HZ (1500 * MHZ)
#endif
// 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
#ifndef PLL_SYS_POSTDIV1
#if SYS_CLK_HZ == 125 * MHZ
#define PLL_SYS_POSTDIV1 6
#else
#define PLL_SYS_POSTDIV1 5
#endif
#endif
// PICO_CONFIG: PLL_SYS_POSTDIV2, System clock PLL post divider 2 setting, type=int, default=2, advanced=true, group=hardware_clocks
#ifndef PLL_SYS_POSTDIV2
#define PLL_SYS_POSTDIV2 2
#endif
#endif // SYS_CLK_KHZ == 125000 && XOSC_KHZ == 12000 && PLL_COMMON_REFDIV == 1
#if PICO_RP2040 && (SYS_CLK_HZ == 200 * MHZ) && (XOSC_HZ == 12 * MHZ) && (PLL_SYS_REFDIV == 1)
// 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
#ifndef SYS_CLK_VREG_VOLTAGE_AUTO_ADJUST
#define SYS_CLK_VREG_VOLTAGE_AUTO_ADJUST 1
#endif
// 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
#if SYS_CLK_VREG_VOLTAGE_AUTO_ADJUST && !defined(SYS_CLK_VREG_VOLTAGE_MIN)
#define SYS_CLK_VREG_VOLTAGE_MIN VREG_VOLTAGE_1_15
#endif
// PLL settings for fast 200 MHz system clock on RP2040
#ifndef PLL_SYS_VCO_FREQ_HZ
#define PLL_SYS_VCO_FREQ_HZ (1200 * MHZ)
#endif
#ifndef PLL_SYS_POSTDIV1
#define PLL_SYS_POSTDIV1 6
#endif
#ifndef PLL_SYS_POSTDIV2
#define PLL_SYS_POSTDIV2 1
#endif
#else
#ifndef SYS_CLK_VREG_VOLTAGE_AUTO_ADJUST
#define SYS_CLK_VREG_VOLTAGE_AUTO_ADJUST 0
#endif
#endif // PICO_RP2040 && SYS_CLK_KHZ == 200000 && XOSC_KHZ == 12000 && PLL_COMMON_REFDIV == 1
// 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
#ifndef SYS_CLK_VREG_VOLTAGE_AUTO_ADJUST_DELAY_US
#define SYS_CLK_VREG_VOLTAGE_AUTO_ADJUST_DELAY_US 1000
#endif
#if !defined(PLL_SYS_VCO_FREQ_HZ) || !defined(PLL_SYS_POSTDIV1) || !defined(PLL_SYS_POSTDIV2)
#error PLL_SYS_VCO_FREQ_HZ, PLL_SYS_POSTDIV1 and PLL_SYS_POSTDIV2 must all be specified when using custom clock setup
#endif
// PICO_CONFIG: PLL_USB_REFDIV, PLL reference divider setting for PLL_USB, type=int, default=1, advanced=true, group=hardware_clocks
#ifndef PLL_USB_REFDIV
// backwards compatibility with deprecated PLL_COMMON_REFDIV
#ifdef PLL_COMMON_REFDIV
#define PLL_USB_REFDIV PLL_COMMON_REFDIV
#else
#define PLL_USB_REFDIV 1
#endif
#endif
#ifndef PLL_USB_VCO_FREQ_HZ
// For backwards compatibility define PLL_USB_VCO_FREQ_HZ if PLL_USB_VCO_FREQ_KHZ is defined
#ifdef PLL_USB_VCO_FREQ_KHZ
#define PLL_USB_VCO_FREQ_HZ (PLL_USB_VCO_FREQ_KHZ * KHZ)
#endif
#endif
#if (USB_CLK_HZ == 48 * MHZ) && (XOSC_HZ == 12 * MHZ) && (PLL_USB_REFDIV == 1)
// PLL settings for a USB clock of 48MHz.
// PICO_CONFIG: PLL_USB_VCO_FREQ_HZ, USB clock PLL frequency, type=int, default=(1200 * MHZ), advanced=true, group=hardware_clocks
#ifndef PLL_USB_VCO_FREQ_HZ
#define PLL_USB_VCO_FREQ_HZ (1200 * MHZ)
#endif
// PICO_CONFIG: PLL_USB_POSTDIV1, USB clock PLL post divider 1 setting, type=int, default=5, advanced=true, group=hardware_clocks
#ifndef PLL_USB_POSTDIV1
#define PLL_USB_POSTDIV1 5
#endif
// PICO_CONFIG: PLL_USB_POSTDIV2, USB clock PLL post divider 2 setting, type=int, default=5, advanced=true, group=hardware_clocks
#ifndef PLL_USB_POSTDIV2
#define PLL_USB_POSTDIV2 5
#endif
#endif // USB_CLK_HZ == 48000000 && XOSC_HZ == 12000000 && PLL_COMMON_REFDIV == 1
#if !defined(PLL_USB_VCO_FREQ_HZ) || !defined(PLL_USB_POSTDIV1) || !defined(PLL_USB_POSTDIV2)
#error PLL_USB_VCO_FREQ_HZ, PLL_USB_POSTDIV1 and PLL_USB_POSTDIV2 must all be specified when using custom clock setup.
#endif
// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_HARDWARE_CLOCKS, Enable/disable assertions in the hardware_clocks module, type=bool, default=0, group=hardware_clocks
#ifndef PARAM_ASSERTIONS_ENABLED_HARDWARE_CLOCKS
#ifdef PARAM_ASSERTIONS_ENABLED_CLOCKS // backwards compatibility with SDK < 2.0.0
#define PARAM_ASSERTIONS_ENABLED_HARDWARE_CLOCKS PARAM_ASSERTIONS_ENABLED_CLOCKS
#else
#define PARAM_ASSERTIONS_ENABLED_HARDWARE_CLOCKS 0
#endif
#endif
// 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
#ifndef PICO_CLOCK_GPIO_CLKDIV_ROUND_NEAREST
#define PICO_CLOCK_GPIO_CLKDIV_ROUND_NEAREST PICO_CLKDIV_ROUND_NEAREST
#endif
typedef clock_num_t clock_handle_t;
bool clock_configure(clock_handle_t clock, uint32_t src, uint32_t auxsrc, uint32_t src_freq, uint32_t freq);
void clock_configure_undivided(clock_handle_t clock, uint32_t src, uint32_t auxsrc, uint32_t src_freq);
void clock_configure_int_divider(clock_handle_t clock, uint32_t src, uint32_t auxsrc, uint32_t src_freq, uint32_t int_divider);
void clock_stop(clock_handle_t clock);
uint32_t clock_get_hz(clock_handle_t clock);
uint32_t frequency_count_khz(uint src);
void clock_set_reported_hz(clock_handle_t clock, uint hz);
static inline float frequency_count_mhz(uint src) {
return ((float) (frequency_count_khz(src))) / KHZ;
}
typedef void (*resus_callback_t)(void);
void clocks_enable_resus(resus_callback_t resus_callback);
void clock_gpio_init_int_frac16(uint gpio, uint src, uint32_t div_int, uint16_t div_frac16);
static inline void clock_gpio_init_int_frac8(uint gpio, uint src, uint32_t div_int, uint8_t div_frac8) {
return clock_gpio_init_int_frac16(gpio, src, div_int, (uint16_t)(div_frac8 << 8u));
}
// backwards compatibility
static inline void clock_gpio_init_int_frac(uint gpio, uint src, uint32_t div_int, uint8_t div_frac8) {
return clock_gpio_init_int_frac8(gpio, src, div_int, div_frac8);
}
static inline void clock_gpio_init(uint gpio, uint src, float div)
{
uint div_int = (uint)div;
const int frac_bit_count = REG_FIELD_WIDTH(CLOCKS_CLK_GPOUT0_DIV_FRAC);
#if PICO_CLOCK_GPIO_CLKDIV_ROUND_NEAREST
div += 0.5f / (1 << frac_bit_count); // round to the nearest fraction
#endif
#if REG_FIELD_WIDTH(CLOCKS_CLK_GPOUT0_DIV_FRAC) == 16
uint16_t frac = (uint16_t)((div - (float)div_int) * (1u << frac_bit_count));
clock_gpio_init_int_frac16(gpio, src, div_int, frac);
#elif REG_FIELD_WIDTH(CLOCKS_CLK_GPOUT0_DIV_FRAC) == 8
uint8_t frac = (uint8_t)((div - (float)div_int) * (1u << frac_bit_count));
clock_gpio_init_int_frac8(gpio, src, div_int, frac);
#else
#error unsupported number of fractional bits
#endif
}
bool clock_configure_gpin(clock_handle_t clock, uint gpio, uint32_t src_freq, uint32_t freq);
void set_sys_clock_48mhz(void);
void set_sys_clock_pll(uint32_t vco_freq, uint post_div1, uint post_div2);
bool check_sys_clock_hz(uint32_t freq_hz, uint *vco_freq_out, uint *post_div1_out, uint *post_div2_out);
bool check_sys_clock_khz(uint32_t freq_khz, uint *vco_freq_out, uint *post_div1_out, uint *post_div2_out);
static inline bool set_sys_clock_hz(uint32_t freq_hz, bool required) {
uint vco, postdiv1, postdiv2;
if (check_sys_clock_hz(freq_hz, &vco, &postdiv1, &postdiv2)) {
set_sys_clock_pll(vco, postdiv1, postdiv2);
return true;
} else if (required) {
panic("System clock of %u Hz cannot be exactly achieved", freq_hz);
}
return false;
}
static inline bool set_sys_clock_khz(uint32_t freq_khz, bool required) {
uint vco, postdiv1, postdiv2;
if (check_sys_clock_khz(freq_khz, &vco, &postdiv1, &postdiv2)) {
set_sys_clock_pll(vco, postdiv1, postdiv2);
return true;
} else if (required) {
panic("System clock of %u kHz cannot be exactly achieved", freq_khz);
}
return false;
}
#define GPIO_TO_GPOUT_CLOCK_HANDLE_RP2040(gpio, default_clk_handle) \
((gpio) == 21 ? clk_gpout0 : \
((gpio) == 23 ? clk_gpout1 : \
((gpio) == 24 ? clk_gpout2 : \
((gpio) == 25 ? clk_gpout3 : \
(default_clk_handle)))))
#define GPIO_TO_GPOUT_CLOCK_HANDLE_RP2350(gpio, default_clk_handle) \
((gpio) == 13 ? clk_gpout0 : \
((gpio) == 15 ? clk_gpout1 : \
(GPIO_TO_GPOUT_CLOCK_HANDLE_RP2040(gpio, default_clk_handle))))
#ifndef GPIO_TO_GPOUT_CLOCK_HANDLE
#if PICO_RP2040
#define GPIO_TO_GPOUT_CLOCK_HANDLE GPIO_TO_GPOUT_CLOCK_HANDLE_RP2040
#else
#define GPIO_TO_GPOUT_CLOCK_HANDLE GPIO_TO_GPOUT_CLOCK_HANDLE_RP2350
#endif
#endif
static inline clock_handle_t gpio_to_gpout_clock_handle(uint gpio, clock_handle_t default_clk_handle) {
return GPIO_TO_GPOUT_CLOCK_HANDLE(gpio, ({invalid_params_if(HARDWARE_CLOCKS, true); default_clk_handle;}));
}
#ifdef __cplusplus
}
#endif
#endif
clock_configure_int_divider
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
clock_gpio_init_int_frac8
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
set_sys_clock_hz
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
clock_stop
void clock_stop(clock_handle_t clock)
Stop the specified clock.
Definition clocks.c:33
set_sys_clock_pll
void set_sys_clock_pll(uint32_t vco_freq, uint post_div1, uint post_div2)
Initialise the system clock.
Definition clocks.c:367
GPIO_TO_GPOUT_CLOCK_HANDLE
#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
clock_configure
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
resus_callback_t
void(* resus_callback_t)(void)
Resus callback function type.
Definition clocks.h:387
clocks_enable_resus
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
clock_configure_undivided
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
clock_gpio_init
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
check_sys_clock_khz
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
set_sys_clock_48mhz
void set_sys_clock_48mhz(void)
Initialise the system clock to 48MHz.
Definition clocks.c:333
clock_set_reported_hz
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
clock_get_hz
uint32_t clock_get_hz(clock_handle_t clock)
Get the current frequency of the specified clock.
Definition clocks.c:137
clock_gpio_init_int_frac16
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
set_sys_clock_khz
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
gpio_to_gpout_clock_handle
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
clock_configure_gpin
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
clock_num_t
enum clock_num_rp2040 clock_num_t
Clock numbers on RP2040 (used as typedef clock_num_t).
frequency_count_khz
uint32_t frequency_count_khz(uint src)
Measure a clocks frequency using the Frequency counter.
Definition clocks.c:147
check_sys_clock_hz
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
panic
void panic(const char *fmt,...)
Displays a panic message and halts execution.
Definition panic.c:64
pico.h