Skip to content

Commit c26437f

Browse files
committed
Adds Arduino Nano ESP32 support to Servo library
Enables the Servo library to be used with Arduino Nano ESP32 board.
1 parent aeef55f commit c26437f

File tree

4 files changed

+161
-1
lines changed

4 files changed

+161
-1
lines changed

.github/workflows/compile-examples.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ jobs:
7171
platforms: |
7272
- name: arduino:mbed_nano
7373
artifact-name-suffix: arduino-mbed_nano-nanorp2040connect
74+
- fqbn: arduino:esp32:nano_nora
75+
platforms: |
76+
- name: arduino:esp32
77+
artifact-name-suffix: arduino-esp32-nano_nora
7478

7579
steps:
7680
- name: Checkout repository

src/Servo.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,10 @@
7777
#include "renesas/ServoTimers.h"
7878
#elif defined(ARDUINO_ARCH_XMC)
7979
#include "xmc/ServoTimers.h"
80+
#elif defined(ARDUINO_ARCH_ESP32)
81+
#include "esp32/ServoTimers.h"
8082
#else
81-
#error "This library only supports boards with an AVR, SAM, SAMD, NRF52, STM32F4, Renesas or XMC processor."
83+
#error "This library only supports boards with an AVR, SAM, SAMD, NRF52, STM32F4, Renesas, XMC or ESP32 processor."
8284
#endif
8385

8486
#define Servo_VERSION 2 // software version of this library

src/esp32/Servo.cpp

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
#if defined(ARDUINO_ARCH_ESP32)
2+
3+
#include <Arduino.h>
4+
#include <Servo.h>
5+
6+
#if defined __has_include
7+
# if __has_include ("pinDefinitions.h")
8+
# include "pinDefinitions.h"
9+
# endif
10+
#endif
11+
12+
/*
13+
* This group/channel/timmer mapping is for information only;
14+
* the details are handled by lower-level code
15+
*
16+
* LEDC Chan to Group/Channel/Timer Mapping
17+
** ledc: 0 => Group: 0, Channel: 0, Timer: 0
18+
** ledc: 1 => Group: 0, Channel: 1, Timer: 0
19+
** ledc: 2 => Group: 0, Channel: 2, Timer: 1
20+
** ledc: 3 => Group: 0, Channel: 3, Timer: 1
21+
** ledc: 4 => Group: 0, Channel: 4, Timer: 2
22+
** ledc: 5 => Group: 0, Channel: 5, Timer: 2
23+
** ledc: 6 => Group: 0, Channel: 6, Timer: 3
24+
** ledc: 7 => Group: 0, Channel: 7, Timer: 3
25+
** ledc: 8 => Group: 1, Channel: 0, Timer: 0
26+
** ledc: 9 => Group: 1, Channel: 1, Timer: 0
27+
** ledc: 10 => Group: 1, Channel: 2, Timer: 1
28+
** ledc: 11 => Group: 1, Channel: 3, Timer: 1
29+
** ledc: 12 => Group: 1, Channel: 4, Timer: 2
30+
** ledc: 13 => Group: 1, Channel: 5, Timer: 2
31+
** ledc: 14 => Group: 1, Channel: 6, Timer: 3
32+
** ledc: 15 => Group: 1, Channel: 7, Timer: 3
33+
*/
34+
35+
class ServoImpl {
36+
uint8_t pin;
37+
38+
public:
39+
ServoImpl(const uint8_t _pin, const uint8_t _channel) : pin(_pin) {
40+
// Setup timer
41+
ledcSetup(_channel, (1000000 / REFRESH_INTERVAL), LEDC_MAX_BIT_WIDTH);
42+
43+
// Attach timer to a LED pin
44+
ledcAttachPin(pin, _channel);
45+
}
46+
47+
~ServoImpl() {
48+
ledcDetachPin(pin);
49+
}
50+
51+
void set(const uint8_t _channel, const uint32_t duration_us) {
52+
ledcWrite(_channel, LEDC_US_TO_TICKS(duration_us));
53+
}
54+
55+
uint32_t get(const uint8_t _channel) const {
56+
return LEDC_TICKS_TO_US(ledcRead(_channel));
57+
}
58+
};
59+
60+
static ServoImpl* servos[MAX_PWM_SERVOS] = {nullptr}; // static array of servo structures
61+
uint8_t ServoCount = 0; // the total number of attached servos
62+
63+
#define SERVO_MIN() (MIN_PULSE_WIDTH - this->min) // minimum value in us for this servo
64+
#define SERVO_MAX() (MAX_PULSE_WIDTH - this->max) // maximum value in us for this servo
65+
66+
Servo::Servo()
67+
{
68+
if (ServoCount < MAX_PWM_SERVOS) {
69+
this->servoIndex = ServoCount++;
70+
} else {
71+
this->servoIndex = INVALID_SERVO; // too many servos
72+
}
73+
}
74+
75+
uint8_t Servo::attach(int pin)
76+
{
77+
return this->attach(pin, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
78+
}
79+
80+
uint8_t Servo::attach(int pin, int min, int max)
81+
{
82+
servos[this->servoIndex] = new ServoImpl(pin, this->servoIndex);
83+
84+
this->min = (MIN_PULSE_WIDTH - min);
85+
this->max = (MAX_PULSE_WIDTH - max);
86+
return this->servoIndex;
87+
}
88+
89+
void Servo::detach()
90+
{
91+
delete servos[this->servoIndex];
92+
servos[this->servoIndex] = NULL;
93+
}
94+
95+
void Servo::write(int value)
96+
{
97+
// treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds)
98+
if (value < MIN_PULSE_WIDTH)
99+
{
100+
if (value < 0)
101+
value = 0;
102+
else if (value > 180)
103+
value = 180;
104+
105+
value = map(value, 0, 180, SERVO_MIN(), SERVO_MAX());
106+
}
107+
writeMicroseconds(value);
108+
}
109+
110+
void Servo::writeMicroseconds(int value)
111+
{
112+
if (!servos[this->servoIndex]) {
113+
return;
114+
}
115+
// calculate and store the values for the given channel
116+
byte channel = this->servoIndex;
117+
if( (channel < MAX_PWM_SERVOS) ) // ensure channel is valid
118+
{
119+
if (value < SERVO_MIN()) // ensure pulse width is valid
120+
value = SERVO_MIN();
121+
else if (value > SERVO_MAX())
122+
value = SERVO_MAX();
123+
124+
servos[this->servoIndex]->set(this->servoIndex, value);
125+
}
126+
}
127+
128+
int Servo::read() // return the value as degrees
129+
{
130+
return map(readMicroseconds(), SERVO_MIN(), SERVO_MAX(), 0, 180);
131+
}
132+
133+
int Servo::readMicroseconds()
134+
{
135+
if (!servos[this->servoIndex]) {
136+
return 0;
137+
}
138+
return servos[this->servoIndex]->get(this->servoIndex);
139+
}
140+
141+
bool Servo::attached()
142+
{
143+
return servos[this->servoIndex] != NULL;
144+
}
145+
146+
#endif

src/esp32/ServoTimers.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#define MAX_PWM_SERVOS 16
2+
3+
#define LEDC_MAX_BIT_WIDTH SOC_LEDC_TIMER_BIT_WIDE_NUM
4+
5+
constexpr uint32_t BIT_RESOLUTION = (1 << LEDC_MAX_BIT_WIDTH) - 1;
6+
7+
#define LEDC_US_TO_TICKS(us) static_cast<uint32_t>((us * BIT_RESOLUTION) / REFRESH_INTERVAL)
8+
#define LEDC_TICKS_TO_US(ticks) static_cast<uint32_t>((ticks * REFRESH_INTERVAL) / BIT_RESOLUTION)

0 commit comments

Comments
 (0)