~aleteoryx/muditaos

3cbbeff551230786ae13c23a7bf4fa8c50099896 — Lefucjusz 2 years ago 321f56e
[MOS-1011] Fix frequency switching stability

Multiple fixes of clock switching related
stability issues:
* added RC oscillator hysteresis as in NXP example;
* changed DCDC converter config;
* configure PLL2 to be able to run on any CPU
frequency level;
* added switching to 1.275V (overdrive) voltage
when applying any clock change above 12MHz as
well as LDO or bandgap switching, as done in
Mbed OS' lpm.c for RT1050;
* changed BMCR AXI queues weighs for SDRAM
in JLink scripts to disable operations
reordering, as it is known to cause data
integrity issues;
* extracted some code to separate files;
* smaller or bigger code cleanups.
36 files changed, 399 insertions(+), 317 deletions(-)

M evkbimxrt1050_sdram_init.jlinkscript
M evkbimxrt1050_sdram_init_T6.jlinkscript
M harmony_changelog.md
M module-apps/application-settings/windows/advanced/CPUModeTestWindow.cpp
M module-bsp/board/linux/lpm/LinuxLPM.cpp
M module-bsp/board/linux/lpm/LinuxLPM.h
M module-bsp/board/rt1051/CMakeLists.txt
M module-bsp/board/rt1051/bellpx/bsp/lpm/RT1051LPM.cpp
M module-bsp/board/rt1051/bellpx/bsp/lpm/RT1051LPM.hpp
M module-bsp/board/rt1051/bsp/lpm/Bandgap.cpp
M module-bsp/board/rt1051/bsp/lpm/CpuFreqLPM.cpp
M module-bsp/board/rt1051/bsp/lpm/CpuFreqLPM.hpp
A module-bsp/board/rt1051/bsp/lpm/DCDC.cpp
A module-bsp/board/rt1051/bsp/lpm/DCDC.hpp
A module-bsp/board/rt1051/bsp/lpm/LDO.cpp
A module-bsp/board/rt1051/bsp/lpm/LDO.hpp
M module-bsp/board/rt1051/bsp/lpm/Oscillator.cpp
M module-bsp/board/rt1051/bsp/lpm/Oscillator.hpp
M module-bsp/board/rt1051/bsp/lpm/RT1051LPMCommon.cpp
M module-bsp/board/rt1051/bsp/lpm/RT1051LPMCommon.hpp
M module-bsp/board/rt1051/common/board.cpp
M module-bsp/board/rt1051/drivers/RT1051DriverOscillator.cpp
M module-bsp/board/rt1051/drivers/RT1051DriverPLL2.cpp
M module-bsp/board/rt1051/drivers/RT1051DriverPLL2.hpp
M module-bsp/board/rt1051/drivers/RT1051DriverPWM.cpp
M module-bsp/board/rt1051/puretx/bsp/lpm/RT1051LPM.cpp
M module-bsp/board/rt1051/puretx/bsp/lpm/RT1051LPM.hpp
M module-bsp/bsp/common.cpp
M module-bsp/bsp/common.hpp
M module-bsp/bsp/lpm/bsp_lpm.hpp
M module-sys/SystemManager/PowerManager.cpp
M module-sys/SystemManager/SystemManagerCommon.cpp
M module-sys/SystemManager/cpu/algorithm/FrequencyStepping.cpp
M module-sys/SystemManager/include/SystemManager/PowerManager.hpp
M module-sys/common/include/system/messages/RequestCpuFrequencyMessage.hpp
M pure_changelog.md
M evkbimxrt1050_sdram_init.jlinkscript => evkbimxrt1050_sdram_init.jlinkscript +2 -2
@@ 187,8 187,8 @@ void SDRAM_Init() {

  // Config SDR Controller Registers/
  MEM_WriteU32(0x402F0000,0x10000004); // MCR
  MEM_WriteU32(0x402F0008,0x20200E44); // BMCR0
  MEM_WriteU32(0x402F000C,0x20200E40); // BMCR1
  MEM_WriteU32(0x402F0008,0x00000081); // BMCR0
  MEM_WriteU32(0x402F000C,0x00000081); // BMCR1
  MEM_WriteU32(0x402F0010,0x8000001D); // BR0, 64MB OK
  MEM_WriteU32(0x402F0040,0x00000E31); // SDRAMCR0 OK
  MEM_WriteU32(0x402F0044,0x00774D22); // SDRAMCR1

M evkbimxrt1050_sdram_init_T6.jlinkscript => evkbimxrt1050_sdram_init_T6.jlinkscript +12 -12
@@ 239,21 239,21 @@ void SDRAM_SEMC_Init(void)
    reg_val |= 0x00000002;
    MEM_WriteU32(SEMC_MCR, reg_val);

    /* Configure queues for AXI bus:
    /* Configure queues for AXI bus as suggested in https://community.nxp.com/t5/i-MX-RT/i-MXRT1060-SEMC-SDRAM-Data-Corruption/m-p/11696908:
     * Queue A:
     * WQOS = 4;
     * WAGE = 2;
     * WSH = 3;
     * WRWS = 5 */
    MEM_WriteU32(SEMC_BMCR0, 0x00030524);
     * WQOS = 1;
     * WAGE = 8;
     * WSH = 0;
     * WRWS = 0 */
    MEM_WriteU32(SEMC_BMCR0, 0x00000081);

    /* Queue B:
     * WQOS = 4;
     * WAGE = 2;
     * WPH = 3;
     * WRWS = 5;
     * WBR = 6 */
    MEM_WriteU32(SEMC_BMCR1, 0x06050324);
     * WQOS = 1;
     * WAGE = 8;
     * WPH = 0;
     * WRWS = 0;
     * WBR = 0 */
    MEM_WriteU32(SEMC_BMCR1, 0x00000081);

    /* Configure MCR:
     * set bus timeout cycles to 0x10;

M harmony_changelog.md => harmony_changelog.md +1 -0
@@ 52,6 52,7 @@
* General improvement in Eink display and error handling
* Changed the "Turn off Harmony" popup display time to 10 seconds
* The default year has been updated to 2023
* Improved device stability related to frequency scaling

## [2.0.0 2023-06-29]


M module-apps/application-settings/windows/advanced/CPUModeTestWindow.cpp => module-apps/application-settings/windows/advanced/CPUModeTestWindow.cpp +5 -5
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "CPUModeTestWindow.hpp"


@@ 134,9 134,9 @@ namespace gui
        permanentFreqSpinner = new gui::TextSpinnerBox(permanentFreqBody, {"OFF", "ON"}, Boundaries::Continuous);
        permanentFreqSpinner->setMinimumSize(100, 30);
        auto ret =
            application->async_call<sys::IsCpuPernament, sys::IsCpuPernamentResponse>(service::name::system_manager);
            application->async_call<sys::IsCpuPermanent, sys::IsCpuPermanentResponse>(service::name::system_manager);
        application->sync(ret);
        permanentFreqSpinner->setCurrentValue(ret.getResult().pernament ? "ON" : "OFF");
        permanentFreqSpinner->setCurrentValue(ret.getResult().permanent ? "ON" : "OFF");

        permanentFreqBody->inputCallback = [&](Item &item, const InputEvent &event) {
            auto ret = permanentFreqSpinner->onInput(event);


@@ 193,10 193,10 @@ namespace gui
        newFreqBody->inputCallback = [&](Item &item, const InputEvent &event) {
            auto ret = currentFreqSpinner->onInput(event);

            auto async = application->async_call<sys::IsCpuPernament, sys::IsCpuPernamentResponse>(
            auto async = application->async_call<sys::IsCpuPermanent, sys::IsCpuPermanentResponse>(
                service::name::system_manager);
            application->sync(async);
            if (async.getResult().pernament) {
            if (async.getResult().permanent) {
                application->bus.sendUnicastSync(
                    std::make_shared<sys::HoldCpuFrequencyPermanentlyMessage>(
                        magic_enum::enum_cast<bsp::CpuFrequencyMHz>(std::stoi(currentFreqSpinner->getCurrentValue()))

M module-bsp/board/linux/lpm/LinuxLPM.cpp => module-bsp/board/linux/lpm/LinuxLPM.cpp +5 -17
@@ 1,36 1,31 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

//
// Created by mati on 09.09.2019.
//

#include "LinuxLPM.h"

namespace bsp
{

    int32_t LinuxLPM::PowerOff()
    std::int32_t LinuxLPM::PowerOff()
    {
        return 0;
    }

    int32_t LinuxLPM::Reboot(RebootType)
    std::int32_t LinuxLPM::Reboot([[maybe_unused]] RebootType reason)
    {
        return 0;
    }

    void LinuxLPM::SetCpuFrequency(bsp::CpuFrequencyMHz freq)
    void LinuxLPM::SetCpuFrequency(CpuFrequencyMHz freq)
    {
        currentFrequency = freq;
    }

    uint32_t LinuxLPM::GetCpuFrequency() const noexcept
    std::uint32_t LinuxLPM::GetCpuFrequency() const noexcept
    {
        return 0;
    }

    void LinuxLPM::SwitchOscillatorSource(bsp::LowPowerMode::OscillatorSource source)
    void LinuxLPM::SwitchOscillatorSource(LowPowerMode::OscillatorSource source)
    {}

    void LinuxLPM::EnableDcdcPowerSaveMode()


@@ 38,11 33,4 @@ namespace bsp

    void LinuxLPM::DisableDcdcPowerSaveMode()
    {}

    void LinuxLPM::SwitchToRegularModeLDO()
    {}

    void LinuxLPM::SwitchToLowPowerModeLDO()
    {}

} // namespace bsp

M module-bsp/board/linux/lpm/LinuxLPM.h => module-bsp/board/linux/lpm/LinuxLPM.h +4 -12
@@ 1,30 1,22 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#ifndef PUREPHONE_LINUXLPM_H
#define PUREPHONE_LINUXLPM_H
#pragma once

#include "bsp/lpm/bsp_lpm.hpp"

namespace bsp
{

    class LinuxLPM : public LowPowerMode
    {
      public:
        int32_t PowerOff() override final;
        int32_t Reboot(RebootType reason) override final;
        std::int32_t PowerOff() override final;
        std::int32_t Reboot(RebootType reason) override final;
        void SetCpuFrequency(CpuFrequencyMHz freq) final;
        [[nodiscard]] uint32_t GetCpuFrequency() const noexcept final;
        [[nodiscard]] std::uint32_t GetCpuFrequency() const noexcept final;
        void SwitchOscillatorSource(OscillatorSource source) final;

        void EnableDcdcPowerSaveMode() final;
        void DisableDcdcPowerSaveMode() final;

        void SwitchToRegularModeLDO() final;
        void SwitchToLowPowerModeLDO() final;
    };

} // namespace bsp

#endif // PUREPHONE_LINUXLPM_H

M module-bsp/board/rt1051/CMakeLists.txt => module-bsp/board/rt1051/CMakeLists.txt +4 -1
@@ 1,7 1,6 @@
# Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
# For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md


target_sources(module-bsp
	PRIVATE
		bluetooth/BlueKitchen.cpp


@@ 28,6 27,8 @@ target_sources(module-bsp
		bsp/lpm/Oscillator.cpp
		bsp/lpm/RT1051LPMCommon.cpp
		bsp/lpm/Bandgap.cpp
		bsp/lpm/LDO.cpp
		bsp/lpm/DCDC.cpp
		bsp/magnetometer/ALS31300.cpp
		bsp/pit/pit.cpp
		bsp/trng/trng.cpp


@@ 74,6 75,8 @@ set_source_files_properties(

target_compile_definitions(module-bsp PUBLIC USB_STACK_FREERTOS)

target_compile_definitions(module-bsp PRIVATE BOARD_${PRODUCT}=1)

add_subdirectory(common/fsl_drivers)
add_subdirectory(os)
add_subdirectory(${BOARD})

M module-bsp/board/rt1051/bellpx/bsp/lpm/RT1051LPM.cpp => module-bsp/board/rt1051/bellpx/bsp/lpm/RT1051LPM.cpp +0 -15
@@ 2,8 2,6 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "RT1051LPM.hpp"
#include <board.h>
#include <board/BoardDefinitions.hpp>

namespace bsp
{


@@ 12,17 10,4 @@ namespace bsp

    void RT1051LPM::DisableDcdcPowerSaveMode()
    {}

    void RT1051LPM::SwitchToRegularModeLDO()
    {
        RT1051LPMCommon::RegularLDOMode();
        NVIC_ClearPendingIRQ(ANATOP_EVENT0_IRQn);
        EnableIRQ(ANATOP_EVENT0_IRQn);
    }

    void RT1051LPM::SwitchToLowPowerModeLDO()
    {
        DisableIRQ(ANATOP_EVENT0_IRQn);
        RT1051LPMCommon::LowPowerLDOMode();
    }
} // namespace bsp

M module-bsp/board/rt1051/bellpx/bsp/lpm/RT1051LPM.hpp => module-bsp/board/rt1051/bellpx/bsp/lpm/RT1051LPM.hpp +1 -4
@@ 2,6 2,7 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <bsp/lpm/RT1051LPMCommon.hpp>

namespace bsp


@@ 11,9 12,5 @@ namespace bsp
      public:
        void EnableDcdcPowerSaveMode() final;
        void DisableDcdcPowerSaveMode() final;

        void SwitchToRegularModeLDO() final;
        void SwitchToLowPowerModeLDO() final;
    };

} // namespace bsp

M module-bsp/board/rt1051/bsp/lpm/Bandgap.cpp => module-bsp/board/rt1051/bsp/lpm/Bandgap.cpp +10 -1
@@ 4,6 4,7 @@
#include "Bandgap.hpp"
#include <cstdint>
#include <fsl_common.h>
#include <critical.hpp>

namespace
{


@@ 14,6 15,8 @@ namespace bsp::bandgap
{
    void SwitchToRegularMode()
    {
        cpp_freertos::CriticalSection::Enter();

        /* Enable regular bandgap and wait for it to stabilize */
        CCM_ANALOG->MISC0_CLR = CCM_ANALOG_MISC0_REFTOP_PWD_MASK;
        while ((CCM_ANALOG->MISC0 & CCM_ANALOG_MISC0_REFTOP_VBGUP_MASK) == 0) {}


@@ 21,15 24,21 @@ namespace bsp::bandgap
        /* Disable low power bandgap */
        XTALOSC24M->LOWPWR_CTRL_CLR = XTALOSC24M_LOWPWR_CTRL_LPBG_SEL_MASK;
        PMU->MISC0_CLR              = REFTOP_LOWPOWER_MASK;

        cpp_freertos::CriticalSection::Exit();
    }

    void SwitchToLowPowerMode()
    {
        cpp_freertos::CriticalSection::Enter();

        /* Enable low power bandgap */
        PMU->MISC0_SET = REFTOP_LOWPOWER_MASK;
        XTALOSC24M->LOWPWR_CTRL_SET = XTALOSC24M_LOWPWR_CTRL_LPBG_SEL_MASK;

        /* Disable regular bandgap */
        XTALOSC24M->LOWPWR_CTRL_SET = XTALOSC24M_LOWPWR_CTRL_LPBG_SEL_MASK;
        PMU->MISC0_SET              = CCM_ANALOG_MISC0_REFTOP_PWD_MASK;

        cpp_freertos::CriticalSection::Exit();
    }
} // namespace bsp::bandgap

M module-bsp/board/rt1051/bsp/lpm/CpuFreqLPM.cpp => module-bsp/board/rt1051/bsp/lpm/CpuFreqLPM.cpp +1 -1
@@ 2,7 2,7 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "CpuFreqLPM.hpp"
#include "fsl_dcdc.h"
#include <fsl_dcdc.h>

namespace bsp
{

M module-bsp/board/rt1051/bsp/lpm/CpuFreqLPM.hpp => module-bsp/board/rt1051/bsp/lpm/CpuFreqLPM.hpp +1 -0
@@ 9,6 9,7 @@ namespace bsp
{
    inline constexpr std::uint32_t VDDRun_950_mV  = 0x06;
    inline constexpr std::uint32_t VDDRun_1150_mV = 0x0E;
    inline constexpr std::uint32_t VDDRun_1275_mV = 0x13;

    inline constexpr std::uint32_t VDDStandby_925_mV = 0x01;


A module-bsp/board/rt1051/bsp/lpm/DCDC.cpp => module-bsp/board/rt1051/bsp/lpm/DCDC.cpp +48 -0
@@ 0,0 1,48 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "DCDC.hpp"
#include "CpuFreqLPM.hpp"
#include <fsl_dcdc.h>

namespace bsp::dcdc
{
    void SwitchToOverdriveConfig()
    {
        /* Switch to CCM mode for improved stability */
        DCDC_BootIntoCCM(DCDC);

        /* Connect internal DCDC load resistor */
        DCDC->REG1 |= DCDC_REG1_REG_RLOAD_SW_MASK;

        /* Adjust target voltage to 1.275V */
        DCDC_AdjustTargetVoltage(DCDC, VDDRun_1275_mV, VDDStandby_925_mV);

        /* Disable FET ODRIVE */
        PMU->REG_CORE_CLR = PMU_REG_CORE_FET_ODRIVE_MASK;
    }

    void SwitchToRegularConfig()
    {
        /* Adjust target voltage to 1.15V */
        DCDC_AdjustTargetVoltage(DCDC, VDDRun_1150_mV, VDDStandby_925_mV);
    }

    void SwitchToLowPowerConfig()
    {
        /* Adjust target voltage to nominal 0.95V */
        DCDC_AdjustTargetVoltage(DCDC, VDDRun_950_mV, VDDStandby_925_mV);

        /* Switch to DCM mode to reduce current consumption */
        DCDC_BootIntoDCM(DCDC);

        /* Disconnect internal DCDC load resistor */
        DCDC->REG1 &= ~DCDC_REG1_REG_RLOAD_SW_MASK;

        /* Power down output range comparator */
        DCDC->REG0 |= DCDC_REG0_PWD_CMP_OFFSET_MASK;

        /* Enable FET ODRIVE */
        PMU->REG_CORE_SET = PMU_REG_CORE_FET_ODRIVE_MASK;
    }
} // namespace bsp::dcdc

A module-bsp/board/rt1051/bsp/lpm/DCDC.hpp => module-bsp/board/rt1051/bsp/lpm/DCDC.hpp +11 -0
@@ 0,0 1,11 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

namespace bsp::dcdc
{
    void SwitchToOverdriveConfig();
    void SwitchToRegularConfig();
    void SwitchToLowPowerConfig();
} // namespace bsp::dcdc

A module-bsp/board/rt1051/bsp/lpm/LDO.cpp => module-bsp/board/rt1051/bsp/lpm/LDO.cpp +62 -0
@@ 0,0 1,62 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "LDO.hpp"
#include <fsl_common.h>
#include <critical.hpp>

namespace
{
    constexpr auto ldoStabilizationDelayUs{40};
}

namespace bsp::ldo
{
    void SwitchToRegularMode()
    {
        cpp_freertos::CriticalSection::Enter();

        /* Enable regular 2P5 and disable weak 2P5 LDO */
        PMU->REG_2P5_SET = PMU_REG_2P5_ENABLE_LINREG_MASK;
        PMU->REG_2P5_CLR = PMU_REG_2P5_ENABLE_WEAK_LINREG_MASK;

        /* Wait for regular 2P5 to become stable (documentation Low Power AN12085) */
        while ((PMU->REG_2P5 & PMU_REG_2P5_OK_VDD2P5_MASK) == 0) {}

        /* Enable regular 1P1 and disable weak 1P1 LDO */
        PMU->REG_1P1_SET = PMU_REG_1P1_ENABLE_LINREG_MASK;
        PMU->REG_1P1_CLR = PMU_REG_1P1_ENABLE_WEAK_LINREG_MASK;

        /* Wait for regular 1P1 to become stable (documentation Low Power AN12085) */
        while ((PMU->REG_1P1 & PMU_REG_1P1_OK_VDD1P1_MASK) == 0) {}

        cpp_freertos::CriticalSection::Exit();

#if BOARD_BellHybrid == 1
        NVIC_ClearPendingIRQ(ANATOP_EVENT0_IRQn);
        EnableIRQ(ANATOP_EVENT0_IRQn);
#endif
    }

    void SwitchToLowPowerMode()
    {
#if BOARD_BellHybrid == 1
        DisableIRQ(ANATOP_EVENT0_IRQn);
#endif

        cpp_freertos::CriticalSection::Enter();

        /* Enable weak 2P5 and disable regular 2P5 LDO */
        PMU->REG_2P5_SET = PMU_REG_2P5_ENABLE_WEAK_LINREG_MASK;
        PMU->REG_2P5_CLR = PMU_REG_2P5_ENABLE_LINREG_MASK;

        /* Enable weak 1P1 and disable regular 1P1 LDO */
        PMU->REG_1P1_SET = PMU_REG_1P1_ENABLE_WEAK_LINREG_MASK;
        PMU->REG_1P1_CLR = PMU_REG_1P1_ENABLE_LINREG_MASK;

        /* Wait for weak LDOs to stabilize */
        SDK_DelayAtLeastUs(ldoStabilizationDelayUs, CLOCK_GetCpuClkFreq());

        cpp_freertos::CriticalSection::Exit();
    }
} // namespace bsp::ldo

A module-bsp/board/rt1051/bsp/lpm/LDO.hpp => module-bsp/board/rt1051/bsp/lpm/LDO.hpp +10 -0
@@ 0,0 1,10 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

namespace bsp::ldo
{
    void SwitchToRegularMode();
    void SwitchToLowPowerMode();
} // namespace bsp::ldo

M module-bsp/board/rt1051/bsp/lpm/Oscillator.cpp => module-bsp/board/rt1051/bsp/lpm/Oscillator.cpp +45 -26
@@ 3,73 3,92 @@

#include "Oscillator.hpp"
#include "ClockState.hpp"
#include <critical.hpp>
#include <fsl_dcdc.h>
#include <fsl_common.h>
#include <cstdint>

namespace bsp
namespace
{
    inline constexpr std::uint8_t OscillatorReadyCounterValue{127};
    inline constexpr std::uint32_t CurrentTuningValueInUseForConfig0{0x4};
    inline constexpr std::uint32_t NegativeHysteresisValue{0x2};
    inline constexpr std::uint32_t TuningValue{0xA7};
    inline constexpr std::uint32_t CurrentTuningValueInUseForConfig1{0x40};
    inline constexpr std::uint32_t TargetCountUsedToTune{0x2DC};
    constexpr std::uint8_t oscillatorReadyCounterValue{127};
    constexpr std::uint32_t currentTuningValueInUseForConfig0{0x4};
    constexpr std::uint32_t initialNegativeHysteresisValue{0x2};
    constexpr std::uint32_t negativeHysteresisValue{0x3};
    constexpr std::uint32_t positiveHysteresisValue{0x3};
    constexpr std::uint32_t tuningValue{0xA7};
    constexpr std::uint32_t currentTuningValueInUseForConfig1{0x40};
    constexpr std::uint32_t targetCountUsedToTune{0x2DC};

    inline constexpr std::uint32_t XtalStabilizationTimeUs{200};
    inline constexpr std::uint32_t RcOscStabilizationTimeUs{4000};
    constexpr std::uint32_t xtalStabilizationTimeUs{200};
    constexpr std::uint32_t rcOscStabilizationTimeUs{4000};
} // namespace

    void EnableExternalOscillator()
namespace bsp
{
    void SwitchToExternalOscillator()
    {
        cpp_freertos::CriticalSection::Enter();
        if (!IsExternalOscillatorEnabled()) {
            /// Init internal oscillator
            CLOCK_InitExternalClk(false);
            /// Wait for XTAL to become stable
            SDK_DelayAtLeastUs(XtalStabilizationTimeUs, CLOCK_GetCpuClkFreq());
            SDK_DelayAtLeastUs(xtalStabilizationTimeUs, CLOCK_GetCpuClkFreq());
            /// 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) {}
            /// Deinit internal oscillator
            CLOCK_DeinitRcOsc24M();
            /// Set Oscillator ready counter value.
            CCM->CCR = (CCM->CCR & (~CCM_CCR_OSCNT_MASK)) | CCM_CCR_OSCNT(bsp::OscillatorReadyCounterValue);
            CCM->CCR = (CCM->CCR & (~CCM_CCR_OSCNT_MASK)) | CCM_CCR_OSCNT(oscillatorReadyCounterValue);
        }
        cpp_freertos::CriticalSection::Exit();
    }

    void DisableExternalOscillator()
    bool SwitchToInternalOscillator()
    {
        cpp_freertos::CriticalSection::Enter();
        if (IsExternalOscillatorEnabled()) {
            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;
                cpp_freertos::CriticalSection::Exit();
                return false;
            }

            /// Enable RC OSC. It needs at least 4ms to be stable, so self tuning need to be enabled.
            XTALOSC24M->LOWPWR_CTRL |= XTALOSC24M_LOWPWR_CTRL_RC_OSC_EN_MASK;
            CLOCK_InitRcOsc24M();
            /// Configure self-tuning for RC OSC
            XTALOSC24M->OSC_CONFIG0 = XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG_CUR(bsp::CurrentTuningValueInUseForConfig0) |
                                      XTALOSC24M_OSC_CONFIG0_SET_HYST_MINUS(bsp::NegativeHysteresisValue) |
                                      XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG(bsp::TuningValue) |
            XTALOSC24M->OSC_CONFIG0 = XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG_CUR(currentTuningValueInUseForConfig0) |
                                      XTALOSC24M_OSC_CONFIG0_SET_HYST_MINUS(initialNegativeHysteresisValue) |
                                      XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG(tuningValue) |
                                      XTALOSC24M_OSC_CONFIG0_START_MASK | XTALOSC24M_OSC_CONFIG0_ENABLE_MASK;
            XTALOSC24M->OSC_CONFIG1 = XTALOSC24M_OSC_CONFIG1_COUNT_RC_CUR(bsp::CurrentTuningValueInUseForConfig1) |
                                      XTALOSC24M_OSC_CONFIG1_COUNT_RC_TRG(bsp::TargetCountUsedToTune);

            XTALOSC24M->OSC_CONFIG1 = XTALOSC24M_OSC_CONFIG1_COUNT_RC_CUR(currentTuningValueInUseForConfig1) |
                                      XTALOSC24M_OSC_CONFIG1_COUNT_RC_TRG(targetCountUsedToTune);

            /// Wait for RC OSC to become stable
            SDK_DelayAtLeastUs(RcOscStabilizationTimeUs, CLOCK_GetCpuClkFreq());
            SDK_DelayAtLeastUs(rcOscStabilizationTimeUs, CLOCK_GetCpuClkFreq());
            /// Add hysteresis
            std::uint32_t oscConfig0Value = XTALOSC24M->OSC_CONFIG0;
            oscConfig0Value &= ~(XTALOSC24M_OSC_CONFIG0_HYST_PLUS_MASK | XTALOSC24M_OSC_CONFIG0_HYST_MINUS_MASK);
            oscConfig0Value |= XTALOSC24M_OSC_CONFIG0_HYST_PLUS(positiveHysteresisValue) |
                               XTALOSC24M_OSC_CONFIG0_HYST_MINUS(negativeHysteresisValue);
            XTALOSC24M->OSC_CONFIG0 = oscConfig0Value;
            /// Switch DCDC to use DCDC internal OSC
            DCDC_SetClockSource(DCDC, kDCDC_ClockInternalOsc);
            /// Switch clock source to internal RC
            CLOCK_SwitchOsc(kCLOCK_RcOsc);
            /// Deinit external oscillator
            CLOCK_DeinitExternalClk();
            /// Wait CCM operation finishes
            while (CCM->CDHIPR != 0) {}
        }
        cpp_freertos::CriticalSection::Exit();

        return true;
    }

    [[nodiscard]] bool IsExternalOscillatorEnabled()
    {
        return !(XTALOSC24M->LOWPWR_CTRL & XTALOSC24M_LOWPWR_CTRL_OSC_SEL_MASK);
        return not static_cast<bool>(XTALOSC24M->LOWPWR_CTRL & XTALOSC24M_LOWPWR_CTRL_OSC_SEL_MASK);
    }
}; // namespace bsp

M module-bsp/board/rt1051/bsp/lpm/Oscillator.hpp => module-bsp/board/rt1051/bsp/lpm/Oscillator.hpp +3 -3
@@ 1,11 1,11 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

namespace bsp
{
    void EnableExternalOscillator();
    void DisableExternalOscillator();
    void SwitchToExternalOscillator();
    bool SwitchToInternalOscillator();
    [[nodiscard]] bool IsExternalOscillatorEnabled();
} // namespace bsp

M module-bsp/board/rt1051/bsp/lpm/RT1051LPMCommon.cpp => module-bsp/board/rt1051/bsp/lpm/RT1051LPMCommon.cpp +49 -73
@@ 2,15 2,13 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "RT1051LPMCommon.hpp"

#include <log/log.hpp>
#include <fsl_clock.h>
#include <fsl_dcdc.h>
#include <bsp/bsp.hpp>
#include "Oscillator.hpp"
#include "critical.hpp"
#include "drivers/semc/DriverSEMC.hpp"
#include <hal/boot_reason.h>
#include "DCDC.hpp"

namespace bsp
{


@@ 22,13 20,13 @@ namespace bsp
        CpuFreq    = std::make_unique<CpuFreqLPM>();
    }

    int32_t RT1051LPMCommon::PowerOff()
    std::int32_t RT1051LPMCommon::PowerOff()
    {
        board_power_off();
        return 0;
    }

    int32_t RT1051LPMCommon::Reboot(RebootType reason)
    std::int32_t RT1051LPMCommon::Reboot(RebootType reason)
    {
        switch (reason) {
        case RebootType::GoToRecoveryUpdate:


@@ 62,75 60,83 @@ namespace bsp
        Down
    };

    CpuFrequencyMHz RT1051LPMCommon::onChangeUp(CpuFrequencyMHz freq, bsp::CpuFrequencyMHz newFrequency)
    void RT1051LPMCommon::onChangeUp(CpuFrequencyMHz freq, CpuFrequencyMHz newFrequency)
    {
        if ((freq <= CpuFrequencyMHz::Level_1) && (newFrequency > CpuFrequencyMHz::Level_1)) {
            // Switch DCDC to CCM mode to improve stability
            DCDC_BootIntoCCM(DCDC);
            // Switch external RAM clock source to PLL2
            /* Switch to external crystal oscillator */
            SwitchOscillatorSource(LowPowerMode::OscillatorSource::External);

            /* Switch external RAM clock source to PLL2 */
            if (driverSEMC) {
                driverSEMC->SwitchToPLL2ClockSource();
            }
            // Enable regular 2P5 and 1P1 LDO, turn off weak 2P5 and 1P1 LDO
            SwitchToRegularModeLDO();
            // Switch to external crystal oscillator
            SwitchOscillatorSource(LowPowerMode::OscillatorSource::External);
        }
        return newFrequency;
    }

    void RT1051LPMCommon::onChangeDown(CpuFrequencyMHz newFrequency)
    {
        if (newFrequency <= bsp::CpuFrequencyMHz::Level_1) {
            // Switch to internal RC oscillator
            SwitchOscillatorSource(bsp::LowPowerMode::OscillatorSource::Internal);
            // Enable weak 2P5 and 1P1 LDO, turn off regular 2P5 and 1P1 LDO
            SwitchToLowPowerModeLDO();
            // Switch external RAM clock source to OSC
        if (newFrequency <= CpuFrequencyMHz::Level_1) {
            /* Switch to internal RC oscillator */
            SwitchOscillatorSource(LowPowerMode::OscillatorSource::Internal);

            /* Switch external RAM clock source to OSC */
            if (driverSEMC) {
                driverSEMC->SwitchToPeripheralClockSource();
            }
            // Switch DCDC to DCM mode to reduce current consumption
            DCDC_BootIntoDCM(DCDC);
        }
    }

    void RT1051LPMCommon::SetCpuFrequency(bsp::CpuFrequencyMHz freq)
    void RT1051LPMCommon::SetCpuFrequency(CpuFrequencyMHz freq)
    {
        if (currentFrequency == freq) {
            return;
        }
        const Change change = (currentFrequency < freq) ? Change::Up : Change::Down;
        if (Change::Up == change) {
            freq = onChangeUp(currentFrequency, freq);

        /* Switch to overdrive config for any frequency change above 12MHz */
        const auto isChangeAbove12MHz =
            (currentFrequency > CpuFrequencyMHz::Level_1) || (freq > CpuFrequencyMHz::Level_1);
        if (isChangeAbove12MHz) {
            dcdc::SwitchToOverdriveConfig();
        }

        const auto changeDirection = (currentFrequency < freq) ? Change::Up : Change::Down;
        if (Change::Up == changeDirection) {
            onChangeUp(currentFrequency, freq);
        }

        switch (freq) {
        case bsp::CpuFrequencyMHz::Level_0:
        case CpuFrequencyMHz::Level_0:
            CpuFreq->SetCpuFrequency(CpuFreqLPM::CpuClock::CpuClock_Osc_4_Mhz);
            break;
        case bsp::CpuFrequencyMHz::Level_1:
        case CpuFrequencyMHz::Level_1:
            CpuFreq->SetCpuFrequency(CpuFreqLPM::CpuClock::CpuClock_Osc_12_Mhz);
            break;
        case bsp::CpuFrequencyMHz::Level_2:
        case CpuFrequencyMHz::Level_2:
            CpuFreq->SetCpuFrequency(CpuFreqLPM::CpuClock::CpuClock_Osc_24_Mhz);
            break;
        case bsp::CpuFrequencyMHz::Level_3:
        case CpuFrequencyMHz::Level_3:
            CpuFreq->SetCpuFrequency(CpuFreqLPM::CpuClock::CpuClock_Pll2_66_Mhz);
            break;
        case bsp::CpuFrequencyMHz::Level_4:
        case CpuFrequencyMHz::Level_4:
            CpuFreq->SetCpuFrequency(CpuFreqLPM::CpuClock::CpuClock_Pll2_132_Mhz);
            break;
        case bsp::CpuFrequencyMHz::Level_5:
        case CpuFrequencyMHz::Level_5:
            CpuFreq->SetCpuFrequency(CpuFreqLPM::CpuClock::CpuClock_Pll2_264_Mhz);
            break;
        case bsp::CpuFrequencyMHz::Level_6:
        case CpuFrequencyMHz::Level_6:
            CpuFreq->SetCpuFrequency(CpuFreqLPM::CpuClock::CpuClock_Pll2_528_Mhz);
            break;
        }

        if (Change::Down == change) {
        /* Switch back to regular config after clock change is done */
        if (isChangeAbove12MHz) {
            dcdc::SwitchToRegularConfig();
        }

        if (Change::Down == changeDirection) {
            onChangeDown(freq);
        }

        LOG_INFO("CPU frequency changed to %lu", CLOCK_GetFreq(kCLOCK_CpuClk));
        currentFrequency = freq;
    }


@@ 140,46 146,16 @@ namespace bsp
        return CLOCK_GetCpuClkFreq();
    }

    void RT1051LPMCommon::SwitchOscillatorSource(bsp::LowPowerMode::OscillatorSource source)
    {
        if (source == bsp::LowPowerMode::OscillatorSource::Internal) {
            cpp_freertos::CriticalSection::Enter();
            bsp::DisableExternalOscillator();
            cpp_freertos::CriticalSection::Exit();
        }
        else if (source == bsp::LowPowerMode::OscillatorSource::External) {
            cpp_freertos::CriticalSection::Enter();
            bsp::EnableExternalOscillator();
            cpp_freertos::CriticalSection::Exit();
        }
    }

    void RT1051LPMCommon::RegularLDOMode()
    void RT1051LPMCommon::SwitchOscillatorSource(LowPowerMode::OscillatorSource source)
    {
        // Enable regular 2P5 and 1P1 LDO
        PMU->REG_2P5_SET = PMU_REG_2P5_ENABLE_LINREG_MASK;
        PMU->REG_1P1_SET = PMU_REG_1P1_ENABLE_LINREG_MASK;

        // Wait for regular LDOs to become stable (documentation Low Power AN12085)
        while ((PMU->REG_2P5 & PMU_REG_2P5_OK_VDD2P5_MASK) == 0) {}
        while ((PMU->REG_1P1 & PMU_REG_1P1_OK_VDD1P1_MASK) == 0) {}

        // Turn off weak 2P5 and 1P1 LDO
        PMU->REG_2P5_CLR = PMU_REG_2P5_ENABLE_WEAK_LINREG_MASK;
        PMU->REG_1P1_CLR = PMU_REG_1P1_ENABLE_WEAK_LINREG_MASK;
    }

    void RT1051LPMCommon::LowPowerLDOMode()
    {
        // Enable weak 2P5 and 1P1 LDO
        PMU->REG_2P5_SET = PMU_REG_2P5_ENABLE_WEAK_LINREG_MASK;
        PMU->REG_1P1_SET = PMU_REG_1P1_ENABLE_WEAK_LINREG_MASK;

        // Wait for 40us for weak LDOs to stabilize
        SDK_DelayAtLeastUs(40, CLOCK_GetCpuClkFreq());
        switch (source) {
        case LowPowerMode::OscillatorSource::Internal:
            SwitchToInternalOscillator();
            break;

        // Disable regular 2P5 and 1P1 LDO
        PMU->REG_2P5_CLR = PMU_REG_2P5_ENABLE_LINREG_MASK;
        PMU->REG_1P1_CLR = PMU_REG_1P1_ENABLE_LINREG_MASK;
        case LowPowerMode::OscillatorSource::External:
            SwitchToExternalOscillator();
            break;
        }
    }
} // namespace bsp

M module-bsp/board/rt1051/bsp/lpm/RT1051LPMCommon.hpp => module-bsp/board/rt1051/bsp/lpm/RT1051LPMCommon.hpp +5 -9
@@ 13,21 13,17 @@ namespace bsp
    {
      public:
        RT1051LPMCommon();
        int32_t PowerOff() final;
        int32_t Reboot(RebootType reason) final;
        std::int32_t PowerOff() final;
        std::int32_t Reboot(RebootType reason) final;
        void SetCpuFrequency(CpuFrequencyMHz freq) final;
        [[nodiscard]] uint32_t GetCpuFrequency() const noexcept final;
        [[nodiscard]] std::uint32_t GetCpuFrequency() const noexcept final;
        void SwitchOscillatorSource(OscillatorSource source) final;

        void RegularLDOMode();
        void LowPowerLDOMode();

      private:
        CpuFrequencyMHz onChangeUp(CpuFrequencyMHz freq, CpuFrequencyMHz newFrequency);
        void onChangeDown(bsp::CpuFrequencyMHz freq);
        void onChangeUp(CpuFrequencyMHz freq, CpuFrequencyMHz newFrequency);
        void onChangeDown(CpuFrequencyMHz freq);

        std::unique_ptr<bsp::CpuFreqLPM> CpuFreq;
        std::shared_ptr<drivers::DriverSEMC> driverSEMC;
    };

} // namespace bsp

M module-bsp/board/rt1051/common/board.cpp => module-bsp/board/rt1051/common/board.cpp +0 -6
@@ 179,12 179,6 @@ namespace bsp
        //        SNVS->LPGPR[0] = rebootCode::rebootFailedToBoot;
        // TODO: Here we can implement boot-time fail detection

        // Set internal DCDC to CCM mode, DCM is allowed ONLY in low power modes (see AN12085, 5.3.9, p.33)
        DCDC_BootIntoCCM(DCDC);

        // Disconnect DCDC internal load resistor
        DCDC->REG1 &= ~DCDC_REG1_REG_RLOAD_SW_MASK;

        PrintSystemClocks();
        clearAndPrintBootReason();


M module-bsp/board/rt1051/drivers/RT1051DriverOscillator.cpp => module-bsp/board/rt1051/drivers/RT1051DriverOscillator.cpp +2 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "RT1051DriverOscillator.hpp"


@@ 9,7 9,7 @@ namespace drivers

    RT1051DriverOscillator::RT1051DriverOscillator() noexcept
    {
        bsp::EnableExternalOscillator();
        bsp::SwitchToExternalOscillator();
    }

} // namespace drivers

M module-bsp/board/rt1051/drivers/RT1051DriverPLL2.cpp => module-bsp/board/rt1051/drivers/RT1051DriverPLL2.cpp +35 -14
@@ 3,41 3,63 @@

#include "RT1051DriverPLL2.hpp"
#include "board/rt1051/bsp/lpm/ClockState.hpp"
#include "board/rt1051/bsp/lpm/Bandgap.hpp"
#include "board/rt1051/bsp/lpm/CpuFreqLPM.hpp"
#include <fsl_dcdc.h>
#include "board/rt1051/bsp/lpm/Bandgap.hpp"
#include "board/rt1051/bsp/lpm/LDO.hpp"
#include "board/rt1051/bsp/lpm/DCDC.hpp"

namespace
{
    inline std::uint32_t getCurrentVDDRunVoltage()
    {
        return (DCDC->REG3 & DCDC_REG3_TRG_MASK);
    }
} // namespace

namespace drivers
{
    RT1051DriverPLL2::RT1051DriverPLL2() noexcept
    {
        if (!IsPLL2Enabled()) {
            // Set VDD_SOC_IN to 1.15V required to safely start PLL2
            DCDC_AdjustTargetVoltage(DCDC, bsp::VDDRun_1150_mV, bsp::VDDStandby_925_mV);
            /* Check if switching conditions already met */
            const auto isCurrentVoltageOverdrive = (getCurrentVDDRunVoltage() >= bsp::VDDRun_1275_mV);
            if (!isCurrentVoltageOverdrive) {
                bsp::dcdc::SwitchToOverdriveConfig();
            }

            // Switch to regular bandgap
            /* Switch to regular bandgap */
            bsp::bandgap::SwitchToRegularMode();

            // Enable PLL2
            /* Switch to regular LDO */
            bsp::ldo::SwitchToRegularMode();

            /* Switch back to regular config */
            if (!isCurrentVoltageOverdrive) {
                bsp::dcdc::SwitchToRegularConfig();
            }

            /* Enable PLL2 */
            clkPLL2setup(CLK_ENABLE);
        }
    }

    RT1051DriverPLL2::~RT1051DriverPLL2()
    RT1051DriverPLL2::~RT1051DriverPLL2() noexcept
    {
        if ((CLOCK_GetMux(kCLOCK_SemcMux) == SemcMuxPeripheralClock) && !bsp::IsClockEnabled(kCLOCK_Lpspi1) &&
            !bsp::IsClockEnabled(kCLOCK_Lpspi2) && !bsp::IsClockEnabled(kCLOCK_Lpspi3) &&
            !bsp::IsClockEnabled(kCLOCK_Lpspi4) && !bsp::IsClockEnabled(kCLOCK_Usdhc1) &&
            !bsp::IsClockEnabled(kCLOCK_Usdhc2)) {

            // Disable PLL2
            /* Disable PLL2 */
            clkPLL2setup(CLK_DISABLE);

            // Switch to low power bandgap
            bsp::bandgap::SwitchToLowPowerMode();
            /* Switch DCDC to low power config */
            bsp::dcdc::SwitchToLowPowerConfig();

            // After turning off PLL2 and with CPU @4MHZ VDD_SOC_IN can be set to 950mV
            DCDC_AdjustTargetVoltage(DCDC, bsp::VDDRun_950_mV, bsp::VDDStandby_925_mV);
            /* Switch to low power LDO */
            bsp::ldo::SwitchToLowPowerMode();

            /* Switch to low power bandgap */
            bsp::bandgap::SwitchToLowPowerMode();
        }
    }



@@ 45,5 67,4 @@ namespace drivers
    {
        return not static_cast<bool>(CCM_ANALOG->PLL_SYS & CCM_ANALOG_PLL_SYS_POWERDOWN_MASK);
    }

} // namespace drivers

M module-bsp/board/rt1051/drivers/RT1051DriverPLL2.hpp => module-bsp/board/rt1051/drivers/RT1051DriverPLL2.hpp +5 -5
@@ 1,23 1,23 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "board/clock_config.h"
#include <cstdint>

namespace drivers
{
    inline constexpr uint32_t SemcMuxPLL2Clock{1};
    inline constexpr uint32_t SemcMuxPeripheralClock{0};
    inline constexpr std::uint32_t SemcMuxPLL2Clock{1};
    inline constexpr std::uint32_t SemcMuxPeripheralClock{0};

    class RT1051DriverPLL2
    {
      public:
        RT1051DriverPLL2() noexcept;
        ~RT1051DriverPLL2();
        ~RT1051DriverPLL2() noexcept;

      private:
        [[nodiscard]] bool IsPLL2Enabled() const noexcept;
    };

} // namespace drivers

M module-bsp/board/rt1051/drivers/RT1051DriverPWM.cpp => module-bsp/board/rt1051/drivers/RT1051DriverPWM.cpp +2 -4
@@ 1,10 1,9 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "RT1051DriverPWM.hpp"
#include "RT1051DriverPWMhelper.hpp"
#include <log/log.hpp>
#include "../board.h"
#include <algorithm>

namespace drivers


@@ 155,7 154,6 @@ namespace drivers
                                           unsigned numOfChannels,
                                           std::uint32_t _clockFrequency)
    {
        pwm_mode_t pwmMode = kPWM_SignedCenterAligned;
        PWM_SetupPwm(base, pwmModule, config, numOfChannels, pwmMode, parameters.frequency, _clockFrequency);
    }



@@ 174,7 172,7 @@ namespace drivers
    void RT1051DriverPWM::UpdateClockFrequency(bsp::CpuFrequencyMHz newFrequency)
    {
        cpp_freertos::LockGuard lock(frequencyChangeMutex);
        std::uint32_t convertedFrequency = static_cast<std::uint32_t>(newFrequency) * bsp::MHz_frequency_multiplier;
        const auto convertedFrequency = static_cast<std::uint32_t>(newFrequency) * bsp::HzPerMHz;

        if (clockFrequency != convertedFrequency) {
            SetupPWMInstance(pwmSignalsConfig.data(), enabledChannels.size(), convertedFrequency);

M module-bsp/board/rt1051/puretx/bsp/lpm/RT1051LPM.cpp => module-bsp/board/rt1051/puretx/bsp/lpm/RT1051LPM.cpp +15 -26
@@ 2,12 2,10 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "RT1051LPM.hpp"
#include <board.h>
#include <board/BoardDefinitions.hpp>

namespace bsp
{

    using namespace drivers;

    RT1051LPM::RT1051LPM()


@@ 16,17 14,19 @@ namespace bsp
                                    DriverGPIOParams{});
        gpio_2 = DriverGPIO::Create(static_cast<GPIOInstances>(BoardDefinitions::DCDC_INVERTER_MODE_GPIO),
                                    DriverGPIOParams{});
        gpio_1->ConfPin(DriverGPIOPinParams{.dir      = DriverGPIOPinParams::Direction::Output,
                                            .irqMode  = DriverGPIOPinParams::InterruptMode::NoIntmode,
                                            .defLogic = 1,
                                            .pin = static_cast<uint32_t>(BoardDefinitions::POWER_SWITCH_HOLD_BUTTON)});

        gpio_2->ConfPin(DriverGPIOPinParams{.dir      = DriverGPIOPinParams::Direction::Output,
                                            .irqMode  = DriverGPIOPinParams::InterruptMode::NoIntmode,
                                            .defLogic = 0,
                                            .pin = static_cast<uint32_t>(BoardDefinitions::DCDC_INVERTER_MODE_PIN)});

        gpio_1->WritePin(static_cast<uint32_t>(BoardDefinitions::POWER_SWITCH_HOLD_BUTTON), 1);
        gpio_1->ConfPin(
            DriverGPIOPinParams{.dir      = DriverGPIOPinParams::Direction::Output,
                                .irqMode  = DriverGPIOPinParams::InterruptMode::NoIntmode,
                                .defLogic = 1,
                                .pin      = static_cast<std::uint32_t>(BoardDefinitions::POWER_SWITCH_HOLD_BUTTON)});

        gpio_2->ConfPin(
            DriverGPIOPinParams{.dir      = DriverGPIOPinParams::Direction::Output,
                                .irqMode  = DriverGPIOPinParams::InterruptMode::NoIntmode,
                                .defLogic = 0,
                                .pin      = static_cast<std::uint32_t>(BoardDefinitions::DCDC_INVERTER_MODE_PIN)});

        gpio_1->WritePin(static_cast<std::uint32_t>(BoardDefinitions::POWER_SWITCH_HOLD_BUTTON), 1);
        EnableDcdcPowerSaveMode();
    }



@@ 34,23 34,12 @@ namespace bsp
    // Current threshold for entry to and exit from the PSM mode is set to 100 mA
    void RT1051LPM::EnableDcdcPowerSaveMode()
    {
        gpio_2->WritePin(static_cast<uint32_t>(BoardDefinitions::DCDC_INVERTER_MODE_PIN), 0);
        gpio_2->WritePin(static_cast<std::uint32_t>(BoardDefinitions::DCDC_INVERTER_MODE_PIN), 0);
    }

    // Forces both bucks to operate in PWM mode
    void RT1051LPM::DisableDcdcPowerSaveMode()
    {
        gpio_2->WritePin(static_cast<uint32_t>(BoardDefinitions::DCDC_INVERTER_MODE_PIN), 1);
    }

    void RT1051LPM::SwitchToRegularModeLDO()
    {
        RT1051LPMCommon::RegularLDOMode();
        gpio_2->WritePin(static_cast<std::uint32_t>(BoardDefinitions::DCDC_INVERTER_MODE_PIN), 1);
    }

    void RT1051LPM::SwitchToLowPowerModeLDO()
    {
        RT1051LPMCommon::LowPowerLDOMode();
    }

} // namespace bsp

M module-bsp/board/rt1051/puretx/bsp/lpm/RT1051LPM.hpp => module-bsp/board/rt1051/puretx/bsp/lpm/RT1051LPM.hpp +0 -4
@@ 14,12 14,8 @@ namespace bsp
        void EnableDcdcPowerSaveMode() final;
        void DisableDcdcPowerSaveMode() final;

        void SwitchToRegularModeLDO() final;
        void SwitchToLowPowerModeLDO() final;

      private:
        std::shared_ptr<drivers::DriverGPIO> gpio_1;
        std::shared_ptr<drivers::DriverGPIO> gpio_2;
    };

} // namespace bsp

M module-bsp/bsp/common.cpp => module-bsp/bsp/common.cpp +25 -29
@@ 1,41 1,37 @@
#include "common.hpp"

namespace bsp{
   	const char *c_str(const Board &board)
namespace bsp
{
    std::uint8_t CpuMHZToLevel(enum CpuFrequencyMHz val)
    {
            switch (board) {
            case Board::RT1051:
                return "RT1051";
                break;
            case Board::Linux:
                return "Linux";
                break;
            case Board::none:
            default:
                return "none";
                break;
        }
   }

   uint8_t CpuMHZToLevel(enum CpuFrequencyMHz val)
   {
       switch (val) {
       case CpuFrequencyMHz::Level_0:
        switch (val) {
        case CpuFrequencyMHz::Level_0:
           return 0;
       case CpuFrequencyMHz::Level_1:
        case CpuFrequencyMHz::Level_1:
           return 1;
       case CpuFrequencyMHz::Level_2:
        case CpuFrequencyMHz::Level_2:
           return 2;
       case CpuFrequencyMHz::Level_3:
        case CpuFrequencyMHz::Level_3:
           return 3;
       case CpuFrequencyMHz::Level_4:
        case CpuFrequencyMHz::Level_4:
           return 4;
       case CpuFrequencyMHz::Level_5:
        case CpuFrequencyMHz::Level_5:
           return 5;
       case CpuFrequencyMHz::Level_6:
        case CpuFrequencyMHz::Level_6:
           return 6;
       }
       return -1;
        }
        return -1;
    }

   	const char *c_str(Board board)
    {
        switch (board) {
        case Board::RT1051:
            return "RT1051";
        case Board::Linux:
            return "Linux";
        default:
            return "none";
        }
   }
};


M module-bsp/bsp/common.hpp => module-bsp/bsp/common.hpp +11 -11
@@ 4,12 4,13 @@
#pragma once

#include <cstdint>

namespace bsp
{
    enum class RetCode{
    enum class RetCode
    {
        Success,
        Failure

    };

    /// CPU frequency is dependent on the clock settings.


@@ 25,16 26,15 @@ namespace bsp
        Level_6 = 528
    };

    uint8_t CpuMHZToLevel(enum CpuFrequencyMHz val);

    constexpr auto MHz_frequency_multiplier = 1000000U;

    enum class Board{
    enum class Board
    {
        RT1051,
    	Linux,
    	none
        Linux,
        none
    };
    [[nodiscard]] const char *c_str(const Board &board);

}
    constexpr auto HzPerMHz = 1000000U;

    [[nodiscard]] std::uint8_t CpuMHZToLevel(CpuFrequencyMHz val);
    [[nodiscard]] const char *c_str(Board board);
}

M module-bsp/bsp/lpm/bsp_lpm.hpp => module-bsp/bsp/lpm/bsp_lpm.hpp +4 -7
@@ 14,7 14,6 @@ namespace drivers

namespace bsp
{

    class LowPowerMode
    {
      public:


@@ 23,6 22,7 @@ namespace bsp
            External,
            Internal
        };
        
        enum class RebootType
        {
            NormalRestart,


@@ 38,21 38,18 @@ namespace bsp

        static std::optional<std::unique_ptr<LowPowerMode>> Create();

        virtual int32_t PowerOff()                = 0;
        virtual int32_t Reboot(RebootType reason) = 0;
        virtual std::int32_t PowerOff()                = 0;
        virtual std::int32_t Reboot(RebootType reason) = 0;

        virtual void SetCpuFrequency(CpuFrequencyMHz freq) = 0;
        [[nodiscard]] CpuFrequencyMHz GetCurrentFrequencyLevel() const noexcept;
        [[nodiscard]] virtual uint32_t GetCpuFrequency() const noexcept = 0;
        [[nodiscard]] virtual std::uint32_t GetCpuFrequency() const noexcept = 0;

        virtual void SwitchOscillatorSource(OscillatorSource source) = 0;

        virtual void EnableDcdcPowerSaveMode()  = 0;
        virtual void DisableDcdcPowerSaveMode() = 0;

        virtual void SwitchToRegularModeLDO()  = 0;
        virtual void SwitchToLowPowerModeLDO() = 0;

      protected:
        CpuFrequencyMHz currentFrequency = CpuFrequencyMHz::Level_6;
    };

M module-sys/SystemManager/PowerManager.cpp => module-sys/SystemManager/PowerManager.cpp +4 -4
@@ 21,7 21,7 @@ namespace sys
        constexpr auto highestLevelName{"highestCpuFrequency"};
    } // namespace

    CpuFrequencyMonitor::CpuFrequencyMonitor(const std::string name) : levelName(name)
    CpuFrequencyMonitor::CpuFrequencyMonitor(const std::string &name) : levelName(name)
    {}

    [[nodiscard]] auto CpuFrequencyMonitor::GetName() const noexcept -> std::string


@@ 153,18 153,18 @@ namespace sys
        cpuStatistics.TrackChange(ret);
    }

    bool PowerManager::IsCpuPernamentFrequency()
    bool PowerManager::IsCpuPermanentFrequency()
    {
        return cpuAlgorithms->get(sys::cpu::AlgoID::FrequencyHold) != nullptr;
    }

    void PowerManager::SetPernamentFrequency(bsp::CpuFrequencyMHz freq)
    void PowerManager::SetPermanentFrequency(bsp::CpuFrequencyMHz freq)
    {
        cpuAlgorithms->emplace(sys::cpu::AlgoID::FrequencyHold,
                               std::make_unique<sys::cpu::FrequencyHold>(freq, powerProfile));
    }

    void PowerManager::ResetPernamentFrequency()
    void PowerManager::ResetPermanentFrequency()
    {
        cpuAlgorithms->remove(sys::cpu::AlgoID::FrequencyHold);
    }

M module-sys/SystemManager/SystemManagerCommon.cpp => module-sys/SystemManager/SystemManagerCommon.cpp +5 -9
@@ 592,21 592,18 @@ namespace sys
        connect(typeid(sys::DeviceRegistrationMessage), [this](sys::Message *message) -> sys::MessagePointer {
            auto msg = static_cast<sys::DeviceRegistrationMessage *>(message);
            deviceManager->RegisterNewDevice(msg->getDevice());

            return sys::MessageNone{};
        });

        connect(typeid(sys::SentinelRegistrationMessage), [this](sys::Message *message) -> sys::MessagePointer {
            auto msg = static_cast<sys::SentinelRegistrationMessage *>(message);
            powerManager->RegisterNewSentinel(msg->getSentinel());

            return sys::MessageNone{};
        });

        connect(typeid(sys::SentinelRemovalMessage), [this](sys::Message *message) -> sys::MessagePointer {
            auto msg = static_cast<sys::SentinelRemovalMessage *>(message);
            powerManager->RemoveSentinel(msg->getSentinelName());

            return std::make_shared<sys::ResponseMessage>();
        });



@@ 622,22 619,21 @@ namespace sys
        connect(typeid(sys::ReleaseCpuFrequencyMessage), [this](sys::Message *message) -> sys::MessagePointer {
            auto msg = static_cast<sys::ReleaseCpuFrequencyMessage *>(message);
            powerManager->ResetCpuFrequencyRequest(msg->getName());

            return sys::MessageNone{};
        });

        connect(typeid(sys::IsCpuPernament), [this](sys::Message *message) -> sys::MessagePointer {
            return std::make_shared<sys::IsCpuPernamentResponse>(powerManager->IsCpuPernamentFrequency());
        connect(typeid(sys::IsCpuPermanent), [this](sys::Message *message) -> sys::MessagePointer {
            return std::make_shared<sys::IsCpuPermanentResponse>(powerManager->IsCpuPermanentFrequency());
        });

        connect(typeid(sys::HoldCpuFrequencyPermanentlyMessage), [this](sys::Message *message) -> sys::MessagePointer {
            auto msg = static_cast<sys::HoldCpuFrequencyPermanentlyMessage *>(message);
            powerManager->SetPernamentFrequency(msg->request);
            powerManager->SetPermanentFrequency(msg->request);
            return std::make_shared<sys::HoldCpuFrequencyPermanentlyResponse>();
        });

        connect(typeid(sys::ReleaseCpuPermanentFrequencyMessage), [this](sys::Message *message) -> sys::MessagePointer {
            powerManager->ResetPernamentFrequency();
            powerManager->ResetPermanentFrequency();
            return std::make_shared<sys::HoldCpuFrequencyPermanentlyResponse>();
        });



@@ 754,7 750,7 @@ namespace sys

    void SystemManagerCommon::UpdateResourcesAfterCpuFrequencyChange(bsp::CpuFrequencyMHz newFrequency)
    {
        if (newFrequency <= bsp::CpuFrequencyMHz::Level_1) {
        if (newFrequency <= bsp::CpuFrequencyMHz::Level_2) {
            purefs::subsystem::disk_mgr()->pm_control(purefs::blkdev::pm_state::suspend);
        }
        else {

M module-sys/SystemManager/cpu/algorithm/FrequencyStepping.cpp => module-sys/SystemManager/cpu/algorithm/FrequencyStepping.cpp +1 -3
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "FrequencyStepping.hpp"


@@ 23,9 23,7 @@ namespace sys::cpu
        case bsp::CpuFrequencyMHz::Level_3:
            return bsp::CpuFrequencyMHz::Level_2;
        case bsp::CpuFrequencyMHz::Level_2:
            [[fallthrough]];
        case bsp::CpuFrequencyMHz::Level_1:
            [[fallthrough]];
        case bsp::CpuFrequencyMHz::Level_0:
            return profile.minimalFrequency;
        }

M module-sys/SystemManager/include/SystemManager/PowerManager.hpp => module-sys/SystemManager/include/SystemManager/PowerManager.hpp +4 -4
@@ 25,7 25,7 @@ namespace sys
    class CpuFrequencyMonitor
    {
      public:
        explicit CpuFrequencyMonitor(const std::string name);
        explicit CpuFrequencyMonitor(const std::string &name);

        [[nodiscard]] auto GetName() const noexcept -> std::string;
        [[nodiscard]] auto GetPeriodRuntimePercentage(const TickType_t periodTicksIncrease) const noexcept


@@ 65,9 65,9 @@ namespace sys
        void RemoveSentinel(std::string sentinelName) const;
        void SetCpuFrequencyRequest(const std::string &sentinelName, bsp::CpuFrequencyMHz request);
        void ResetCpuFrequencyRequest(const std::string &sentinelName);
        bool IsCpuPernamentFrequency();
        void SetPernamentFrequency(bsp::CpuFrequencyMHz freq);
        void ResetPernamentFrequency();
        bool IsCpuPermanentFrequency();
        void SetPermanentFrequency(bsp::CpuFrequencyMHz freq);
        void ResetPermanentFrequency();

        void LogPowerManagerStatistics();


M module-sys/common/include/system/messages/RequestCpuFrequencyMessage.hpp => module-sys/common/include/system/messages/RequestCpuFrequencyMessage.hpp +6 -8
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 8,20 8,19 @@

namespace sys
{

    struct IsCpuPernament : public sys::DataMessage
    struct IsCpuPermanent : public sys::DataMessage
    {
      public:
        explicit IsCpuPernament()
        explicit IsCpuPermanent()
        {}
    };

    struct IsCpuPernamentResponse : public sys::ResponseMessage
    struct IsCpuPermanentResponse : public sys::ResponseMessage
    {
      public:
        explicit IsCpuPernamentResponse(bool pernament) : pernament(pernament)
        explicit IsCpuPermanentResponse(bool permanent) : permanent(permanent)
        {}
        const bool pernament = false;
        const bool permanent = false;
    };

    struct HoldCpuFrequencyPermanentlyMessage : public sys::DataMessage


@@ 37,5 36,4 @@ namespace sys

    class ReleaseCpuPermanentFrequencyMessage : public sys::DataMessage
    {};

} // namespace sys

M pure_changelog.md => pure_changelog.md +1 -0
@@ 16,6 16,7 @@
* Change roaming indicator to show domestic roaming as home network
* Optimized ServiceAudio power management
* Blocked call execution with empty phone number field
* Improved device stability related to frequency scaling

### Fixed