blob: cf44d6050ff98c652f70608b37cb6f31480ccfd5 [file]
// Copyright 2024 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
#include "pw_clock_tree_mcuxpresso/clock_tree.h"
#include "pw_clock_tree_mcuxpresso/sync_selector.h"
// Test headers
#include "pw_unit_test/framework.h"
// DOCSTAG: [pw_clock_tree_mcuxpresso-examples-ClockTreeElementDefs-Flexcomm0]
// Define the FRO clock source
PW_CONSTINIT pw::clock_tree::ClockMcuxpressoFroSource fro;
// Define FRO_DIV_4 clock divider
PW_CONSTINIT pw::clock_tree::ClockMcuxpressoFroDivider fro_div4(
fro, kCLOCK_FroDiv4OutEn);
// Define FRG0 configuration
constexpr clock_frg_clk_config_t kFrg0Config = {
.num = 0,
.sfg_clock_src = _clock_frg_clk_config::kCLOCK_FrgFroDiv4,
.divider = 255U,
.mult = 144,
};
PW_CONSTINIT pw::clock_tree::ClockMcuxpressoFrgNonBlocking frg_0(fro_div4,
kFrg0Config);
// Define clock source selector FLEXCOMM0
PW_CONSTINIT pw::clock_tree::ClockMcuxpressoSelectorNonBlocking
flexcomm_selector_0(frg_0, kFRG_to_FLEXCOMM0, kNONE_to_FLEXCOMM0);
// Define clock source clock ip name kCLOCK_Flexcomm0
PW_CONSTINIT pw::clock_tree::ClockMcuxpressoClockIpNonBlocking flexcomm_0(
flexcomm_selector_0, kCLOCK_Flexcomm0);
// DOCSTAG: [pw_clock_tree_mcuxpresso-examples-ClockTreeElementDefs-Flexcomm0]
// DOCSTAG: [pw_clock_tree_mcuxpresso-examples-ClockTreeElementDefs-fro_div8]
// Define FRO_DIV8 clock divider
PW_CONSTINIT pw::clock_tree::ClockMcuxpressoFroDivider fro_div8(
fro, kCLOCK_FroDiv8OutEn);
// DOCSTAG: [pw_clock_tree_mcuxpresso-examples-ClockTreeElementDefs-fro_div8]
// DOCSTAG: [pw_clock_tree_mcuxpresso-examples-ClockTreeElementDefs-i3c0]
// Define clock source selector I3C01FCLKSEL
PW_CONSTINIT pw::clock_tree::ClockMcuxpressoSelectorNonBlocking i3c0_selector(
fro_div8, kFRO_DIV8_to_I3C_CLK, kNONE_to_I3C_CLK);
// Define clock divider I3C01FCLKDIV
PW_CONSTINIT pw::clock_tree::ClockMcuxpressoDividerNonBlocking i3c0_divider(
i3c0_selector, kCLOCK_DivI3cClk, 12);
// Define clock source clock ip name kCLOCK_I3c0
PW_CONSTINIT pw::clock_tree::ClockMcuxpressoClockIpNonBlocking i3c0(
i3c0_divider, kCLOCK_I3c0);
// DOCSTAG: [pw_clock_tree_mcuxpresso-examples-ClockTreeElementDefs-i3c0]
// DOCSTAG: [pw_clock_tree_mcuxpresso-examples-ClkTreeElemDefs-ClockSourceNoOp]
// Need to define `ClockSourceNoOp` clock tree element to satisfy dependency for
// ClockMcuxpressoClkIn` class.
PW_CONSTINIT pw::clock_tree::ClockSourceNoOp clock_source_no_op;
// DOCSTAG: [pw_clock_tree_mcuxpresso-examples-ClkTreeElemDefs-ClockSourceNoOp]
// DOCSTAG: [pw_clock_tree_mcuxpresso-examples-ClkTreeElemDefs-ClockSourceNoOpB]
// Need to define `ClockSourceNoOpBlocking` clock tree element to satisfy
// dependency for `ClockMcuxpressoMclk` class.
PW_CONSTINIT pw::clock_tree::ClockSourceNoOpBlocking
clock_source_no_op_blocking;
// DOCSTAG: [pw_clock_tree_mcuxpresso-examples-ClkTreeElemDefs-ClockSourceNoOpB]
// inclusive-language: disable
// DOCSTAG: [pw_clock_tree_mcuxpresso-examples-ClockTreeElementDefs-Ctimer0]
// Define Master clock
PW_CONSTINIT pw::clock_tree::ClockMcuxpressoMclkBlocking mclk(
clock_source_no_op_blocking, 19200000);
// Define clock selector CTIMER0
PW_CONSTINIT pw::clock_tree::ClockMcuxpressoSelectorBlocking ctimer_selector_0(
mclk, kMASTER_CLK_to_CTIMER0, kNONE_to_CTIMER0);
// Define clock source clock ip name kCLOCK_Ct32b0
PW_CONSTINIT pw::clock_tree::ClockMcuxpressoClockIpBlocking ctimer_0(
ctimer_selector_0, kCLOCK_Ct32b0);
// DOCSTAG: [pw_clock_tree_mcuxpresso-examples-ClockTreeElementDefs-Ctimer0]
// inclusive-language: enable
// DOCSTAG: [pw_clock_tree_mcuxpresso-examples-ClockTreeElementDefs-Ctimer1]
// Define FRO_DIV_1 clock source
PW_CONSTINIT pw::clock_tree::ClockMcuxpressoFroDivider fro_div1(
fro, kCLOCK_FroDiv1OutEn);
// Define synchronized clock selector for CTIMER1
// Initial source is fro_div1.
PW_CONSTINIT pw::clock_tree::ClockMcuxpressoSyncSelectorBlocking
ctimer_sync_selector_1(fro_div1, kFRO_DIV1_to_CTIMER1, kNONE_to_CTIMER1);
// Define clock source clock ip name kCLOCK_Ct32b1
PW_CONSTINIT pw::clock_tree::ClockMcuxpressoClockIpBlocking ctimer_1(
ctimer_sync_selector_1, kCLOCK_Ct32b1);
// DOCSTAG: [pw_clock_tree_mcuxpresso-examples-ClockTreeElementDefs-Ctimer1]
// DOCSTAG: [pw_clock_tree_mcuxpresso-examples-ClockTreeElementDefs-LpOsc]
// Define Low-Power Oscillator
PW_CONSTINIT pw::clock_tree::ClockMcuxpressoLpOsc lp_osc_clk;
// DOCSTAG: [pw_clock_tree_mcuxpresso-examples-ClockTreeElementDefs-LpOsc]
// DOCSTAG: [pw_clock_tree_mcuxpresso-examples-ClockTreeElemDefs-AudioPll]
// Define ClkIn pin clock source
PW_CONSTINIT pw::clock_tree::ClockMcuxpressoClkInNonBlocking clk_in(
clock_source_no_op, 19200000);
// Define audio PLL configuration with ClkIn pin as clock source
const clock_audio_pll_config_t kAudioPllConfig = {
.audio_pll_src = kCLOCK_AudioPllXtalIn, /* OSC clock */
.numerator =
0, /* Numerator of the Audio PLL fractional loop divider is 0 */
.denominator =
1000, /* Denominator of the Audio PLL fractional loop divider is 1 */
.audio_pll_mult = kCLOCK_AudioPllMult16 /* Divide by 16 */
};
// Define Audio PLL sourced by ClkIn pin clock source
PW_CONSTINIT pw::clock_tree::ClockMcuxpressoAudioPllNonBlocking audio_pll(
clk_in, kAudioPllConfig, 18);
// DOCSTAG: [pw_clock_tree_mcuxpresso-examples-ClockTreeElemDefs-AudioPll]
// DOCSTAG:[pw_clock_tree_mcuxpresso-examples-ClockTreeElemDefs-AudioPllBypass]
// Define Audio PLL in bypass mode sourced by FRO_DIV8 clock source
PW_CONSTINIT pw::clock_tree::ClockMcuxpressoAudioPllNonBlocking
audio_pll_bypass(fro_div8, kCLOCK_AudioPllFroDiv8Clk);
// DOCSTAG: [pw_clock_tree_mcuxpresso-examples-ClockTreeElemDefs-AudioPllBypass]
// DOCSTAG: [pw_clock_tree_mcuxpresso-examples-ClockTreeElemDefs-SysPll]
// SysPLL configuration with ClkIn pin as clock source
const clock_sys_pll_config_t kSysPllConfig = {
.sys_pll_src = kCLOCK_SysPllXtalIn, /* OSC clock */
.numerator = 0, /* Numerator of the SYSPLL0 fractional loop divider is 0 */
.denominator =
1, /* Denominator of the SYSPLL0 fractional loop divider is 1 */
.sys_pll_mult = kCLOCK_SysPllMult20 /* Divide by 20 */
};
// Define Sys PLL sourced by ClkIn pin clock source
PW_CONSTINIT pw::clock_tree::ClockMcuxpressoSysPllNonBlocking sys_pll(
clk_in, kSysPllConfig, 18, 0, 0, 0);
// DOCSTAG: [pw_clock_tree_mcuxpresso-examples-ClockTreeElemDefs-SysPll]
PW_CONSTINIT pw::clock_tree::ClockMcuxpressoRtcNonBlocking rtc(
clock_source_no_op);
TEST(ClockTreeMcuxpresso, UseExample) {
// inclusive-language: disable
// DOCSTAG: [pw_clock_tree_mcuxpresso-examples-UseExample]
// Enable the low-power oscillator
lp_osc_clk.Acquire();
// Enable the i3c0
i3c0.Acquire();
// Change the i3c0_divider value
i3c0_divider.SetDivider(24);
// Enable the flexcomm0 interface
flexcomm_0.Acquire();
// Enable CTimer1
pw::Status acquire_status = ctimer_1.Acquire();
pw::Status change_status = pw::Status::Unavailable();
if (acquire_status.ok()) {
change_status =
ctimer_sync_selector_1.ChangeSource(mclk, kMASTER_CLK_to_CTIMER1);
}
// Disable the low-power oscillator
lp_osc_clk.Release();
// DOCSTAG: [pw_clock_tree_mcuxpresso-examples-UseExample]
// inclusive-language: enable
PW_TEST_EXPECT_OK(acquire_status);
PW_TEST_EXPECT_OK(change_status);
}
TEST(ClockTreeMcuxpresso, AudioPll) {
// DOCSTAG:[pw_clock_tree_mcuxpresso-examples-Use-AudioPll]
// Enable audio PLL. We use AcquireWith to ensure that FRO_DIV8
// is enabled while enabling the audio PLL. If FRO_DIV8 wasn't enabled
// before, it will only be enabled while configuring the audio PLL
// and be disabled afterward to save power.
PW_TEST_EXPECT_OK(audio_pll.AcquireWith(fro_div8));
// Do something while audio PLL is enabled.
// Release audio PLL to save power.
audio_pll.Release();
// DOCSTAG:[pw_clock_tree_mcuxpresso-examples-Use-AudioPll]
}
TEST(ClockTreeMcuxpresso, SysPll) {
// DOCSTAG:[pw_clock_tree_mcuxpresso-examples-Use-SysPll]
// Enable sys PLL.
sys_pll.Acquire();
// Do something while sys PLL is enabled.
// Release audio PLL to save power.
sys_pll.Release();
// DOCSTAG:[pw_clock_tree_mcuxpresso-examples-Use-sysPll]
}
TEST(ClockTreeMcuxpresso, AudioPllBypass) {
audio_pll_bypass.Acquire();
audio_pll_bypass.Release();
}
TEST(ClockTreeMcuxpresso, Rtc) {
rtc.Acquire();
rtc.Release();
}