Skip to content

Dlloydev/ESP32-ESP32S2-AnalogWrite

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

85 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ESP32 PWM, Servo, Easing and Tone Library

arduino-library-badge PlatformIO Registry

Comparison to Servo Library for Arduino

  • Both libraries use the same header filename: Servo.h
  • Methods in both libraries have identical names.
  • With the Servo Library for Arduino, each servo is instantiated, whereas only one instance is used with the ESP32 ESP32S2 AnalogWrite library to control up to 16 servos. Therefore, the write() method in the ESP32 ESP32S2 AnalogWrite library has a pin parameter to select the attached servo.

Comparison Table

  • Superscript values represent the number of available overload functions .
  • With the ESP32 ESP32S2 AnalogWrite library, both Servo.h and pwmWrite.h have access to all methods. Choose one header only that best suits your application. Note that Servo.h uses a Servo class that translates method names to match the Servo Library for Arduino. Each header gives full access to the libraries features.
Library: Servo Library for Arduino ESP32 ESP32S2 AnalogWrite ESP32 ESP32S2 AnalogWrite
Header Servo.h Servo.h pwmWrite.h
Includes ServoTimers.h pwmWrite.h driver/ledc.h
Methods attach() 2 attach() 10 attachServo() 10
write() write() 2 writeServo() 2
writeMicroseconds() writeMicroseconds() n/a
read() read() read()
attached() attached() attached()
detach() detach() detach()
attachedPin() attachedPin() attachedPin()
readMicroseconds() readMicroseconds() readMicroseconds()
attachPwm() 2 attach() 2
attachInvert() 2 attachInvert() 2
writePwm() 4 write() 4
detached() detached()
firstFreeCh() firstFreeCh()
pause() pause()
resume() resume()
printDebug() printDebug()
setFrequency() setFrequency()
setResolution() setResolution()
tone() tone()
note() note()

image

Description

This library uses the ESP32 Arduino framework's ledc functions and provides up to 16 channels for servos, pwm, leds, buzzers etc. Includes smart GPIO pin management where any pin will not be automatically attached if previously accessed by other code. Includes advanced control methods like timer pause/resume, phase delay using hpoint, inverted pwm and tunable servo easing.

Servo Easing is fully integrated into the servo write and attach functions. Only 2 parameters give complete control over the speed and the easing characteristic of the servo. The method used for easing is a Normalized Tunable Sigmoid (reference).

Arduino core for the ESP32, ESP32-S2, ESP32-S3 and ESP32-C3

Recommend using the latest release, however this library works with release 2.0.7 or newer.

Servo Easing

Just 2 easing parameters (speed and easing constant) for unlimited control ...

myservo.write(servoPin1, pos1, speed1, 0.0);  // move 90 deg at 70 deg/s, linear
myservo.write(servoPin2, pos2, speed2, 0.6);  // mpve 180 deg at 140 deg/s, avg sigmoid
myservo.write(servoPin3, pos3, speed3, 0.8);  // move 90 deg at 180 deg/s, steep sigmoid

ServoEasing

Speed Control:

The maximum speed in degrees/sec is derived from the servo's datasheet. For this SG90 Micro Servo we have Operating speed: 0.1 s/60 degree. In this case, the maximum value for the speed parameter is 600 deg/sec. When a new servo position value is set, the operating time in milliseconds = degrees to move / speed * 1000.

Easing Control:

The easing constant ke controls how the servo moves to the set position by varying the speed. Its effect from linear (ke = 0.0) to maximum steep curve (ke = 0.99).

Position Feedback:

The calculated position of the servo is the returned value "ye" of the writeServo function. The easing position ye is normalized (0.0-1.0) but can slightly over/undershoot this range. The servo has reached its programmed position when ye = 1.0 if the new setting is larger than previous and also when ye = 0.0 if the new position setting is smaller than previous.

servoWrite:

After a new servo position is programmed, repeatedly call the servoWrite function with the same parameters until the servo completes its motion (returned value ye = 1.0 or 0.0). The servo responds according to ke and speed. Servo position is incremented after each call.

Examples

Wokwi_badge Note Explorer ♩ ♪ ♫ ♬ Plays all 96 ledc notes that are available, non blocking

Wokwi_badge Note_Player Playing Notes based on sliding pot position, 4th octave, non blocking

Wokwi_badge Pwm_3phase_40kHz ESP32 3 Phase PWM Outputs (40kHz, 10-bit)

Wokwi_badge Pwm_ESP32_3phase_10kHz ESP32 3 Phase PWM Outputs (10kHz, 10-bit)

Wokwi_badge Pwm_ESP32_C3_3phase_10kHz ESP32 C3 3 Phase PWM Outputs (10kHz, 10-bit)

Wokwi_badge Pwm_ESP32_S2_3phase_10kHz ESP32 S2 3 Phase PWM Outputs (10kHz, 10-bit)

Wokwi_badge Pwm_Fade_Servo ESP32 fading 14 pairs of LEDs and controlling 2 servo motors

Wokwi_badge Pwm_Fade16 ESP32 fading 16 pairs of LEDs

Wokwi_badge Pwm_Sync2_300kHz 2 synchronized PWM outputs using the same timer (channel pair)

Wokwi_badge Servo_Easing_Interrupt Servo Easing with position feedback and Interrupt control

Wokwi_badge Servo_Easing_Position 3 servos with easing and position feedback control

Wokwi_badge Servo Knob Controls servo position by using a potentiometer

Wokwi_badge Servo_Knob_Six Potentiometer control of 6 servos on an ESP32-C3

Wokwi_badge Servo Sweep Sweep a servo motor from 0-180 degrees and back

Wokwi_badge Servo_Sweep_Inverted Using inverted PWM mode to sweep a servo motor

Wokwi_badge Servo_Sweep_Speed Independent speed control of 2 servos

Wokwi_badge Tone_Player Playing Tones based on sliding pot position

PWM Channel Configuration

Board PWM Pins PWM, Duty and Phase Channels Frequency and Resolution Channels
ESP32 0-19, 21-23, 25-27, 32-39 16 8
ESP32‑S2/S3 0-21, 26, 33-45 8 4
ESP32‑C3 0- 10, 18-21 6 3

Frequency and resolution values are shared by each channel pair thats on the same timer. When any channel gets configured, the next lower or higher channel gets updated with the same frequency and resolution values as appropriate.

PWM Channel Speed Mode Timer Frequency Resolution Duty Phase
0 0 0 1 1 1 1
1 0 0 1 1 2 2
2 0 1 2 2 3 3
3 0 1 2 2 4 4
4 0 2 3 3 5 5
5 0 2 3 3 6 6
6 0 3 4 4 7 7
7 0 3 4 4 8 8
8 1 0 5 5 9 9
9 1 0 5 5 10 10
10 1 1 6 6 11 11
11 1 1 6 6 12 12
12 1 2 7 7 13 13
13 1 2 7 7 14 14
14 1 3 8 8 15 15
15 1 3 8 8 16 16

Reference (Servo.h)

Include and Instantiate

#include <Servo.h>
Servo myservo = Servo();

write()

Description:

This function accepts a value of type float that's processed to an unsigned duty value that takes full advantage of the servo channel's set resolution. If using a standard positional servo, this will set the angle of the shaft in degrees with range 0-180. If using a continuous rotation servo, this will set the speed where the limits 0 and 180 are full speed in each direction and where the mid range (90) is no movement.

Entered Value (float) Coerced Value (float) Units
< 0 0 degrees
0-180 0-180 degrees
> 180 AND < 500 180 degrees
≥ 500 AND < servoMinUs servoMinUs microseconds
servoMinUs to servoMaxUs servoMinUs to servoMaxUs microseconds
> servoMaxUs servoMaxUs microseconds

Timer Width (resolution)

When using this function, the timer width (resolution) will be14 bit if the target architecture is ESP32C3. For ESP32/S2/S3, the maximum bit width will be 20, which allows setting any width from14 to 20.

Servo Frequency

The allowed range for servo frequency is 40 to 900 Hz. Any saved or entered frequency that's out of this range, will be set and saved as 50Hz.

Channel Pairing

The frequency and resolution values are shared by each channel pair. When any channel gets configured, the next lower or higher channel on the same timer gets updated with the same frequency and resolution values as appropriate.

Attaching to free Channel

This process is automatic - the servo pin will be attached to the next free channel. If you need to assign the servo pin(s) to specific channels or to set the minimum or maximum microsecond values, then call the attach()method first.

Syntax
myservo.write(pin, value)
myservo.write(pin, value, speed, ke)
Parameters
  • pin The pin number which (if necessary) will be attached to the next free channel (int)
  • value This value is converted to the pwm duty. See above table for range and units *(double)
  • speed This value has units degrees/second (double). For example, if speed is set to 100 deg/s and the servo position value is changed from 0 to 180 deg, then the servo will take 1.8 sec (1800 ms) to complete its travel. Its motion (response) will be determined by ke,
  • ke Servo easing constant for a Normalized Tunable Sigmoid. A ke value of 0.0 represents a linear response. As you increase ke, this increases the steepness of a sigmoid response. When ke is 1.0, normal "instantaneous" servo response is enabled and the speed parameter is ignored.
Returns
  • If the servo easing constant ke is 1.0 (default) then the pwm duty value (uint32_t) is returned.
  • If ke is less than 1.0, then a normalized double value (0.0 to 1.0) is returned. This represents the programmed servo position from start to stop as it moves over time. When the returned value reaches 0.5, this represents both 50% travel and 50% time duration, no matter what easing constant is set.

writeMicroseconds()

Description

This function calls the write() function above.

Syntax

myservo.writeMicroseconds()

read()

Description

Read the current angle of the servo in degrees. The returned value is float type which provides improved resolution and takes advantage of the high resolution offered by the timer.

Syntax

myservo.read(pin)
Parameters
  • pin The pin number (int)
Returns
  • The angle of the servo, from 0 to 180 degrees (float)

readMicroseconds()

Description

Reads the timer channel's duty value in microseconds. The minimum limit is 544 ÎĽs representing 0 degrees shaft rotation and the maximum limit is 2400 ÎĽs representing 180 degrees shaft rotation. The returned value is float type which provides improved resolution and takes advantage of the high resolution offered by the timer.

Syntax

myservo.readMicroseconds(pin)
Parameters
  • pin The pin number (int)
Returns
  • The channel's duty value converted to microseconds (float)

attach()

Description

This function allows auto-attaching a pin to the first available channel if only the pin is specified. To have the pin assigned to a specific channel, use both the pin and channel (ch) parameters. Additionally, there are parameters available for setting the servo timer values for minimum and maximum microseconds.

Syntax

myservo.attach(pin)                                       // auto attach to 1st free channel
myservo.attach(pin, invert)                               // as above with invert
myservo.attach(pin, ch)                                   // attach to specified channel
myservo.attach(pin, ch, invert)                           // as above with invert
myservo.attach(pin, minUs, maxUs)                         // auto attach to free ch, servo limits
myservo.attach(pin, ch, minUs, maxUs)                     // attach to specified ch, servo limits
myservo.attach(pin, ch, minUs, maxUs, invert)             // as above with invert
myservo.attach(pin, minUs, maxUs, speed, ke)              // attach to free ch, speed, easing const
myservo.attach(pin, ch, minUs, maxUs, speed, ke)          // as above but attaches to specified ch
myservo.attach(pin, ch, minUs, maxUs, speed, ke, invert)  // as above with invert
Parameters
  • pin The pin number (int)

  • ch This optional parameter is used to attach the pin to a specific channel (int))

  • minUs Minimum timer width in microseconds (int)

  • maxUs Maximum timer width in microseconds (int)

  • speed This servo easing parameter has units degrees/second (double). For example, if speed is set to 100 deg/s and the servo position value is changed from 0 to 180 deg, then the servo will take 1.8 sec (1800 ms) to complete its travel. Its motion (response) will be determined by ke,

  • ke Servo easing constant for a Normalized Tunable Sigmoid. A ke value of 0.0 represents a linear response. As you increase ke, this increases the steepness of a sigmoid response. When ke is 1.0, normal "instantaneous" servo response is enabled and the speed parameter is ignored.

  • invert Inverts the PWM output. Allows using a simpler driver for higher voltage servo control. Only one NPN transistor or N-Channel MOSFET needed. No additional latency added as found with software inversion because the inverted pulse remains at the start of the refresh period rather than being flipped to the end of the refresh period (bool).

    Servo_Sweep_Inverted

    image

Returns
  • If not a valid pin, 254 (uint8_t)
  • free channels exist, 253 (uint8_t)
  • If attached, the channel number (0-15) (uint8_t)
  • If not attached, 255 (uint8_t)

attachPwm()

Description

This function allows auto-attaching a pin to the first available channel if only the pin is specified. To have the pin assigned to a specific channel, use both the pin and channel (ch) parameters.

Syntax

myservo.attach(pin)       // auto attach to 1st free channel
myservo.attach(pin, ch)   // attach to specified channel
Parameters
  • pin The pin number (int)
Returns
  • If not a valid pin, 254 (uint8_t)
  • free channels exist, 253 (uint8_t)
  • If attached, the channel number (0-15) (uint8_t)
  • If not attached, 255 (uint8_t)

attached()

Description

This function checks the pin status and if attached, returns the channel number.

Syntax

myservo.attached(pin)
Parameters
  • pin The pin number (int)
Returns
  • If not a valid pin, 254 (uint8_t)
  • free channels exist, 253 (uint8_t)
  • If attached, the channel number (0-15) (uint8_t)
  • If not attached, 255 (uint8_t)

attachInvert()

Description

This function allows auto-attaching a pin to the first available channel if only the pin is specified. To have the pin assigned to a specific channel, use both the pin and channel (ch) parameters. The pwm output will be inverted. The duty value represents the low period.

Syntax

myservo.attachInvert(pin);      // attach pin to next free channel with inverted pwm
myservo.attachInvert(pin, ch);  // attach to specified ch with inverted pwm
Parameters
  • pin The pin number (int)
  • ch This optional parameter is used to attach the pin to a specific channel (int)
Returns
  • If not a valid pin, 254 (uint8_t)
  • free channels exist, 253 (uint8_t)
  • If attached, the channel number (0-15) (uint8_t)
  • If not attached, 255 (uint8_t)

attachedPin()

Description

This function returns the pin that's attached to the specified channel.

Syntax

myservo.attachedPin(ch)
Parameters
  • pin The pin number (int)
Returns
  • If attached, the pin number (uint8_t)
  • If the channel is free, 255 (uint8_t)

writePwm()

Description

This function writes the duty and optionally the frequency, resolution and phase parameters. If necessary, the pin will be automatically attached to the first available pwm channel. To avoid conflicts with other code, the pin will not be attached if previously accessed.

Syntax
myservo.writePwm(pin, duty)
myservo.writePwm(pin, duty, frequency)
myservo.writePwm(pin, duty, frequency, resolution)
myservo.writePwm(pin, duty, frequency, resolution, phase)
Parameters
  • pin The pin number which (if necessary) will be attached to the next free channel (int)
  • duty This sets the pwm duty. The range is 0 to (2**resolution) - 1 (uint32_t)
  • frequency The pwm timer frequency (Hz). The frequency and resolution limits are interdependent (uint32_t). For more details, see Supported Range of Frequency and Duty Resolutions.
  • resolution The bit resolution of the pwm duty (uint8_t)
  • phase This is also referred to as the hpoint value, which is the timer/counter value that the pwm output turns on. The useable range is the same as for the duty parameter. This can be used to phase shift the output or for synchronization. When the phase parameter is used, the pwm output will initiate in a paused state to allow synchronization (uint32_t)
Returns

The set frequency (float)

detachPin()

Description

This function removes control of the pin from the specified PWM channel. Also, the channel defaults are applied.

Syntax

myservo.detachPin(pin)
Parameters
  • pin The pin number (int)
Returns
  • nothing

pause()

Description

This function is used internally by the write() function when the phase parameter is used to allow synchronization of multiple pwm signals.

If this function is manually called, any channel(s) that get configured will have their PWM output paused. Then calling resume() will start all newly configured channels at the same time. Note that this approach limits the maximum pwm frequency to about 10kHz or some pulses or glitches might occur during channel configuration.

Syntax

myservo.pause()
Parameters
  • none.
Returns
  • nothing

resume()

Description

This function is used to start the pwm outputs of all channels to synchronize (align) the signals. Note that there will be a consistent delay between the startup of each timer which can be corrected by using the write() function's phase parameter.

Syntax

myservo.resume()
Parameters
  • none.
Returns
  • nothing

setFrequency()

Description

Sets the PWM frequency on any PWM pin.

Syntax

myservo.setFrequency(pin, frequency)
Parameters
  • pin The pin number (int) If the pin is detached (free) and there's a free channel available, the pin will be attached to the first free channel that's found (int)
  • frequency The frequency in Hz. The default is 1000 Hz (uint32_t)
Returns
  • The frequency set by the timer hardware (float)

setResolution()

Description

Sets the PWM resolution for any PWM pin.

Syntax

myservo.setResolution(pin, resolution)
Parameters
  • pin The pin number (int) If the pin is detached (free) and there's a free channel available, the pin will be attached to the first free channel that's found (int)
  • resolution The PWM resolution can be set from 1-bit to 16-bit, default is 8-bit (uint8_t)
Returns
  • The set resolution reported by the pin channel (uint8_t)

tone()

Description:

This function generates a square wave of the specified frequency (and 50% duty cycle and 8-bit resolution) on a pin. There will be no output (no tone) if the duration isn't specified or equals 0. The duration in milliseconds has range 0-65535 where 0 is off and 65535 is always on. The last parameter (interval) specifies the pause time before the next call to tone becomes ready. The pin can be connected to a piezo buzzer or other speaker to play tones.

Channel Pairing

The frequency and resolution values are shared by each channel pair. When the tone pin is attached, the next lower or higher channel on the same timer gets updated with the same frequency and resolution values as appropriate.

Attaching to free Channel

This process is automatic - the tone pin will be attached to the next free channel. If you need to assign the tone pin to a specific channel, then call the attach()method first.

Syntax
myservo.tone(pin, frequency, duration)
myservo.tone(pin, frequency, duration, interval)
Parameters
  • pin The pin number which (if necessary) will be attached to the next free channel (int)
  • frequency The tone frequency (Hz) with range 1-65535 (uint16_t).
  • duration The duration in milliseconds with range 0-65535 (uint16_t), where 0 is off (default) and 65535 is always on.
  • interval This optional parameter specifies the pause time in milliseconds before the next call to tone becomes ready. (uint16_t), range 0-65535, default = 0.
Returns
  • nothing

note()

Description:

This function generates a square wave of the specified frequency (and 50% duty cycle and 8-bit resolution) on a pin. There will be no output (no tone) if the duration isn't specified or equals 0. The duration in milliseconds has range 0-65535 where 0 is off and 65535 is always on. The last parameter (interval) specifies the pause time before the next call to note becomes ready. The pin can be connected to a piezo buzzer or other speaker to play notes.

Channel Pairing

The frequency and resolution values are shared by each channel pair. When the note pin is attached, the next lower or higher channel on the same timer gets updated with the same frequency and resolution values as appropriate.

Attaching to free Channel

This process is automatic - the note pin will be attached to the next free channel. If you need to assign the tone pin to a specific channel, then call the attach()method first.

Syntax
pwm.note(pin, note, octave, duration, interval)
Parameters
  • pin The pin number which (if necessary) will be attached to the next free channel (int)
  • note The type is defined in esp32-hal-ledc.h (note_t).
  • octave There are 8 octaves available, 1 to 8 (uint8_t)
  • duration The duration in milliseconds with range 0-65535 (uint16_t), where 0 is off (default) and 65535 is always on.
  • interval This parameter specifies the pause time in milliseconds before the next call to tone becomes ready. (uint16_t), range 0-65535, default = 0.
Returns
  • nothing

printDebug()

Description

This function prints the available PWM pins to choose from and a formatted output showing the PWM pins that are in use (attached) and the channels that are unassigned (255).

Syntax

myservo.printDebug()
Parameters (optional)
  • none
Returns
  • serial report on serial monitor

image

This Library is licensed under the MIT License