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();
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.