M changelog.md => changelog.md +1 -0
@@ 17,6 17,7 @@
* Add custom repeat window for the alarm application.
* Add GUI for custom MMI messages.
* Add CPU frequency shift mechanism to save power.
+* Add oscillator clock switching mechanisms.
### Fixed
M module-bsp/board/linux/lpm/LinuxLPM.cpp => module-bsp/board/linux/lpm/LinuxLPM.cpp +5 -0
@@ 24,4 24,9 @@ namespace bsp
{
currentFrequency = freq;
}
+
+ void LinuxLPM::SwitchOscillatorSource(bsp::LowPowerMode::OscillatorSource source)
+ {
+ currentOscSource = source;
+ }
} // namespace bsp
M module-bsp/board/linux/lpm/LinuxLPM.h => module-bsp/board/linux/lpm/LinuxLPM.h +1 -0
@@ 16,6 16,7 @@ namespace bsp
int32_t PowerOff() override final;
int32_t Reboot() override final;
void SetCpuFrequency(CpuFrequency freq) final;
+ void SwitchOscillatorSource(OscillatorSource source) final;
};
} // namespace bsp
M module-bsp/board/rt1051/bsp/lpm/RT1051LPM.cpp => module-bsp/board/rt1051/bsp/lpm/RT1051LPM.cpp +43 -0
@@ 7,6 7,8 @@
#include "log/log.hpp"
#include "bsp/BoardDefinitions.hpp"
#include "bsp/watchdog/watchdog.hpp"
+#include <fsl_clock.h>
+#include <fsl_dcdc.h>
namespace bsp
{
@@ 66,4 68,45 @@ namespace bsp
}
LOG_INFO("CPU frequency changed to %lu", CLOCK_GetFreq(kCLOCK_CpuClk));
}
+
+ void RT1051LPM::SwitchOscillatorSource(bsp::LowPowerMode::OscillatorSource source)
+ {
+ if (source == bsp::LowPowerMode::OscillatorSource::Internal) {
+ if (IsClockEnabled(kCLOCK_Lpuart1) || IsClockEnabled(kCLOCK_Lpuart2) || IsClockEnabled(kCLOCK_Lpuart3) ||
+ IsClockEnabled(kCLOCK_Lpuart4) || IsClockEnabled(kCLOCK_Lpuart5) || IsClockEnabled(kCLOCK_Lpuart6) ||
+ IsClockEnabled(kCLOCK_Lpuart7) || IsClockEnabled(kCLOCK_Lpuart8)) {
+ return;
+ }
+
+ /// Switch DCDC to use DCDC internal OSC
+ DCDC_SetClockSource(DCDC, kDCDC_ClockInternalOsc);
+ /// Switch clock source to internal RC
+ CLOCK_SwitchOsc(kCLOCK_RcOsc);
+ CLOCK_DeinitExternalClk();
+ /// Wait CCM operation finishes
+ while (CCM->CDHIPR != 0) {}
+ }
+ else if (source == bsp::LowPowerMode::OscillatorSource::External) {
+ CLOCK_InitExternalClk(0);
+ /// Switch DCDC to use DCDC external OSC
+ DCDC_SetClockSource(DCDC, kDCDC_ClockExternalOsc);
+ /// Switch clock source to external OSC.
+ CLOCK_SwitchOsc(kCLOCK_XtalOsc);
+ /// Wait CCM operation finishes
+ while (CCM->CDHIPR != 0) {}
+ /// Set Oscillator ready counter value.
+ CCM->CCR = (CCM->CCR & (~CCM_CCR_OSCNT_MASK)) | CCM_CCR_OSCNT(bsp::OscillatorReadyCounterValue);
+ }
+
+ currentOscSource = source;
+ }
+
+ bool RT1051LPM::IsClockEnabled(clock_ip_name_t name) const noexcept
+ {
+ const auto index = static_cast<uint32_t>(name) >> CCM_TupleShift;
+ const auto shift = static_cast<uint32_t>(name) & CCM_TupleMask;
+
+ return ((*reinterpret_cast<volatile uint32_t *>(&CCM->CCGR0 + index)) & (ClockNeededRunWaitMode << shift));
+ }
+
} // namespace bsp
M module-bsp/board/rt1051/bsp/lpm/RT1051LPM.hpp => module-bsp/board/rt1051/bsp/lpm/RT1051LPM.hpp +8 -0
@@ 7,9 7,14 @@
#include "bsp/lpm/bsp_lpm.hpp"
#include "drivers/gpio/DriverGPIO.hpp"
#include "CpuFreqLPM.hpp"
+#include <fsl_clock.h>
namespace bsp
{
+ inline constexpr uint8_t OscillatorReadyCounterValue{127};
+ inline constexpr uint8_t CCM_TupleShift{8};
+ inline constexpr uint8_t CCM_TupleMask{0x1F};
+ inline constexpr uint32_t ClockNeededRunWaitMode{3};
class RT1051LPM : public LowPowerMode
{
@@ 18,8 23,11 @@ namespace bsp
int32_t PowerOff() override final;
int32_t Reboot() override final;
void SetCpuFrequency(CpuFrequency freq) final;
+ void SwitchOscillatorSource(OscillatorSource source) final;
private:
+ [[nodiscard]] bool IsClockEnabled(clock_ip_name_t name) const noexcept;
+
std::shared_ptr<drivers::DriverGPIO> gpio;
std::unique_ptr<bsp::CpuFreqLPM> CpuFreq;
};
M module-bsp/bsp/lpm/bsp_lpm.cpp => module-bsp/bsp/lpm/bsp_lpm.cpp +5 -0
@@ 30,4 30,9 @@ namespace bsp{
{
return currentFrequency;
}
+
+ LowPowerMode::OscillatorSource LowPowerMode::GetCurrentOscillatorSource() const noexcept
+ {
+ return currentOscSource;
+ }
}
M module-bsp/bsp/lpm/bsp_lpm.hpp => module-bsp/bsp/lpm/bsp_lpm.hpp +10 -0
@@ 18,6 18,11 @@ namespace bsp {
Level_5, // 264 MHz
Level_6 // 528 MHz
};
+ enum class OscillatorSource
+ {
+ External,
+ Internal
+ };
LowPowerMode() = default;
virtual ~LowPowerMode() = default;
@@ 26,11 31,16 @@ namespace bsp {
virtual int32_t PowerOff() = 0;
virtual int32_t Reboot() = 0;
+
virtual void SetCpuFrequency(CpuFrequency freq) = 0;
[[nodiscard]] CpuFrequency GetCurrentFrequency() const noexcept;
+ virtual void SwitchOscillatorSource(OscillatorSource source) = 0;
+ [[nodiscard]] OscillatorSource GetCurrentOscillatorSource() const noexcept;
+
protected:
CpuFrequency currentFrequency = CpuFrequency::Level_6;
+ OscillatorSource currentOscSource = OscillatorSource::External;
};
} // namespace bsp
M module-sys/SystemManager/PowerManager.cpp => module-sys/SystemManager/PowerManager.cpp +18 -1
@@ 53,7 53,16 @@ namespace sys
void PowerManager::IncreaseCpuFrequency() const
{
- bsp::LowPowerMode::CpuFrequency freq = lowPowerControl->GetCurrentFrequency();
+ const auto freq = lowPowerControl->GetCurrentFrequency();
+ const auto oscSource = lowPowerControl->GetCurrentOscillatorSource();
+
+ /// switch osc source first
+ if (freq == bsp::LowPowerMode::CpuFrequency::Level_1 &&
+ oscSource == bsp::LowPowerMode::OscillatorSource::Internal) {
+ lowPowerControl->SwitchOscillatorSource(bsp::LowPowerMode::OscillatorSource::External);
+ }
+
+ /// then increase frequency
if (freq < bsp::LowPowerMode::CpuFrequency::Level_6) {
lowPowerControl->SetCpuFrequency(bsp::LowPowerMode::CpuFrequency::Level_6);
}
@@ 62,6 71,7 @@ namespace sys
void PowerManager::DecreaseCpuFrequency() const
{
const auto freq = lowPowerControl->GetCurrentFrequency();
+ const auto oscSource = lowPowerControl->GetCurrentOscillatorSource();
auto level = bsp::LowPowerMode::CpuFrequency::Level_1;
switch (freq) {
@@ 84,9 94,16 @@ namespace sys
break;
}
+ /// decrease frequency first
if (level != freq) {
lowPowerControl->SetCpuFrequency(level);
}
+
+ /// then switch osc source
+ if (level == bsp::LowPowerMode::CpuFrequency::Level_1 &&
+ oscSource == bsp::LowPowerMode::OscillatorSource::External) {
+ lowPowerControl->SwitchOscillatorSource(bsp::LowPowerMode::OscillatorSource::Internal);
+ }
}
void PowerManager::ResetFrequencyShiftCounter()