mirror of https://github.com/arendst/Tasmota.git
Merge pull request #14628 from s-hadinger/pwm_multi
Increase PWM channels to 16 (Esp32 only)
This commit is contained in:
commit
1033bdf7df
|
@ -19,6 +19,7 @@ All notable changes to this project will be documented in this file.
|
|||
- Command ``SspmScan`` to rescan Sonoff SPM modbus
|
||||
- Support for MQ analog sensor for air quality by Francesco Adriani (#14581)
|
||||
- Command ``SetOption134 1`` to disable PWM auto-phasing for lights by default (new behavior) (#14590)
|
||||
- Increase PWM channels to 16 (Esp32 only)
|
||||
|
||||
### Changed
|
||||
- BME68x-Sensor-API library from v3.5.9 to v4.4.7
|
||||
|
|
|
@ -18,6 +18,7 @@ const uint16_t ST7789_colors[]={ST7789_BLACK,ST7789_WHITE,ST7789_RED,ST7789_GREE
|
|||
ST7789_LIGHTGREY,ST7789_DARKGREY,ST7789_ORANGE,ST7789_GREENYELLOW,ST7789_PINK};
|
||||
|
||||
#ifdef ESP32
|
||||
#include "esp8266toEsp32.h"
|
||||
#define ST7789_DIMMER
|
||||
#endif
|
||||
|
||||
|
@ -258,11 +259,9 @@ void Arduino_ST7789::commonInit(const uint8_t *cmdList) {
|
|||
}
|
||||
|
||||
if (_bp>=0) {
|
||||
#define ESP32_PWM_CHANNEL 1
|
||||
// #define ESP32_PWM_CHANNEL 1
|
||||
#ifdef ST7789_DIMMER
|
||||
ledcSetup(ESP32_PWM_CHANNEL,4000,8);
|
||||
ledcAttachPin(_bp,ESP32_PWM_CHANNEL);
|
||||
ledcWrite(ESP32_PWM_CHANNEL,128);
|
||||
analogWrite(_bp, 128);
|
||||
#else
|
||||
pinMode(_bp, OUTPUT);
|
||||
#endif
|
||||
|
@ -575,7 +574,8 @@ void Arduino_ST7789::DisplayOnff(int8_t on) {
|
|||
writecommand(ST7789_DISPON); //Display on
|
||||
if (_bp>=0) {
|
||||
#ifdef ST7789_DIMMER
|
||||
ledcWrite(ESP32_PWM_CHANNEL,dimmer);
|
||||
analogWrite(_bp, dimmer);
|
||||
// ledcWrite(ESP32_PWM_CHANNEL,dimmer);
|
||||
#else
|
||||
digitalWrite(_bp,HIGH);
|
||||
#endif
|
||||
|
@ -584,7 +584,8 @@ void Arduino_ST7789::DisplayOnff(int8_t on) {
|
|||
writecommand(ST7789_DISPOFF);
|
||||
if (_bp>=0) {
|
||||
#ifdef ST7789_DIMMER
|
||||
ledcWrite(ESP32_PWM_CHANNEL,0);
|
||||
analogWrite(_bp, 0);
|
||||
// ledcWrite(ESP32_PWM_CHANNEL,0);
|
||||
#else
|
||||
digitalWrite(_bp,LOW);
|
||||
#endif
|
||||
|
@ -598,7 +599,8 @@ void Arduino_ST7789::dim(uint8_t dim) {
|
|||
if (dimmer>15) dimmer=15;
|
||||
dimmer=((float)dimmer/15.0)*255.0;
|
||||
#ifdef ESP32
|
||||
ledcWrite(ESP32_PWM_CHANNEL,dimmer);
|
||||
analogWrite(_bp, dimmer);
|
||||
// ledcWrite(ESP32_PWM_CHANNEL,dimmer);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -59,10 +59,10 @@ uint16_t Renderer::GetColorFromIndex(uint8_t index) {
|
|||
|
||||
void Renderer::dim(uint8_t contrast) {
|
||||
uint8_t contrast8 = ((uint32_t)contrast * 255) / 15;
|
||||
dim8(contrast8, contrast8);
|
||||
dim10(contrast8, contrast8 * 4);
|
||||
}
|
||||
|
||||
void Renderer::dim8(uint8_t contrast, uint8_t contrast_gamma) {
|
||||
void Renderer::dim10(uint8_t contrast, uint16_t contrast_gamma) {
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ public:
|
|||
virtual void Begin(int16_t p1,int16_t p2,int16_t p3);
|
||||
virtual void Updateframe();
|
||||
virtual void dim(uint8_t contrast); // input has range 0..15
|
||||
virtual void dim8(uint8_t contrast, uint8_t contrast_gamma); // input has range 0..255, second arg has gamma correction for PWM
|
||||
virtual void dim10(uint8_t contrast, uint16_t contrast_gamma); // input has range 0..255, second arg has gamma correction for PWM with 10 bits resolution
|
||||
virtual void pushColors(uint16_t *data, uint16_t len, boolean first);
|
||||
virtual void setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
|
||||
virtual void invertDisplay(boolean i);
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
|
||||
// ESP32 uses 2. SPI BUS, ESP8266 uses software spi
|
||||
#ifdef ESP32
|
||||
#include "esp8266toEsp32.h"
|
||||
#undef ILI9341_2_DIMMER
|
||||
#define ILI9341_2_DIMMER
|
||||
#undef ESP32_PWM_CHANNEL
|
||||
|
@ -248,9 +249,7 @@ void ILI9341_2::init(uint16_t width, uint16_t height) {
|
|||
|
||||
if (_bp >= 0) {
|
||||
#ifdef ILI9341_2_DIMMER
|
||||
ledcSetup(ESP32_PWM_CHANNEL, 4000, 8);
|
||||
ledcAttachPin(_bp, ESP32_PWM_CHANNEL);
|
||||
ledcWrite(ESP32_PWM_CHANNEL, 128);
|
||||
analogWrite(_bp, 511);
|
||||
#else
|
||||
pinMode(_bp, OUTPUT);
|
||||
#endif
|
||||
|
@ -544,7 +543,8 @@ void ILI9341_2::DisplayOnff(int8_t on) {
|
|||
SPI_END_TRANSACTION();
|
||||
if (_bp >= 0) {
|
||||
#ifdef ILI9341_2_DIMMER
|
||||
ledcWrite(ESP32_PWM_CHANNEL, dimmer);
|
||||
analogWrite(_bp, dimmer * 4);
|
||||
// ledcWrite(ESP32_PWM_CHANNEL, dimmer);
|
||||
#else
|
||||
digitalWrite(_bp, HIGH);
|
||||
#endif
|
||||
|
@ -557,7 +557,8 @@ void ILI9341_2::DisplayOnff(int8_t on) {
|
|||
SPI_END_TRANSACTION();
|
||||
if (_bp >= 0) {
|
||||
#ifdef ILI9341_2_DIMMER
|
||||
ledcWrite(ESP32_PWM_CHANNEL, 0);
|
||||
analogWrite(_bp, 0);
|
||||
// ledcWrite(ESP32_PWM_CHANNEL, 0);
|
||||
#else
|
||||
digitalWrite(_bp, LOW);
|
||||
#endif
|
||||
|
@ -604,7 +605,8 @@ void ILI9341_2::dim(uint8_t dim) {
|
|||
dimmer=((float)dimmer/15.0)*255.0;
|
||||
#ifdef ESP32
|
||||
if (_bp>=0) {
|
||||
ledcWrite(ESP32_PWM_CHANNEL,dimmer);
|
||||
analogWrite(_bp, dimmer * 4);
|
||||
// ledcWrite(ESP32_PWM_CHANNEL,dimmer);
|
||||
} else {
|
||||
if (_hwspi>=2) {
|
||||
//ili9342_dimm(dim);
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
#include <Arduino.h>
|
||||
#include "uDisplay.h"
|
||||
|
||||
#ifdef ESP32
|
||||
#include "esp8266toEsp32.h"
|
||||
#endif
|
||||
|
||||
// #define UDSP_DEBUG
|
||||
|
||||
const uint16_t udisp_colors[]={UDISP_BLACK,UDISP_WHITE,UDISP_RED,UDISP_GREEN,UDISP_BLUE,UDISP_CYAN,UDISP_MAGENTA,\
|
||||
|
@ -428,9 +432,7 @@ Renderer *uDisplay::Init(void) {
|
|||
|
||||
if (bpanel >= 0) {
|
||||
#ifdef ESP32
|
||||
ledcSetup(ESP32_PWM_CHANNEL, 977, 8); // use 10 bits resolution like in Light
|
||||
ledcAttachPin(bpanel, ESP32_PWM_CHANNEL);
|
||||
ledcWrite(ESP32_PWM_CHANNEL, 8); // 38/255 correspond roughly to 50% visual brighness (with Gamma)
|
||||
analogWrite(bpanel, 32);
|
||||
#else
|
||||
pinMode(bpanel, OUTPUT);
|
||||
digitalWrite(bpanel, HIGH);
|
||||
|
@ -1353,7 +1355,8 @@ void uDisplay::DisplayOnff(int8_t on) {
|
|||
if (dsp_on != 0xff) spi_command_one(dsp_on);
|
||||
if (bpanel >= 0) {
|
||||
#ifdef ESP32
|
||||
ledcWrite(ESP32_PWM_CHANNEL, dimmer8_gamma);
|
||||
analogWrite(bpanel, dimmer10_gamma);
|
||||
// ledcWrite(ESP32_PWM_CHANNEL, dimmer8_gamma);
|
||||
#else
|
||||
digitalWrite(bpanel, HIGH);
|
||||
#endif
|
||||
|
@ -1363,7 +1366,8 @@ void uDisplay::DisplayOnff(int8_t on) {
|
|||
if (dsp_off != 0xff) spi_command_one(dsp_off);
|
||||
if (bpanel >= 0) {
|
||||
#ifdef ESP32
|
||||
ledcWrite(ESP32_PWM_CHANNEL, 0);
|
||||
analogWrite(bpanel, 0);
|
||||
// ledcWrite(ESP32_PWM_CHANNEL, 0);
|
||||
#else
|
||||
digitalWrite(bpanel, LOW);
|
||||
#endif
|
||||
|
@ -1402,16 +1406,17 @@ void udisp_dimm(uint8_t dim);
|
|||
// }
|
||||
|
||||
// dim is 0..255
|
||||
void uDisplay::dim8(uint8_t dim, uint8_t dim_gamma) { // dimmer with 8 bits resolution, 0..255. Gamma correction must be done by caller
|
||||
void uDisplay::dim10(uint8_t dim, uint16_t dim_gamma) { // dimmer with 8 bits resolution, 0..255. Gamma correction must be done by caller
|
||||
dimmer8 = dim;
|
||||
dimmer8_gamma = dim_gamma;
|
||||
dimmer10_gamma = dim_gamma;
|
||||
if (ep_mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef ESP32 // TODO should we also add a ESP8266 version for bpanel?
|
||||
if (bpanel >= 0) { // is the BaclPanel GPIO configured
|
||||
ledcWrite(ESP32_PWM_CHANNEL, dimmer8_gamma);
|
||||
analogWrite(bpanel, dimmer10_gamma);
|
||||
// ledcWrite(ESP32_PWM_CHANNEL, dimmer8_gamma);
|
||||
} else if (dim_cbp) {
|
||||
dim_cbp(dim);
|
||||
}
|
||||
|
|
|
@ -74,9 +74,6 @@ enum uColorType { uCOLOR_BW, uCOLOR_COLOR };
|
|||
#define SPI_DC_LOW if (spi_dc >= 0) GPIO_CLR_SLOW(spi_dc);
|
||||
#define SPI_DC_HIGH if (spi_dc >= 0) GPIO_SET_SLOW(spi_dc);
|
||||
|
||||
|
||||
#define ESP32_PWM_CHANNEL 1
|
||||
|
||||
#define LUTMAXSIZE 64
|
||||
|
||||
class uDisplay : public Renderer {
|
||||
|
@ -93,7 +90,7 @@ class uDisplay : public Renderer {
|
|||
uint16_t bgcol(void);
|
||||
int8_t color_type(void);
|
||||
// void dim(uint8_t dim); // original version with 4 bits resolution 0..15
|
||||
virtual void dim8(uint8_t dim, uint8_t dim_gamma); // dimmer with 8 bits resolution, 0..255. Gamma correction must be done by caller
|
||||
virtual void dim10(uint8_t dim, uint16_t dim_gamma); // dimmer with 8 bits resolution, 0..255. Gamma correction must be done by caller with 10 bits resolution
|
||||
uint16_t GetColorFromIndex(uint8_t index);
|
||||
void setRotation(uint8_t m);
|
||||
void fillScreen(uint16_t color);
|
||||
|
@ -186,7 +183,7 @@ class uDisplay : public Renderer {
|
|||
int8_t bpanel; // backbanel GPIO, -1 if none
|
||||
int8_t spi_miso;
|
||||
uint8_t dimmer8; // 8 bits resolution, 0..255
|
||||
uint8_t dimmer8_gamma; // 8 bits resolution, 0..255, gamma corrected
|
||||
uint16_t dimmer10_gamma; // 10 bits resolution, 0..1023, gamma corrected
|
||||
SPIClass *uspi;
|
||||
uint8_t sspi;
|
||||
SPISettings spiSettings;
|
||||
|
|
|
@ -50,7 +50,9 @@ extern "C"
|
|||
#include <lwip/inet.h>
|
||||
#include <lwip/netif.h>
|
||||
#include <include/ClientContext.h>
|
||||
#ifdef ESP8266
|
||||
#include <c_types.h>
|
||||
#endif
|
||||
#include <coredecls.h>
|
||||
|
||||
#if !CORE_MOCK
|
||||
|
|
|
@ -43,8 +43,8 @@
|
|||
#include "lwip/netif.h"
|
||||
#ifdef ESP8266
|
||||
#include <include/ClientContext.h>
|
||||
#endif
|
||||
#include "c_types.h"
|
||||
#endif
|
||||
|
||||
#include <core_version.h>
|
||||
#undef DEBUG_TLS
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
#pragma once
|
||||
/**/
|
||||
#include <stdint.h>
|
||||
#ifndef ICACHE_FLASH_ATTR
|
||||
#define ICACHE_FLASH_ATTR
|
||||
#endif
|
|
@ -1,3 +0,0 @@
|
|||
//
|
||||
// Compat with ESP32
|
||||
//
|
|
@ -13,58 +13,64 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
//
|
||||
|
||||
#ifdef ESP32
|
||||
|
||||
#include "Arduino.h"
|
||||
//#include "lwip/apps/sntp.h"
|
||||
#include <nvs.h>
|
||||
|
||||
// See libraries\ESP32\examples\ResetReason.ino
|
||||
#if ESP_IDF_VERSION_MAJOR > 3 // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/rom/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2 // ESP32-S2
|
||||
#include "esp32s2/rom/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3 // ESP32-C3
|
||||
#include "esp32c3/rom/rtc.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/rtc.h"
|
||||
#endif
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include "esp8266toEsp32.h"
|
||||
#include "driver/ledc.h"
|
||||
|
||||
// Tasmota Logging
|
||||
extern void AddLog(uint32_t loglevel, PGM_P formatP, ...);
|
||||
enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE};
|
||||
|
||||
// ESP Stuff
|
||||
|
||||
// replicated from `tasmota.h`
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32)
|
||||
const uint8_t MAX_PWMS = 16; // ESP32: 16 ledc PWM channels in total - TODO for now
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
const uint8_t MAX_PWMS = 8; // ESP32S2: 8 ledc PWM channels in total
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
const uint8_t MAX_PWMS = 6; // ESP32C3: 6 ledc PWM channels in total
|
||||
#else
|
||||
const uint8_t MAX_PWMS = 5; // Unknown - revert to 5 PWM max
|
||||
#endif
|
||||
|
||||
// channel mapping
|
||||
static uint8_t pwm_channel[MAX_PWMS];
|
||||
static uint32_t pwm_frequency = 977; // Default 977Hz
|
||||
static uint8_t pwm_bit_num = 10; // Default 1023
|
||||
static bool pwm_impl_inited = false; // trigger initialization
|
||||
|
||||
/*********************************************************************************************\
|
||||
* ESP32 analogWrite emulation support
|
||||
\*********************************************************************************************/
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
uint8_t _pwm_channel[PWM_SUPPORTED_CHANNELS] = { 99, 99, 99, 99, 99, 99 };
|
||||
uint32_t _pwm_frequency = 977; // Default 977Hz
|
||||
uint8_t _pwm_bit_num = 10; // Default 1023
|
||||
#else // other ESP32
|
||||
uint8_t _pwm_channel[PWM_SUPPORTED_CHANNELS] = { 99, 99, 99, 99, 99, 99, 99, 99 };
|
||||
uint32_t _pwm_frequency = 977; // Default 977Hz
|
||||
uint8_t _pwm_bit_num = 10; // Default 1023
|
||||
#endif // CONFIG_IDF_TARGET_ESP32C3 vs ESP32
|
||||
void _analogInit(void) {
|
||||
if (pwm_impl_inited) return;
|
||||
// set all channels to unaffected (255)
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) {
|
||||
pwm_channel[i] = 255;
|
||||
}
|
||||
pwm_impl_inited = true;
|
||||
}
|
||||
|
||||
uint32_t _analog_pin2chan(uint32_t pin) {
|
||||
for (uint32_t channel = 0; channel < PWM_SUPPORTED_CHANNELS; channel++) {
|
||||
if ((_pwm_channel[channel] < 99) && (_pwm_channel[channel] == pin)) {
|
||||
int32_t _analog_pin2chan(uint32_t pin) { // returns -1 if uallocated
|
||||
_analogInit(); // make sure the mapping array is initialized
|
||||
for (uint32_t channel = 0; channel < MAX_PWMS; channel++) {
|
||||
if ((pwm_channel[channel] < 255) && (pwm_channel[channel] == pin)) {
|
||||
return channel;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void _analogWriteFreqRange(void) {
|
||||
for (uint32_t channel = 0; channel < PWM_SUPPORTED_CHANNELS; channel++) {
|
||||
if (_pwm_channel[channel] < 99) {
|
||||
ledcSetup(channel + PWM_CHANNEL_OFFSET, _pwm_frequency, _pwm_bit_num);
|
||||
_analogInit(); // make sure the mapping array is initialized
|
||||
for (uint32_t channel = 0; channel < MAX_PWMS; channel++) {
|
||||
if (pwm_channel[channel] < 255) {
|
||||
ledcSetup(channel, pwm_frequency, pwm_bit_num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -80,50 +86,43 @@ uint32_t _analogGetResolution(uint32_t x) {
|
|||
}
|
||||
|
||||
void analogWriteRange(uint32_t range) {
|
||||
_pwm_bit_num = _analogGetResolution(range);
|
||||
pwm_bit_num = _analogGetResolution(range);
|
||||
_analogWriteFreqRange();
|
||||
}
|
||||
|
||||
void analogWriteFreq(uint32_t freq) {
|
||||
_pwm_frequency = freq;
|
||||
pwm_frequency = freq;
|
||||
_analogWriteFreqRange();
|
||||
}
|
||||
|
||||
bool analogAttach(uint32_t pin) {
|
||||
int32_t analogAttach(uint32_t pin) { // returns ledc channel used, or -1 if failed
|
||||
_analogInit(); // make sure the mapping array is initialized
|
||||
// Find if pin is already attached
|
||||
uint32_t channel;
|
||||
for (channel = 0; channel < PWM_SUPPORTED_CHANNELS; channel++) {
|
||||
if (_pwm_channel[channel] == pin) {
|
||||
// Already attached
|
||||
// Serial.printf("PWM: Already attached pin %d to channel %d\n", pin, channel);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
int32_t channel = _analog_pin2chan(pin);
|
||||
if (channel >= 0) { return channel; }
|
||||
// Find an empty channel
|
||||
for (channel = 0; channel < PWM_SUPPORTED_CHANNELS; channel++) {
|
||||
if (99 == _pwm_channel[channel]) {
|
||||
_pwm_channel[channel] = pin;
|
||||
ledcAttachPin(pin, channel + PWM_CHANNEL_OFFSET);
|
||||
ledcSetup(channel + PWM_CHANNEL_OFFSET, _pwm_frequency, _pwm_bit_num);
|
||||
for (channel = 0; channel < MAX_PWMS; channel++) {
|
||||
if (255 == pwm_channel[channel]) {
|
||||
pwm_channel[channel] = pin;
|
||||
ledcAttachPin(pin, channel);
|
||||
ledcSetup(channel, pwm_frequency, pwm_bit_num);
|
||||
// Serial.printf("PWM: New attach pin %d to channel %d\n", pin, channel);
|
||||
return true;
|
||||
return channel;
|
||||
}
|
||||
}
|
||||
// No more channels available
|
||||
return false;
|
||||
AddLog(LOG_LEVEL_INFO, "PWM: no more PWM (ledc) channel for GPIO %i", pin);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// void analogWrite(uint8_t pin, int val);
|
||||
extern "C" void __wrap__Z11analogWritehi(uint8_t pin, int val)
|
||||
{
|
||||
uint32_t channel = _analog_pin2chan(pin);
|
||||
if ( val >> (_pwm_bit_num-1) ) ++val;
|
||||
ledcWrite(channel + PWM_CHANNEL_OFFSET, val);
|
||||
// Serial.printf("write %d - %d\n",channel,val);
|
||||
extern "C" void __wrap__Z11analogWritehi(uint8_t pin, int val) {
|
||||
analogWritePhase(pin, val, 0); // if unspecified, use phase = 0
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
The primary goal of this library is to add phase control to PWM ledc
|
||||
The primary goal of this function is to add phase control to PWM ledc
|
||||
functions.
|
||||
|
||||
Phase control allows to stress less the power supply of LED lights.
|
||||
|
@ -142,35 +141,28 @@ extern "C" void __wrap__Z11analogWritehi(uint8_t pin, int val)
|
|||
implementation changes.
|
||||
*/
|
||||
|
||||
#include "driver/ledc.h"
|
||||
|
||||
#ifdef SOC_LEDC_SUPPORT_HS_MODE
|
||||
#define LEDC_CHANNELS (SOC_LEDC_CHANNEL_NUM<<1)
|
||||
#else
|
||||
#define LEDC_CHANNELS (SOC_LEDC_CHANNEL_NUM)
|
||||
#endif
|
||||
|
||||
// exported from Arduno Core
|
||||
extern uint8_t channels_resolution[LEDC_CHANNELS];
|
||||
extern uint8_t channels_resolution[MAX_PWMS];
|
||||
|
||||
void analogWritePhase(uint8_t pin, uint32_t duty, uint32_t phase)
|
||||
{
|
||||
uint32_t chan = _analog_pin2chan(pin) + PWM_CHANNEL_OFFSET;
|
||||
if (duty >> (_pwm_bit_num-1) ) ++duty;
|
||||
|
||||
if(chan >= LEDC_CHANNELS){
|
||||
return;
|
||||
int32_t chan = _analog_pin2chan(pin);
|
||||
if (chan < 0) { // not yet allocated, try to allocate
|
||||
chan = analogAttach(pin);
|
||||
if (chan < 0) { return; } // failed
|
||||
}
|
||||
|
||||
if (duty >> (pwm_bit_num-1) ) ++duty; // input is 0..1023 but PWM takes 0..1024 - so we skip at mid-range. It creates a small non-linearity
|
||||
if (phase >> (pwm_bit_num-1) ) ++phase;
|
||||
|
||||
uint8_t group=(chan/8), channel=(chan%8);
|
||||
|
||||
//Fixing if all bits in resolution is set = LEDC FULL ON
|
||||
uint32_t max_duty = (1 << channels_resolution[chan]) - 1;
|
||||
phase = phase % max_duty;
|
||||
|
||||
if(duty == max_duty){ // no sure whether this is needed anymore TODO
|
||||
duty = max_duty + 1;
|
||||
}
|
||||
phase = phase & max_duty;
|
||||
|
||||
ledc_set_duty_with_hpoint((ledc_mode_t)group, (ledc_channel_t)channel, duty, phase);
|
||||
ledc_update_duty((ledc_mode_t)group, (ledc_channel_t)channel);
|
||||
}
|
||||
|
||||
#endif // ESP32
|
||||
|
|
|
@ -13,39 +13,21 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef __ESP8266TOESP32_H__
|
||||
#define __ESP8266TOESP32_H__
|
||||
|
||||
#ifdef ESP32
|
||||
// my debug Stuff
|
||||
#define Serial_Debug1(p) Serial.printf p
|
||||
#define Serial_DebugX(p)
|
||||
|
||||
//
|
||||
// basics
|
||||
//
|
||||
// dummy defines
|
||||
//#define SPIFFS_END (SPI_FLASH_SEC_SIZE * 200)
|
||||
//#define SETTINGS_LOCATION SPIFFS_END
|
||||
|
||||
#include <Esp.h>
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
#define PWM_SUPPORTED_CHANNELS 6
|
||||
#define PWM_CHANNEL_OFFSET 1 // Webcam uses channel 0, so we offset standard PWM
|
||||
#else // other ESP32
|
||||
#define PWM_SUPPORTED_CHANNELS 8
|
||||
#define PWM_CHANNEL_OFFSET 2 // Webcam uses channel 0, so we offset standard PWM
|
||||
#endif // CONFIG_IDF_TARGET_ESP32C3 vs ESP32
|
||||
|
||||
extern uint8_t _pwm_channel[PWM_SUPPORTED_CHANNELS];
|
||||
extern uint32_t _pwm_frequency;
|
||||
extern uint8_t _pwm_bit_num;
|
||||
|
||||
void _analogWriteFreqRange(void);
|
||||
// input range is in full range, ledc needs bits
|
||||
uint32_t _analogGetResolution(uint32_t x);
|
||||
void analogWriteRange(uint32_t range);
|
||||
void analogWriteFreq(uint32_t freq);
|
||||
bool analogAttach(uint32_t pin);
|
||||
int32_t analogAttach(uint32_t pin); // returns the ledc channel, or -1 if failed. This is implicitly called by analogWrite if the channel was not already allocated
|
||||
void analogWrite(uint8_t pin, int val);
|
||||
|
||||
// Extended version that also allows to change phase
|
||||
|
@ -56,8 +38,6 @@ extern void analogWritePhase(uint8_t pin, uint32_t duty, uint32_t phase = 0);
|
|||
|
||||
#define INPUT_PULLDOWN_16 INPUT_PULLUP
|
||||
|
||||
typedef double real64_t;
|
||||
|
||||
//
|
||||
// Time and Timer
|
||||
//
|
||||
|
@ -71,7 +51,6 @@ typedef double real64_t;
|
|||
// Serial minimal type to hold the config
|
||||
typedef int SerConfu8;
|
||||
typedef int SerialConfig;
|
||||
//#define analogWrite(a, b)
|
||||
|
||||
//
|
||||
// UDP
|
||||
|
@ -79,9 +58,6 @@ typedef int SerialConfig;
|
|||
//#define PortUdp_writestr(log_data) PortUdp.write((const uint8_t *)(log_data), strlen(log_data))
|
||||
#define PortUdp_write(log_data, n) PortUdp.write((const uint8_t *)(log_data), n)
|
||||
|
||||
//
|
||||
#define wifi_forceSleepBegin()
|
||||
|
||||
#undef LWIP_IPV6
|
||||
|
||||
#define REASON_DEFAULT_RST 0 // "Power on" normal startup by power on
|
||||
|
@ -106,4 +82,5 @@ typedef int SerialConfig;
|
|||
|
||||
#define STATION_IF 0
|
||||
|
||||
#endif
|
||||
#endif // ESP32
|
||||
#endif // __ESP8266TOESP32_H__
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
#pragma once
|
||||
/**/
|
||||
#include <lwip/ip_addr.h>
|
||||
/*
|
||||
#ifndef ICACHE_FLASH_ATTR
|
||||
#define ICACHE_FLASH_ATTR
|
||||
#endif
|
||||
*/
|
|
@ -474,7 +474,7 @@ typedef struct {
|
|||
TimeRule tflag[2]; // 2E2
|
||||
uint16_t pwm_frequency; // 2E6
|
||||
power_t power; // 2E8
|
||||
uint16_t pwm_value[MAX_PWMS]; // 2EC
|
||||
uint16_t pwm_value[MAX_PWMS_LEGACY];// 2EC
|
||||
int16_t altitude; // 2F6
|
||||
uint16_t tele_period; // 2F8
|
||||
uint8_t display_rotate; // 2FA
|
||||
|
@ -579,7 +579,7 @@ typedef struct {
|
|||
uint8_t ex_my_adc0; // 495 Free since 9.0.0.1
|
||||
|
||||
uint16_t light_pixels; // 496
|
||||
uint8_t light_color[5]; // 498
|
||||
uint8_t light_color[LST_MAX]; // 498 LST_MAX = 5
|
||||
uint8_t light_correction; // 49D
|
||||
uint8_t light_dimmer; // 49E
|
||||
uint8_t rule_enabled; // 49F
|
||||
|
@ -614,7 +614,8 @@ typedef struct {
|
|||
uint32_t ipv4_rgx_address; // 558
|
||||
uint32_t ipv4_rgx_subnetmask; // 55C
|
||||
|
||||
uint8_t free_560[92]; // 560
|
||||
uint16_t pwm_value_ext[16-5]; // 560 Extension to pwm_value to store up to 16 PWM for ESP32. This array stores values 5..15
|
||||
uint8_t free_560[70]; // 576
|
||||
|
||||
SysMBitfield1 flag2; // 5BC
|
||||
uint32_t pulse_counter[MAX_COUNTERS]; // 5C0
|
||||
|
|
|
@ -184,10 +184,11 @@ bool RtcRebootValid(void) {
|
|||
extern "C" {
|
||||
#include "spi_flash.h"
|
||||
}
|
||||
#include "eboot_command.h"
|
||||
|
||||
#ifdef ESP8266
|
||||
|
||||
#include "eboot_command.h"
|
||||
|
||||
extern "C" uint32_t _FS_start; // 1M = 0x402fb000, 2M = 0x40300000, 4M = 0x40300000
|
||||
const uint32_t FLASH_FS_START = (((uint32_t)&_FS_start - 0x40200000) / SPI_FLASH_SEC_SIZE);
|
||||
uint32_t SETTINGS_LOCATION = FLASH_FS_START -1; // 0xFA, 0x0FF or 0x0FF
|
||||
|
@ -1094,7 +1095,7 @@ void SettingsDefaultSet2(void) {
|
|||
|
||||
Settings->pwm_frequency = PWM_FREQ;
|
||||
Settings->pwm_range = PWM_RANGE;
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) {
|
||||
for (uint32_t i = 0; i < LST_MAX; i++) {
|
||||
Settings->light_color[i] = DEFAULT_LIGHT_COMPONENT;
|
||||
// Settings->pwm_value[i] = 0;
|
||||
}
|
||||
|
|
|
@ -1523,56 +1523,6 @@ void CmndTemplate(void)
|
|||
if (!error) { TemplateJson(); }
|
||||
}
|
||||
|
||||
void CmndPwm(void)
|
||||
{
|
||||
if (TasmotaGlobal.pwm_present && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_PWMS)) {
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= Settings->pwm_range) && PinUsed(GPIO_PWM1, XdrvMailbox.index -1)) {
|
||||
Settings->pwm_value[XdrvMailbox.index -1] = XdrvMailbox.payload;
|
||||
analogWrite(Pin(GPIO_PWM1, XdrvMailbox.index -1), bitRead(TasmotaGlobal.pwm_inverted, XdrvMailbox.index -1) ? Settings->pwm_range - XdrvMailbox.payload : XdrvMailbox.payload);
|
||||
}
|
||||
Response_P(PSTR("{"));
|
||||
MqttShowPWMState(); // Render the PWM status to MQTT
|
||||
ResponseJsonEnd();
|
||||
}
|
||||
}
|
||||
|
||||
void CmndPwmfrequency(void)
|
||||
{
|
||||
if ((1 == XdrvMailbox.payload) || ((XdrvMailbox.payload >= PWM_MIN) && (XdrvMailbox.payload <= PWM_MAX))) {
|
||||
Settings->pwm_frequency = (1 == XdrvMailbox.payload) ? PWM_FREQ : XdrvMailbox.payload;
|
||||
analogWriteFreq(Settings->pwm_frequency); // Default is 1000 (core_esp8266_wiring_pwm.c)
|
||||
#ifdef USE_LIGHT
|
||||
LightReapplyColor();
|
||||
LightAnimate();
|
||||
#endif // USE_LIGHT
|
||||
}
|
||||
ResponseCmndNumber(Settings->pwm_frequency);
|
||||
}
|
||||
|
||||
void CmndPwmrange(void) {
|
||||
// Support only 8 (=255), 9 (=511) and 10 (=1023) bits resolution
|
||||
if ((1 == XdrvMailbox.payload) || ((XdrvMailbox.payload > 254) && (XdrvMailbox.payload < 1024))) {
|
||||
uint32_t pwm_range = XdrvMailbox.payload;
|
||||
uint32_t pwm_resolution = 0;
|
||||
while (pwm_range) {
|
||||
pwm_resolution++;
|
||||
pwm_range >>= 1;
|
||||
}
|
||||
pwm_range = (1 << pwm_resolution) - 1;
|
||||
uint32_t old_pwm_range = Settings->pwm_range;
|
||||
Settings->pwm_range = (1 == XdrvMailbox.payload) ? PWM_RANGE : pwm_range;
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) {
|
||||
if (Settings->pwm_value[i] > Settings->pwm_range) {
|
||||
Settings->pwm_value[i] = Settings->pwm_range;
|
||||
}
|
||||
}
|
||||
if (Settings->pwm_range != old_pwm_range) { // On ESP32 this prevents loss of duty state
|
||||
analogWriteRange(Settings->pwm_range); // Default is 1023 (Arduino.h)
|
||||
}
|
||||
}
|
||||
ResponseCmndNumber(Settings->pwm_range);
|
||||
}
|
||||
|
||||
void CmndButtonDebounce(void)
|
||||
{
|
||||
if ((XdrvMailbox.payload > 39) && (XdrvMailbox.payload < 1001)) {
|
||||
|
|
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
support_pwm.ino - command support for Tasmota
|
||||
|
||||
Copyright (C) 2021 Theo Arends & Stephan Hadinger
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
/***********************************************************************\
|
||||
* PWM Control for ESP32
|
||||
\***********************************************************************/
|
||||
#ifdef ESP32
|
||||
|
||||
// All changes in PWM have been applied, rearm all change indicators
|
||||
void PwmRearmChanges(void) {
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) {
|
||||
// Init expected changes
|
||||
TasmotaGlobal.pwm_value[i] = -1; // no change wanted
|
||||
TasmotaGlobal.pwm_phase[i] = -1; // no change wanted
|
||||
}
|
||||
}
|
||||
|
||||
// Load PWM values from settings and intiliaze values
|
||||
// void PwmLoadFromSettings(void) {
|
||||
// for (uint32_t i = 0; i < MAX_PWMS; i++) {
|
||||
// if (i < MAX_PWMS_LEGACY) {
|
||||
// TasmotaGlobal.pwm_cur_value[i] = Settings->pwm_value[i]; // retrieve in Legacy pool for 0..4
|
||||
// } else {
|
||||
// TasmotaGlobal.pwm_cur_value[i] = Settings->pwm_value_ext[i - MAX_PWMS_LEGACY]; // retrieve in Legacy pool for 5..15
|
||||
// }
|
||||
// TasmotaGlobal.pwm_cur_phase[i] = 0; // no phase shift for now, will be recomputed at first push to GPIOs
|
||||
// }
|
||||
// PwmRearmChanges(); // reset expected changes
|
||||
// }
|
||||
|
||||
// Copy current values to Settings
|
||||
void PwmSaveToSettings(void) {
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) {
|
||||
if (i < MAX_PWMS_LEGACY) {
|
||||
Settings->pwm_value[i] = TasmotaGlobal.pwm_cur_value[i]; // store in Legacy pool for 0..4
|
||||
} else {
|
||||
Settings->pwm_value_ext[i - MAX_PWMS_LEGACY] = TasmotaGlobal.pwm_cur_value[i]; // retrieve in Legacy pool for 5..15
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************\
|
||||
* PWM Control for ESP32
|
||||
\***********************************************************************/
|
||||
// Apply PWM expected values to actual GPIO PWM
|
||||
// As input, `TasmotaGlobal.pwm_value[]` and `TasmotaGlobal.pwm_phase[]` contain the new expected values
|
||||
// or `-1` if no change.
|
||||
// Auto-phasing is recomputed, and changes are applied to GPIO if there is a physical GPIO configured and an actual change needed
|
||||
//
|
||||
void PwmApplyGPIO(void) {
|
||||
uint32_t pwm_phase_accumulator = 0; // dephase each PWM channel with the value of the previous
|
||||
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) {
|
||||
// compute `pwm_val`, the virtual value of PWM (not taking into account inverted)
|
||||
uint32_t pwm_val = TasmotaGlobal.pwm_cur_value[i]; // logical value of PWM, 0..1023
|
||||
if (TasmotaGlobal.pwm_value[i] >= 0) { pwm_val = TasmotaGlobal.pwm_value[i]; } // new value explicitly specified
|
||||
if (pwm_val > Settings->pwm_range) { pwm_val = Settings->pwm_range; } // prevent overflow
|
||||
|
||||
// gpio_val : actual value of GPIO, taking into account inversion
|
||||
uint32_t gpio_val = bitRead(TasmotaGlobal.pwm_inverted, i) ? Settings->pwm_range - pwm_val : pwm_val;
|
||||
|
||||
// compute phase
|
||||
uint32_t pwm_phase = TasmotaGlobal.pwm_cur_phase[i]; // pwm_phase is the logical phase of the active pulse, ignoring inverted
|
||||
uint32_t gpio_phase = pwm_phase; // gpio is the physical phase taking into account inverted
|
||||
if (TasmotaGlobal.pwm_phase[i] >= 0) {
|
||||
pwm_phase = TasmotaGlobal.pwm_phase[i]; // if explicit set explicitly,
|
||||
} else if (Settings->flag5.pwm_force_same_phase) {
|
||||
pwm_phase = 0; // if auto-phase is off
|
||||
} else {
|
||||
// compute auto-phase
|
||||
pwm_phase = pwm_phase_accumulator;
|
||||
uint32_t pwm_phase_invert = bitRead(TasmotaGlobal.pwm_inverted, i) ? pwm_val : 0; // move phase if inverted
|
||||
gpio_phase = (pwm_phase + pwm_phase_invert) & Settings->pwm_range;
|
||||
// accumulate phase for next GPIO
|
||||
pwm_phase_accumulator = (pwm_phase + pwm_val) & Settings->pwm_range;
|
||||
}
|
||||
|
||||
// apply new values to GPIO if GPIO is set
|
||||
if (PinUsed(GPIO_PWM1, i)) {
|
||||
if ((pwm_val != TasmotaGlobal.pwm_cur_value[i]) || (pwm_phase != TasmotaGlobal.pwm_cur_phase[i])) {
|
||||
// GPIO has PWM and there is a chnage to apply, apply it
|
||||
analogWritePhase(Pin(GPIO_PWM1, i), gpio_val, gpio_phase);
|
||||
}
|
||||
}
|
||||
|
||||
// set new current values
|
||||
TasmotaGlobal.pwm_cur_value[i] = pwm_val;
|
||||
TasmotaGlobal.pwm_cur_phase[i] = pwm_phase;
|
||||
}
|
||||
// AddLog(LOG_LEVEL_INFO, "PWM: Val=%03X-%03X-%03X-%03X-%03X Phase=%03X-%03X-%03X-%03X-%03X Range=%03X",
|
||||
// TasmotaGlobal.pwm_cur_value[0], TasmotaGlobal.pwm_cur_value[1], TasmotaGlobal.pwm_cur_value[2], TasmotaGlobal.pwm_cur_value[3],
|
||||
// TasmotaGlobal.pwm_cur_value[4],
|
||||
// TasmotaGlobal.pwm_cur_phase[0], TasmotaGlobal.pwm_cur_phase[1], TasmotaGlobal.pwm_cur_phase[2], TasmotaGlobal.pwm_cur_phase[3],
|
||||
// TasmotaGlobal.pwm_cur_phase[4],
|
||||
// Settings->pwm_range
|
||||
// );
|
||||
PwmSaveToSettings(); // copy to Settings
|
||||
PwmRearmChanges(); // reset expected changes
|
||||
}
|
||||
|
||||
void CmndPwm(void)
|
||||
{
|
||||
if (TasmotaGlobal.pwm_present && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_PWMS)) {
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= Settings->pwm_range) && PinUsed(GPIO_PWM1, XdrvMailbox.index -1)) {
|
||||
TasmotaGlobal.pwm_value[XdrvMailbox.index - 1] = XdrvMailbox.payload;
|
||||
PwmApplyGPIO();
|
||||
}
|
||||
Response_P(PSTR("{"));
|
||||
MqttShowPWMState(); // Render the PWM status to MQTT
|
||||
ResponseJsonEnd();
|
||||
}
|
||||
}
|
||||
|
||||
void GpioInitPwm(void) {
|
||||
PwmRearmChanges();
|
||||
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) { // Basic PWM control only
|
||||
if (PinUsed(GPIO_PWM1, i)) {
|
||||
analogAttach(Pin(GPIO_PWM1, i));
|
||||
if (i < TasmotaGlobal.light_type) {
|
||||
// force PWM GPIOs to black
|
||||
TasmotaGlobal.pwm_value[i] = 0;
|
||||
} else {
|
||||
TasmotaGlobal.pwm_present = true;
|
||||
if (i < MAX_PWMS_LEGACY) {
|
||||
TasmotaGlobal.pwm_value[i] = Settings->pwm_value[i];
|
||||
} else {
|
||||
TasmotaGlobal.pwm_value[i] = Settings->pwm_value_ext[i - MAX_PWMS_LEGACY];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PwmApplyGPIO(); // apply all changes
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
void ResetPwm(void)
|
||||
{
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) { // Basic PWM control only
|
||||
TasmotaGlobal.pwm_value[i] = 0;
|
||||
}
|
||||
PwmApplyGPIO();
|
||||
}
|
||||
|
||||
#else // now for ESP8266
|
||||
|
||||
void PwmRearmChanges(void) {}
|
||||
|
||||
void CmndPwm(void)
|
||||
{
|
||||
if (TasmotaGlobal.pwm_present && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_PWMS)) {
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= Settings->pwm_range) && PinUsed(GPIO_PWM1, XdrvMailbox.index -1)) {
|
||||
uint32_t pwm_index = XdrvMailbox.index - 1;
|
||||
if (pwm_index < MAX_PWMS_LEGACY) { // write in the appropriate settings pool
|
||||
Settings->pwm_value[pwm_index] = XdrvMailbox.payload;
|
||||
} else {
|
||||
Settings->pwm_value_ext[pwm_index - MAX_PWMS_LEGACY] = XdrvMailbox.payload;
|
||||
}
|
||||
analogWrite(Pin(GPIO_PWM1, pwm_index), bitRead(TasmotaGlobal.pwm_inverted, pwm_index) ? Settings->pwm_range - XdrvMailbox.payload : XdrvMailbox.payload);
|
||||
}
|
||||
Response_P(PSTR("{"));
|
||||
MqttShowPWMState(); // Render the PWM status to MQTT
|
||||
ResponseJsonEnd();
|
||||
}
|
||||
}
|
||||
|
||||
void GpioInitPwm(void) {
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) { // Basic PWM control only
|
||||
if (PinUsed(GPIO_PWM1, i)) {
|
||||
pinMode(Pin(GPIO_PWM1, i), OUTPUT);
|
||||
if (i < TasmotaGlobal.light_type) {
|
||||
// force PWM GPIOs to low or high mode if belongs to the light (always <5), see #7165
|
||||
analogWrite(Pin(GPIO_PWM1, i), bitRead(TasmotaGlobal.pwm_inverted, i) ? Settings->pwm_range : 0);
|
||||
} else {
|
||||
TasmotaGlobal.pwm_present = true;
|
||||
if (i < MAX_PWMS_LEGACY) {
|
||||
analogWrite(Pin(GPIO_PWM1, i), bitRead(TasmotaGlobal.pwm_inverted, i) ? Settings->pwm_range - Settings->pwm_value[i] : Settings->pwm_value[i]);
|
||||
} else {
|
||||
analogWrite(Pin(GPIO_PWM1, i), bitRead(TasmotaGlobal.pwm_inverted, i) ? Settings->pwm_range - Settings->pwm_value_ext[i] : Settings->pwm_value_ext[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
void ResetPwm(void)
|
||||
{
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) { // Basic PWM control only
|
||||
if (PinUsed(GPIO_PWM1, i)) {
|
||||
analogWrite(Pin(GPIO_PWM1, i), bitRead(TasmotaGlobal.pwm_inverted, i) ? Settings->pwm_range : 0);
|
||||
// analogWrite(Pin(GPIO_PWM1, i), bitRead(TasmotaGlobal.pwm_inverted, i) ? Settings->pwm_range - Settings->pwm_value[i] : Settings->pwm_value[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ESP8266
|
||||
|
||||
void CmndPwmfrequency(void)
|
||||
{
|
||||
if ((1 == XdrvMailbox.payload) || ((XdrvMailbox.payload >= PWM_MIN) && (XdrvMailbox.payload <= PWM_MAX))) {
|
||||
Settings->pwm_frequency = (1 == XdrvMailbox.payload) ? PWM_FREQ : XdrvMailbox.payload;
|
||||
analogWriteFreq(Settings->pwm_frequency); // Default is 1000 (core_esp8266_wiring_pwm.c)
|
||||
#ifdef USE_LIGHT
|
||||
LightReapplyColor();
|
||||
LightAnimate();
|
||||
#endif // USE_LIGHT
|
||||
}
|
||||
ResponseCmndNumber(Settings->pwm_frequency);
|
||||
}
|
||||
|
||||
void CmndPwmrange(void) {
|
||||
// Support only 8 (=255), 9 (=511) and 10 (=1023) bits resolution
|
||||
if ((1 == XdrvMailbox.payload) || ((XdrvMailbox.payload > 254) && (XdrvMailbox.payload < 1024))) {
|
||||
uint32_t pwm_range = XdrvMailbox.payload;
|
||||
uint32_t pwm_resolution = 0;
|
||||
while (pwm_range) {
|
||||
pwm_resolution++;
|
||||
pwm_range >>= 1;
|
||||
}
|
||||
pwm_range = (1 << pwm_resolution) - 1;
|
||||
uint32_t old_pwm_range = Settings->pwm_range;
|
||||
Settings->pwm_range = (1 == XdrvMailbox.payload) ? PWM_RANGE : pwm_range;
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) {
|
||||
if (i < MAX_PWMS_LEGACY) {
|
||||
if (Settings->pwm_value[i] > Settings->pwm_range) {
|
||||
Settings->pwm_value[i] = Settings->pwm_range;
|
||||
}
|
||||
} else {
|
||||
if (Settings->pwm_value_ext[i - MAX_PWMS_LEGACY] > Settings->pwm_range) {
|
||||
Settings->pwm_value_ext[i - MAX_PWMS_LEGACY] = Settings->pwm_range;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Settings->pwm_range != old_pwm_range) { // On ESP32 this prevents loss of duty state
|
||||
analogWriteRange(Settings->pwm_range); // Default is 1023 (Arduino.h)
|
||||
}
|
||||
}
|
||||
ResponseCmndNumber(Settings->pwm_range);
|
||||
}
|
||||
|
||||
void MqttShowPWMState(void)
|
||||
{
|
||||
ResponseAppend_P(PSTR("\"" D_CMND_PWM "\":{"));
|
||||
bool first = true;
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) { // TODO
|
||||
if (PinUsed(GPIO_PWM1, i)) {
|
||||
uint32_t pwm_val = (i < MAX_PWMS_LEGACY) ? Settings->pwm_value[i] : Settings->pwm_value_ext[i - MAX_PWMS_LEGACY];
|
||||
ResponseAppend_P(PSTR("%s\"" D_CMND_PWM "%d\":%d"), first ? "" : ",", i+1, pwm_val);
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
ResponseJsonEnd();
|
||||
}
|
|
@ -444,7 +444,7 @@ void SetLedPowerIdx(uint32_t led, uint32_t state)
|
|||
pwm = changeUIntScale((uint16_t)(state ? Settings->ledpwm_on : Settings->ledpwm_off), 0, 255, 0, Settings->pwm_range); // linear
|
||||
#endif //USE_LIGHT
|
||||
#ifdef ESP32
|
||||
if (analogAttach(Pin(GPIO_LED1, led)))
|
||||
if (analogAttach(Pin(GPIO_LED1, led)) >= 0)
|
||||
#endif
|
||||
analogWrite(Pin(GPIO_LED1, led), bitRead(TasmotaGlobal.led_inverted, led) ? Settings->pwm_range - pwm : pwm);
|
||||
} else {
|
||||
|
@ -735,19 +735,6 @@ void StopAllPowerBlink(void)
|
|||
}
|
||||
}
|
||||
|
||||
void MqttShowPWMState(void)
|
||||
{
|
||||
ResponseAppend_P(PSTR("\"" D_CMND_PWM "\":{"));
|
||||
bool first = true;
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) {
|
||||
if (PinUsed(GPIO_PWM1, i)) {
|
||||
ResponseAppend_P(PSTR("%s\"" D_CMND_PWM "%d\":%d"), first ? "" : ",", i+1, Settings->pwm_value[i]);
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
ResponseJsonEnd();
|
||||
}
|
||||
|
||||
void MqttShowState(void)
|
||||
{
|
||||
char stemp1[TOPSZ];
|
||||
|
@ -1670,17 +1657,6 @@ void SerialInput(void)
|
|||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
void ResetPwm(void)
|
||||
{
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) { // Basic PWM control only
|
||||
if (PinUsed(GPIO_PWM1, i)) {
|
||||
analogWrite(Pin(GPIO_PWM1, i), bitRead(TasmotaGlobal.pwm_inverted, i) ? Settings->pwm_range : 0);
|
||||
// analogWrite(Pin(GPIO_PWM1, i), bitRead(TasmotaGlobal.pwm_inverted, i) ? Settings->pwm_range - Settings->pwm_value[i] : Settings->pwm_value[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
|
@ -1825,7 +1801,7 @@ void GpioInit(void)
|
|||
mpin -= (AGPIO(GPIO_HEARTBEAT_INV) - AGPIO(GPIO_HEARTBEAT));
|
||||
}
|
||||
else if ((mpin >= AGPIO(GPIO_PWM1_INV)) && (mpin < (AGPIO(GPIO_PWM1_INV) + MAX_PWMS))) {
|
||||
bitSet(TasmotaGlobal.pwm_inverted, mpin - AGPIO(GPIO_PWM1_INV));
|
||||
bitSet(TasmotaGlobal.pwm_inverted, mpin - AGPIO(GPIO_PWM1_INV)); // PWMi are later converted to PMW, but marked as inverted in TasmotaGlobal.pwm_inverted
|
||||
mpin -= (AGPIO(GPIO_PWM1_INV) - AGPIO(GPIO_PWM1));
|
||||
}
|
||||
else if (XdrvCall(FUNC_PIN_STATE)) {
|
||||
|
@ -2002,23 +1978,7 @@ void GpioInit(void)
|
|||
#endif // USE_SONOFF_SC
|
||||
#endif // ESP8266
|
||||
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) { // Basic PWM control only
|
||||
if (PinUsed(GPIO_PWM1, i)) {
|
||||
#ifdef ESP8266
|
||||
pinMode(Pin(GPIO_PWM1, i), OUTPUT);
|
||||
#endif // ESP8266
|
||||
#ifdef ESP32
|
||||
analogAttach(Pin(GPIO_PWM1, i));
|
||||
#endif // ESP32
|
||||
if (TasmotaGlobal.light_type) {
|
||||
// force PWM GPIOs to low or high mode, see #7165
|
||||
analogWrite(Pin(GPIO_PWM1, i), bitRead(TasmotaGlobal.pwm_inverted, i) ? Settings->pwm_range : 0);
|
||||
} else {
|
||||
TasmotaGlobal.pwm_present = true;
|
||||
analogWrite(Pin(GPIO_PWM1, i), bitRead(TasmotaGlobal.pwm_inverted, i) ? Settings->pwm_range - Settings->pwm_value[i] : Settings->pwm_value[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
GpioInitPwm();
|
||||
|
||||
for (uint32_t i = 0; i < MAX_RELAYS; i++) {
|
||||
if (PinUsed(GPIO_REL1, i)) {
|
||||
|
|
|
@ -60,7 +60,21 @@ const uint8_t MAX_KEYS = 8; // Max number of keys or buttons (up
|
|||
const uint8_t MAX_INTERLOCKS_SET = 14; // Max number of interlock groups (MAX_RELAYS / 2)
|
||||
const uint8_t MAX_SWITCHES_SET = 28; // Max number of switches
|
||||
const uint8_t MAX_LEDS = 4; // Max number of leds
|
||||
const uint8_t MAX_PWMS = 5; // Max number of PWM channels
|
||||
const uint8_t MAX_PWMS_LEGACY = 5; // Max number of PWM channels in first settings block - Legacy limit for ESP8266, but extended for ESP32 (see below)
|
||||
#ifdef ESP32
|
||||
// Max number of PWM channels (total including extended) - ESP32 only
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32)
|
||||
const uint8_t MAX_PWMS = 16; // ESP32: 16 ledc PWM channels in total - TODO for now
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
const uint8_t MAX_PWMS = 8; // ESP32S2: 8 ledc PWM channels in total
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
const uint8_t MAX_PWMS = 6; // ESP32C3: 6 ledc PWM channels in total
|
||||
#else
|
||||
const uint8_t MAX_PWMS = 5; // Unknown - revert to 5 PWM max
|
||||
#endif
|
||||
#else
|
||||
const uint8_t MAX_PWMS = 5; // (not used on ESP8266)
|
||||
#endif
|
||||
const uint8_t MAX_COUNTERS = 4; // Max number of counter sensors
|
||||
const uint8_t MAX_TIMERS = 16; // Max number of Timers
|
||||
const uint8_t MAX_PULSETIMERS = 8; // Max number of supported pulse timers
|
||||
|
|
|
@ -154,6 +154,13 @@ struct TasmotaGlobal_t {
|
|||
bool enable_logging; // Enable logging
|
||||
|
||||
StateBitfield global_state; // Global states (currently Wifi and Mqtt) (8 bits)
|
||||
uint16_t pwm_inverted; // PWM inverted flag (1 = inverted) - extended to 16 bits for ESP32
|
||||
#ifdef ESP32
|
||||
int16_t pwm_cur_value[MAX_PWMS]; // Current effective values of PWMs as applied to GPIOs
|
||||
int16_t pwm_cur_phase[MAX_PWMS]; // Current phase values of PWMs as applied to GPIOs
|
||||
int16_t pwm_value[MAX_PWMS]; // Wanted values of PWMs after update - -1 means no change
|
||||
int16_t pwm_phase[MAX_PWMS]; // Wanted phase of PWMs after update - -1 means no change
|
||||
#endif // ESP32
|
||||
uint8_t init_state; // Tasmota init state
|
||||
uint8_t heartbeat_inverted; // Heartbeat pulse inverted flag
|
||||
uint8_t spi_enabled; // SPI configured
|
||||
|
@ -172,7 +179,7 @@ struct TasmotaGlobal_t {
|
|||
uint8_t led_inverted; // LED inverted flag (1 = (0 = On, 1 = Off))
|
||||
uint8_t led_power; // LED power state
|
||||
uint8_t ledlnk_inverted; // Link LED inverted flag (1 = (0 = On, 1 = Off))
|
||||
uint8_t pwm_inverted; // PWM inverted flag (1 = inverted)
|
||||
// uint8_t pwm_inverted; // PWM inverted flag (1 = inverted) -- TODO
|
||||
uint8_t energy_driver; // Energy monitor configured
|
||||
uint8_t light_driver; // Light module configured
|
||||
uint8_t light_type; // Light types
|
||||
|
|
|
@ -449,7 +449,7 @@ const uint16_t kGpioNiceList[] PROGMEM = {
|
|||
AGPIO(GPIO_CNTR1_NP) + MAX_COUNTERS,
|
||||
#endif
|
||||
AGPIO(GPIO_PWM1) + MAX_PWMS, // RGB Red or C Cold White
|
||||
AGPIO(GPIO_PWM1_INV) + MAX_PWMS,
|
||||
AGPIO(GPIO_PWM1_INV) + MAX_PWMS, // or extended PWM for ESP32
|
||||
#ifdef USE_BUZZER
|
||||
AGPIO(GPIO_BUZZER), // Buzzer
|
||||
AGPIO(GPIO_BUZZER_INV), // Inverted buzzer
|
||||
|
|
|
@ -227,7 +227,7 @@ struct LIGHT {
|
|||
uint8_t old_power = 1;
|
||||
uint8_t wakeup_active = 0; // 0=inctive, 1=on-going, 2=about to start, 3=will be triggered next cycle
|
||||
uint8_t fixed_color_index = 1;
|
||||
uint8_t pwm_offset = 0; // Offset in color buffer
|
||||
uint8_t pwm_offset = 0; // Offset in color buffer, used by sm16716 to drive itself RGB, and PWM for CCT (value is 0 or 3)
|
||||
uint8_t max_scheme = LS_MAX -1;
|
||||
|
||||
uint32_t wakeup_start_time = 0;
|
||||
|
@ -1030,7 +1030,7 @@ bool LightModuleInit(void)
|
|||
TasmotaGlobal.light_type = LT_BASIC; // Use basic PWM control if SetOption15 = 0
|
||||
|
||||
if (Settings->flag.pwm_control) { // SetOption15 - Switch between commands PWM or COLOR/DIMMER/CT/CHANNEL
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) {
|
||||
for (uint32_t i = 0; i < LST_MAX; i++) {
|
||||
if (PinUsed(GPIO_PWM1, i)) { TasmotaGlobal.light_type++; } // Use Dimmer/Color control for all PWM as SetOption15 = 1
|
||||
}
|
||||
}
|
||||
|
@ -1164,9 +1164,7 @@ void LightInit(void)
|
|||
#ifdef ESP8266
|
||||
pinMode(Pin(GPIO_PWM1, i), OUTPUT);
|
||||
#endif // ESP8266
|
||||
#ifdef ESP32
|
||||
analogAttach(Pin(GPIO_PWM1, i));
|
||||
#endif // ESP32
|
||||
// For ESP32, the PWM are already attached by GpioInit() - GpioInitPwm()
|
||||
}
|
||||
}
|
||||
if (PinUsed(GPIO_ARIRFRCV)) {
|
||||
|
@ -2087,10 +2085,6 @@ void LightApplyPower(uint8_t new_color[LST_MAX], power_t power) {
|
|||
void LightSetOutputs(const uint16_t *cur_col_10) {
|
||||
// now apply the actual PWM values, adjusted and remapped 10-bits range
|
||||
if (TasmotaGlobal.light_type < LT_PWM6) { // only for direct PWM lights, not for Tuya, Armtronix...
|
||||
#ifdef ESP32
|
||||
uint32_t pwm_phase = 0; // dephase each PWM channel with the value of the previous
|
||||
uint32_t pwm_modulus = (1 << _pwm_bit_num) - 1; // 1023
|
||||
#endif // ESP32
|
||||
|
||||
#ifdef USE_PWM_DIMMER
|
||||
uint16_t max_col = 0;
|
||||
|
@ -2116,17 +2110,18 @@ void LightSetOutputs(const uint16_t *cur_col_10) {
|
|||
cur_col = cur_col > 0 ? changeUIntScale(cur_col, 0, Settings->pwm_range, Light.pwm_min, Light.pwm_max) : 0; // shrink to the range of pwm_min..pwm_max
|
||||
}
|
||||
if (!Settings->flag4.zerocross_dimmer) {
|
||||
uint32_t pwm_val = bitRead(TasmotaGlobal.pwm_inverted, i) ? Settings->pwm_range - cur_col : cur_col;
|
||||
#ifdef ESP32
|
||||
uint32_t pwm_phase_invert = bitRead(TasmotaGlobal.pwm_inverted, i) ? cur_col : 0; // move phase if inverted
|
||||
analogWritePhase(Pin(GPIO_PWM1, i), pwm_val, Settings->flag5.pwm_force_same_phase ? 0 : (pwm_phase + pwm_phase_invert) & pwm_modulus);
|
||||
pwm_phase = (pwm_phase + cur_col) & pwm_modulus;
|
||||
TasmotaGlobal.pwm_value[i] = cur_col; // mark the new expected value
|
||||
#else // ESP32
|
||||
analogWrite(Pin(GPIO_PWM1, i), pwm_val);
|
||||
analogWrite(Pin(GPIO_PWM1, i), bitRead(TasmotaGlobal.pwm_inverted, i) ? Settings->pwm_range - cur_col : cur_col);
|
||||
#endif // ESP32
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef ESP32
|
||||
PwmApplyGPIO();
|
||||
#endif // ESP32
|
||||
|
||||
#ifdef USE_PWM_DIMMER
|
||||
// Animate brightness LEDs to follow PWM dimmer brightness
|
||||
if (PWM_DIMMER == TasmotaGlobal.module_type) PWMDimmerSetBrightnessLeds(change10to8(max_col));
|
||||
|
|
|
@ -1989,7 +1989,7 @@ void CmndDisplayMode(void) {
|
|||
// Apply the current display dimmer
|
||||
void ApplyDisplayDimmer(void) {
|
||||
uint8_t dimmer8 = changeUIntScale(GetDisplayDimmer(), 0, 100, 0, 255);
|
||||
uint8_t dimmer8_gamma = ledGamma(dimmer8);
|
||||
uint16_t dimmer10_gamma = ledGamma10(dimmer8);
|
||||
if (dimmer8 && !(disp_power)) {
|
||||
ExecuteCommandPower(disp_device, POWER_ON, SRC_DISPLAY);
|
||||
}
|
||||
|
@ -1997,7 +1997,7 @@ void ApplyDisplayDimmer(void) {
|
|||
ExecuteCommandPower(disp_device, POWER_OFF, SRC_DISPLAY);
|
||||
}
|
||||
if (renderer) {
|
||||
renderer->dim8(dimmer8, dimmer8_gamma); // provide 8 bits and gamma corrected dimmer in 8 bits
|
||||
renderer->dim10(dimmer8, dimmer10_gamma); // provide 8 bits and gamma corrected dimmer in 8 bits
|
||||
#ifdef USE_BERRY
|
||||
// still call Berry virtual display in case it is not managed entirely by renderer
|
||||
Xdsp18(FUNC_DISPLAY_DIM);
|
||||
|
|
|
@ -50,9 +50,6 @@ void BuzzerSet(uint32_t state) {
|
|||
if (Settings->flag4.buzzer_freq_mode) { // SetOption111 - Enable frequency output mode for buzzer
|
||||
static uint8_t last_state = 0;
|
||||
if (last_state != state) {
|
||||
#ifdef ESP32
|
||||
if (analogAttach(Pin(GPIO_BUZZER)))
|
||||
#endif // ESP32
|
||||
// Set 50% duty cycle for frequency output
|
||||
// Set 0% (or 100% for inverted PWM) duty cycle which turns off frequency output either way
|
||||
analogWrite(Pin(GPIO_BUZZER), (state) ? Settings->pwm_range / 2 : 0); // set duty cycle for frequency output
|
||||
|
|
|
@ -219,12 +219,6 @@ uint32_t WcSetup(int32_t fsiz) {
|
|||
//esp_log_level_set("*", ESP_LOG_VERBOSE);
|
||||
|
||||
camera_config_t config;
|
||||
config.ledc_channel = LEDC_CHANNEL_0;
|
||||
config.ledc_timer = LEDC_TIMER_0;
|
||||
config.xclk_freq_hz = 20000000;
|
||||
config.pixel_format = PIXFORMAT_JPEG;
|
||||
// config.pixel_format = PIXFORMAT_GRAYSCALE;
|
||||
// config.pixel_format = PIXFORMAT_RGB565;
|
||||
|
||||
if (WcPinUsed()) {
|
||||
config.pin_d0 = Pin(GPIO_WEBCAM_DATA); // Y2_GPIO_NUM;
|
||||
|
@ -266,7 +260,16 @@ uint32_t WcSetup(int32_t fsiz) {
|
|||
AddLog(LOG_LEVEL_DEBUG, PSTR("CAM: Default template"));
|
||||
}
|
||||
|
||||
//ESP.getPsramSize()
|
||||
int32_t ledc_channel = analogAttach(config.pin_xclk);
|
||||
if (ledc_channel < 0) {
|
||||
AddLog(LOG_LEVEL_ERROR, "CAM: cannot allocated ledc cahnnel, remove a PWM GPIO");
|
||||
}
|
||||
config.ledc_channel = (ledc_channel_t) ledc_channel;
|
||||
AddLog(LOG_LEVEL_DEBUG_MORE, "CAM: XCLK on GPIO %i using ledc channel %i", config.pin_xclk, config.ledc_channel);
|
||||
config.ledc_timer = LEDC_TIMER_0;
|
||||
config.xclk_freq_hz = 20000000;
|
||||
config.pixel_format = PIXFORMAT_JPEG;
|
||||
|
||||
|
||||
//esp_log_level_set("*", ESP_LOG_INFO);
|
||||
|
||||
|
|
Loading…
Reference in New Issue