Skip to content

Commit

Permalink
Fixup 7122, new startWaveformCycles more aptly named startWaveformClo…
Browse files Browse the repository at this point in the history
…ckCycles (like in rest of core API for this type of use).

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.
  • Loading branch information
dok-net committed Apr 17, 2020
1 parent 9632e86 commit bea599b
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 27 deletions.
13 changes: 8 additions & 5 deletions cores/esp8266/Tone.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@
*/

#include "Arduino.h"
#include "user_interface.h"
#include "core_esp8266_waveform.h"
#include "user_interface.h"

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


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

if (startWaveformCycles(_pin, high, low, microsecondsToClockCycles(duration * 1000))) {
duration = microsecondsToClockCycles(duration * 1000UL);
duration += high + low - 1;
duration -= duration % (high + low);
if (startWaveformClockCycles(_pin, high, low, duration)) {
_toneMap |= 1 << _pin;
}
}
Expand All @@ -49,7 +52,7 @@ void tone(uint8_t _pin, unsigned int frequency, unsigned long duration) {
if (frequency == 0) {
noTone(_pin);
} else {
uint32_t period = (1000000L * system_get_cpu_freq()) / frequency;
uint32_t period = microsecondsToClockCycles(1000000UL) / frequency;
uint32_t high = period / 2;
uint32_t low = period - high;
_startTone(_pin, high, low, duration);
Expand All @@ -63,7 +66,7 @@ void tone(uint8_t _pin, double frequency, unsigned long duration) {
if (frequency < 1.0) { // FP means no exact comparisons
noTone(_pin);
} else {
double period = (1000000.0L * system_get_cpu_freq()) / frequency;
double period = (double)microsecondsToClockCycles(1000000UL) / frequency;
uint32_t high = (uint32_t)((period / 2.0) + 0.5);
uint32_t low = (uint32_t)(period + 0.5) - high;
_startTone(_pin, high, low, duration);
Expand Down
17 changes: 9 additions & 8 deletions cores/esp8266/core_esp8266_waveform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,23 @@
Copyright (c) 2018 Earle F. Philhower, III. All rights reserved.
The core idea is to have a programmable waveform generator with a unique
high and low period (defined in microseconds). TIMER1 is set to 1-shot
mode and is always loaded with the time until the next edge of any live
waveforms.
high and low period (defined in microseconds or CPU clock cycles). TIMER1 is
set to 1-shot mode and is always loaded with the time until the next edge
of any live waveforms.
Up to one waveform generator per pin supported.
Each waveform generator is synchronized to the ESP cycle counter, not the
Each waveform generator is synchronized to the ESP clock cycle counter, not the
timer. This allows for removing interrupt jitter and delay as the counter
always increments once per 80MHz clock. Changes to a waveform are
contiguous and only take effect on the next waveform transition,
allowing for smooth transitions.
This replaces older tone(), analogWrite(), and the Servo classes.
Everywhere in the code where "cycles" is used, it means ESP.getCycleTime()
cycles, not TIMER1 cycles (which may be 2 CPU clocks @ 160MHz).
Everywhere in the code where "cycles" is used, it means ESP.getCycleCount()
clock cycle count, or an interval measured in CPU clock cycles, but not TIMER1
cycles (which may be 2 CPU clock cycles @ 160MHz).
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
Expand Down Expand Up @@ -112,10 +113,10 @@ void setTimer1Callback(uint32_t (*fn)()) {
// waveform smoothly on next low->high transition. For immediate change, stopWaveform()
// first, then it will immediately begin.
int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t runTimeUS) {
return startWaveformCycles(pin, microsecondsToClockCycles(timeHighUS), microsecondsToClockCycles(timeLowUS), microsecondsToClockCycles(runTimeUS));
return startWaveformClockCycles(pin, microsecondsToClockCycles(timeHighUS), microsecondsToClockCycles(timeLowUS), microsecondsToClockCycles(runTimeUS));
}

int startWaveformCycles(uint8_t pin, uint32_t timeHighCycles, uint32_t timeLowCycles, uint32_t runTimeCycles) {
int startWaveformClockCycles(uint8_t pin, uint32_t timeHighCycles, uint32_t timeLowCycles, uint32_t runTimeCycles) {
if ((pin > 16) || isFlashInterfacePin(pin)) {
return false;
}
Expand Down
19 changes: 11 additions & 8 deletions cores/esp8266/core_esp8266_waveform.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,23 @@
Copyright (c) 2018 Earle F. Philhower, III. All rights reserved.
The core idea is to have a programmable waveform generator with a unique
high and low period (defined in microseconds). TIMER1 is set to 1-shot
mode and is always loaded with the time until the next edge of any live
waveforms.
high and low period (defined in microseconds or CPU clock cycles). TIMER1 is
set to 1-shot mode and is always loaded with the time until the next edge
of any live waveforms.
Up to one waveform generator per pin supported.
Each waveform generator is synchronized to the ESP cycle counter, not the
Each waveform generator is synchronized to the ESP clock cycle counter, not the
timer. This allows for removing interrupt jitter and delay as the counter
always increments once per 80MHz clock. Changes to a waveform are
contiguous and only take effect on the next waveform transition,
allowing for smooth transitions.
This replaces older tone(), analogWrite(), and the Servo classes.
Everywhere in the code where "cycles" is used, it means ESP.getCycleTime()
cycles, not TIMER1 cycles (which may be 2 CPU clocks @ 160MHz).
Everywhere in the code where "cycles" is used, it means ESP.getCycleCount()
clock cycle count, or an interval measured in CPU clock cycles, but not TIMER1
cycles (which may be 2 CPU clock cycles @ 160MHz).
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
Expand Down Expand Up @@ -50,8 +51,10 @@ extern "C" {
// If runtimeUS > 0 then automatically stop it after that many usecs.
// Returns true or false on success or failure.
int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t runTimeUS);
// Same as above, but pass in CPU clock cycles instead of microseconds
int startWaveformCycles(uint8_t pin, uint32_t timeHighCycles, uint32_t timeLowCycles, uint32_t runTimeCycles);
// Start or change a waveform of the specified high and low CPU clock cycles on specific pin.
// If runtimeCycles > 0 then automatically stop it after that many CPU clock cycles.
// Returns true or false on success or failure.
int startWaveformClockCycles(uint8_t pin, uint32_t timeHighCycles, uint32_t timeLowCycles, uint32_t runTimeCycles);
// Stop a waveform, if any, on the specified pin.
// Returns true or false on success or failure.
int stopWaveform(uint8_t pin);
Expand Down
7 changes: 2 additions & 5 deletions cores/esp8266/core_esp8266_wiring_pwm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
#include "core_esp8266_waveform.h"

extern "C" {
#include "user_interface.h"

static uint32_t analogMap = 0;
static int32_t analogScale = PWMRANGE;
Expand All @@ -51,7 +50,7 @@ extern void __analogWrite(uint8_t pin, int val) {
if (pin > 16) {
return;
}
uint32_t analogPeriod = (1000000L * system_get_cpu_freq()) / analogFreq;
uint32_t analogPeriod = microsecondsToClockCycles(1000000UL) / analogFreq;
if (val < 0) {
val = 0;
} else if (val > analogScale) {
Expand All @@ -63,13 +62,11 @@ extern void __analogWrite(uint8_t pin, int val) {
uint32_t low = analogPeriod - high;
pinMode(pin, OUTPUT);
if (low == 0) {
stopWaveform(pin);
digitalWrite(pin, HIGH);
} else if (high == 0) {
stopWaveform(pin);
digitalWrite(pin, LOW);
} else {
if (startWaveformCycles(pin, high, low, 0)) {
if (startWaveformClockCycles(pin, high, low, 0)) {
analogMap |= (1 << pin);
}
}
Expand Down
8 changes: 7 additions & 1 deletion libraries/Servo/src/Servo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include <Servo.h>
#include "core_esp8266_waveform.h"

uint32_t Servo::_servoMap = 0;

// similiar to map but will have increased accuracy that provides a more
// symetric api (call it and use result to reverse will provide the original value)
int improved_map(int value, int minIn, int maxIn, int minOut, int maxOut)
Expand Down Expand Up @@ -82,6 +84,7 @@ uint8_t Servo::attach(int pin, uint16_t minUs, uint16_t maxUs)
void Servo::detach()
{
if (_attached) {
_servoMap &= ~(1 << _pin);
stopWaveform(_pin);
_attached = false;
digitalWrite(_pin, LOW);
Expand All @@ -105,7 +108,10 @@ void Servo::writeMicroseconds(int value)
{
_valueUs = value;
if (_attached) {
startWaveform(_pin, _valueUs, REFRESH_INTERVAL - _valueUs, 0);
_servoMap &= ~(1 << _pin);
if (startWaveform(_pin, _valueUs, REFRESH_INTERVAL - _valueUs, 0)) {
_servoMap |= (1 << _pin);
}
}
}

Expand Down
1 change: 1 addition & 0 deletions libraries/Servo/src/Servo.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class Servo
int readMicroseconds(); // returns current pulse width in microseconds for this servo (was read_us() in first release)
bool attached(); // return true if this servo is attached, otherwise false
private:
static uint32_t _servoMap;
bool _attached;
uint8_t _pin;
uint16_t _minUs;
Expand Down

0 comments on commit bea599b

Please sign in to comment.