#include "Pwm.h" #include "Config.h" void PwmGenerator::begin() { pinMode(GPIO_PWM, OUTPUT); stop(); } bool PwmGenerator::start(uint32_t hz, uint8_t dutyPct, ActualPwm &a) { stop(); uint8_t bits = LEDC_MAX_BITS; while (bits > 1 && static_cast(hz) * (1ULL << bits) > 80000000ULL) --bits; if (!ledcAttachChannel(GPIO_PWM, hz, bits, LEDC_CHANNEL)) return false; const uint32_t top = (1UL << bits) - 1UL; const uint32_t duty = (static_cast(top) * dutyPct + 50U) / 100U; if (!ledcWriteChannel(LEDC_CHANNEL, duty)) { ledcDetach(GPIO_PWM); return false; } const uint32_t actualHz = ledcReadFreq(GPIO_PWM); if (!actualHz) { ledcDetach(GPIO_PWM); return false; } a = {hz, actualHz, 100.0f * duty / top, bits}; running_ = true; return true; } bool PwmGenerator::preview(uint32_t hz, uint8_t dutyPct, ActualPwm &a) { stop(); uint8_t bits = LEDC_MAX_BITS; while (bits > 1 && static_cast(hz) * (1ULL << bits) > 80000000ULL) --bits; if (!ledcAttachChannel(GPIO_PWM, hz, bits, LEDC_CHANNEL)) return false; ledcWriteChannel(LEDC_CHANNEL, 0); // query hardware without emitting test pulses const uint32_t actualHz = ledcReadFreq(GPIO_PWM); const uint32_t top = (1UL << bits) - 1UL; const uint32_t duty = (static_cast(top) * dutyPct + 50U) / 100U; a = {hz, actualHz, 100.0f * duty / top, bits}; ledcDetach(GPIO_PWM); pinMode(GPIO_PWM, OUTPUT); digitalWrite(GPIO_PWM, PWM_SAFE_LEVEL); return actualHz != 0; } void PwmGenerator::stop() { if (running_) ledcDetach(GPIO_PWM); pinMode(GPIO_PWM, OUTPUT); digitalWrite(GPIO_PWM, PWM_SAFE_LEVEL); running_ = false; }