Skip to content

Commit

Permalink
Refactor PWMOutput
Browse files Browse the repository at this point in the history
It now allows adjustment of PWM frequency and channel resolution.
The interface changed slightly; no need to mess with PWM channels
manually.
  • Loading branch information
mairas committed Nov 3, 2024
1 parent 85336c1 commit cb568a2
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 65 deletions.
6 changes: 2 additions & 4 deletions examples/smart_switch/remote_switch_example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include "sensesp/transforms/click_type.h"
#include "sensesp/transforms/debounce.h"
#include "sensesp/transforms/press_repeater.h"
#include "sensesp/transforms/repeat_report.h"
#include "sensesp/transforms/repeat.h"
#include "sensesp_app.h"
#include "sensesp_app_builder.h"

Expand Down Expand Up @@ -88,9 +88,7 @@ void setup() {

auto click_type = new ClickType(config_path_button_c);

ConfigItem(click_type)
->set_title("Click Type")
->set_sort_order(1000);
ConfigItem(click_type)->set_title("Click Type")->set_sort_order(1000);

pr->connect_to(click_type)->connect_to(controller->click_consumer_);

Expand Down
2 changes: 1 addition & 1 deletion src/sensesp/controllers/smart_switch_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ class SmartSwitchController : public ValueProducer<bool>, FileSystemSaveable {
std::set<SyncPath> sync_paths_;
};

const String ConfigSchema(const SmartSwitchController& obj) {
inline const String ConfigSchema(const SmartSwitchController& obj) {
return R"({"type":"object","properties":{"sync_paths":{"title":"Sync on double click","type":"array","items":{"type":"string"}}} })";
}

Expand Down
45 changes: 18 additions & 27 deletions src/sensesp/system/pwm_output.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#include "sensesp.h"

#include "pwm_output.h"

#include <algorithm>
Expand All @@ -6,23 +8,22 @@ namespace sensesp {

// For info on frequency and resolution for ESP32, see
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/ledc.html#ledc-api-supported-range-frequency-duty-resolution
constexpr int CHANNEL_FREQUENCY = 5000;
constexpr int CHANNEL_RESOLUTION = 13;
constexpr int PWMRANGE = 4095;

std::map<uint8_t, int8_t> PWMOutput::channel_to_pin_;

PWMOutput::PWMOutput(int pin, int pwm_channel) {
PWMOutput::PWMOutput(int pin, int pwm_channel, int channel_frequency,
int channel_resolution)
: ValueConsumer<float>(),
pwm_channel_{static_cast<uint8_t>(pwm_channel)},
channel_frequency_{channel_frequency},
channel_resolution_{channel_resolution},
pwmrange_{static_cast<int>(pow(2, channel_resolution) - 1)} {
if (pin >= 0) {
default_channel_ = assign_channel(pin, pwm_channel);
pwm_channel_ = assign_channel(pin, pwm_channel);
}
}

void PWMOutput::set(const float& new_value) {
uint8_t pwm_channel = default_channel_;

set_pwm(pwm_channel, new_value);
}
void PWMOutput::set(const float& new_value) { set_pwm(new_value); }

int PWMOutput::assign_channel(int pin, int pwm_channel) {
if (pwm_channel == -1) {
Expand All @@ -40,34 +41,24 @@ int PWMOutput::assign_channel(int pin, int pwm_channel) {
ESP_LOGD(__FILENAME__, "PWM channel %d assigned to pin %d", pwm_channel, pin);

pinMode(pin, OUTPUT);
#ifdef ESP32
ledcSetup(pwm_channel, CHANNEL_FREQUENCY, CHANNEL_RESOLUTION);
ledcSetup(pwm_channel, channel_frequency_, channel_resolution_);
ledcAttachPin(pin, pwm_channel);
#endif

return pwm_channel;
}

void PWMOutput::set_pwm(int pwm_channel, float value) {
void PWMOutput::set_pwm(float value) {
std::map<uint8_t, int8_t>::iterator it;
it = channel_to_pin_.find(pwm_channel);
it = channel_to_pin_.find(pwm_channel_);
if (it != channel_to_pin_.end()) {
int pin = it->second;
int const output_val = value * PWMRANGE;
int const output_val = value * pwmrange_;
ESP_LOGD(__FILENAME__, "Outputting %d to pwm channel %d (pin %d)",
output_val, pwm_channel, pin);

#ifdef ESP32
uint32_t levels = pow(2, CHANNEL_RESOLUTION);
uint32_t duty =
((levels - 1) / PWMRANGE) * std::min(output_val, (int)PWMRANGE);
ledcWrite(pwm_channel, duty);
#else
analogWrite(pin, output_val);
#endif
output_val, pwm_channel_, pin);
ledcWrite(pwm_channel_, output_val);
} else {
ESP_LOGW(__FILENAME__, "No pin assigned to channel %d. Ignoring set_pwm()",
pwm_channel);
pwm_channel_);
}
}

Expand Down
20 changes: 12 additions & 8 deletions src/sensesp/system/pwm_output.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ class PWMOutput : public ValueConsumer<float> {
* to. Pass -1 if you would like the system to auto-select the
* next unassigned pin.
*/
PWMOutput(int pin = -1, int pwm_channel = -1);
PWMOutput(int pin = -1, int pwm_channel = -1, int channel_frequency = 5000,
int channel_resolution = 13);

/**
* Sets the duty cycle of the specified pwm_channel to new_value. If
Expand All @@ -50,6 +51,14 @@ class PWMOutput : public ValueConsumer<float> {
*/
virtual void set(const float& new_value) override;

protected:
int channel_frequency_;
int channel_resolution_;
int pwmrange_;

static std::map<uint8_t, int8_t> channel_to_pin_;
uint8_t pwm_channel_{};

/**
* Assigns the specified GPIO pin to the specified pwm channel.
* @param pin the GPIO pin used for the pwm output
Expand All @@ -59,19 +68,14 @@ class PWMOutput : public ValueConsumer<float> {
* @returns The actual pwm channel assigned to the GPIO pin
* to the pin
*/
static int assign_channel(int pin, int pwm_channel = -1);
int assign_channel(int pin, int pwm_channel = -1);

/**
* Sets duty cycle on specified pwm channel
* @param pwm_channel The pwm_channel assigned to the GPIO pin
* @param value A number between 0.0 and 1.0, where 1.0 is the maximum
* duty cycle the output pin supports.
*/
static void set_pwm(int pwm_channel, float value);

protected:
static std::map<uint8_t, int8_t> channel_to_pin_;
uint8_t default_channel_{};
void set_pwm(float value);
};

} // namespace sensesp
Expand Down
27 changes: 9 additions & 18 deletions src/sensesp/system/rgb_led.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,9 @@ namespace sensesp {
RgbLed::RgbLed(int led_r_pin, int led_g_pin, int led_b_pin, String config_path,
long int led_on_rgb, long int led_off_rgb, bool common_anode)
: FileSystemSaveable(config_path),
led_r_channel_((led_r_pin < 0) ? -1
: PWMOutput::assign_channel(led_r_pin)),
led_g_channel_((led_g_pin < 0) ? -1
: PWMOutput::assign_channel(led_g_pin)),
led_b_channel_((led_b_pin < 0) ? -1
: PWMOutput::assign_channel(led_b_pin)),
led_r_output_{std::make_shared<PWMOutput>(led_r_pin)},
led_g_output_{std::make_shared<PWMOutput>(led_g_pin)},
led_b_output_{std::make_shared<PWMOutput>(led_b_pin)},
led_on_rgb_{led_on_rgb},
led_off_rgb_{led_off_rgb},
common_anode_{common_anode} {
Expand Down Expand Up @@ -52,20 +49,14 @@ bool RgbLed::from_json(const JsonObject& config) {
}

void RgbLed::set_color(long new_value) {
if (led_r_channel_ >= 0) {
float r = get_pwm(new_value, 16, common_anode_);
PWMOutput::set_pwm(led_r_channel_, r);
}
float r = get_pwm(new_value, 16, common_anode_);
led_r_output_->set(r);

if (led_g_channel_ >= 0) {
float g = get_pwm(new_value, 8, common_anode_);
PWMOutput::set_pwm(led_g_channel_, g);
}
float g = get_pwm(new_value, 8, common_anode_);
led_g_output_->set(g);

if (led_b_channel_ >= 0) {
float b = get_pwm(new_value, 0, common_anode_);
PWMOutput::set_pwm(led_b_channel_, b);
}
float b = get_pwm(new_value, 0, common_anode_);
led_b_output_->set(b);
}

const String ConfigSchema(const RgbLed& obj) {
Expand Down
12 changes: 5 additions & 7 deletions src/sensesp/system/rgb_led.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef SENSESP_SYSTEM_RGB_LED_H
#define SENSESP_SYSTEM_RGB_LED_H

#include "pwm_output.h"
#include "sensesp/system/lambda_consumer.h"
#include "sensesp/ui/config_item.h"
#include "valueconsumer.h"
Expand Down Expand Up @@ -56,9 +57,7 @@ class RgbLed : public FileSystemSaveable {
*/

LambdaConsumer<long> rgb_consumer_ =
LambdaConsumer<long>([this](long new_value) {
set_color(new_value);
});
LambdaConsumer<long>([this](long new_value) { set_color(new_value); });

/**
* Used to set the current display state of the LED with a simple on/off
Expand All @@ -78,15 +77,14 @@ class RgbLed : public FileSystemSaveable {
virtual bool from_json(const JsonObject& config) override;

protected:
int led_r_channel_;
int led_g_channel_;
int led_b_channel_;
std::shared_ptr<PWMOutput> led_r_output_ = nullptr;
std::shared_ptr<PWMOutput> led_g_output_ = nullptr;
std::shared_ptr<PWMOutput> led_b_output_ = nullptr;
long led_on_rgb_;
long led_off_rgb_;
bool common_anode_;

void set_color(long new_value);

};

const String ConfigSchema(const RgbLed& obj);
Expand Down

0 comments on commit cb568a2

Please sign in to comment.