Skip to content

Commit ea1fdb2

Browse files
authored
Fixup 7122, new startWaveformCycles more aptly named startWaveformClockCycles (like in rest of core API for this type of use). (#7218)
Fix/clarify comments. Fix redundancies in Tone, end Tone waveform on exact period limit for proper sound. Fix redundancies in wiring_pwmExtend Servo to map in-use pins, Tone already has this.
1 parent 4ca69bc commit ea1fdb2

File tree

6 files changed

+38
-27
lines changed

6 files changed

+38
-27
lines changed

cores/esp8266/Tone.cpp

+8-5
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@
2222
*/
2323

2424
#include "Arduino.h"
25-
#include "user_interface.h"
2625
#include "core_esp8266_waveform.h"
26+
#include "user_interface.h"
2727

2828
// Which pins have a tone running on them?
2929
static uint32_t _toneMap = 0;
3030

3131

32-
static void _startTone(uint8_t _pin, uint32_t high, uint32_t low, unsigned long duration) {
32+
static void _startTone(uint8_t _pin, uint32_t high, uint32_t low, uint32_t duration) {
3333
if (_pin > 16) {
3434
return;
3535
}
@@ -39,7 +39,10 @@ static void _startTone(uint8_t _pin, uint32_t high, uint32_t low, unsigned long
3939
high = std::max(high, (uint32_t)microsecondsToClockCycles(25)); // new 20KHz maximum tone frequency,
4040
low = std::max(low, (uint32_t)microsecondsToClockCycles(25)); // (25us high + 25us low period = 20KHz)
4141

42-
if (startWaveformCycles(_pin, high, low, microsecondsToClockCycles(duration * 1000))) {
42+
duration = microsecondsToClockCycles(duration * 1000UL);
43+
duration += high + low - 1;
44+
duration -= duration % (high + low);
45+
if (startWaveformClockCycles(_pin, high, low, duration)) {
4346
_toneMap |= 1 << _pin;
4447
}
4548
}
@@ -49,7 +52,7 @@ void tone(uint8_t _pin, unsigned int frequency, unsigned long duration) {
4952
if (frequency == 0) {
5053
noTone(_pin);
5154
} else {
52-
uint32_t period = (1000000L * system_get_cpu_freq()) / frequency;
55+
uint32_t period = microsecondsToClockCycles(1000000UL) / frequency;
5356
uint32_t high = period / 2;
5457
uint32_t low = period - high;
5558
_startTone(_pin, high, low, duration);
@@ -63,7 +66,7 @@ void tone(uint8_t _pin, double frequency, unsigned long duration) {
6366
if (frequency < 1.0) { // FP means no exact comparisons
6467
noTone(_pin);
6568
} else {
66-
double period = (1000000.0L * system_get_cpu_freq()) / frequency;
69+
double period = (double)microsecondsToClockCycles(1000000UL) / frequency;
6770
uint32_t high = (uint32_t)((period / 2.0) + 0.5);
6871
uint32_t low = (uint32_t)(period + 0.5) - high;
6972
_startTone(_pin, high, low, duration);

cores/esp8266/core_esp8266_waveform.cpp

+9-8
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,23 @@
55
Copyright (c) 2018 Earle F. Philhower, III. All rights reserved.
66
77
The core idea is to have a programmable waveform generator with a unique
8-
high and low period (defined in microseconds). TIMER1 is set to 1-shot
9-
mode and is always loaded with the time until the next edge of any live
10-
waveforms.
8+
high and low period (defined in microseconds or CPU clock cycles). TIMER1 is
9+
set to 1-shot mode and is always loaded with the time until the next edge
10+
of any live waveforms.
1111
1212
Up to one waveform generator per pin supported.
1313
14-
Each waveform generator is synchronized to the ESP cycle counter, not the
14+
Each waveform generator is synchronized to the ESP clock cycle counter, not the
1515
timer. This allows for removing interrupt jitter and delay as the counter
1616
always increments once per 80MHz clock. Changes to a waveform are
1717
contiguous and only take effect on the next waveform transition,
1818
allowing for smooth transitions.
1919
2020
This replaces older tone(), analogWrite(), and the Servo classes.
2121
22-
Everywhere in the code where "cycles" is used, it means ESP.getCycleTime()
23-
cycles, not TIMER1 cycles (which may be 2 CPU clocks @ 160MHz).
22+
Everywhere in the code where "cycles" is used, it means ESP.getCycleCount()
23+
clock cycle count, or an interval measured in CPU clock cycles, but not TIMER1
24+
cycles (which may be 2 CPU clock cycles @ 160MHz).
2425
2526
This library is free software; you can redistribute it and/or
2627
modify it under the terms of the GNU Lesser General Public
@@ -112,10 +113,10 @@ void setTimer1Callback(uint32_t (*fn)()) {
112113
// waveform smoothly on next low->high transition. For immediate change, stopWaveform()
113114
// first, then it will immediately begin.
114115
int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t runTimeUS) {
115-
return startWaveformCycles(pin, microsecondsToClockCycles(timeHighUS), microsecondsToClockCycles(timeLowUS), microsecondsToClockCycles(runTimeUS));
116+
return startWaveformClockCycles(pin, microsecondsToClockCycles(timeHighUS), microsecondsToClockCycles(timeLowUS), microsecondsToClockCycles(runTimeUS));
116117
}
117118

118-
int startWaveformCycles(uint8_t pin, uint32_t timeHighCycles, uint32_t timeLowCycles, uint32_t runTimeCycles) {
119+
int startWaveformClockCycles(uint8_t pin, uint32_t timeHighCycles, uint32_t timeLowCycles, uint32_t runTimeCycles) {
119120
if ((pin > 16) || isFlashInterfacePin(pin)) {
120121
return false;
121122
}

cores/esp8266/core_esp8266_waveform.h

+11-8
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,23 @@
55
Copyright (c) 2018 Earle F. Philhower, III. All rights reserved.
66
77
The core idea is to have a programmable waveform generator with a unique
8-
high and low period (defined in microseconds). TIMER1 is set to 1-shot
9-
mode and is always loaded with the time until the next edge of any live
10-
waveforms.
8+
high and low period (defined in microseconds or CPU clock cycles). TIMER1 is
9+
set to 1-shot mode and is always loaded with the time until the next edge
10+
of any live waveforms.
1111
1212
Up to one waveform generator per pin supported.
1313
14-
Each waveform generator is synchronized to the ESP cycle counter, not the
14+
Each waveform generator is synchronized to the ESP clock cycle counter, not the
1515
timer. This allows for removing interrupt jitter and delay as the counter
1616
always increments once per 80MHz clock. Changes to a waveform are
1717
contiguous and only take effect on the next waveform transition,
1818
allowing for smooth transitions.
1919
2020
This replaces older tone(), analogWrite(), and the Servo classes.
2121
22-
Everywhere in the code where "cycles" is used, it means ESP.getCycleTime()
23-
cycles, not TIMER1 cycles (which may be 2 CPU clocks @ 160MHz).
22+
Everywhere in the code where "cycles" is used, it means ESP.getCycleCount()
23+
clock cycle count, or an interval measured in CPU clock cycles, but not TIMER1
24+
cycles (which may be 2 CPU clock cycles @ 160MHz).
2425
2526
This library is free software; you can redistribute it and/or
2627
modify it under the terms of the GNU Lesser General Public
@@ -50,8 +51,10 @@ extern "C" {
5051
// If runtimeUS > 0 then automatically stop it after that many usecs.
5152
// Returns true or false on success or failure.
5253
int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t runTimeUS);
53-
// Same as above, but pass in CPU clock cycles instead of microseconds
54-
int startWaveformCycles(uint8_t pin, uint32_t timeHighCycles, uint32_t timeLowCycles, uint32_t runTimeCycles);
54+
// Start or change a waveform of the specified high and low CPU clock cycles on specific pin.
55+
// If runtimeCycles > 0 then automatically stop it after that many CPU clock cycles.
56+
// Returns true or false on success or failure.
57+
int startWaveformClockCycles(uint8_t pin, uint32_t timeHighCycles, uint32_t timeLowCycles, uint32_t runTimeCycles);
5558
// Stop a waveform, if any, on the specified pin.
5659
// Returns true or false on success or failure.
5760
int stopWaveform(uint8_t pin);

cores/esp8266/core_esp8266_wiring_pwm.cpp

+2-5
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
#include "core_esp8266_waveform.h"
2626

2727
extern "C" {
28-
#include "user_interface.h"
2928

3029
static uint32_t analogMap = 0;
3130
static int32_t analogScale = PWMRANGE;
@@ -51,7 +50,7 @@ extern void __analogWrite(uint8_t pin, int val) {
5150
if (pin > 16) {
5251
return;
5352
}
54-
uint32_t analogPeriod = (1000000L * system_get_cpu_freq()) / analogFreq;
53+
uint32_t analogPeriod = microsecondsToClockCycles(1000000UL) / analogFreq;
5554
if (val < 0) {
5655
val = 0;
5756
} else if (val > analogScale) {
@@ -63,13 +62,11 @@ extern void __analogWrite(uint8_t pin, int val) {
6362
uint32_t low = analogPeriod - high;
6463
pinMode(pin, OUTPUT);
6564
if (low == 0) {
66-
stopWaveform(pin);
6765
digitalWrite(pin, HIGH);
6866
} else if (high == 0) {
69-
stopWaveform(pin);
7067
digitalWrite(pin, LOW);
7168
} else {
72-
if (startWaveformCycles(pin, high, low, 0)) {
69+
if (startWaveformClockCycles(pin, high, low, 0)) {
7370
analogMap |= (1 << pin);
7471
}
7572
}

libraries/Servo/src/Servo.cpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2424
#include <Servo.h>
2525
#include "core_esp8266_waveform.h"
2626

27+
uint32_t Servo::_servoMap = 0;
28+
2729
// similiar to map but will have increased accuracy that provides a more
2830
// symetric api (call it and use result to reverse will provide the original value)
2931
int improved_map(int value, int minIn, int maxIn, int minOut, int maxOut)
@@ -82,6 +84,7 @@ uint8_t Servo::attach(int pin, uint16_t minUs, uint16_t maxUs)
8284
void Servo::detach()
8385
{
8486
if (_attached) {
87+
_servoMap &= ~(1 << _pin);
8588
stopWaveform(_pin);
8689
_attached = false;
8790
digitalWrite(_pin, LOW);
@@ -105,7 +108,10 @@ void Servo::writeMicroseconds(int value)
105108
{
106109
_valueUs = value;
107110
if (_attached) {
108-
startWaveform(_pin, _valueUs, REFRESH_INTERVAL - _valueUs, 0);
111+
_servoMap &= ~(1 << _pin);
112+
if (startWaveform(_pin, _valueUs, REFRESH_INTERVAL - _valueUs, 0)) {
113+
_servoMap |= (1 << _pin);
114+
}
109115
}
110116
}
111117

libraries/Servo/src/Servo.h

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ class Servo
7272
int readMicroseconds(); // returns current pulse width in microseconds for this servo (was read_us() in first release)
7373
bool attached(); // return true if this servo is attached, otherwise false
7474
private:
75+
static uint32_t _servoMap;
7576
bool _attached;
7677
uint8_t _pin;
7778
uint16_t _minUs;

0 commit comments

Comments
 (0)