@@ -42,33 +42,51 @@ ws_ledc::~ws_ledc() {
42
42
}
43
43
}
44
44
45
+ /* *************************************************************************/
46
+ /* !
47
+ @brief Checks if a channel has already been allocated for a pin.
48
+ @param pin Desired GPIO pin number.
49
+ @return The channel number if the pin was successfully or already
50
+ attached, otherwise LEDC_CH_ERR.
51
+ */
52
+ /* *************************************************************************/
53
+ uint8_t ws_ledc::_getChannel (uint8_t pin) {
54
+ // have we already attached this pin?
55
+ for (int i = 0 ; i < MAX_LEDC_PWMS; i++) {
56
+ if (_ledcPins[i].pin == pin)
57
+ return _ledcPins[i].chan ;
58
+ }
59
+ return LEDC_CH_ERR;
60
+ }
61
+
45
62
/* *************************************************************************/
46
63
/* !
47
64
@brief Allocates a timer + channel for a pin and attaches it.
48
65
@param pin Desired GPIO pin number.
49
- @param freq Desired LEDC timer frequency, in Hz.
50
- @param resolution Desired LEDC timer resolution, in bits.
51
- @return The channel number if the pin was successfully attached,
52
- otherwise 255.
66
+ @param freq Desired timer frequency, in Hz.
67
+ @param resolution Desired timer resolution, in bits.
68
+ @return The channel number if the pin was successfully or already
69
+ attached, otherwise 255.
53
70
*/
54
71
/* *************************************************************************/
55
72
uint8_t ws_ledc::attachPin (uint8_t pin, double freq, uint8_t resolution) {
56
73
// have we already attached this pin?
57
74
for (int i = 0 ; i < MAX_LEDC_PWMS; i++) {
58
75
if (_ledcPins[i].pin == pin)
59
- return 255 ;
76
+ return _ledcPins[i]. chan ;
60
77
}
61
78
62
79
// allocate chanel
63
80
uint8_t chanNum = _allocateChannel (freq, resolution);
64
- if (chanNum == 255 )
81
+ if (chanNum == LEDC_CH_ERR )
65
82
return chanNum;
66
83
67
84
// attach pin to channel
68
85
ledcAttachPin (pin, chanNum);
69
86
70
87
// allocate pin in pool
71
88
_ledcPins[chanNum].pin = pin;
89
+ _ledcPins[chanNum].chan = chanNum;
72
90
73
91
return chanNum;
74
92
}
@@ -97,25 +115,17 @@ void ws_ledc::detachPin(uint8_t pin) {
97
115
/* *************************************************************************/
98
116
/* !
99
117
@brief Allocates a channel and timer.
100
- @param freq Desired LEDC timer frequency, in Hz.
101
- @param resolution Desired LEDC timer resolution, in bits.
118
+ @param freq Timer frequency, in Hz.
119
+ @param resolution Timer resolution, in bits.
102
120
@return The channel number if the timer was successfully initialized,
103
121
otherwise 255.
104
122
*/
105
123
/* *************************************************************************/
106
- uint8_t ws_ledc::_allocateChannel (double freq, uint8_t resolution) {
107
- // attempt to allocate an inactive channel
108
- uint8_t chanNum = 255 ;
109
- for (int i = 0 ; i < MAX_LEDC_PWMS; i++) {
110
- if (_ledcPins[i].isActive == false ) {
111
- chanNum = i;
112
- break ;
113
- }
114
- }
115
-
116
- // did we fail to allocate?
117
- if (chanNum == 255 )
118
- return 255 ;
124
+ uint8_t ws_ledc::_allocateChannel (double freq, uint8_t resolution = 16 ) {
125
+ // obtain an inactive channel number
126
+ uint8_t chanNum = _getInactiveChannel ();
127
+ if (chanNum == LEDC_CH_ERR)
128
+ return LEDC_CH_ERR; // failed to obtain inactive channel #
119
129
120
130
// attempt to set up a ledc_timer on the free channel
121
131
double rc = ledcSetup (uint8_t (chanNum), freq, resolution);
@@ -129,6 +139,47 @@ uint8_t ws_ledc::_allocateChannel(double freq, uint8_t resolution) {
129
139
return chanNum;
130
140
}
131
141
142
+ /* *************************************************************************/
143
+ /* !
144
+ @brief Returns an inactive LEDC channel number.
145
+ @returns Inactive channel number if free, otherwise LEDC_CH_ERR.
146
+ */
147
+ /* *************************************************************************/
148
+ uint8_t ws_ledc::_getInactiveChannel () {
149
+ for (int ch = 0 ; ch < sizeof (_ledcPins); ch++) {
150
+ if (_ledcPins[ch].isActive == false ) {
151
+ return ch;
152
+ }
153
+ }
154
+ return LEDC_CH_ERR;
155
+ }
156
+
157
+ /* *************************************************************************/
158
+ /* !
159
+ @brief Arduino AnalogWrite function, but for ESP32's LEDC.
160
+ @param pin The desired pin to write to.
161
+ @param value The duty cycle.
162
+ */
163
+ /* *************************************************************************/
164
+ void ws_ledc::analogWrite (uint8_t pin, int value) {
165
+ if (value > 255 || value < 0 )
166
+ return ;
167
+
168
+ uint8_t ch;
169
+ ch = _getChannel (pin);
170
+ if (ch == LEDC_CH_ERR) {
171
+ Serial.println (" ERROR: Pin not attached to channel" );
172
+ return ;
173
+ }
174
+
175
+ // perform duty cycle calculation provided value
176
+ // (assumes 12-bit resolution, 2^12)
177
+ uint32_t dutyCycle = (4095 / 255 ) * min (value, 255 );
178
+
179
+ // set the duty cycle of the pin
180
+ setDuty (pin, dutyCycle);
181
+ }
182
+
132
183
/* *************************************************************************/
133
184
/* !
134
185
@brief Sets the duty cycle of a pin
@@ -150,4 +201,21 @@ void ws_ledc::setDuty(uint8_t pin, uint32_t duty) {
150
201
ledcWrite (chan, duty);
151
202
}
152
203
204
+ /* *************************************************************************/
205
+ /* !
206
+ @brief Writes a square wave with a fixed duty cycle and variable
207
+ frequency to a pin. Used by piezo buzzers and speakers.
208
+ @param pin The desired pin to write to.
209
+ @param freq The frequency of the tone, in Hz.
210
+ */
211
+ /* *************************************************************************/
212
+ void ws_ledc::tone (uint8_t pin, uint32_t freq) {
213
+ uint8_t ch;
214
+ ch = _getChannel (pin);
215
+ if (ch == LEDC_CH_ERR) {
216
+ // Serial.println("ERROR: Pin not previously attached!");
217
+ }
218
+ ledcWriteTone (ch, freq);
219
+ }
220
+
153
221
#endif // ARDUINO_ARCH_ESP32
0 commit comments