1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-19 23:22:16 +03:00

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.
This commit is contained in:
Dirk O. Kaar 2020-04-19 14:57:46 +02:00 committed by GitHub
parent 4ca69bc21d
commit ea1fdb210f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 38 additions and 27 deletions

View File

@ -22,14 +22,14 @@
*/ */
#include "Arduino.h" #include "Arduino.h"
#include "user_interface.h"
#include "core_esp8266_waveform.h" #include "core_esp8266_waveform.h"
#include "user_interface.h"
// Which pins have a tone running on them? // Which pins have a tone running on them?
static uint32_t _toneMap = 0; 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) { if (_pin > 16) {
return; return;
} }
@ -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, 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) 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; _toneMap |= 1 << _pin;
} }
} }
@ -49,7 +52,7 @@ void tone(uint8_t _pin, unsigned int frequency, unsigned long duration) {
if (frequency == 0) { if (frequency == 0) {
noTone(_pin); noTone(_pin);
} else { } else {
uint32_t period = (1000000L * system_get_cpu_freq()) / frequency; uint32_t period = microsecondsToClockCycles(1000000UL) / frequency;
uint32_t high = period / 2; uint32_t high = period / 2;
uint32_t low = period - high; uint32_t low = period - high;
_startTone(_pin, high, low, duration); _startTone(_pin, high, low, duration);
@ -63,7 +66,7 @@ void tone(uint8_t _pin, double frequency, unsigned long duration) {
if (frequency < 1.0) { // FP means no exact comparisons if (frequency < 1.0) { // FP means no exact comparisons
noTone(_pin); noTone(_pin);
} else { } 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 high = (uint32_t)((period / 2.0) + 0.5);
uint32_t low = (uint32_t)(period + 0.5) - high; uint32_t low = (uint32_t)(period + 0.5) - high;
_startTone(_pin, high, low, duration); _startTone(_pin, high, low, duration);

View File

@ -5,13 +5,13 @@
Copyright (c) 2018 Earle F. Philhower, III. All rights reserved. Copyright (c) 2018 Earle F. Philhower, III. All rights reserved.
The core idea is to have a programmable waveform generator with a unique 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 high and low period (defined in microseconds or CPU clock cycles). TIMER1 is
mode and is always loaded with the time until the next edge of any live set to 1-shot mode and is always loaded with the time until the next edge
waveforms. of any live waveforms.
Up to one waveform generator per pin supported. 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 timer. This allows for removing interrupt jitter and delay as the counter
always increments once per 80MHz clock. Changes to a waveform are always increments once per 80MHz clock. Changes to a waveform are
contiguous and only take effect on the next waveform transition, contiguous and only take effect on the next waveform transition,
@ -19,8 +19,9 @@
This replaces older tone(), analogWrite(), and the Servo classes. This replaces older tone(), analogWrite(), and the Servo classes.
Everywhere in the code where "cycles" is used, it means ESP.getCycleTime() Everywhere in the code where "cycles" is used, it means ESP.getCycleCount()
cycles, not TIMER1 cycles (which may be 2 CPU clocks @ 160MHz). 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 This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
@ -112,10 +113,10 @@ void setTimer1Callback(uint32_t (*fn)()) {
// waveform smoothly on next low->high transition. For immediate change, stopWaveform() // waveform smoothly on next low->high transition. For immediate change, stopWaveform()
// first, then it will immediately begin. // first, then it will immediately begin.
int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t runTimeUS) { 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)) { if ((pin > 16) || isFlashInterfacePin(pin)) {
return false; return false;
} }

View File

@ -5,13 +5,13 @@
Copyright (c) 2018 Earle F. Philhower, III. All rights reserved. Copyright (c) 2018 Earle F. Philhower, III. All rights reserved.
The core idea is to have a programmable waveform generator with a unique 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 high and low period (defined in microseconds or CPU clock cycles). TIMER1 is
mode and is always loaded with the time until the next edge of any live set to 1-shot mode and is always loaded with the time until the next edge
waveforms. of any live waveforms.
Up to one waveform generator per pin supported. 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 timer. This allows for removing interrupt jitter and delay as the counter
always increments once per 80MHz clock. Changes to a waveform are always increments once per 80MHz clock. Changes to a waveform are
contiguous and only take effect on the next waveform transition, contiguous and only take effect on the next waveform transition,
@ -19,8 +19,9 @@
This replaces older tone(), analogWrite(), and the Servo classes. This replaces older tone(), analogWrite(), and the Servo classes.
Everywhere in the code where "cycles" is used, it means ESP.getCycleTime() Everywhere in the code where "cycles" is used, it means ESP.getCycleCount()
cycles, not TIMER1 cycles (which may be 2 CPU clocks @ 160MHz). 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 This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
@ -50,8 +51,10 @@ extern "C" {
// If runtimeUS > 0 then automatically stop it after that many usecs. // If runtimeUS > 0 then automatically stop it after that many usecs.
// Returns true or false on success or failure. // Returns true or false on success or failure.
int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t runTimeUS); 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 // Start or change a waveform of the specified high and low CPU clock cycles on specific pin.
int startWaveformCycles(uint8_t pin, uint32_t timeHighCycles, uint32_t timeLowCycles, uint32_t runTimeCycles); // 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. // Stop a waveform, if any, on the specified pin.
// Returns true or false on success or failure. // Returns true or false on success or failure.
int stopWaveform(uint8_t pin); int stopWaveform(uint8_t pin);

View File

@ -25,7 +25,6 @@
#include "core_esp8266_waveform.h" #include "core_esp8266_waveform.h"
extern "C" { extern "C" {
#include "user_interface.h"
static uint32_t analogMap = 0; static uint32_t analogMap = 0;
static int32_t analogScale = PWMRANGE; static int32_t analogScale = PWMRANGE;
@ -51,7 +50,7 @@ extern void __analogWrite(uint8_t pin, int val) {
if (pin > 16) { if (pin > 16) {
return; return;
} }
uint32_t analogPeriod = (1000000L * system_get_cpu_freq()) / analogFreq; uint32_t analogPeriod = microsecondsToClockCycles(1000000UL) / analogFreq;
if (val < 0) { if (val < 0) {
val = 0; val = 0;
} else if (val > analogScale) { } else if (val > analogScale) {
@ -63,13 +62,11 @@ extern void __analogWrite(uint8_t pin, int val) {
uint32_t low = analogPeriod - high; uint32_t low = analogPeriod - high;
pinMode(pin, OUTPUT); pinMode(pin, OUTPUT);
if (low == 0) { if (low == 0) {
stopWaveform(pin);
digitalWrite(pin, HIGH); digitalWrite(pin, HIGH);
} else if (high == 0) { } else if (high == 0) {
stopWaveform(pin);
digitalWrite(pin, LOW); digitalWrite(pin, LOW);
} else { } else {
if (startWaveformCycles(pin, high, low, 0)) { if (startWaveformClockCycles(pin, high, low, 0)) {
analogMap |= (1 << pin); analogMap |= (1 << pin);
} }
} }

View File

@ -24,6 +24,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include <Servo.h> #include <Servo.h>
#include "core_esp8266_waveform.h" #include "core_esp8266_waveform.h"
uint32_t Servo::_servoMap = 0;
// similiar to map but will have increased accuracy that provides a more // 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) // 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) 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)
void Servo::detach() void Servo::detach()
{ {
if (_attached) { if (_attached) {
_servoMap &= ~(1 << _pin);
stopWaveform(_pin); stopWaveform(_pin);
_attached = false; _attached = false;
digitalWrite(_pin, LOW); digitalWrite(_pin, LOW);
@ -105,7 +108,10 @@ void Servo::writeMicroseconds(int value)
{ {
_valueUs = value; _valueUs = value;
if (_attached) { if (_attached) {
startWaveform(_pin, _valueUs, REFRESH_INTERVAL - _valueUs, 0); _servoMap &= ~(1 << _pin);
if (startWaveform(_pin, _valueUs, REFRESH_INTERVAL - _valueUs, 0)) {
_servoMap |= (1 << _pin);
}
} }
} }

View File

@ -72,6 +72,7 @@ public:
int readMicroseconds(); // returns current pulse width in microseconds for this servo (was read_us() in first release) 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 bool attached(); // return true if this servo is attached, otherwise false
private: private:
static uint32_t _servoMap;
bool _attached; bool _attached;
uint8_t _pin; uint8_t _pin;
uint16_t _minUs; uint16_t _minUs;