Clock

group group_hal_clock

Interface for getting and changing clock configuration.

group_hal_syspm

The clock driver is a single API designed to allow reading and configuring any clock in the system. The driver works the same to configure System clocks as it does for Peripheral clocks. It supports both a readonly mode where any number of items can get information about the clock. Alternatively, each clock can have a single owner that is able to adjust the configuration of the clock.

This driver supports source clocks, clock dividers, and clock signal muxes. All clock objects support the get() functions. Only some clocks support setting specific attributes. Use the cyhal_clock_get_features() function to determine which features are settable for a specific clock. Calling a set() function on a clock that does not support it will return an error.

This driver makes no assumptions about how the device is currently configured. It can be used from a completely unconfigured system (eg: device just booted) to a fully pre-configured (eg: setup by the Device Configurator). The drivers query and modify the actual state of the hardware, there is no caching or remembering of state. To maximize portability of code, it is often convenient to place all system clock configuration into a Board Support Package (BSP) so the main application code is flexible and can port between devices.

cyhal_clock_get allows for getting access to a specific clock object. This clock reference can be used to call any of the get() functions at any time. If a clock needs to be modified, either cyhal_clock_allocate or cyhal_clock_init must be called to obtain a lock on the clock object and to ensure that nothing else in the application is currently using it or assuming its configuration is stable. If exclusive control of a clock is no longer needed cyhal_clock_free can be called to release it. This will remove the lock allowing something else in the system to potentially modify its state.

cyhal_clock_init and cyhal_clock_allocate are very similar. They both reserve a clock object that can then be modified. The difference between them is the argument that is passed in. cyhal_clock_init takes a specific instance that it will attemt to reserve. cyhal_clock_allocate takes in a type of clock that it will attempt to find a free instance for and reserve that.

note

After calling cyhal_clock_free the clock object can still be used to call any of the get() functions just as is possible from the instance returned by cyhal_clock_get.

note

A clock only needs to be allocated ( cyhal_clock_allocate ) or initialized ( cyhal_clock_init ) if its configuration needs to be changed by calling one of the set() functions.

note

While the API is generic, the specific clock resource instances (cyhal_resource_inst_t) are device specific. See the implementation specific sections for more details on what clocks and hardware resources are available.

Features

  • Queryable clock features

  • Configurable clock enablement

  • Configurable clock frequency/divider

  • Configurable clock sources

  • Reserve or share clock objects

Quick Start

See Snippet 1: Simple clock read only access for a code snippet that shows how to reserve and configure a clock object.

Code snippets

note

Error handling code has been intentionally left out of snippets to highlight API usage.

Snippet 1: Simple clock read only access

The following snippet shows how get details about a clock if there is no need to adjust any of its settings (e.g. read only access). This does not require initializing a clock object.

    uint32_t      freq;
    cyhal_clock_t clock;

    cy_rslt_t rslt = cyhal_clock_get(&clock, &CYHAL_CLOCK_IMO);

    bool enabled = cyhal_clock_is_enabled(&clock);

    if (enabled)
    {
        freq = cyhal_clock_get_frequency(&clock);

        // Use frequency information for something
    }

Snippet 2: Simple clock reservation and configuration

The following snippet initializes a clock object, updates its frequency then enables it.

    cy_rslt_t     rslt;
    cyhal_clock_t clock_obj;

    rslt = cyhal_clock_get(&clock_obj, &CYHAL_CLOCK_IMO);
    // Initialize, take ownership of, the specified clock instance
    rslt = cyhal_clock_init(&clock_obj);

    // Set the clock frequency to 1MHz, no tolerance restriction
    rslt = cyhal_clock_set_frequency(&clock_obj, 1000000, NULL);

    // If the clock is not already enabled, enable it
    if (!cyhal_clock_is_enabled(&clock_obj))
    {
        rslt = cyhal_clock_set_enabled(&clock_obj, true, true);
    }

    // If no longer need to directly control the clock, it can be freed
    cyhal_clock_free(&clock_obj);

Snippet 3: Clock allocation and reuse

The following snippet shows how a clock can be allocated and reused for multiple peripheral instances.

    cy_rslt_t     rslt;
    cyhal_clock_t clock_obj;
    rslt = cyhal_clock_allocate(&clock_obj, CYHAL_CLOCK_BLOCK_HF);

    // Set the clock frequency to 1MHz, no tolerance restriction
    rslt = cyhal_clock_set_frequency(&clock_obj, 1000000, NULL);

    // If the clock is not already enabled, enable it
    if (!cyhal_clock_is_enabled(&clock_obj))
    {
        rslt = cyhal_clock_set_enabled(&clock_obj, true, true);
    }

    cyhal_peripheral1_t my_peripheral1;
    cyhal_peripheral2_t my_peripheral2;
    rslt = cyhal_peripheral1_init(&my_peripheral1, &clock_obj);
    rslt = cyhal_peripheral2_init(&my_peripheral2, &clock_obj);

Snippet 4: Change clock source

The following snippet shows how a to change the source of a clock.

    cy_rslt_t     rslt;
    cyhal_clock_t clock_pll, clock_hf;

    #if defined(COMPONENT_CAT1)
    rslt = cyhal_clock_get(&clock_hf, &CYHAL_CLOCK_HF[1]);
    #elif defined(COMPONENT_CAT2)
    rslt = cyhal_clock_get(&clock_hf, &CYHAL_CLOCK_HF);
    #endif
    // Initialize, take ownership of, the specified clock instance
    rslt = cyhal_clock_init(&clock_hf);

    // Allocate a generic PLL instance
    rslt = cyhal_clock_allocate(&clock_pll, CYHAL_CLOCK_BLOCK_PLL);

    // Set the clock frequency to 90.316MHz (44.1, 32-bit sample)
    rslt = cyhal_clock_set_frequency(&clock_pll, 90316000, NULL);

    // If the clock is not already enabled, enable it
    if (!cyhal_clock_is_enabled(&clock_pll))
    {
        rslt = cyhal_clock_set_enabled(&clock_pll, true, true);
    }

    // Change the source for the High Frequency clock to be the allocated PLL
    rslt = cyhal_clock_set_source(&clock_hf, &clock_pll);

Snippet 5: System initialization

note

This example is device specific. See Snippet: System initialization for specific implementation.

Enums

enum cyhal_clock_feature_t

cyhal_clock_feature_t: Enum defining the different features each clock can support of clocks.

These are bit masks. These can be used to determine which set() APIs are legal for a particular clock.

Values:

enumerator CYHAL_CLOCK_FEATURE_NONE

No features of the clock are configurable.

enumerator CYHAL_CLOCK_FEATURE_ENABLE

The clock can be enabled & disabled cyhal_clock_set_enabled.

enumerator CYHAL_CLOCK_FEATURE_FREQUENCY

The clock frequency can be adjusted cyhal_clock_set_frequency.

enumerator CYHAL_CLOCK_FEATURE_DIVIDER

The clock divider can be adjusted cyhal_clock_set_divider.

enumerator CYHAL_CLOCK_FEATURE_SOURCE

The clock source can be adjusted cyhal_clock_set_source.

enum cyhal_clock_tolerance_unit_t

cyhal_clock_tolerance_unit_t: Enum defining the different ways of specifying the acceptable clock tolerance.

Values:

enumerator CYHAL_TOLERANCE_HZ

Clock tolerance specified directly in Hertz.

enumerator CYHAL_TOLERANCE_PPM

Clock tolerance specified in parts-per-million.

enumerator CYHAL_TOLERANCE_PERCENT

Clock tolerance specified in a percent.

Functions

cy_rslt_t cyhal_clock_allocate(cyhal_clock_t *clock, cyhal_clock_block_t block)

Allocates and Initializes a Clock instance, of the provided block type, for use.

This should be used when needing a specific type of clock but the exact instance does not matter. This does everything that is done by cyhal_clock_get and cyhal_clock_init. Once the clock has been allocated the get() and set() functions can be used. If at any time the clock is no longer needed, it can be released by calling cyhal_clock_free.

note

This does not change the clock configuration or connections.

Return

The status of the allocate request.

Parameters
  • [out] clock: The clock object to initialize. The caller must allocate the memory for this object but the init function will initialize its contents.

  • [in] block: The specific type of clock to allocate

cy_rslt_t cyhal_clock_get(cyhal_clock_t *clock, const cyhal_resource_inst_t *resource)

Get a Clock instance for readonly use.

This clock object can be used to call any of the get() functions. To call any of the set() functions, cyhal_clock_init must be called to get exclusive access to the clock object to allow it to be modified.

Return

The status of the get request. This will only return an error if the provided resource instance is not a valid clock object.

Parameters
  • [out] clock: The clock object to store the initialized data into. The caller must allocate the memory for this object but the init function will initialize its contents.

  • [in] resource: The clock resource instance to initialize.

cy_rslt_t cyhal_clock_init(cyhal_clock_t *clock)

Initialize a Clock instance for read/write use.

This instance should be what was returned from cyhal_clock_get.

note

This does not change the behavior (e.g.: enablement) of the clock.

Return

The status of the init request.

Parameters
  • [inout] clock: The clock object to store the initialized data into.

cyhal_clock_feature_t cyhal_clock_get_features(const cyhal_clock_t *clock)

Gets the features supported by the specified clock.

This can be used to determine which set() APIs are legal to be called for this clock.

Return

The feature set that can be configured by this clock. Features are bit mask values.

Parameters
  • [in] clock: The clock object to get features for.

bool cyhal_clock_is_enabled(const cyhal_clock_t *clock)

Gets whether the specified clock is currently enabled and locked, if appropriate.

While most clocks simply have an enabled state, Crystals, PLL, and a few others may also check to make sure the clock has locked and is stable before returning true.

note

External clocks which cannot be enabled/disabled directly will return true if a frequency has been set for them, and false otherwise

Return

Whether the specified clock is enabled or not.

Parameters
  • [in] clock: The clock object to check if it is enabled.

cy_rslt_t cyhal_clock_set_enabled(cyhal_clock_t *clock, bool enabled, bool wait_for_lock)

Attempts to update the enablement of the specified clock.

This is only legal to call if the cyhal_clock_get_features API indicates support for CYHAL_CLOCK_FEATURE_ENABLE.

note

cyhal_clock_allocate or cyhal_clock_init must be called on the clock instace before using this function.

note

If disabled, any clocks or peripherals that are using this will stop working. Make sure to switch the clock source (cyhal_clock_set_source) of any downstream clocks if necessary to keep them running prior to disabling their source.

Return

The status of the requested to change the clocks enablement.

Parameters
  • [in] clock: The clock object to update the enablement of.

  • [in] enabled: Whether the clock should be enabled (true) or disabled (false).

  • [in] wait_for_lock: Whether to wait for the clock to enable & lock (true), or just send the request and return (false). Most clocks behave the same either way, however Crystals, PLLs, and similar require time to lock. If false, cyhal_clock_is_enabled needs to be used to check that it is running before using the clock.

uint32_t cyhal_clock_get_frequency(const cyhal_clock_t *clock)

Gets the frequency (in Hz) the clock is currently operating at.

Return

The frequency the clock is currently running at. 0 if the clock is disabled.

Parameters
  • [in] clock: The clock object to get the frequency of.

cy_rslt_t cyhal_clock_set_frequency(cyhal_clock_t *clock, uint32_t hz, const cyhal_clock_tolerance_t *tolerance)

Attempts to update the operating frequency of the clock.

This is only legal to call if the cyhal_clock_get_features API indicates support for CYHAL_CLOCK_FEATURE_FREQUENCY.

note

cyhal_clock_allocate or cyhal_clock_init must be called on the clock instace before using this function.

note

Some clocks (eg: FLLs & PLLs) may need to be stopped before their frequency can be changed. This function will take care of disabling & re-enabling as necessary, however, this can cause a temporary glitch on anything that is running off of the clock at the time. If glitch free operation is required, change the source of any downstream clocks the application before changing the clock frequency.

Return

The status of the request to set the clock frequency.

Parameters
  • [in] clock: The clock object to set the frequency for.

  • [in] hz: The frequency, in hertz, to set the clock to.

  • [in] tolerance: The allowed tolerance from the desired hz that is acceptable, use NULL if no tolerance check is required.

cy_rslt_t cyhal_clock_set_divider(cyhal_clock_t *clock, uint32_t divider)

Attempts to update the divider, and by extension the operating frequency, of the clock.

This is only legal to call if the cyhal_clock_get_features API indicates support for CYHAL_CLOCK_FEATURE_DIVIDER.

note

cyhal_clock_allocate or cyhal_clock_init must be called on the clock instace before using this function.

Return

The status of the request to set the clock divider.

Parameters
  • [in] clock: The clock object to set the divider for.

  • [in] divider: The divider value to use.

cy_rslt_t cyhal_clock_get_sources(const cyhal_clock_t *clock, const cyhal_resource_inst_t **sources[], uint32_t *count)

Gets the clocks that can serve as inputs to the current clock.

note

the array does not need to be allocated before calling this the pointer will be updated to point to an existing const array.

Return

The status of the request to get clock sources.

Parameters
  • [in] clock: The clock object to get legal sources for.

  • [out] sources: The sources that are legal for the current clock.

Parameters
  • [out] count: The number of clock sources contained in the sources variable.

cy_rslt_t cyhal_clock_set_source(cyhal_clock_t *clock, const cyhal_clock_t *source)

Attempts to update the source for the specified clock.

This is only legal to call if the cyhal_clock_get_features API indicates support for CYHAL_CLOCK_FEATURE_SOURCE.

note

cyhal_clock_allocate or cyhal_clock_init must be called on the clock instace before using this function.

note

Some clocks (eg: FLLs & PLLs) may need to be stopped before their source can be changed. This function will take care of disabling & re-enabling as necessary, however, this can cause a temporary glitch on anything that is running off of the clock at the time. If glitch free operation is required, change the source for any downstream clocks in the application before changing the source clock.

note

No checking is done to verify that the source clock is running. This needs to be done by the caller.

Return

The status of the request to set the source of the clock

Parameters
  • [in] clock: The clock object to set a new source for.

  • [in] source: The source clock to update to.

void cyhal_clock_free(cyhal_clock_t *clock)

Releases the exclusive lock the clock.

This instance can no longer be used to with any set() functions. It can still be used for readonly access to Clock APIs just like is possible after calling cyhal_clock_get.

note

This does not change the behavior (e.g.: enablement) of the clock.

Parameters
  • [inout] clock: The clock object to free

struct cyhal_clock_tolerance_t
#include <cyhal_general_types.h>

Structure defining a clock tolerance.

Public Members

cyhal_clock_tolerance_unit_t type

The type of the clock tolerance value.

uint32_t value

The tolerance value to use.