Examples#

pw_clock_tree: Clock tree management for embedded devices

Integration into device driver

Example that shows how to integrate the clock tree functionality into a device driver.

Clock tree usage

Example that shows how to define platform specific clock tree elements and how to interact with them to manage clocks of an embedded system.

Clock tree integration into device drivers#

The example below shows how the clock tree functionality can get integrated into a new device driver that requires that a clock tree abstraction is present in the system.

 1#include "pw_clock_tree/clock_tree.h"
 2
 3class UartStreamMcuxpresso {
 4 public:
 5  // Device constructor that optionally accepts `clock_tree_element` to manage
 6  // clock lifecycle.
 7  constexpr UartStreamMcuxpresso(pw::clock_tree::ElementNonBlockingCannotFail*
 8                                     clock_tree_element = nullptr)
 9      : clock_tree_element_(clock_tree_element) {}
10
11  pw::Status Init() {
12    // Acquire reference to clock before initializing device.
13    PW_TRY(clock_tree_element_.Acquire());
14    pw::Status status = USART_RTOS_Init();
15    if (!status.ok()) {
16      // Failed to initialize device, release the acquired clock.
17      clock_tree_element_.Release().IgnoreError();
18    }
19    return status;
20  }
21
22  void Deinit() {
23    // Deinitialize the device before we can release the reference
24    // to the clock.
25    USART_RTOS_Deinit();
26    clock_tree_element_.Release().IgnoreError();
27  }
28
29 private:
30  pw::clock_tree::OptionalElement clock_tree_element_;
31};

Definition and use of clock tree elements#

For the example below we define a clock tree with a clock source clock_a which is an input into divider clock_divider_d.

flowchart LR A(clock_a)--> D(clock_divider_d)

Derived ClockSourceExample class template that overrides DoEnable() and DoDisable() methods.

 1/// Class template implementing a clock source.
 2///
 3/// Template argument `ElementType` can be of class `ElementBlocking`,
 4/// `ElementNonBlockingCannotFail` or
 5/// `ElementNonBlockingMightFail.`
 6template <typename ElementType>
 7class ClockSourceExample : public pw::clock_tree::ClockSource<ElementType> {
 8 private:
 9  pw::Status DoEnable() final { return EnableClock(); }
10
11  pw::Status DoDisable() final { return DisableClock(); }
12};
13using ClockSourceExampleNonBlocking =
14    ClockSourceExample<pw::clock_tree::ElementNonBlockingCannotFail>;

Derived ClockDividerExample class template that overrides DoEnable() method.

 1/// Class template implementing a clock divider.
 2///
 3/// Template argument `ElementType` can be of class `ElementBlocking`,
 4/// `ElementNonBlockingCannotFail` or
 5/// `ElementNonBlockingMightFail.`
 6template <typename ElementType>
 7class ClockDividerExample
 8    : public pw::clock_tree::ClockDividerElement<ElementType> {
 9 public:
10  constexpr ClockDividerExample(ElementType& source,
11                                uint32_t divider_name,
12                                uint32_t divider)
13      : pw::clock_tree::ClockDividerElement<ElementType>(source, divider),
14        divider_name_(divider_name) {}
15
16 private:
17  pw::Status DoEnable() final {
18    return EnableClockDivider(divider_name_, this->divider());
19  }
20
21  uint32_t divider_name_;
22};
23using ClockDividerExampleNonBlocking =
24    ClockDividerExample<pw::clock_tree::ElementNonBlockingCannotFail>;

Declare the clock tree elements. clock_divider_d depends on clock_a.

1  // Define the clock tree
2  ClockSourceExampleNonBlocking clock_a;
3
4  const uint32_t kDividerId = 12;
5  const uint32_t kDividerValue1 = 42;
6  // clock_divider_d depends on clock_a.
7  ClockDividerExampleNonBlocking clock_divider_d(
8      clock_a, kDividerId, kDividerValue1);

Acquire a reference to clock_divider_d, which will acquire a reference to the dependent source clock_a. When the reference to clock_a gets acquired, clock_a gets enabled. Once the reference to clock_a has been acquired and it is enabled, clock_divider_d gets enabled.

flowchart LR A(clock_a)--> D(clock_divider_d) style A fill:#0f0,stroke:#333,stroke-width:4px style D fill:#0f0,stroke:#333,stroke-width:4px
1  // Acquire a reference to clock_divider_d, which will enable clock_divider_d
2  // and its dependent clock_a.
3  clock_divider_d.Acquire();

Set the clock divider value while the clock_divider_d is enabled.

1  // Change the divider value for clock_divider_d.
2  const uint32_t kDividerValue2 = 21;
3  clock_divider_d.SetDivider(kDividerValue2);

Release the reference to the clock_divider_d, which will disable clock_divider_d before it releases its reference to clock_b that gets disabled afterward. At this point all clock tree elements are disabled.

1  // Release reference to clock_divider_d, which will disable clock_divider_d,
2  // and clock_a.
3  clock_divider_d.Release();
4  // All clock tree elements are disabled now.