// Copyright (c) 2017-2021, 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 #include "../board.h" #include namespace drivers { namespace { constexpr pwm_mode_t pwmMode = kPWM_SignedCenterAligned; } RT1051DriverPWM::RT1051DriverPWM(PWMInstances inst, PWMModules mod, const DriverPWMParams ¶ms) : DriverPWM(inst, mod, params) { pwm_config_t pwmConfig = {}; switch (instance) { case PWMInstances::PWM_1: base = PWM1; LOG_DEBUG("Init: PWM1"); break; case PWMInstances::PWM_2: base = PWM2; LOG_DEBUG("Init: PWM2"); break; case PWMInstances::PWM_3: base = PWM3; LOG_DEBUG("Init: PWM3"); break; case PWMInstances::PWM_4: base = PWM4; LOG_DEBUG("Init: PWM4"); break; default: break; } switch (module) { case PWMModules::MODULE0: pwmModule = kPWM_Module_0; LOG_DEBUG("Init: PWM module 0"); break; case PWMModules::MODULE1: pwmModule = kPWM_Module_1; LOG_DEBUG("Init: PWM module 1"); break; case PWMModules::MODULE2: pwmModule = kPWM_Module_2; LOG_DEBUG("Init: PWM module 2"); break; case PWMModules::MODULE3: pwmModule = kPWM_Module_3; LOG_DEBUG("Init: PWM module 3"); break; default: break; } PWM_GetDefaultConfig(&pwmConfig); PWM_Init(base, pwmModule, &pwmConfig); SetupPWMChannel(parameters.channel); Start(parameters.channel); } void RT1051DriverPWM::InitNextChannel(const DriverPWMParams ¶ms) { LOG_INFO("Channel from this PWM module already enabled - PWM will use parameters from initial config"); SetupPWMChannel(params.channel); Start(params.channel); } RT1051DriverPWM::~RT1051DriverPWM() { PWM_Deinit(base, pwmModule); LOG_DEBUG("Deinit: PWM"); } void RT1051DriverPWM::SetDutyCycle(std::uint8_t dutyCyclePercent, PWMChannel channel) { std::uint8_t dutyCycle = std::clamp(dutyCyclePercent, static_cast(0), static_cast(100)); auto pwmChannel = getChannelMask(channel); for (unsigned i = 0; i < enabledChannels.size(); ++i) { if (pwmSignalsConfig[i].pwmChannel == pwmChannel) { pwmSignalsConfig[i].dutyCyclePercent = dutyCycle; } } PWM_UpdatePwmDutycycle(base, pwmModule, pwmChannel, pwmMode, dutyCycle); PWM_SetPwmLdok(base, 1 << pwmModule, true); } void RT1051DriverPWM::Start(PWMChannel channel) { pwmChannelState[channel] = RT1051DriverPWM::PwmState::On; RestorePwmOutput(channel); if (not otherChannelRunning(channel)) { PWM_StartTimer(base, 1 << pwmModule); } } void RT1051DriverPWM::Stop(PWMChannel channel) { if (not otherChannelRunning(channel)) { PWM_StopTimer(base, 1 << pwmModule); } ForceLowOutput(channel); pwmChannelState[channel] = RT1051DriverPWM::PwmState::Off; } RT1051DriverPWM::PwmState RT1051DriverPWM::GetPwmState() { if (PWM_GetPwmGeneratorState(base, 1 << pwmModule)) { return PwmState::On; } else { return PwmState::Off; } } void RT1051DriverPWM::SetupPWMChannel(PWMChannel channel) { if (channelNotEnabled(channel)) { auto currentInstance = enabledChannels.size(); auto pwmChannel = getChannelMask(channel); pwmSignalsConfig[currentInstance].pwmChannel = pwmChannel; pwmSignalsConfig[currentInstance].dutyCyclePercent = 0; pwmSignalsConfig[currentInstance].level = kPWM_HighTrue; pwmSignalsConfig[currentInstance].deadtimeValue = 0; pwmSignalsConfig[currentInstance].faultState = kPWM_PwmFaultState0; clockFrequency = DEFAULT_SYSTEM_CLOCK; SetupPWMInstance(&pwmSignalsConfig[currentInstance], 1, clockFrequency); PWM_SetupFaultDisableMap(base, pwmModule, pwmChannel, kPWM_faultchannel_0, 0); // Force logic config PWM_SetupSwCtrlOut(base, pwmModule, pwmChannel, false); base->SM[pwmModule].CTRL2 |= PWM_CTRL2_FRCEN(1U); enabledChannels.push_back(channel); } } void RT1051DriverPWM::SetupPWMInstance(pwm_signal_param_t *config, unsigned numOfChannels, std::uint32_t _clockFrequency) { pwm_mode_t pwmMode = kPWM_SignedCenterAligned; PWM_SetupPwm(base, pwmModule, config, numOfChannels, pwmMode, parameters.frequency, _clockFrequency); } void RT1051DriverPWM::ForceLowOutput(PWMChannel channel) { PWM_SetupForceSignal(base, pwmModule, getChannelMask(channel), kPWM_SoftwareControl); base->SM[pwmModule].CTRL2 |= PWM_CTRL2_FORCE(1U); } void RT1051DriverPWM::RestorePwmOutput(PWMChannel channel) { PWM_SetupForceSignal(base, pwmModule, getChannelMask(channel), kPWM_UsePwm); base->SM[pwmModule].CTRL2 |= PWM_CTRL2_FORCE(1U); } void RT1051DriverPWM::UpdateClockFrequency(bsp::CpuFrequencyMHz newFrequency) { cpp_freertos::LockGuard lock(frequencyChangeMutex); std::uint32_t convertedFrequency = static_cast(newFrequency) * bsp::MHz_frequency_multiplier; if (clockFrequency != convertedFrequency) { SetupPWMInstance(pwmSignalsConfig.data(), enabledChannels.size(), convertedFrequency); if (GetPwmState() == PwmState::On) { stopAll(); restoreDutyCycle(); startAll(); } clockFrequency = convertedFrequency; } } pwm_channels_t RT1051DriverPWM::getChannelMask(PWMChannel channel) { switch (channel) { case PWMChannel::A: return kPWM_PwmA; case PWMChannel::B: return kPWM_PwmB; case PWMChannel::X: return kPWM_PwmX; } LOG_FATAL("No mask for given PWM channel!"); return kPWM_PwmB; } bool RT1051DriverPWM::channelNotEnabled(PWMChannel channel) { for (const auto &chan : enabledChannels) { if (chan == channel || chan == PWMChannel::X) { LOG_FATAL("PWM Channel already enabled!"); return false; } } return true; } bool RT1051DriverPWM::otherChannelRunning(PWMChannel channel) { for (const auto &[otherChannel, state] : pwmChannelState) { if (channel != otherChannel && state == RT1051DriverPWM::PwmState::On) { return true; } } return false; } void RT1051DriverPWM::stopAll() { PWM_StopTimer(base, 1 << pwmModule); for (const auto &[channel, state] : pwmChannelState) { if (state == RT1051DriverPWM::PwmState::On) { ForceLowOutput(channel); } } } void RT1051DriverPWM::startAll() { for (const auto &[channel, state] : pwmChannelState) { if (state == RT1051DriverPWM::PwmState::On) { RestorePwmOutput(channel); } } PWM_StartTimer(base, 1 << pwmModule); } void RT1051DriverPWM::restoreDutyCycle() { for (unsigned i = 0; i < enabledChannels.size(); ++i) { PWM_UpdatePwmDutycycle( base, pwmModule, pwmSignalsConfig[i].pwmChannel, pwmMode, pwmSignalsConfig[i].dutyCyclePercent); PWM_SetPwmLdok(base, 1 << pwmModule, true); } } } // namespace drivers