pw_clock_tree#

Clock tree management for embedded devices

Unstable C++17

  • Constinit compatible: Clock tree elements can be declared as constinit

  • Platform independent: Clock tree management sits above the platform layer

  • Handles complex topologies: Clock tree elements can be used to model complex clock tree topologies

pw_clock_tree provides class definitions to implement a platform specific clock tree management solution. By passing the clock tree element that clocks a particular device to the corresponding device driver, the device driver can ensure that the clock is only enabled when required to maximize power savings.

For example the clock tree functionality could be integrated into a uart device driver like this:

 1#include "pw_clock_tree/clock_tree.h"
 2
 3class UartStreamMcuxpresso {
 4 public:
 5  pw::Status Init() {
 6    // Acquire reference to clock before initializing device.
 7    PW_TRY(clock_tree_element_controller_.Acquire());
 8    pw::Status status = USART_RTOS_Init();
 9    if (!status.ok()) {
10      // Failed to initialize device, release the acquired clock.
11      clock_tree_element_controller_.Release().IgnoreError();
12    }
13    return status;
14  }
15
16  void Deinit() {
17    // Deinitialize the device before we can release the reference
18    // to the clock.
19    USART_RTOS_Deinit();
20    clock_tree_element_controller_.Release().IgnoreError();
21  }

It could be initialized and used like this:

 1  // Declare the clock tree
 2  pw::clock_tree::ClockTree clock_tree;
 3  // Declare the uart clock source
 4  ClockSourceUart uart_clock_source;
 5  UartStreamMcuxpresso uart(&clock_tree, &uart_clock_source);
 6
 7  // Initialize the uart which enables the uart clock source.
 8  PW_TRY(uart.Init());
 9  PW_CHECK(uart_clock_source.ref_count() > 0);
10
11  // Do something with uart
12
13  // Deinitialize the uart which disable the uart clock source.
14  uart.Deinit();
Quickstart

Examples that show how to integrate a clock tree into a device driver, and how to define and use platform specific clock tree elements.

Reference

API references for pw::clock_tree::Element, pw::clock_tree::DependentElement, pw::clock_tree::ClockTree, and more.

Overview#

Pigweed’s clock tree module provides the ability to represent the clock tree of an embedded device, and to manage the individual clocks and clock tree elements.

The ClockTree implements two basic methods that apply to all clock tree elements:

In addition, clock divider elements can use the SetDividerValue() method to update the current clock divider value.

The clock tree module defines the Element abstract class from which all other classes are derived from. The Element abstract class implements basic reference counting methods IncRef() and DecRef(), but requires derived classes to use the reference counting methods to properly acquire and release references to clock tree elements. If an Element reference is passed to a constructor of a derived Element, the class object depends on the referenced Element object.

Three derived abstract classes are defined for Element:

  • ElementBlocking for clock tree elements that might block when acquired or released. Acquiring or releasing such a clock tree element might fail.

  • ElementNonBlockingCannotFail for clock tree elements that will not block when acquired or released. Acquiring or releasing such a clock tree element will always succeed.

  • ElementNonBlockingMightFail for clock tree elements that will not block when acquired or released. Acquiring or releasing such a clock tree element might fail.

ElementNonBlockingCannotFail and ElementsNonBlockingMightFail elements can be acquired from an interrupt context.

All classes representing a clock tree element should be implemented as a template and accept ElementBlocking, ElementNonBlockingCannotFail or ElementNonBlockingMightFail as a template argument. Only if it is known at compile time that a clock tree element can only be either blocking or non-blocking, one can directly derive the class from ElementBlocking or ElementNonBlockingCannotFail / ElementNonBlockingMightFail, respectively.

For ease of use ElementController encapsulates ClockTree and Element into a single object and provides Acquire() and Release() methods that check whether both optional objects have been specified, and only if yes, call the respective ClockTree methods, otherwise they return pw::OkStatus().

Synchronization#

The clock tree class uses a mutex to serialize access to ElementBlocking clock tree elements, and uses an interrupt spin lock to serialize access to ElementNonBlockingCannotFail and ElementNonBlockingMightFail clock tree elements. ElementBlocking clock tree elements and ElementNonBlockingCannotFail / ElementNonBlockingMightFail clock tree elements are not serialized with each other, while ElementNonBlockingCannotFail and ElementNonBlockingMightFail are serialized with each other.