mirror of
https://github.com/esp8266/Arduino.git
synced 2025-04-19 23:22:16 +03:00
Allow waveforms to be specified in clock cycles (#7211)
* Allow waveforms to be specified in clock cycles Allow the PWM to specify sub-microsecond waveform edges, as have been proposed by @dok-net and me. No other changes intended. This will increase the linearity at 30 and 40 kHZ PWM rates, but leave most other things unaffected. * Cycle-accurate wafveform to specify Tone periods Co-authored-by: Develo <deveyes@gmail.com>
This commit is contained in:
parent
6cb16997d8
commit
1af4ea661f
@ -22,6 +22,7 @@
|
||||
*/
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "user_interface.h"
|
||||
#include "core_esp8266_waveform.h"
|
||||
|
||||
// Which pins have a tone running on them?
|
||||
@ -35,10 +36,10 @@ static void _startTone(uint8_t _pin, uint32_t high, uint32_t low, unsigned long
|
||||
|
||||
pinMode(_pin, OUTPUT);
|
||||
|
||||
high = std::max(high, (uint32_t)25); // new 20KHz maximum tone frequency,
|
||||
low = std::max(low, (uint32_t)25); // (25us high + 25us low period = 20KHz)
|
||||
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 (startWaveform(_pin, high, low, (uint32_t) duration * 1000)) {
|
||||
if (startWaveformCycles(_pin, high, low, microsecondsToClockCycles(duration * 1000))) {
|
||||
_toneMap |= 1 << _pin;
|
||||
}
|
||||
}
|
||||
@ -48,7 +49,7 @@ void tone(uint8_t _pin, unsigned int frequency, unsigned long duration) {
|
||||
if (frequency == 0) {
|
||||
noTone(_pin);
|
||||
} else {
|
||||
uint32_t period = 1000000L / frequency;
|
||||
uint32_t period = (1000000L * system_get_cpu_freq()) / frequency;
|
||||
uint32_t high = period / 2;
|
||||
uint32_t low = period - high;
|
||||
_startTone(_pin, high, low, duration);
|
||||
@ -62,7 +63,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.0 / frequency;
|
||||
double period = (1000000.0L * system_get_cpu_freq()) / 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);
|
||||
|
@ -112,15 +112,19 @@ 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) {
|
||||
if ((pin > 16) || isFlashInterfacePin(pin)) {
|
||||
return startWaveformCycles(pin, microsecondsToClockCycles(timeHighUS), microsecondsToClockCycles(timeLowUS), microsecondsToClockCycles(runTimeUS));
|
||||
}
|
||||
|
||||
int startWaveformCycles(uint8_t pin, uint32_t timeHighCycles, uint32_t timeLowCycles, uint32_t runTimeCycles) {
|
||||
if ((pin > 16) || isFlashInterfacePin(pin)) {
|
||||
return false;
|
||||
}
|
||||
Waveform *wave = &waveform[pin];
|
||||
// Adjust to shave off some of the IRQ time, approximately
|
||||
wave->nextTimeHighCycles = microsecondsToClockCycles(timeHighUS);
|
||||
wave->nextTimeLowCycles = microsecondsToClockCycles(timeLowUS);
|
||||
wave->expiryCycle = runTimeUS ? GetCycleCount() + microsecondsToClockCycles(runTimeUS) : 0;
|
||||
if (runTimeUS && !wave->expiryCycle) {
|
||||
wave->nextTimeHighCycles = timeHighCycles;
|
||||
wave->nextTimeLowCycles = timeLowCycles;
|
||||
wave->expiryCycle = runTimeCycles ? GetCycleCount() + runTimeCycles : 0;
|
||||
if (runTimeCycles && !wave->expiryCycle) {
|
||||
wave->expiryCycle = 1; // expiryCycle==0 means no timeout, so avoid setting it
|
||||
}
|
||||
|
||||
|
@ -50,6 +50,8 @@ 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);
|
||||
// Stop a waveform, if any, on the specified pin.
|
||||
// Returns true or false on success or failure.
|
||||
int stopWaveform(uint8_t pin);
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "core_esp8266_waveform.h"
|
||||
|
||||
extern "C" {
|
||||
#include "user_interface.h"
|
||||
|
||||
static uint32_t analogMap = 0;
|
||||
static int32_t analogScale = PWMRANGE;
|
||||
@ -50,7 +51,7 @@ extern void __analogWrite(uint8_t pin, int val) {
|
||||
if (pin > 16) {
|
||||
return;
|
||||
}
|
||||
uint32_t analogPeriod = 1000000L / analogFreq;
|
||||
uint32_t analogPeriod = (1000000L * system_get_cpu_freq()) / analogFreq;
|
||||
if (val < 0) {
|
||||
val = 0;
|
||||
} else if (val > analogScale) {
|
||||
@ -68,7 +69,7 @@ extern void __analogWrite(uint8_t pin, int val) {
|
||||
stopWaveform(pin);
|
||||
digitalWrite(pin, LOW);
|
||||
} else {
|
||||
if (startWaveform(pin, high, low, 0)) {
|
||||
if (startWaveformCycles(pin, high, low, 0)) {
|
||||
analogMap |= (1 << pin);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user