mirror of
https://github.com/raspberrypi/pico-sdk.git
synced 2025-12-10 07:14:36 +01:00
515 lines
26 KiB
C
515 lines
26 KiB
C
/*
|
|
* 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
|
|
|
|
/** \file hardware/clocks.h
|
|
* \defgroup hardware_clocks hardware_clocks
|
|
*
|
|
* \brief Clock Management API
|
|
*
|
|
* This API provides a high level interface to the clock functions.
|
|
*
|
|
* The clocks block provides independent clocks to on-chip and external components. It takes inputs from a variety of clock
|
|
* sources allowing the user to trade off performance against cost, board area and power consumption. From these sources
|
|
* it uses multiple clock generators to provide the required clocks. This architecture allows the user flexibility to start and
|
|
* stop clocks independently and to vary some clock frequencies whilst maintaining others at their optimum frequencies
|
|
*
|
|
* Please refer to the appropriate datasheet for more details on the RP-series clocks.
|
|
*
|
|
* The clock source depends on which clock you are attempting to configure. The first table below shows main clock sources. If
|
|
* you are not setting the Reference clock or the System clock, or you are specifying that one of those two will be using an auxiliary
|
|
* clock source, then you will need to use one of the entries from the subsequent tables.
|
|
*
|
|
* * \if rp2040_specific
|
|
* On RP2040 the clock sources are:
|
|
*
|
|
* **Main Clock Sources**
|
|
*
|
|
* Source | Reference Clock | System Clock
|
|
* -------|-----------------|---------
|
|
* ROSC | CLOCKS_CLK_REF_CTRL_SRC_VALUE_ROSC_CLKSRC_PH | |
|
|
* Auxiliary | CLOCKS_CLK_REF_CTRL_SRC_VALUE_CLKSRC_CLK_REF_AUX | CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX
|
|
* XOSC | CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC | |
|
|
* Reference | | CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLK_REF
|
|
*
|
|
* **Auxiliary Clock Sources**
|
|
*
|
|
* The auxiliary clock sources available for use in the configure function depend on which clock is being configured. The following table
|
|
* describes the available values that can be used. Note that for clk_gpout[x], x can be 0-3.
|
|
*
|
|
*
|
|
* Aux Source | clk_gpout[x] | clk_ref | clk_sys
|
|
* -----------|------------|---------|--------
|
|
* System PLL | CLOCKS_CLK_GPOUTx_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS | | CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS
|
|
* GPIO in 0 | CLOCKS_CLK_GPOUTx_CTRL_AUXSRC_VALUE_CLKSRC_GPIN0 | CLOCKS_CLK_REF_CTRL_AUXSRC_VALUE_CLKSRC_GPIN0 | CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_GPIN0
|
|
* GPIO in 1 | CLOCKS_CLK_GPOUTx_CTRL_AUXSRC_VALUE_CLKSRC_GPIN1 | CLOCKS_CLK_REF_CTRL_AUXSRC_VALUE_CLKSRC_GPIN1 | CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_GPIN1
|
|
* USB PLL | CLOCKS_CLK_GPOUTx_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB | CLOCKS_CLK_REF_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB| CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB
|
|
* ROSC | CLOCKS_CLK_GPOUTx_CTRL_AUXSRC_VALUE_ROSC_CLKSRC | | CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_ROSC_CLKSRC
|
|
* XOSC | CLOCKS_CLK_GPOUTx_CTRL_AUXSRC_VALUE_XOSC_CLKSRC | | CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_XOSC_CLKSRC
|
|
* System clock | CLOCKS_CLK_GPOUTx_CTRL_AUXSRC_VALUE_CLK_SYS | | |
|
|
* USB Clock | CLOCKS_CLK_GPOUTx_CTRL_AUXSRC_VALUE_CLK_USB | | |
|
|
* ADC clock | CLOCKS_CLK_GPOUTx_CTRL_AUXSRC_VALUE_CLK_ADC | | |
|
|
* RTC Clock | CLOCKS_CLK_GPOUTx_CTRL_AUXSRC_VALUE_CLK_RTC | | |
|
|
* Ref clock | CLOCKS_CLK_GPOUTx_CTRL_AUXSRC_VALUE_CLK_REF | | |
|
|
*
|
|
* Aux Source | clk_peri | clk_usb | clk_adc
|
|
* -----------|-----------|---------|--------
|
|
* System PLL | CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS | CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS | CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS
|
|
* GPIO in 0 | CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_GPIN0 | CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_CLKSRC_GPIN0 | CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_CLKSRC_GPIN0
|
|
* GPIO in 1 | CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_GPIN1 | CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_CLKSRC_GPIN1 | CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_CLKSRC_GPIN1
|
|
* USB PLL | CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB | CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB | CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB
|
|
* ROSC | CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_ROSC_CLKSRC_PH | CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_ROSC_CLKSRC_PH | CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_ROSC_CLKSRC_PH
|
|
* XOSC | CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_XOSC_CLKSRC | CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_XOSC_CLKSRC | CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_XOSC_CLKSRC
|
|
* System clock | CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS | | |
|
|
*
|
|
* Aux Source | clk_rtc
|
|
* -----------|----------
|
|
* System PLL | CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS
|
|
* GPIO in 0 | CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_CLKSRC_GPIN0
|
|
* GPIO in 1 | CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_CLKSRC_GPIN1
|
|
* USB PLL | CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB
|
|
* ROSC | CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_ROSC_CLKSRC_PH
|
|
* XOSC | CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_XOSC_CLKSRC
|
|
* \endif
|
|
*
|
|
* \if rp2350_specific
|
|
* On RP2350 the clock sources are:
|
|
* * **Main Clock Sources**
|
|
*
|
|
* Source | Reference Clock | System Clock
|
|
* -------|-----------------|---------
|
|
* ROSC | CLOCKS_CLK_REF_CTRL_SRC_VALUE_ROSC_CLKSRC_PH | |
|
|
* Auxiliary | CLOCKS_CLK_REF_CTRL_SRC_VALUE_CLKSRC_CLK_REF_AUX | CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX
|
|
* XOSC | CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC | |
|
|
* LPOSC | CLOCKS_CLK_REF_CTRL_SRC_VALUE_LPOSC_CLKSRC | |
|
|
* Reference | | CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLK_REF
|
|
*
|
|
* **Auxiliary Clock Sources**
|
|
*
|
|
* The auxiliary clock sources available for use in the configure function depend on which clock is being configured. The following table
|
|
* describes the available values that can be used. Note that for clk_gpout[x], x can be 0-3.
|
|
*
|
|
*
|
|
* Aux Source | clk_gpout[x] | clk_ref | clk_sys
|
|
* -----------|------------|---------|--------
|
|
* System PLL | CLOCKS_CLK_GPOUTx_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS | | CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS
|
|
* GPIO in 0 | CLOCKS_CLK_GPOUTx_CTRL_AUXSRC_VALUE_CLKSRC_GPIN0 | CLOCKS_CLK_REF_CTRL_AUXSRC_VALUE_CLKSRC_GPIN0 | CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_GPIN0
|
|
* GPIO in 1 | CLOCKS_CLK_GPOUTx_CTRL_AUXSRC_VALUE_CLKSRC_GPIN1 | CLOCKS_CLK_REF_CTRL_AUXSRC_VALUE_CLKSRC_GPIN1 | CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_GPIN1
|
|
* USB PLL | CLOCKS_CLK_GPOUTx_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB | CLOCKS_CLK_REF_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB| CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB
|
|
* ROSC | CLOCKS_CLK_GPOUTx_CTRL_AUXSRC_VALUE_ROSC_CLKSRC | | CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_ROSC_CLKSRC
|
|
* XOSC | CLOCKS_CLK_GPOUTx_CTRL_AUXSRC_VALUE_XOSC_CLKSRC | | CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_XOSC_CLKSRC
|
|
* LPOSC | CLOCKS_CLK_GPOUTx_CTRL_AUXSRC_VALUE_LPOSC_CLKSRC | | |
|
|
* System clock | CLOCKS_CLK_GPOUTx_CTRL_AUXSRC_VALUE_CLK_SYS | | |
|
|
* USB Clock | CLOCKS_CLK_GPOUTx_CTRL_AUXSRC_VALUE_CLK_USB | | |
|
|
* ADC clock | CLOCKS_CLK_GPOUTx_CTRL_AUXSRC_VALUE_CLK_ADC | | |
|
|
* REF clock | CLOCKS_CLK_GPOUTx_CTRL_AUXSRC_VALUE_CLK_REF | | |
|
|
* PERI clock | CLOCKS_CLK_GPOUTx_CTRL_AUXSRC_VALUE_CLK_PERI | | |
|
|
* HSTX clock | CLOCKS_CLK_GPOUTx_CTRL_AUXSRC_VALUE_CLK_PERI | | |
|
|
|
|
*
|
|
* Aux Source | clk_peri | clk_hstx | clk_usb | clk_adc
|
|
* -----------|-----------|----------|---------|--------
|
|
* System PLL | CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS | CLOCKS_CLK_HSTX_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS | CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS | CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS
|
|
* GPIO in 0 | CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_GPIN0 | | CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_CLKSRC_GPIN0 | CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_CLKSRC_GPIN0
|
|
* GPIO in 1 | CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_GPIN1 | | CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_CLKSRC_GPIN1 | CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_CLKSRC_GPIN1
|
|
* USB PLL | CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB | CLOCKS_CLK_HSTX_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB | CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB | CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB
|
|
* ROSC | CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_ROSC_CLKSRC_PH | | CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_ROSC_CLKSRC_PH | CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_ROSC_CLKSRC_PH
|
|
* XOSC | CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_XOSC_CLKSRC | | CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_XOSC_CLKSRC | CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_XOSC_CLKSRC
|
|
* System clock | CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS | CLOCKS_CLK_HSTX_CTRL_AUXSRC_VALUE_CLK_SYS | | |
|
|
* \endif
|
|
|
|
*
|
|
* \section clock_example Example
|
|
* \addtogroup hardware_clocks
|
|
* \include hello_48MHz.c
|
|
*/
|
|
|
|
#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 !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;
|
|
|
|
/*! \brief Configure the specified clock with automatic clock divisor setup
|
|
* \ingroup hardware_clocks
|
|
*
|
|
* This method allows both the src_frequency of the input clock source AND the desired
|
|
* frequency to be specified, and will set the clock divider to achieve the exact or higher frequency
|
|
* achievable, with the maximum being the src_freq.
|
|
*
|
|
* Note: That the clock hardware only support divisors of exactly 1 or 2.0->65535.0
|
|
*
|
|
* See the tables in the description for details on the possible values for clock sources.
|
|
*
|
|
*
|
|
* \param clock The clock to configure
|
|
* \param src The main clock source, can be 0.
|
|
* \param auxsrc The auxiliary clock source, which depends on which clock is being set. Can be 0
|
|
* \param src_freq Frequency of the input clock source
|
|
* \param freq Requested frequency
|
|
*/
|
|
bool clock_configure(clock_handle_t clock, uint32_t src, uint32_t auxsrc, uint32_t src_freq, uint32_t freq);
|
|
|
|
/*! \brief Configure the specified clock to use the undivided input source
|
|
* \ingroup hardware_clocks
|
|
*
|
|
* See the tables in the description for details on the possible values for clock sources.
|
|
*
|
|
* \param clock The clock to configure
|
|
* \param src The main clock source, can be 0.
|
|
* \param auxsrc The auxiliary clock source, which depends on which clock is being set. Can be 0
|
|
* \param src_freq Frequency of the input clock source
|
|
*/
|
|
void clock_configure_undivided(clock_handle_t clock, uint32_t src, uint32_t auxsrc, uint32_t src_freq);
|
|
|
|
/*! \brief Configure the specified clock to use the undivided input source
|
|
* \ingroup hardware_clocks
|
|
*
|
|
* See the tables in the description for details on the possible values for clock sources.
|
|
*
|
|
* \param clock The clock to configure
|
|
* \param src The main clock source, can be 0.
|
|
* \param auxsrc The auxiliary clock source, which depends on which clock is being set. Can be 0
|
|
* \param src_freq Frequency of the input clock source
|
|
* \param int_divider an integer divider
|
|
*/
|
|
void clock_configure_int_divider(clock_handle_t clock, uint32_t src, uint32_t auxsrc, uint32_t src_freq, uint32_t int_divider);
|
|
|
|
/*! \brief Stop the specified clock
|
|
* \ingroup hardware_clocks
|
|
*
|
|
* \param clock The clock to stop
|
|
*/
|
|
void clock_stop(clock_handle_t clock);
|
|
|
|
/*! \brief Get the current frequency of the specified clock
|
|
* \ingroup hardware_clocks
|
|
*
|
|
* \param clock Clock
|
|
* \return Clock frequency in Hz
|
|
*/
|
|
uint32_t clock_get_hz(clock_handle_t clock);
|
|
|
|
/*! \brief Measure a clocks frequency using the Frequency counter.
|
|
* \ingroup hardware_clocks
|
|
*
|
|
* Uses the inbuilt frequency counter to measure the specified clocks frequency.
|
|
* Currently, this function is accurate to +-1KHz. See the datasheet for more details.
|
|
*/
|
|
uint32_t frequency_count_khz(uint src);
|
|
|
|
/*! \brief Set the "current frequency" of the clock as reported by clock_get_hz without actually changing the clock
|
|
* \ingroup hardware_clocks
|
|
*
|
|
* \see clock_get_hz()
|
|
*/
|
|
void clock_set_reported_hz(clock_handle_t clock, uint hz);
|
|
|
|
/// \tag::frequency_count_mhz[]
|
|
static inline float frequency_count_mhz(uint src) {
|
|
return ((float) (frequency_count_khz(src))) / KHZ;
|
|
}
|
|
/// \end::frequency_count_mhz[]
|
|
|
|
/*! \brief Resus callback function type.
|
|
* \ingroup hardware_clocks
|
|
*
|
|
* User provided callback for a resus event (when clk_sys is stopped by the programmer and is restarted for them).
|
|
*/
|
|
typedef void (*resus_callback_t)(void);
|
|
|
|
/*! \brief Enable the resus function. Restarts clk_sys if it is accidentally stopped.
|
|
* \ingroup hardware_clocks
|
|
*
|
|
* The resuscitate function will restart the system clock if it falls below a certain speed (or stops). This
|
|
* could happen if the clock source the system clock is running from stops. For example if a PLL is stopped.
|
|
*
|
|
* \param resus_callback a function pointer provided by the user to call if a resus event happens.
|
|
*/
|
|
void clocks_enable_resus(resus_callback_t resus_callback);
|
|
|
|
/*! \brief Output an optionally divided clock to the specified gpio pin.
|
|
* \ingroup hardware_clocks
|
|
*
|
|
* \param gpio The GPIO pin to output the clock to. Valid GPIOs are: 21, 23, 24, 25. These GPIOs are connected to the GPOUT0-3 clock generators.
|
|
* \param src The source clock. See the register field CLOCKS_CLK_GPOUT0_CTRL_AUXSRC for a full list. The list is the same for each GPOUT clock generator.
|
|
* \param div_int The integer part of the value to divide the source clock by. This is useful to not overwhelm the GPIO pin with a fast clock. This is in range of 1..2^24-1 on RP2040
|
|
* and 1..2^16-1 on RP2350
|
|
* \param div_frac16 The fractional part of the value to divide the source clock by. This is in range of 0..65535 (/65536).
|
|
*/
|
|
void clock_gpio_init_int_frac16(uint gpio, uint src, uint32_t div_int, uint16_t div_frac16);
|
|
|
|
/*! \brief Output an optionally divided clock to the specified gpio pin.
|
|
* \ingroup hardware_clocks
|
|
*
|
|
* \param gpio The GPIO pin to output the clock to. Valid GPIOs are: 21, 23, 24, 25. These GPIOs are connected to the GPOUT0-3 clock generators.
|
|
* \param src The source clock. See the register field CLOCKS_CLK_GPOUT0_CTRL_AUXSRC for a full list. The list is the same for each GPOUT clock generator.
|
|
* \param div_int The integer part of the value to divide the source clock by. This is useful to not overwhelm the GPIO pin with a fast clock. This is in range of 1..2^24-1 on RP2040
|
|
* and 1..2^16-1 on RP2350
|
|
* \param div_frac8 The fractional part of the value to divide the source clock by. This is in range of 0..255 (/256).
|
|
*/
|
|
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);
|
|
}
|
|
|
|
/*! \brief Output an optionally divided clock to the specified gpio pin.
|
|
* \ingroup hardware_clocks
|
|
*
|
|
* \param gpio The GPIO pin to output the clock to. Valid GPIOs are: 21, 23, 24, 25. These GPIOs are connected to the GPOUT0-3 clock generators.
|
|
* \param src The source clock. See the register field CLOCKS_CLK_GPOUT0_CTRL_AUXSRC for a full list. The list is the same for each GPOUT clock generator.
|
|
* \param div The float amount to divide the source clock by. This is useful to not overwhelm the GPIO pin with a fast clock.
|
|
*/
|
|
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
|
|
}
|
|
|
|
/*! \brief Configure a clock to come from a gpio input
|
|
* \ingroup hardware_clocks
|
|
*
|
|
* \param clock The clock to configure
|
|
* \param gpio The GPIO pin to run the clock from. Valid GPIOs are: 20 and 22.
|
|
* \param src_freq Frequency of the input clock source
|
|
* \param freq Requested frequency
|
|
*/
|
|
bool clock_configure_gpin(clock_handle_t clock, uint gpio, uint32_t src_freq, uint32_t freq);
|
|
|
|
/*! \brief Initialise the system clock to 48MHz
|
|
* \ingroup hardware_clocks
|
|
*
|
|
* Set the system clock to 48MHz, and set the peripheral clock to match.
|
|
*/
|
|
void set_sys_clock_48mhz(void);
|
|
|
|
/*! \brief Initialise the system clock
|
|
* \ingroup hardware_clocks
|
|
*
|
|
* \param vco_freq The voltage controller oscillator frequency to be used by the SYS PLL
|
|
* \param post_div1 The first post divider for the SYS PLL
|
|
* \param post_div2 The second post divider for the SYS PLL.
|
|
*
|
|
* See the PLL documentation in the datasheet for details of driving the PLLs.
|
|
*/
|
|
void set_sys_clock_pll(uint32_t vco_freq, uint post_div1, uint post_div2);
|
|
|
|
/*! \brief Check if a given system clock frequency is valid/attainable
|
|
* \ingroup hardware_clocks
|
|
*
|
|
* \param freq_hz Requested frequency
|
|
* \param vco_freq_out On success, the voltage controlled oscillator frequency to be used by the SYS PLL
|
|
* \param post_div1_out On success, The first post divider for the SYS PLL
|
|
* \param post_div2_out On success, The second post divider for the SYS PLL.
|
|
* @return true if the frequency is possible and the output parameters have been written.
|
|
*/
|
|
bool check_sys_clock_hz(uint32_t freq_hz, uint *vco_freq_out, uint *post_div1_out, uint *post_div2_out);
|
|
|
|
/*! \brief Check if a given system clock frequency is valid/attainable
|
|
* \ingroup hardware_clocks
|
|
*
|
|
* \param freq_khz Requested frequency
|
|
* \param vco_freq_out On success, the voltage controlled oscillator frequency to be used by the SYS PLL
|
|
* \param post_div1_out On success, The first post divider for the SYS PLL
|
|
* \param post_div2_out On success, The second post divider for the SYS PLL.
|
|
* @return true if the frequency is possible and the output parameters have been written.
|
|
*/
|
|
bool check_sys_clock_khz(uint32_t freq_khz, uint *vco_freq_out, uint *post_div1_out, uint *post_div2_out);
|
|
|
|
/*! \brief Attempt to set a system clock frequency in hz
|
|
* \ingroup hardware_clocks
|
|
*
|
|
* Note that not all clock frequencies are possible; it is preferred that you
|
|
* use src/rp2_common/hardware_clocks/scripts/vcocalc.py to calculate the parameters
|
|
* for use with set_sys_clock_pll
|
|
*
|
|
* \param freq_hz Requested frequency
|
|
* \param required if true then this function will assert if the frequency is not attainable.
|
|
* \return true if the clock was configured
|
|
*/
|
|
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;
|
|
}
|
|
|
|
/*! \brief Attempt to set a system clock frequency in khz
|
|
* \ingroup hardware_clocks
|
|
*
|
|
* Note that not all clock frequencies are possible; it is preferred that you
|
|
* use src/rp2_common/hardware_clocks/scripts/vcocalc.py to calculate the parameters
|
|
* for use with set_sys_clock_pll
|
|
*
|
|
* \param freq_khz Requested frequency
|
|
* \param required if true then this function will assert if the frequency is not attainable.
|
|
* \return true if the clock was configured
|
|
*/
|
|
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;
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|