1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-07-02 14:22:55 +03:00

Allow specifying waveform generator in source code (#7800)

* Allow specifying waveform generator in source code

Allows code to explicitly specify which waveform generator it wants,
without needing to use one of the 100 IDE menus or adding a `-D`
compile-time define.

Uses weakrefs to allow for apps to call `enablePhaseLockedWaveform();`
within their `setup()` (or anywhere, really) and have the phase locked
versions override the default waveform generators automatically.

For example:

````
void setup() {
  // Uncomment following line to use phase-locked waveform generator
  // enablePhaseLockedWaveform();
  Serial.begin(115200);
  pinMode(LED_BUILTIN, OUTPUT);     // Initialize the LED_BUILTIN pin as an output
  analogWriteRange(1000);
}
void loop() {
  analogWrite(LED_BUILTIN, 100);
  delay(1000);                      // Wait for a second
  analogWrite(LED_BUILTIN, 900);
  delay(2000);                      // Wait for two seconds (to demonstrate the active low LED)
}
````

Also adds an example showing it's use.

Address @dok-net's comments and also remove the _weak/_bound version of
startWaveform() since it's invariant of the actual waveform generator.
This commit is contained in:
Earle F. Philhower, III
2021-01-17 15:57:26 -08:00
committed by GitHub
parent a4b6003c2e
commit f5fd5912fe
14 changed files with 283 additions and 413 deletions

View File

@ -23,7 +23,6 @@ menu.stacksmash=Stack Protection
menu.wipe=Erase Flash
menu.sdk=Espressif FW
menu.ssl=SSL Support
menu.waveform=Waveform Flavour
menu.mmu=MMU
menu.non32xfer=Non-32-Bit Access
@ -66,10 +65,6 @@ generic.menu.ssl.all=All SSL ciphers (most compatible)
generic.menu.ssl.all.build.sslflags=
generic.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
generic.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
generic.menu.waveform.pwm=Locked PWM
generic.menu.waveform.pwm.build.waveform=
generic.menu.waveform.phase=Locked Phase
generic.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
generic.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
generic.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
generic.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -551,10 +546,6 @@ esp8285.menu.ssl.all=All SSL ciphers (most compatible)
esp8285.menu.ssl.all.build.sslflags=
esp8285.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
esp8285.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
esp8285.menu.waveform.pwm=Locked PWM
esp8285.menu.waveform.pwm.build.waveform=
esp8285.menu.waveform.phase=Locked Phase
esp8285.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
esp8285.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
esp8285.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
esp8285.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -906,10 +897,6 @@ gen4iod.menu.ssl.all=All SSL ciphers (most compatible)
gen4iod.menu.ssl.all.build.sslflags=
gen4iod.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
gen4iod.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
gen4iod.menu.waveform.pwm=Locked PWM
gen4iod.menu.waveform.pwm.build.waveform=
gen4iod.menu.waveform.phase=Locked Phase
gen4iod.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
gen4iod.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
gen4iod.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
gen4iod.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -1176,10 +1163,6 @@ huzzah.menu.ssl.all=All SSL ciphers (most compatible)
huzzah.menu.ssl.all.build.sslflags=
huzzah.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
huzzah.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
huzzah.menu.waveform.pwm=Locked PWM
huzzah.menu.waveform.pwm.build.waveform=
huzzah.menu.waveform.phase=Locked Phase
huzzah.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
huzzah.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
huzzah.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
huzzah.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -1379,10 +1362,6 @@ wifi_slot.menu.ssl.all=All SSL ciphers (most compatible)
wifi_slot.menu.ssl.all.build.sslflags=
wifi_slot.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
wifi_slot.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
wifi_slot.menu.waveform.pwm=Locked PWM
wifi_slot.menu.waveform.pwm.build.waveform=
wifi_slot.menu.waveform.phase=Locked Phase
wifi_slot.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
wifi_slot.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
wifi_slot.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
wifi_slot.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -1708,10 +1687,6 @@ arduino-esp8266.menu.ssl.all=All SSL ciphers (most compatible)
arduino-esp8266.menu.ssl.all.build.sslflags=
arduino-esp8266.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
arduino-esp8266.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
arduino-esp8266.menu.waveform.pwm=Locked PWM
arduino-esp8266.menu.waveform.pwm.build.waveform=
arduino-esp8266.menu.waveform.phase=Locked Phase
arduino-esp8266.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
arduino-esp8266.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
arduino-esp8266.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
arduino-esp8266.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -1912,10 +1887,6 @@ espmxdevkit.menu.ssl.all=All SSL ciphers (most compatible)
espmxdevkit.menu.ssl.all.build.sslflags=
espmxdevkit.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
espmxdevkit.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
espmxdevkit.menu.waveform.pwm=Locked PWM
espmxdevkit.menu.waveform.pwm.build.waveform=
espmxdevkit.menu.waveform.phase=Locked Phase
espmxdevkit.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
espmxdevkit.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
espmxdevkit.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
espmxdevkit.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -2156,10 +2127,6 @@ oak.menu.ssl.all=All SSL ciphers (most compatible)
oak.menu.ssl.all.build.sslflags=
oak.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
oak.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
oak.menu.waveform.pwm=Locked PWM
oak.menu.waveform.pwm.build.waveform=
oak.menu.waveform.phase=Locked Phase
oak.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
oak.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
oak.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
oak.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -2368,10 +2335,6 @@ espduino.menu.ssl.all=All SSL ciphers (most compatible)
espduino.menu.ssl.all.build.sslflags=
espduino.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
espduino.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
espduino.menu.waveform.pwm=Locked PWM
espduino.menu.waveform.pwm.build.waveform=
espduino.menu.waveform.phase=Locked Phase
espduino.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
espduino.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
espduino.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
espduino.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -2570,10 +2533,6 @@ espectro.menu.ssl.all=All SSL ciphers (most compatible)
espectro.menu.ssl.all.build.sslflags=
espectro.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
espectro.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
espectro.menu.waveform.pwm=Locked PWM
espectro.menu.waveform.pwm.build.waveform=
espectro.menu.waveform.phase=Locked Phase
espectro.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
espectro.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
espectro.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
espectro.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -2773,10 +2732,6 @@ espino.menu.ssl.all=All SSL ciphers (most compatible)
espino.menu.ssl.all.build.sslflags=
espino.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
espino.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
espino.menu.waveform.pwm=Locked PWM
espino.menu.waveform.pwm.build.waveform=
espino.menu.waveform.phase=Locked Phase
espino.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
espino.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
espino.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
espino.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -2979,10 +2934,6 @@ espresso_lite_v1.menu.ssl.all=All SSL ciphers (most compatible)
espresso_lite_v1.menu.ssl.all.build.sslflags=
espresso_lite_v1.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
espresso_lite_v1.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
espresso_lite_v1.menu.waveform.pwm=Locked PWM
espresso_lite_v1.menu.waveform.pwm.build.waveform=
espresso_lite_v1.menu.waveform.phase=Locked Phase
espresso_lite_v1.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
espresso_lite_v1.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
espresso_lite_v1.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
espresso_lite_v1.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -3185,10 +3136,6 @@ espresso_lite_v2.menu.ssl.all=All SSL ciphers (most compatible)
espresso_lite_v2.menu.ssl.all.build.sslflags=
espresso_lite_v2.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
espresso_lite_v2.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
espresso_lite_v2.menu.waveform.pwm=Locked PWM
espresso_lite_v2.menu.waveform.pwm.build.waveform=
espresso_lite_v2.menu.waveform.phase=Locked Phase
espresso_lite_v2.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
espresso_lite_v2.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
espresso_lite_v2.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
espresso_lite_v2.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -3401,10 +3348,6 @@ sonoff.menu.ssl.all=All SSL ciphers (most compatible)
sonoff.menu.ssl.all.build.sslflags=
sonoff.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
sonoff.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
sonoff.menu.waveform.pwm=Locked PWM
sonoff.menu.waveform.pwm.build.waveform=
sonoff.menu.waveform.phase=Locked Phase
sonoff.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
sonoff.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
sonoff.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
sonoff.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -3644,10 +3587,6 @@ inventone.menu.ssl.all=All SSL ciphers (most compatible)
inventone.menu.ssl.all.build.sslflags=
inventone.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
inventone.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
inventone.menu.waveform.pwm=Locked PWM
inventone.menu.waveform.pwm.build.waveform=
inventone.menu.waveform.phase=Locked Phase
inventone.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
inventone.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
inventone.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
inventone.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -3847,10 +3786,6 @@ d1_mini.menu.ssl.all=All SSL ciphers (most compatible)
d1_mini.menu.ssl.all.build.sslflags=
d1_mini.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
d1_mini.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
d1_mini.menu.waveform.pwm=Locked PWM
d1_mini.menu.waveform.pwm.build.waveform=
d1_mini.menu.waveform.phase=Locked Phase
d1_mini.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
d1_mini.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
d1_mini.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
d1_mini.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -4050,10 +3985,6 @@ d1_mini_lite.menu.ssl.all=All SSL ciphers (most compatible)
d1_mini_lite.menu.ssl.all.build.sslflags=
d1_mini_lite.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
d1_mini_lite.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
d1_mini_lite.menu.waveform.pwm=Locked PWM
d1_mini_lite.menu.waveform.pwm.build.waveform=
d1_mini_lite.menu.waveform.phase=Locked Phase
d1_mini_lite.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
d1_mini_lite.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
d1_mini_lite.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
d1_mini_lite.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -4293,10 +4224,6 @@ d1_mini_pro.menu.ssl.all=All SSL ciphers (most compatible)
d1_mini_pro.menu.ssl.all.build.sslflags=
d1_mini_pro.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
d1_mini_pro.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
d1_mini_pro.menu.waveform.pwm=Locked PWM
d1_mini_pro.menu.waveform.pwm.build.waveform=
d1_mini_pro.menu.waveform.phase=Locked Phase
d1_mini_pro.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
d1_mini_pro.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
d1_mini_pro.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
d1_mini_pro.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -4479,10 +4406,6 @@ d1.menu.ssl.all=All SSL ciphers (most compatible)
d1.menu.ssl.all.build.sslflags=
d1.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
d1.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
d1.menu.waveform.pwm=Locked PWM
d1.menu.waveform.pwm.build.waveform=
d1.menu.waveform.phase=Locked Phase
d1.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
d1.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
d1.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
d1.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -4682,10 +4605,6 @@ nodemcu.menu.ssl.all=All SSL ciphers (most compatible)
nodemcu.menu.ssl.all.build.sslflags=
nodemcu.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
nodemcu.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
nodemcu.menu.waveform.pwm=Locked PWM
nodemcu.menu.waveform.pwm.build.waveform=
nodemcu.menu.waveform.phase=Locked Phase
nodemcu.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
nodemcu.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
nodemcu.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
nodemcu.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -4885,10 +4804,6 @@ nodemcuv2.menu.ssl.all=All SSL ciphers (most compatible)
nodemcuv2.menu.ssl.all.build.sslflags=
nodemcuv2.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
nodemcuv2.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
nodemcuv2.menu.waveform.pwm=Locked PWM
nodemcuv2.menu.waveform.pwm.build.waveform=
nodemcuv2.menu.waveform.phase=Locked Phase
nodemcuv2.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
nodemcuv2.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
nodemcuv2.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
nodemcuv2.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -5092,10 +5007,6 @@ modwifi.menu.ssl.all=All SSL ciphers (most compatible)
modwifi.menu.ssl.all.build.sslflags=
modwifi.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
modwifi.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
modwifi.menu.waveform.pwm=Locked PWM
modwifi.menu.waveform.pwm.build.waveform=
modwifi.menu.waveform.phase=Locked Phase
modwifi.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
modwifi.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
modwifi.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
modwifi.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -5315,10 +5226,6 @@ phoenix_v1.menu.ssl.all=All SSL ciphers (most compatible)
phoenix_v1.menu.ssl.all.build.sslflags=
phoenix_v1.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
phoenix_v1.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
phoenix_v1.menu.waveform.pwm=Locked PWM
phoenix_v1.menu.waveform.pwm.build.waveform=
phoenix_v1.menu.waveform.phase=Locked Phase
phoenix_v1.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
phoenix_v1.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
phoenix_v1.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
phoenix_v1.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -5521,10 +5428,6 @@ phoenix_v2.menu.ssl.all=All SSL ciphers (most compatible)
phoenix_v2.menu.ssl.all.build.sslflags=
phoenix_v2.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
phoenix_v2.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
phoenix_v2.menu.waveform.pwm=Locked PWM
phoenix_v2.menu.waveform.pwm.build.waveform=
phoenix_v2.menu.waveform.phase=Locked Phase
phoenix_v2.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
phoenix_v2.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
phoenix_v2.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
phoenix_v2.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -5727,10 +5630,6 @@ eduinowifi.menu.ssl.all=All SSL ciphers (most compatible)
eduinowifi.menu.ssl.all.build.sslflags=
eduinowifi.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
eduinowifi.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
eduinowifi.menu.waveform.pwm=Locked PWM
eduinowifi.menu.waveform.pwm.build.waveform=
eduinowifi.menu.waveform.phase=Locked Phase
eduinowifi.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
eduinowifi.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
eduinowifi.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
eduinowifi.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -5930,10 +5829,6 @@ wiolink.menu.ssl.all=All SSL ciphers (most compatible)
wiolink.menu.ssl.all.build.sslflags=
wiolink.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
wiolink.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
wiolink.menu.waveform.pwm=Locked PWM
wiolink.menu.waveform.pwm.build.waveform=
wiolink.menu.waveform.phase=Locked Phase
wiolink.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
wiolink.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
wiolink.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
wiolink.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -6133,10 +6028,6 @@ blynk.menu.ssl.all=All SSL ciphers (most compatible)
blynk.menu.ssl.all.build.sslflags=
blynk.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
blynk.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
blynk.menu.waveform.pwm=Locked PWM
blynk.menu.waveform.pwm.build.waveform=
blynk.menu.waveform.phase=Locked Phase
blynk.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
blynk.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
blynk.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
blynk.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -6336,10 +6227,6 @@ thing.menu.ssl.all=All SSL ciphers (most compatible)
thing.menu.ssl.all.build.sslflags=
thing.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
thing.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
thing.menu.waveform.pwm=Locked PWM
thing.menu.waveform.pwm.build.waveform=
thing.menu.waveform.phase=Locked Phase
thing.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
thing.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
thing.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
thing.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -6539,10 +6426,6 @@ thingdev.menu.ssl.all=All SSL ciphers (most compatible)
thingdev.menu.ssl.all.build.sslflags=
thingdev.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
thingdev.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
thingdev.menu.waveform.pwm=Locked PWM
thingdev.menu.waveform.pwm.build.waveform=
thingdev.menu.waveform.phase=Locked Phase
thingdev.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
thingdev.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
thingdev.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
thingdev.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -6742,10 +6625,6 @@ esp210.menu.ssl.all=All SSL ciphers (most compatible)
esp210.menu.ssl.all.build.sslflags=
esp210.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
esp210.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
esp210.menu.waveform.pwm=Locked PWM
esp210.menu.waveform.pwm.build.waveform=
esp210.menu.waveform.phase=Locked Phase
esp210.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
esp210.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
esp210.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
esp210.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -6945,10 +6824,6 @@ espinotee.menu.ssl.all=All SSL ciphers (most compatible)
espinotee.menu.ssl.all.build.sslflags=
espinotee.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
espinotee.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
espinotee.menu.waveform.pwm=Locked PWM
espinotee.menu.waveform.pwm.build.waveform=
espinotee.menu.waveform.phase=Locked Phase
espinotee.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
espinotee.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
espinotee.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
espinotee.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -7148,10 +7023,6 @@ wifiduino.menu.ssl.all=All SSL ciphers (most compatible)
wifiduino.menu.ssl.all.build.sslflags=
wifiduino.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
wifiduino.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
wifiduino.menu.waveform.pwm=Locked PWM
wifiduino.menu.waveform.pwm.build.waveform=
wifiduino.menu.waveform.phase=Locked Phase
wifiduino.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
wifiduino.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
wifiduino.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
wifiduino.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -7368,10 +7239,6 @@ wifinfo.menu.ssl.all=All SSL ciphers (most compatible)
wifinfo.menu.ssl.all.build.sslflags=
wifinfo.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
wifinfo.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
wifinfo.menu.waveform.pwm=Locked PWM
wifinfo.menu.waveform.pwm.build.waveform=
wifinfo.menu.waveform.phase=Locked Phase
wifinfo.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
wifinfo.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
wifinfo.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
wifinfo.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)
@ -7618,10 +7485,6 @@ cw01.menu.ssl.all=All SSL ciphers (most compatible)
cw01.menu.ssl.all.build.sslflags=
cw01.menu.ssl.basic=Basic SSL ciphers (lower ROM use)
cw01.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC
cw01.menu.waveform.pwm=Locked PWM
cw01.menu.waveform.pwm.build.waveform=
cw01.menu.waveform.phase=Locked Phase
cw01.menu.waveform.phase.build.waveform=-DWAVEFORM_LOCKED_PHASE
cw01.menu.mmu.3232=32KB cache + 32KB IRAM (balanced)
cw01.menu.mmu.3232.build.mmuflags=-DMMU_IRAM_SIZE=0x8000 -DMMU_ICACHE_SIZE=0x8000
cw01.menu.mmu.4816=16KB cache + 48KB IRAM (IRAM)

View File

@ -30,10 +30,8 @@ static void _startTone(uint8_t _pin, uint32_t high, uint32_t low, uint32_t durat
return;
}
#ifndef WAVEFORM_LOCKED_PHASE
// Stop any analogWrites (PWM) because they are a different generator
_stopPWM(_pin);
#endif
// If there's another Tone or startWaveform on this pin
// it will be changed on-the-fly (no need to stop it)

View File

@ -1,7 +1,128 @@
// Wrapper to include both versions of the waveform generator
/*
esp8266_waveform - General purpose waveform generation and control,
supporting outputs on all pins in parallel.
-- Default, PWM locked version --
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 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 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.getCycleCount()
clock cycle count, or an interval measured in CPU clock cycles, but not TIMER1
cycles (which may be 2 CPU clock cycles @ 160MHz).
----------
-- Phase locked version --
Copyright (c) 2020 Dirk O. Kaar.
The core idea is to have a programmable waveform generator with a unique
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 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 "ccy" or "ccys" 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
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <Arduino.h>
#ifndef __ESP8266_WAVEFORM_H
#define __ESP8266_WAVEFORM_H
#ifdef __cplusplus
extern "C" {
#endif
// Call this function in your setup() to cause the phase locked version of the generator to
// be linked in automatically. Otherwise, the default PWM locked version will be used.
void enablePhaseLockedWaveform(void);
// Start or change a waveform of the specified high and low times on specific pin.
// If runtimeUS > 0 then automatically stop it after that many usecs, relative to the next
// full period.
// If waveform is not yet started on pin, and on pin == alignPhase a waveform is running,
// the new waveform is started at phaseOffsetUS phase offset, in microseconds, to that.
// Setting autoPwm to true allows the wave generator to maintain PWM duty to idle cycle ratio
// under load, for applications where frequency or duty cycle must not change, leave false.
// Returns true or false on success or failure.
int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t runTimeUS = 0,
// Following parameters are ignored unless in PhaseLocked mode
int8_t alignPhase = -1, uint32_t phaseOffsetUS = 0, bool autoPwm = false);
// 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, relative to the next
// full period.
// If waveform is not yet started on pin, and on pin == alignPhase a waveform is running,
// the new waveform is started at phaseOffsetCcys phase offset, in CPU clock cycles, to that.
// Setting autoPwm to true allows the wave generator to maintain PWM duty to idle cycle ratio
// under load, for applications where frequency or duty cycle must not change, leave false.
// Returns true or false on success or failure.
int startWaveformClockCycles(uint8_t pin, uint32_t timeHighCcys, uint32_t timeLowCcys, uint32_t runTimeCcys = 0,
// Following parameters are ignored unless in PhaseLocked mode
int8_t alignPhase = -1, uint32_t phaseOffsetCcys = 0, bool autoPwm = false);
// Stop a waveform, if any, on the specified pin.
// Returns true or false on success or failure.
int stopWaveform(uint8_t pin);
// Add a callback function to be called on *EVERY* timer1 trigger. The
// callback must return the number of CPU clock cycles until the next desired call.
// However, since it is called every timer1 interrupt, it may be called
// again before this period. It should therefore use the ESP Cycle Counter
// to determine whether or not to perform an operation.
// Pass in NULL to disable the callback and, if no other waveforms being
// generated, stop the timer as well.
// Make sure the CB function has the ICACHE_RAM_ATTR decorator.
void setTimer1Callback(uint32_t (*fn)());
// Internal-only calls, not for applications
extern void _setPWMFreq(uint32_t freq);
extern bool _stopPWM(uint8_t pin);
extern bool _setPWM(int pin, uint32_t val, uint32_t range);
#ifdef __cplusplus
}
#endif
#ifdef WAVEFORM_LOCKED_PHASE
#include "core_esp8266_waveform_phase.h"
#else
#include "core_esp8266_waveform_pwm.h"
#endif

View File

@ -39,13 +39,26 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifdef WAVEFORM_LOCKED_PHASE
#include "core_esp8266_waveform_phase.h"
#include "core_esp8266_waveform.h"
#include <Arduino.h>
#include "debug.h"
#include "ets_sys.h"
#include <atomic>
extern "C" void enablePhaseLockedWaveform (void)
{
// Does nothing, added to app to enable linking these versions
// of the waveform functions instead of the default.
DEBUGV("Enabling phase locked waveform generator\n");
}
// No-op calls to override the PWM implementation
extern "C" void _setPWMFreq_weak(uint32_t freq) { (void) freq; }
extern "C" bool _stopPWM_weak(int pin) { (void) pin; return false; }
extern "C" bool _setPWM_weak(int pin, uint32_t val, uint32_t range) { (void) pin; (void) val; (void) range; return false; }
// Timer is 80MHz fixed. 160MHz CPU frequency need scaling.
constexpr bool ISCPUFREQ160MHZ = clockCyclesPerMicrosecond() == 160;
// Maximum delay between IRQs, Timer1, <= 2^23 / 80MHz
@ -122,7 +135,7 @@ static void ICACHE_RAM_ATTR deinitTimer() {
extern "C" {
// Set a callback. Pass in NULL to stop it
void setTimer1Callback(uint32_t (*fn)()) {
void setTimer1Callback_weak(uint32_t (*fn)()) {
waveform.timer1CB = fn;
std::atomic_thread_fence(std::memory_order_acq_rel);
if (!waveform.timer1Running && fn) {
@ -132,17 +145,10 @@ void setTimer1Callback(uint32_t (*fn)()) {
}
}
int startWaveform(uint8_t pin, uint32_t highUS, uint32_t lowUS,
uint32_t runTimeUS, int8_t alignPhase, uint32_t phaseOffsetUS, bool autoPwm) {
return startWaveformClockCycles(pin,
microsecondsToClockCycles(highUS), microsecondsToClockCycles(lowUS),
microsecondsToClockCycles(runTimeUS), alignPhase, microsecondsToClockCycles(phaseOffsetUS), autoPwm);
}
// Start up a waveform on a pin, or change the current one. Will change to the new
// waveform smoothly on next low->high transition. For immediate change, stopWaveform()
// first, then it will immediately begin.
int startWaveformClockCycles(uint8_t pin, uint32_t highCcys, uint32_t lowCcys,
int startWaveformClockCycles_weak(uint8_t pin, uint32_t highCcys, uint32_t lowCcys,
uint32_t runTimeCcys, int8_t alignPhase, uint32_t phaseOffsetCcys, bool autoPwm) {
uint32_t periodCcys = highCcys + lowCcys;
if (periodCcys < MAXIRQTICKSCCYS) {
@ -212,7 +218,7 @@ int startWaveformClockCycles(uint8_t pin, uint32_t highCcys, uint32_t lowCcys,
}
// Stops a waveform on a pin
int ICACHE_RAM_ATTR stopWaveform(uint8_t pin) {
ICACHE_RAM_ATTR int stopWaveform_weak(uint8_t pin) {
// Can't possibly need to stop anything if there is no timer active
if (!waveform.timer1Running) {
return false;
@ -436,5 +442,3 @@ static ICACHE_RAM_ATTR void timer1Interrupt() {
// Register access is fast and edge IRQ was configured before.
T1L = nextEventCcys;
}
#endif // WAVEFORM_LOCKED_PHASE

View File

@ -1,93 +0,0 @@
/*
esp8266_waveform - General purpose waveform generation and control,
supporting outputs on all pins in parallel.
Copyright (c) 2018 Earle F. Philhower, III. All rights reserved.
Copyright (c) 2020 Dirk O. Kaar.
The core idea is to have a programmable waveform generator with a unique
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 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 "ccy" or "ccys" 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
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifdef WAVEFORM_LOCKED_PHASE
#include <Arduino.h>
#ifndef __ESP8266_WAVEFORM_H
#define __ESP8266_WAVEFORM_H
#ifdef __cplusplus
extern "C" {
#endif
// Start or change a waveform of the specified high and low times on specific pin.
// If runtimeUS > 0 then automatically stop it after that many usecs, relative to the next
// full period.
// If waveform is not yet started on pin, and on pin == alignPhase a waveform is running,
// the new waveform is started at phaseOffsetUS phase offset, in microseconds, to that.
// Setting autoPwm to true allows the wave generator to maintain PWM duty to idle cycle ratio
// under load, for applications where frequency or duty cycle must not change, leave false.
// Returns true or false on success or failure.
int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS,
uint32_t runTimeUS = 0, int8_t alignPhase = -1, uint32_t phaseOffsetUS = 0, bool autoPwm = false);
// 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, relative to the next
// full period.
// If waveform is not yet started on pin, and on pin == alignPhase a waveform is running,
// the new waveform is started at phaseOffsetCcys phase offset, in CPU clock cycles, to that.
// Setting autoPwm to true allows the wave generator to maintain PWM duty to idle cycle ratio
// under load, for applications where frequency or duty cycle must not change, leave false.
// Returns true or false on success or failure.
int startWaveformClockCycles(uint8_t pin, uint32_t timeHighCcys, uint32_t timeLowCcys,
uint32_t runTimeCcys = 0, int8_t alignPhase = -1, uint32_t phaseOffsetCcys = 0, bool autoPwm = false);
// Stop a waveform, if any, on the specified pin.
// Returns true or false on success or failure.
int stopWaveform(uint8_t pin);
// Add a callback function to be called on *EVERY* timer1 trigger. The
// callback must return the number of CPU clock cycles until the next desired call.
// However, since it is called every timer1 interrupt, it may be called
// again before this period. It should therefore use the ESP Cycle Counter
// to determine whether or not to perform an operation.
// Pass in NULL to disable the callback and, if no other waveforms being
// generated, stop the timer as well.
// Make sure the CB function has the ICACHE_RAM_ATTR decorator.
void setTimer1Callback(uint32_t (*fn)());
#ifdef __cplusplus
}
#endif
#endif // __ESP8266_WAVEFORM_H
#endif // WAVEFORM_LOCKED_PHASE

View File

@ -38,12 +38,13 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef WAVEFORM_LOCKED_PHASE
#include <Arduino.h>
#include "ets_sys.h"
#include "core_esp8266_waveform_pwm.h"
#include "core_esp8266_waveform.h"
#include "user_interface.h"
extern "C" {
// Maximum delay between IRQs
@ -169,8 +170,10 @@ static ICACHE_RAM_ATTR void _notifyPWM(PWMState *p, bool idle) {
static void _addPWMtoList(PWMState &p, int pin, uint32_t val, uint32_t range);
// Called when analogWriteFreq() changed to update the PWM total period
void _setPWMFreq(uint32_t freq) {
extern void _setPWMFreq_weak(uint32_t freq) __attribute__((weak));
void _setPWMFreq_weak(uint32_t freq) {
_pwmFreq = freq;
// Convert frequency into clock cycles
@ -204,6 +207,11 @@ void _setPWMFreq(uint32_t freq) {
disableIdleTimer();
}
}
static void _setPWMFreq_bound(uint32_t freq) __attribute__((weakref("_setPWMFreq_weak")));
void _setPWMFreq(uint32_t freq) {
_setPWMFreq_bound(freq);
}
// Helper routine to remove an entry from the state machine
// and clean up any marked-off entries
@ -228,7 +236,8 @@ static void _cleanAndRemovePWM(PWMState *p, int pin) {
// Disable PWM on a specific pin (i.e. when a digitalWrite or analogWrite(0%/100%))
ICACHE_RAM_ATTR bool _stopPWM(int pin) {
extern bool _stopPWM_weak(uint8_t pin) __attribute__((weak));
ICACHE_RAM_ATTR bool _stopPWM_weak(uint8_t pin) {
if (!((1<<pin) & pwmState.mask)) {
return false; // Pin not actually active
}
@ -250,6 +259,10 @@ ICACHE_RAM_ATTR bool _stopPWM(int pin) {
disableIdleTimer();
return true;
}
static bool _stopPWM_bound(uint8_t pin) __attribute__((weakref("_stopPWM_weak")));
bool _stopPWM(uint8_t pin) {
return _stopPWM_bound(pin);
}
static void _addPWMtoList(PWMState &p, int pin, uint32_t val, uint32_t range) {
// Stash the val and range so we can re-evaluate the fraction
@ -297,7 +310,8 @@ static void _addPWMtoList(PWMState &p, int pin, uint32_t val, uint32_t range) {
}
// Called by analogWrite(1...99%) to set the PWM duty in clock cycles
bool _setPWM(int pin, uint32_t val, uint32_t range) {
extern bool _setPWM_weak(int pin, uint32_t val, uint32_t range) __attribute__((weak));
bool _setPWM_weak(int pin, uint32_t val, uint32_t range) {
stopWaveform(pin);
PWMState p; // Working copy
p = pwmState;
@ -327,15 +341,21 @@ bool _setPWM(int pin, uint32_t val, uint32_t range) {
return true;
}
static bool _setPWM_bound(int pin, uint32_t val, uint32_t range) __attribute__((weakref("_setPWM_weak")));
bool _setPWM(int pin, uint32_t val, uint32_t range) {
return _setPWM_bound(pin, val, range);
}
// Start up a waveform on a pin, or change the current one. Will change to the new
// 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 startWaveformClockCycles(pin, microsecondsToClockCycles(timeHighUS), microsecondsToClockCycles(timeLowUS), microsecondsToClockCycles(runTimeUS));
}
extern int startWaveformClockCycles_weak(uint8_t pin, uint32_t timeHighCycles, uint32_t timeLowCycles, uint32_t runTimeCycles, int8_t alignPhase, uint32_t phaseOffsetUS, bool autoPwm) __attribute__((weak));
int startWaveformClockCycles_weak(uint8_t pin, uint32_t timeHighCycles, uint32_t timeLowCycles, uint32_t runTimeCycles,
int8_t alignPhase, uint32_t phaseOffsetUS, bool autoPwm) {
(void) alignPhase;
(void) phaseOffsetUS;
(void) autoPwm;
int startWaveformClockCycles(uint8_t pin, uint32_t timeHighCycles, uint32_t timeLowCycles, uint32_t runTimeCycles) {
if ((pin > 16) || isFlashInterfacePin(pin)) {
return false;
}
@ -379,10 +399,23 @@ int startWaveformClockCycles(uint8_t pin, uint32_t timeHighCycles, uint32_t time
return true;
}
static int startWaveformClockCycles_bound(uint8_t pin, uint32_t timeHighCycles, uint32_t timeLowCycles, uint32_t runTimeCycles, int8_t alignPhase, uint32_t phaseOffsetUS, bool autoPwm) __attribute__((weakref("startWaveformClockCycles_weak")));
int startWaveformClockCycles(uint8_t pin, uint32_t timeHighCycles, uint32_t timeLowCycles, uint32_t runTimeCycles, int8_t alignPhase, uint32_t phaseOffsetUS, bool autoPwm) {
return startWaveformClockCycles_bound(pin, timeHighCycles, timeLowCycles, runTimeCycles, alignPhase, phaseOffsetUS, autoPwm);
}
// This version falls-thru to the proper startWaveformClockCycles call and is invariant across waveform generators
int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t runTimeUS,
int8_t alignPhase, uint32_t phaseOffsetUS, bool autoPwm) {
return startWaveformClockCycles_bound(pin,
microsecondsToClockCycles(timeHighUS), microsecondsToClockCycles(timeLowUS),
microsecondsToClockCycles(runTimeUS), alignPhase, microsecondsToClockCycles(phaseOffsetUS), autoPwm);
}
// Set a callback. Pass in NULL to stop it
void setTimer1Callback(uint32_t (*fn)()) {
extern void setTimer1Callback_weak(uint32_t (*fn)()) __attribute__((weak));
void setTimer1Callback_weak(uint32_t (*fn)()) {
wvfState.timer1CB = fn;
if (fn) {
initTimer();
@ -390,9 +423,14 @@ void setTimer1Callback(uint32_t (*fn)()) {
}
disableIdleTimer();
}
static void setTimer1Callback_bound(uint32_t (*fn)()) __attribute__((weakref("setTimer1Callback_weak")));
void setTimer1Callback(uint32_t (*fn)()) {
setTimer1Callback_bound(fn);
}
// Stops a waveform on a pin
int ICACHE_RAM_ATTR stopWaveform(uint8_t pin) {
extern int stopWaveform_weak(uint8_t pin) __attribute__((weak));
ICACHE_RAM_ATTR int stopWaveform_weak(uint8_t pin) {
// Can't possibly need to stop anything if there is no timer active
if (!timerRunning) {
return false;
@ -415,6 +453,10 @@ int ICACHE_RAM_ATTR stopWaveform(uint8_t pin) {
disableIdleTimer();
return true;
}
static int stopWaveform_bound(uint8_t pin) __attribute__((weakref("stopWaveform_weak")));
ICACHE_RAM_ATTR int stopWaveform(uint8_t pin) {
return stopWaveform_bound(pin);
}
// Speed critical bits
#pragma GCC optimize ("O2")
@ -622,5 +664,3 @@ static ICACHE_RAM_ATTR void timer1Interrupt() {
}
};
#endif

View File

@ -1,87 +0,0 @@
/*
esp8266_waveform - General purpose waveform generation and control,
supporting outputs on all pins in parallel.
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 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 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.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
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef WAVEFORM_LOCKED_PHASE
#include <Arduino.h>
#ifndef __ESP8266_WAVEFORM_H
#define __ESP8266_WAVEFORM_H
#ifdef __cplusplus
extern "C" {
#endif
// Start or change a waveform of the specified high and low times on specific pin.
// 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);
// 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);
// Add a callback function to be called on *EVERY* timer1 trigger. The
// callback must return the number of CPU clock cycles until the next desired call.
// However, since it is called every timer1 interrupt, it may be called
// again before this period. It should therefore use the ESP Cycle Counter
// to determine whether or not to perform an operation.
// Pass in NULL to disable the callback and, if no other waveforms being
// generated, stop the timer as well.
// Make sure the CB function has the ICACHE_RAM_ATTR decorator.
void setTimer1Callback(uint32_t (*fn)());
// Internal-only calls, not for applications
extern void _setPWMFreq(uint32_t freq);
extern bool _stopPWM(int pin);
extern bool _setPWM(int pin, uint32_t val, uint32_t range);
#ifdef __cplusplus
}
#endif
#endif
#endif

View File

@ -82,10 +82,8 @@ extern void __pinMode(uint8_t pin, uint8_t mode) {
}
extern void ICACHE_RAM_ATTR __digitalWrite(uint8_t pin, uint8_t val) {
stopWaveform(pin); // Disable any tone
#ifndef WAVEFORM_LOCKED_PHASE
_stopPWM(pin); // ...and any analogWrite
#endif
stopWaveform(pin); // Disable any Tone or startWaveform on this pin
_stopPWM(pin); // and any analogWrites (PWM)
if(pin < 16){
if(val) GPOS = (1 << pin);
else GPOC = (1 << pin);

View File

@ -28,7 +28,6 @@ extern "C" {
static int32_t analogScale = 255; // Match upstream default, breaking change from 2.x.x
#ifdef WAVEFORM_LOCKED_PHASE
static uint32_t analogMap = 0;
static uint16_t analogFreq = 1000;
@ -41,6 +40,7 @@ extern void __analogWriteFreq(uint32_t freq) {
} else {
analogFreq = freq;
}
_setPWMFreq(freq);
}
extern void __analogWrite(uint8_t pin, int val) {
@ -68,45 +68,13 @@ extern void __analogWrite(uint8_t pin, int val) {
uint32_t low = analogPeriod - high;
// Find the first GPIO being generated by checking GCC's find-first-set (returns 1 + the bit of the first 1 in an int32_t)
int phaseReference = __builtin_ffs(analogMap) - 1;
if (startWaveformClockCycles(pin, high, low, 0, phaseReference, 0, true)) {
if (_setPWM(pin, val, analogScale)) {
analogMap |= (1 << pin);
} else if (startWaveformClockCycles(pin, high, low, 0, phaseReference, 0, true)) {
analogMap |= (1 << pin);
}
}
#else // !WAVEFORM_LOCKED_PHASE
extern void __analogWriteFreq(uint32_t freq) {
if (freq < 100) {
freq = 100;
} else if (freq > 60000) {
freq = 60000;
} else {
freq = freq;
}
_setPWMFreq(freq);
}
extern void __analogWrite(uint8_t pin, int val) {
if (pin > 16) {
return;
}
if (val < 0) {
val = 0;
} else if (val > analogScale) {
val = analogScale;
}
// Per the Arduino docs at https://www.arduino.cc/reference/en/language/functions/analog-io/analogwrite/
// val: the duty cycle: between 0 (always off) and 255 (always on).
// So if val = 0 we have digitalWrite(LOW), if we have val==range we have digitalWrite(HIGH)
pinMode(pin, OUTPUT);
_setPWM(pin, val, analogScale);
}
#endif // WAVEFORM_LOCKED_PHASE
extern void __analogWriteRange(uint32_t range) {
if ((range >= 15) && (range <= 65535)) {
analogScale = range;

View File

@ -13,6 +13,7 @@ analogWriteFreq KEYWORD2
analogWriteRange KEYWORD2
baudrate KEYWORD2
swap KEYWORD2
enablePhaseLockedWaveform KEYWORD2
######################################
# Constants (LITERAL1)

View File

@ -0,0 +1,73 @@
/*
ESP8266 LED fade with polledTimeout and locked phase PWM
Modified from an BlinkPolledTimeout.ino,
Copyright (c) 2018 Daniel Salazar. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Note that this sketch uses LED_BUILTIN to find the pin with the internal LED
*/
#include <core_esp8266_waveform.h>
#include <PolledTimeout.h>
esp8266::polledTimeout::periodicFastUs stepPeriod(50000);
// the setup function runs only once at start
void setup() {
Serial.begin(115200);
Serial.println();
// This next line will call will cause the code to use the Phase-Locked waveform generator
// instead of the default one. Comment it out to try the default version.
// For more information on choosing between the two options, see the following pull requests:
// Phase-Locked generator: https://github.com/esp8266/Arduino/pull/7022
// PWM-Locked generator: https://github.com/esp8266/Arduino/pull/7231
enablePhaseLockedWaveform();
pinMode(LED_BUILTIN, OUTPUT); // Initialize the LED_BUILTIN pin as an output
analogWriteRange(1000);
using esp8266::polledTimeout::oneShotMs; //import the type to the local namespace
digitalWrite(LED_BUILTIN, LOW); // Turn the LED on (Note that LOW is the voltage level
oneShotMs timeoutOn(2000);
while (!timeoutOn) {
yield();
}
stepPeriod.reset();
}
void loop() {
static int val = 0;
static int delta = 100;
if (stepPeriod) {
val += delta;
if (val < 0) {
val = 100;
delta = 100;
} else if (val > 1000) {
val = 900;
delta = -100;
}
analogWrite(LED_BUILTIN, val);
}
}

View File

@ -59,7 +59,7 @@ compiler.libc.path={runtime.platform.path}/tools/sdk/libc/xtensa-lx106-elf
compiler.cpreprocessor.flags=-D__ets__ -DICACHE_FLASH -U__STRICT_ANSI__ "-I{compiler.sdk.path}/include" "-I{compiler.sdk.path}/{build.lwip_include}" "-I{compiler.libc.path}/include" "-I{build.path}/core"
compiler.c.cmd=xtensa-lx106-elf-gcc
compiler.c.flags=-c {compiler.warning_flags} -std=gnu17 {build.stacksmash_flags} -Os -g -free -fipa-pta -Wpointer-arith -Wno-implicit-function-declaration -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -falign-functions=4 -MMD -ffunction-sections -fdata-sections {build.exception_flags} {build.sslflags} {build.waveform} {build.mmuflags} {build.non32xferflags}
compiler.c.flags=-c {compiler.warning_flags} -std=gnu17 {build.stacksmash_flags} -Os -g -free -fipa-pta -Wpointer-arith -Wno-implicit-function-declaration -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -falign-functions=4 -MMD -ffunction-sections -fdata-sections {build.exception_flags} {build.sslflags} {build.mmuflags} {build.non32xferflags}
compiler.S.cmd=xtensa-lx106-elf-gcc
compiler.S.flags=-c -g -x assembler-with-cpp -MMD -mlongcalls "-I{runtime.tools.xtensa-lx106-elf-gcc.path}/include/"
@ -70,7 +70,7 @@ compiler.c.elf.cmd=xtensa-lx106-elf-gcc
compiler.c.elf.libs=-lhal -lphy -lpp -lnet80211 {build.lwip_lib} -lwpa -lcrypto -lmain -lwps -lbearssl -lespnow -lsmartconfig -lairkiss -lwpa2 {build.stdcpp_lib} -lm -lc -lgcc
compiler.cpp.cmd=xtensa-lx106-elf-g++
compiler.cpp.flags=-c {compiler.warning_flags} {build.stacksmash_flags} -Os -g -free -fipa-pta -mlongcalls -mtext-section-literals -fno-rtti -falign-functions=4 {build.stdcpp_level} -MMD -ffunction-sections -fdata-sections {build.exception_flags} {build.sslflags} {build.waveform} {build.mmuflags} {build.non32xferflags}
compiler.cpp.flags=-c {compiler.warning_flags} {build.stacksmash_flags} -Os -g -free -fipa-pta -mlongcalls -mtext-section-literals -fno-rtti -falign-functions=4 {build.stdcpp_level} -MMD -ffunction-sections -fdata-sections {build.exception_flags} {build.sslflags} {build.mmuflags} {build.non32xferflags}
compiler.as.cmd=xtensa-lx106-elf-as

View File

@ -70,8 +70,6 @@ function build_sketches()
local sketches=$(find $srcpath -name *.ino | sort)
print_size_info >size.log
export ARDUINO_IDE_PATH=$arduino
local pwm_phase=""
[ $(( $build_rem % 2 )) -eq 0 ] && pwm_phase="--waveform_phase"
local testcnt=0
for sketch in $sketches; do
testcnt=$(( ($testcnt + 1) % $build_mod ))
@ -119,8 +117,8 @@ function build_sketches()
export MSYS2_ARG_CONV_EXC="*"
export MSYS_NO_PATHCONV=1
fi
echo "$build_cmd $pwm_phase $sketch"
time ($build_cmd $pwm_phase $sketch >build.log)
echo "$build_cmd $sketch"
time ($build_cmd $sketch >build.log)
local result=$?
if [ $result -ne 0 ]; then
echo "Build failed ($1)"

View File

@ -1488,18 +1488,6 @@ def led (name, default, ledList):
]))
return { name: led }
################################################################
# Waveform flavour
def waveform ():
return { 'waveform': collections.OrderedDict([
('.menu.waveform.pwm', 'Locked PWM'),
('.menu.waveform.pwm.build.waveform', ''),
('.menu.waveform.phase', 'Locked Phase'),
('.menu.waveform.phase.build.waveform', '-DWAVEFORM_LOCKED_PHASE'),
])
}
################################################################
# sdk selection
@ -1551,7 +1539,6 @@ def all_boards ():
macros.update(led('led', led_default, range(0,led_max+1)))
macros.update(led('led216', 2, { 16 }))
macros.update(sdk())
macros.update(waveform())
if boardfilteropt or excludeboards:
print('#')
@ -1596,7 +1583,6 @@ def all_boards ():
print('menu.wipe=Erase Flash')
print('menu.sdk=Espressif FW')
print('menu.ssl=SSL Support')
print('menu.waveform=Waveform Flavour')
print('menu.mmu=MMU')
print('menu.non32xfer=Non-32-Bit Access')
print('')
@ -1619,7 +1605,7 @@ def all_boards ():
print(id + optname + '=' + board['opts'][optname])
# macros
macrolist = [ 'defaults', 'cpufreq_menu', 'vtable_menu', 'exception_menu', 'stacksmash_menu', 'ssl_cipher_menu', 'waveform', 'mmu_menu', 'non32xfer_menu' ]
macrolist = [ 'defaults', 'cpufreq_menu', 'vtable_menu', 'exception_menu', 'stacksmash_menu', 'ssl_cipher_menu', 'mmu_menu', 'non32xfer_menu' ]
if 'macro' in board:
macrolist += board['macro']
macrolist += [ 'lwip', 'debug_menu', 'flash_erase_menu' ]