Skip to content
This repository was archived by the owner on Jan 29, 2023. It is now read-only.

Commit 7730110

Browse files
authored
v1.0.1 adds end-of-duty-cycle callback function
### Releases v1.0.1 1. Adding PWM end-of-duty-cycle callback function. 2. Fix bug. 3. Add end-of-duty-cycle callback feature to examples
1 parent b344467 commit 7730110

16 files changed

+500
-290
lines changed

README.md

Lines changed: 336 additions & 186 deletions
Large diffs are not rendered by default.

changelog.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,20 @@
1212
## Table of Contents
1313

1414
* [Changelog](#changelog)
15+
* [Releases v1.0.1](#releases-v101)
1516
* [Releases v1.0.0](#releases-v100)
1617

1718
---
1819
---
1920

2021
## Changelog
2122

22-
### Releases v1.0.0
23+
### Releases v1.0.1
2324

24-
1. Initial coding for ESP32, ESP32_S2 boards using [ESP32 core v2.0.0+](https://github.com/espressif/arduino-esp32/releases/tag/2.0.0)
25+
1. Adding PWM end-of-duty-cycle callback function.
26+
2. Fix bug.
27+
3. Add end-of-duty-cycle callback feature to examples
2528

29+
### Releases v1.0.0
2630

31+
1. Initial coding for ESP32, ESP32_S2 boards using [ESP32 core v2.0.0+](https://github.com/espressif/arduino-esp32/releases/tag/2.0.0)

library.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "ESP32_PWM",
3-
"version": "1.0.0",
4-
"keywords": "timing, device, control, pwm, timer, interrupt, hardware, isr, isr-based, hardware-timer, isr-timer, isr-based-timer, mission-critical, accuracy, precise, non-blocking, esp32, esp32-s2, esp32-c3",
3+
"version": "1.0.1",
4+
"keywords": "timing, device, control, pwm, timer, interrupt, hardware, isr, isr-based, hardware-timer, isr-timer, isr-based-timer, mission-critical, accuracy, precise, non-blocking, esp32, esp32-s2, esp32-c3, synchronized-PWM",
55
"description": "This library enables you to use Interrupt from Hardware Timers on an ESP32, ESP32_S2 or ESP32_C3-based board to create and output PWM to pins. It now supports 16 ISR-based synchronized PWM channels, while consuming only 1 Hardware Timer. PWM interval can be very long (uint32_t millisecs). The most important feature is they're ISR-based PWM channels. Therefore, their executions are not blocked by bad-behaving functions or tasks. This important feature is absolutely necessary for mission-critical tasks. These hardware PWM channels, using interrupt, still work even if other functions are blocking. Moreover, they are much more precise (certainly depending on clock frequency accuracy) than other software timers using millis() or micros(). That's necessary if you need to measure some data requiring better accuracy.",
66
"authors":
77
{

library.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=ESP32_PWM
2-
version=1.0.0
2+
version=1.0.1
33
author=Khoi Hoang <[email protected]>
44
maintainer=Khoi Hoang <[email protected]>
55
sentence=TThis library enables you to use Interrupt from Hardware Timers on an ESP32, ESP32_S2 or ESP32_C3-based board to create and output PWM to pins.

src/ESP32_PWM.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,12 @@
2121
Therefore, their executions are not blocked by bad-behaving functions / tasks.
2222
This important feature is absolutely necessary for mission-critical tasks.
2323
24-
Version: 1.0.0
24+
Version: 1.0.1
2525
2626
Version Modified By Date Comments
2727
------- ----------- ---------- -----------
2828
1.0.0 K Hoang 20/09/2021 Initial coding for ESP32, ESP32_S2, ESP32_C3 boards with ESP32 core v2.0.0+
29+
1.0.1 K Hoang 21/09/2021 Fix bug. Ading PWM end-of-duty-cycle callback function. Improve examples
2930
*****************************************************************************************************************************/
3031

3132
#pragma once
@@ -52,7 +53,7 @@
5253
#endif
5354

5455
#ifndef ESP32_PWM_VERSION
55-
#define ESP32_PWM_VERSION "ESP32_PWM v1.0.0"
56+
#define ESP32_PWM_VERSION "ESP32_PWM v1.0.1"
5657
#endif
5758

5859
#ifndef TIMER_INTERRUPT_DEBUG
@@ -175,7 +176,7 @@ typedef ESP32TimerInterrupt ESP32Timer;
175176
//esp_err_t timer_group_intr_enable(timer_group_t group_num, timer_intr_t intr_mask);
176177
//esp_err_t timer_group_intr_disable(timer_group_t group_num, timer_intr_t intr_mask);
177178

178-
179+
#define INVALID_ESP32_PIN 255
179180

180181
typedef bool (*esp32_timer_callback) (void *);
181182

src/ESP32_PWM_ISR.h

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,12 @@
2020
Therefore, their executions are not blocked by bad-behaving functions / tasks.
2121
This important feature is absolutely necessary for mission-critical tasks.
2222
23-
Version: 1.0.0
23+
Version: 1.0.1
2424
2525
Version Modified By Date Comments
2626
------- ----------- ---------- -----------
2727
1.0.0 K Hoang 20/09/2021 Initial coding for ESP32, ESP32_S2, ESP32_C3 boards with ESP32 core v2.0.0+
28+
1.0.1 K Hoang 21/09/2021 Fix bug. Ading PWM end-of-duty-cycle callback function. Improve examples
2829
*****************************************************************************************************************************/
2930

3031
#pragma once
@@ -39,7 +40,7 @@
3940
#endif
4041

4142
#ifndef ESP32_PWM_VERSION
42-
#define ESP32_PWM_VERSION "ESP32_PWM v1.0.0"
43+
#define ESP32_PWM_VERSION "ESP32_PWM v1.0.1"
4344
#endif
4445

4546
#ifndef _PWM_LOGLEVEL_
@@ -98,7 +99,8 @@ class ESP32_PWM_ISR
9899

99100
//////////////////////////////////////////////////////////////////
100101
// PWM
101-
void setPWM(uint32_t pin, uint32_t frequency, uint32_t dutycycle, timer_callback StartCallback = nullptr)
102+
void setPWM(uint32_t pin, uint32_t frequency, uint32_t dutycycle, timer_callback StartCallback = nullptr,
103+
timer_callback StopCallback = nullptr)
102104
{
103105
uint32_t period = 0;
104106

@@ -117,19 +119,21 @@ class ESP32_PWM_ISR
117119
PWM_LOGERROR("Error: Invalid frequency, max is 500Hz");
118120
}
119121

120-
setupPWMChannel(pin, period, dutycycle, (void *) StartCallback);
122+
setupPWMChannel(pin, period, dutycycle, (void *) StartCallback, (void *) StopCallback);
121123
}
122124

123125
#if USING_MICROS_RESOLUTION
124126
//period in us
125-
void setPWM_Period(uint32_t pin, uint32_t period, uint32_t dutycycle, timer_callback StartCallback = nullptr)
127+
void setPWM_Period(uint32_t pin, uint32_t period, uint32_t dutycycle, timer_callback StartCallback = nullptr,
128+
timer_callback StopCallback = nullptr)
126129
#else
127130
// PWM
128131
//period in ms
129-
void setPWM_Period(uint32_t pin, uint32_t period, uint32_t dutycycle, timer_callback StartCallback = nullptr)
132+
void setPWM_Period(uint32_t pin, uint32_t period, uint32_t dutycycle, timer_callback StartCallback = nullptr,
133+
timer_callback StopCallback = nullptr)
130134
#endif
131135
{
132-
setupPWMChannel(pin, period, dutycycle, (void *) StartCallback);
136+
setupPWMChannel(pin, period, dutycycle, (void *) StartCallback, (void *) StopCallback);
133137
}
134138

135139
//////////////////////////////////////////////////////////////////
@@ -172,7 +176,7 @@ class ESP32_PWM_ISR
172176
// low level function to initialize and enable a new PWM channel
173177
// returns the PWM channel number (channelNum) on success or
174178
// -1 on failure (f == NULL) or no free PWM channels
175-
int setupPWMChannel(uint32_t pin, uint32_t period, uint32_t dutycycle, void* cbFunc = nullptr);
179+
int setupPWMChannel(uint32_t pin, uint32_t period, uint32_t dutycycle, void* cbStartFunc = nullptr, void* cbStopFunc = nullptr);
176180

177181
// find the first available slot
178182
int findFirstFreeSlot();
@@ -188,7 +192,8 @@ class ESP32_PWM_ISR
188192
uint32_t period; // period value, in us / ms
189193
uint32_t onTime; // onTime value, ( period * dutyCycle / 100 ) us / ms
190194

191-
void* callback; // pointer to the callback function
195+
void* callbackStart; // pointer to the callback function when PWM pulse starts (HIGH)
196+
void* callbackStop; // pointer to the callback function when PWM pulse stops (LOW)
192197

193198
////////////////////////////////////////////////////////////
194199

src/ESP32_PWM_ISR.hpp

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,12 @@
2020
Therefore, their executions are not blocked by bad-behaving functions / tasks.
2121
This important feature is absolutely necessary for mission-critical tasks.
2222
23-
Version: 1.0.0
23+
Version: 1.0.1
2424
2525
Version Modified By Date Comments
2626
------- ----------- ---------- -----------
2727
1.0.0 K Hoang 20/09/2021 Initial coding for ESP32, ESP32_S2, ESP32_C3 boards with ESP32 core v2.0.0+
28+
1.0.1 K Hoang 21/09/2021 Fix bug. Ading PWM end-of-duty-cycle callback function. Improve examples
2829
*****************************************************************************************************************************/
2930

3031
#pragma once
@@ -63,6 +64,7 @@ void ESP32_PWM_ISR::init()
6364
{
6465
memset((void*) &PWM[channelNum], 0, sizeof (PWM_t));
6566
PWM[channelNum].prevTime = currentTime;
67+
PWM[channelNum].pin = INVALID_ESP32_PIN;
6668
}
6769

6870
numChannels = 0;
@@ -94,10 +96,10 @@ void IRAM_ATTR ESP32_PWM_ISR::run()
9496
digitalWrite(PWM[channelNum].pin, HIGH);
9597
PWM[channelNum].pinHigh = true;
9698

97-
// callback
98-
if (PWM[channelNum].callback != nullptr)
99+
// callbackStart
100+
if (PWM[channelNum].callbackStart != nullptr)
99101
{
100-
(*(timer_callback) PWM[channelNum].callback)();
102+
(*(timer_callback) PWM[channelNum].callbackStart)();
101103
}
102104
}
103105
}
@@ -107,6 +109,12 @@ void IRAM_ATTR ESP32_PWM_ISR::run()
107109
{
108110
digitalWrite(PWM[channelNum].pin, LOW);
109111
PWM[channelNum].pinHigh = false;
112+
113+
// callback when PWM pulse stops (LOW)
114+
if (PWM[channelNum].callbackStop != nullptr)
115+
{
116+
(*(timer_callback) PWM[channelNum].callbackStop)();
117+
}
110118
}
111119
}
112120
//else
@@ -134,7 +142,7 @@ int ESP32_PWM_ISR::findFirstFreeSlot()
134142
return -1;
135143
}
136144

137-
// return the first slot with no callback (i.e. free)
145+
// return the first slot with no callbackStart (i.e. free)
138146
for (uint8_t channelNum = 0; channelNum < MAX_NUMBER_CHANNELS; channelNum++)
139147
{
140148
if ( (PWM[channelNum].period == 0) && !PWM[channelNum].enabled )
@@ -149,14 +157,14 @@ int ESP32_PWM_ISR::findFirstFreeSlot()
149157

150158
///////////////////////////////////////////////////
151159

152-
int ESP32_PWM_ISR::setupPWMChannel(uint32_t pin, uint32_t period, uint32_t dutycycle, void* cbFunc)
160+
int ESP32_PWM_ISR::setupPWMChannel(uint32_t pin, uint32_t period, uint32_t dutycycle, void* cbStartFunc, void* cbStopFunc)
153161
{
154162
int channelNum;
155163

156-
// Invalid input, such as pin = 0, period = 0, etc
157-
if ( (pin == 0) || (period == 0) || (dutycycle > 100) )
164+
// Invalid input, such as period = 0, etc
165+
if ( (period == 0) || (dutycycle > 100) )
158166
{
159-
PWM_LOGERROR("Error: Invalid pin, period or dutycycle");
167+
PWM_LOGERROR("Error: Invalid period or dutycycle");
160168
return -1;
161169
}
162170

@@ -172,15 +180,16 @@ int ESP32_PWM_ISR::setupPWMChannel(uint32_t pin, uint32_t period, uint32_t dutyc
172180
return -1;
173181
}
174182

175-
PWM[channelNum].pin = pin;
176-
PWM[channelNum].period = period;
177-
PWM[channelNum].onTime = ( period * dutycycle ) / 100;
183+
PWM[channelNum].pin = pin;
184+
PWM[channelNum].period = period;
185+
PWM[channelNum].onTime = ( period * dutycycle ) / 100;
178186

179187
pinMode(pin, OUTPUT);
180188
digitalWrite(pin, HIGH);
181-
PWM[channelNum].pinHigh = true;
189+
PWM[channelNum].pinHigh = true;
182190

183-
PWM[channelNum].callback = cbFunc;
191+
PWM[channelNum].callbackStart = cbStartFunc;
192+
PWM[channelNum].callbackStop = cbStopFunc;
184193

185194
PWM_LOGDEBUG0("Channel : "); PWM_LOGDEBUG0(channelNum); PWM_LOGDEBUG0("\tPeriod : "); PWM_LOGDEBUG0(PWM[channelNum].period);
186195
PWM_LOGDEBUG0("\t\tOnTime : "); PWM_LOGDEBUG0(PWM[channelNum].onTime); PWM_LOGDEBUG0("\tStart_Time : "); PWM_LOGDEBUGLN0(PWM[channelNum].prevTime);
@@ -207,14 +216,16 @@ void ESP32_PWM_ISR::deleteChannel(unsigned channelNum)
207216
return;
208217
}
209218

210-
// don't decrease the number of timers if the specified slot is already empty
211-
if (PWM[channelNum].callback != NULL)
219+
// don't decrease the number of timers if the specified slot is already empty (zero period, invalid)
220+
if ( (PWM[channelNum].pin != INVALID_ESP32_PIN) && (PWM[channelNum].period != 0) )
212221
{
213222
// ESP32 is a multi core / multi processing chip. It is mandatory to disable task switches during modifying shared vars
214223
portENTER_CRITICAL(&PWM_Mux);
215224

216225
memset((void*) &PWM[channelNum], 0, sizeof (PWM_t));
217226

227+
PWM[channelNum].pin = INVALID_ESP32_PIN;
228+
218229
// update number of timers
219230
numChannels--;
220231

@@ -283,14 +294,14 @@ void ESP32_PWM_ISR::disable(unsigned channelNum)
283294

284295
void ESP32_PWM_ISR::enableAll()
285296
{
286-
// Enable all timers with a callback assigned (used)
297+
// Enable all timers with a callbackStart assigned (used)
287298

288299
// ESP32 is a multi core / multi processing chip. It is mandatory to disable task switches during modifying shared vars
289300
portENTER_CRITICAL(&PWM_Mux);
290301

291302
for (uint8_t channelNum = 0; channelNum < MAX_NUMBER_CHANNELS; channelNum++)
292303
{
293-
if (PWM[channelNum].callback != NULL)
304+
if (PWM[channelNum].period != 0)
294305
{
295306
PWM[channelNum].enabled = true;
296307
}
@@ -304,14 +315,14 @@ void ESP32_PWM_ISR::enableAll()
304315

305316
void ESP32_PWM_ISR::disableAll()
306317
{
307-
// Disable all timers with a callback assigned (used)
318+
// Disable all timers with a callbackStart assigned (used)
308319

309320
// ESP32 is a multi core / multi processing chip. It is mandatory to disable task switches during modifying shared vars
310321
portENTER_CRITICAL(&PWM_Mux);
311322

312323
for (uint8_t channelNum = 0; channelNum < MAX_NUMBER_CHANNELS; channelNum++)
313324
{
314-
if (PWM[channelNum].callback != NULL)
325+
if (PWM[channelNum].period != 0)
315326
{
316327
PWM[channelNum].enabled = false;
317328
}

src/PWM_Generic_Debug.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,12 @@
2020
Therefore, their executions are not blocked by bad-behaving functions / tasks.
2121
This important feature is absolutely necessary for mission-critical tasks.
2222
23-
Version: 1.0.0
23+
Version: 1.0.1
2424
2525
Version Modified By Date Comments
2626
------- ----------- ---------- -----------
2727
1.0.0 K Hoang 20/09/2021 Initial coding for ESP32, ESP32_S2, ESP32_C3 boards with ESP32 core v2.0.0+
28+
1.0.1 K Hoang 21/09/2021 Fix bug. Ading PWM end-of-duty-cycle callback function. Improve examples
2829
*****************************************************************************************************************************/
2930

3031
#pragma once

src_cpp/ESP32_PWM.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,12 @@
2121
Therefore, their executions are not blocked by bad-behaving functions / tasks.
2222
This important feature is absolutely necessary for mission-critical tasks.
2323
24-
Version: 1.0.0
24+
Version: 1.0.1
2525
2626
Version Modified By Date Comments
2727
------- ----------- ---------- -----------
2828
1.0.0 K Hoang 20/09/2021 Initial coding for ESP32, ESP32_S2, ESP32_C3 boards with ESP32 core v2.0.0+
29+
1.0.1 K Hoang 21/09/2021 Fix bug. Ading PWM end-of-duty-cycle callback function. Improve examples
2930
*****************************************************************************************************************************/
3031

3132
#pragma once
@@ -52,7 +53,7 @@
5253
#endif
5354

5455
#ifndef ESP32_PWM_VERSION
55-
#define ESP32_PWM_VERSION "ESP32_PWM v1.0.0"
56+
#define ESP32_PWM_VERSION "ESP32_PWM v1.0.1"
5657
#endif
5758

5859
#ifndef TIMER_INTERRUPT_DEBUG
@@ -175,7 +176,7 @@ typedef ESP32TimerInterrupt ESP32Timer;
175176
//esp_err_t timer_group_intr_enable(timer_group_t group_num, timer_intr_t intr_mask);
176177
//esp_err_t timer_group_intr_disable(timer_group_t group_num, timer_intr_t intr_mask);
177178

178-
179+
#define INVALID_ESP32_PIN 255
179180

180181
typedef bool (*esp32_timer_callback) (void *);
181182

0 commit comments

Comments
 (0)