Skip to content

Commit

Permalink
Merge pull request #320 from brentru/fix-servo-bug-esp32s2
Browse files Browse the repository at this point in the history
Fix servo not working on ESP32-S2
  • Loading branch information
brentru authored Sep 12, 2022
2 parents 9bf7f16 + 7521505 commit 3596f6d
Show file tree
Hide file tree
Showing 6 changed files with 24 additions and 19 deletions.
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=Adafruit WipperSnapper
version=1.0.0-beta.47
version=1.0.0-beta.48
author=Adafruit
maintainer=Adafruit <[email protected]>
sentence=Arduino client for Adafruit.io WipperSnapper
Expand Down
2 changes: 1 addition & 1 deletion src/Wippersnapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
#endif

#define WS_VERSION \
"1.0.0-beta.47" ///< WipperSnapper app. version (semver-formatted)
"1.0.0-beta.48" ///< WipperSnapper app. version (semver-formatted)

// Reserved Adafruit IO MQTT topics
#define TOPIC_IO_THROTTLE "/throttle" ///< Adafruit IO Throttle MQTT Topic
Expand Down
10 changes: 5 additions & 5 deletions src/components/ledc/drivers/ws_ledc_servo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ void ws_ledc_servo::setLEDCDriver(ws_ledc *ledcManager) {
uint8_t ws_ledc_servo::attach(int pin, int minPulseWidth, int maxPulseWidth,
int servoFreq) {
// Attempt to attach a pin to ledc channel
uint8_t chan = _ledcMgr->attachPin((uint8_t)pin, (double)servoFreq);
uint8_t chan =
_ledcMgr->attachPin((uint8_t)pin, (double)servoFreq, LEDC_TIMER_WIDTH);
if (chan == 255) // error!
return chan;
// configure the servo object and assign it to a pin
Expand Down Expand Up @@ -101,7 +102,6 @@ bool ws_ledc_servo::attached() { return _servo.Pin.isActive; }
void ws_ledc_servo::writeMicroseconds(int value) {
// are we attached to a pin?
if (!attached()) {
Serial.println("NOT ATTACHED TO PIN!");
return;
}

Expand All @@ -111,12 +111,12 @@ void ws_ledc_servo::writeMicroseconds(int value) {
if (value > _maxPulseWidth)
value = _maxPulseWidth;

// formula from
// formula from ESP32Servo library
// https://github.com/madhephaestus/ESP32Servo/blob/master/src/ESP32Servo.cpp
// count = (pulse_high_width / (pulse_period/2**timer_width))
// 50Hz servo = 20ms pulse_period
// count = pulse_high_width /((20000/65536))
uint32_t count = ((double)value / 0.30517578);
uint32_t count =
((double)value / ((double)20000 / (double)pow(2, LEDC_TIMER_WIDTH)));
_ledcMgr->setDuty(_servo.Pin.nbr, count);
}
#endif // ARDUINO_ARCH_ESP32
9 changes: 7 additions & 2 deletions src/components/ledc/drivers/ws_ledc_servo.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,13 @@
#define MAX_PULSE_WIDTH 2400 ///< The longest pulse sent to a servo
#define INVALID_SERVO 255 ///< Flag indicating an invalid servo index

#define DEFAULT_SERVO_FREQ 50 ///< default servo frequency
#define MAX_SERVOS MAX_LEDC_PWMS ///< Maximum number of servo instance
#define DEFAULT_SERVO_FREQ 50 ///< default servo frequency
#define LEDC_TIMER_WIDTH \
12 ///< timer width to request from LEDC manager component, in bits (NOTE:
///< While ESP32x can go up to 16 bit timer width, ESP32-S2 does not work
///< at this resolution. So, for the purposes of keeping this library
///< compatible with multiple ESP32x platforms, the timer width has been
///< scaled down to 10 bits and the calculation adjusted accordingly)

/** Defines a servo attached to a pin */
typedef struct {
Expand Down
14 changes: 8 additions & 6 deletions src/components/ledc/ws_ledc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,20 +46,21 @@ ws_ledc::~ws_ledc() {
/*!
@brief Allocates a timer + channel for a pin and attaches it.
@param pin Desired GPIO pin number.
@param freq Desired timer frequency, in Hz.
@param freq Desired LEDC timer frequency, in Hz.
@param resolution Desired LEDC timer resolution, in bits.
@return The channel number if the pin was successfully attached,
otherwise 255.
*/
/**************************************************************************/
uint8_t ws_ledc::attachPin(uint8_t pin, double freq) {
uint8_t ws_ledc::attachPin(uint8_t pin, double freq, uint8_t resolution) {
// have we already attached this pin?
for (int i = 0; i < MAX_LEDC_PWMS; i++) {
if (_ledcPins[i].pin == pin)
return 255;
}

// allocate chanel
uint8_t chanNum = _allocateChannel(freq);
uint8_t chanNum = _allocateChannel(freq, resolution);
if (chanNum == 255)
return chanNum;

Expand Down Expand Up @@ -96,12 +97,13 @@ void ws_ledc::detachPin(uint8_t pin) {
/**************************************************************************/
/*!
@brief Allocates a channel and timer.
@param freq Desired timer frequency, in Hz.
@param freq Desired LEDC timer frequency, in Hz.
@param resolution Desired LEDC timer resolution, in bits.
@return The channel number if the timer was successfully initialized,
otherwise 255.
*/
/**************************************************************************/
uint8_t ws_ledc::_allocateChannel(double freq) {
uint8_t ws_ledc::_allocateChannel(double freq, uint8_t resolution) {
// attempt to allocate an inactive channel
uint8_t chanNum = 255;
for (int i = 0; i < MAX_LEDC_PWMS; i++) {
Expand All @@ -116,7 +118,7 @@ uint8_t ws_ledc::_allocateChannel(double freq) {
return 255;

// attempt to set up a ledc_timer on the free channel
double rc = ledcSetup(uint8_t(chanNum), freq, 16);
double rc = ledcSetup(uint8_t(chanNum), freq, resolution);
if (rc == 0)
return 255;

Expand Down
6 changes: 2 additions & 4 deletions src/components/ledc/ws_ledc.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@
#define MAX_LEDC_PWMS \
16 ///< maximum # of LEDC channels (see: LEDC Chan to Group/Channel/Timer
///< Mapping)
#define LEDC_RESOLUTION 10 ///< max LEDC resolution
#define MAX_TIMER_WIDTH 20 ///< max LEDC esp32 timer width

/** Defines a pin attached to an active LEDC timer group */
typedef struct {
Expand All @@ -51,12 +49,12 @@ class ws_ledc {
public:
ws_ledc();
~ws_ledc();
uint8_t attachPin(uint8_t pin, double freq);
uint8_t attachPin(uint8_t pin, double freq, uint8_t resolution);
void detachPin(uint8_t pin);
void setDuty(uint8_t pin, uint32_t duty);

private:
uint8_t _allocateChannel(double freq);
uint8_t _allocateChannel(double freq, uint8_t resolution);
ledcPin_t _ledcPins[MAX_LEDC_PWMS]; ///< Pool of usable LEDC pins
};
extern Wippersnapper WS;
Expand Down

0 comments on commit 3596f6d

Please sign in to comment.