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 "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;
}
@ -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;
}
}
@ -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);
@ -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);

View File

@ -5,13 +5,13 @@
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,
@ -19,8 +19,9 @@
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
@ -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;
}

View File

@ -5,13 +5,13 @@
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,
@ -19,8 +19,9 @@
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
@ -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);

View File

@ -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;
@ -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) {
@ -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);
}
}

View File

@ -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)
@ -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);
@ -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);
}
}
}

View File

@ -72,6 +72,7 @@ public:
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;