mirror of https://github.com/arendst/Tasmota.git
PCA9685 (driver15) - add INVERT option
The INVERT option makes PWM and ON/OFF values meaningful for open-drain connected lights. - Activate with: driver15 invert 1 - PWM value is inverted, so 0 is "off" and 4096 is "on" - INVERT is included in status and telemetry
This commit is contained in:
parent
692b7ec8c3
commit
8337fba960
|
@ -39,6 +39,7 @@
|
||||||
#define USE_PCA9685_FREQ 50
|
#define USE_PCA9685_FREQ 50
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
bool pca9685_inverted = false; // invert PWM for open-collector load
|
||||||
bool pca9685_detected = false;
|
bool pca9685_detected = false;
|
||||||
uint16_t pca9685_freq = USE_PCA9685_FREQ;
|
uint16_t pca9685_freq = USE_PCA9685_FREQ;
|
||||||
uint16_t pca9685_pin_pwm_value[16];
|
uint16_t pca9685_pin_pwm_value[16];
|
||||||
|
@ -64,13 +65,22 @@ void PCA9685_Reset(void)
|
||||||
{
|
{
|
||||||
I2cWrite8(USE_PCA9685_ADDR, PCA9685_REG_MODE1, 0x80);
|
I2cWrite8(USE_PCA9685_ADDR, PCA9685_REG_MODE1, 0x80);
|
||||||
PCA9685_SetPWMfreq(USE_PCA9685_FREQ);
|
PCA9685_SetPWMfreq(USE_PCA9685_FREQ);
|
||||||
|
pca9685_inverted = false;
|
||||||
for (uint32_t pin=0;pin<16;pin++) {
|
for (uint32_t pin=0;pin<16;pin++) {
|
||||||
PCA9685_SetPWM(pin,0,false);
|
PCA9685_SetPWM(pin,0,pca9685_inverted);
|
||||||
pca9685_pin_pwm_value[pin] = 0;
|
pca9685_pin_pwm_value[pin] = PCA9685_GetPWMvalue(0, pca9685_inverted);
|
||||||
}
|
}
|
||||||
Response_P(PSTR("{\"PCA9685\":{\"RESET\":\"OK\"}}"));
|
Response_P(PSTR("{\"PCA9685\":{\"RESET\":\"OK\"}}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t PCA9685_GetPWMvalue(uint16_t pwm, bool inverted) {
|
||||||
|
uint16_t pwm_val = pwm;
|
||||||
|
if (inverted) {
|
||||||
|
pwm_val = 4096-pwm;
|
||||||
|
}
|
||||||
|
return pwm_val;
|
||||||
|
}
|
||||||
|
|
||||||
void PCA9685_SetPWMfreq(double freq) {
|
void PCA9685_SetPWMfreq(double freq) {
|
||||||
/*
|
/*
|
||||||
7.3.5 from datasheet
|
7.3.5 from datasheet
|
||||||
|
@ -100,12 +110,13 @@ void PCA9685_SetPWM_Reg(uint8_t pin, uint16_t on, uint16_t off) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PCA9685_SetPWM(uint8_t pin, uint16_t pwm, bool inverted) {
|
void PCA9685_SetPWM(uint8_t pin, uint16_t pwm, bool inverted) {
|
||||||
if (4096 == pwm) {
|
uint16_t pwm_val = PCA9685_GetPWMvalue(pwm, inverted);
|
||||||
|
if (4096 == pwm_val) {
|
||||||
PCA9685_SetPWM_Reg(pin, 4096, 0); // Special use additional bit causes channel to turn on completely without PWM
|
PCA9685_SetPWM_Reg(pin, 4096, 0); // Special use additional bit causes channel to turn on completely without PWM
|
||||||
} else {
|
} else {
|
||||||
PCA9685_SetPWM_Reg(pin, 0, pwm);
|
PCA9685_SetPWM_Reg(pin, 0, pwm_val);
|
||||||
}
|
}
|
||||||
pca9685_pin_pwm_value[pin] = pwm;
|
pca9685_pin_pwm_value[pin] = pwm_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PCA9685_Command(void)
|
bool PCA9685_Command(void)
|
||||||
|
@ -130,6 +141,16 @@ bool PCA9685_Command(void)
|
||||||
|
|
||||||
if (!strcmp(ArgV(argument, 1),"STATUS")) { PCA9685_OutputTelemetry(false); return serviced; }
|
if (!strcmp(ArgV(argument, 1),"STATUS")) { PCA9685_OutputTelemetry(false); return serviced; }
|
||||||
|
|
||||||
|
if (!strcmp(ArgV(argument, 1),"INVERT")) {
|
||||||
|
if (paramcount > 1) {
|
||||||
|
pca9685_inverted = (1 == atoi(ArgV(argument, 2)));
|
||||||
|
Response_P(PSTR("{\"PCA9685\":{\"INVERT\":%i, \"Result\":\"OK\"}}"), pca9685_inverted?1:0);
|
||||||
|
return serviced;
|
||||||
|
} else { // No parameter was given for invert, so we return current setting
|
||||||
|
Response_P(PSTR("{\"PCA9685\":{\"INVERT\":%i}}"), pca9685_inverted?1:0);
|
||||||
|
return serviced;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!strcmp(ArgV(argument, 1),"PWMF")) {
|
if (!strcmp(ArgV(argument, 1),"PWMF")) {
|
||||||
if (paramcount > 1) {
|
if (paramcount > 1) {
|
||||||
uint16_t new_freq = atoi(ArgV(argument, 2));
|
uint16_t new_freq = atoi(ArgV(argument, 2));
|
||||||
|
@ -148,20 +169,20 @@ bool PCA9685_Command(void)
|
||||||
uint8_t pin = atoi(ArgV(argument, 2));
|
uint8_t pin = atoi(ArgV(argument, 2));
|
||||||
if (paramcount > 2) {
|
if (paramcount > 2) {
|
||||||
if (!strcmp(ArgV(argument, 3), "ON")) {
|
if (!strcmp(ArgV(argument, 3), "ON")) {
|
||||||
PCA9685_SetPWM(pin, 4096, false);
|
PCA9685_SetPWM(pin, 4096, pca9685_inverted);
|
||||||
Response_P(PSTR("{\"PCA9685\":{\"PIN\":%i,\"PWM\":%i}}"),pin,4096);
|
Response_P(PSTR("{\"PCA9685\":{\"PIN\":%i,\"PWM\":%i}}"),pin,4096);
|
||||||
serviced = true;
|
serviced = true;
|
||||||
return serviced;
|
return serviced;
|
||||||
}
|
}
|
||||||
if (!strcmp(ArgV(argument, 3), "OFF")) {
|
if (!strcmp(ArgV(argument, 3), "OFF")) {
|
||||||
PCA9685_SetPWM(pin, 0, false);
|
PCA9685_SetPWM(pin, 0, pca9685_inverted);
|
||||||
Response_P(PSTR("{\"PCA9685\":{\"PIN\":%i,\"PWM\":%i}}"),pin,0);
|
Response_P(PSTR("{\"PCA9685\":{\"PIN\":%i,\"PWM\":%i}}"),pin,0);
|
||||||
serviced = true;
|
serviced = true;
|
||||||
return serviced;
|
return serviced;
|
||||||
}
|
}
|
||||||
uint16_t pwm = atoi(ArgV(argument, 3));
|
uint16_t pwm = atoi(ArgV(argument, 3));
|
||||||
if ((pin >= 0 && pin <= 15) && (pwm >= 0 && pwm <= 4096)) {
|
if ((pin >= 0 && pin <= 15) && (pwm >= 0 && pwm <= 4096)) {
|
||||||
PCA9685_SetPWM(pin, pwm, false);
|
PCA9685_SetPWM(pin, pwm, pca9685_inverted);
|
||||||
Response_P(PSTR("{\"PCA9685\":{\"PIN\":%i,\"PWM\":%i}}"),pin,pwm);
|
Response_P(PSTR("{\"PCA9685\":{\"PIN\":%i,\"PWM\":%i}}"),pin,pwm);
|
||||||
serviced = true;
|
serviced = true;
|
||||||
return serviced;
|
return serviced;
|
||||||
|
@ -175,8 +196,10 @@ bool PCA9685_Command(void)
|
||||||
void PCA9685_OutputTelemetry(bool telemetry)
|
void PCA9685_OutputTelemetry(bool telemetry)
|
||||||
{
|
{
|
||||||
ResponseTime_P(PSTR(",\"PCA9685\":{\"PWM_FREQ\":%i,"),pca9685_freq);
|
ResponseTime_P(PSTR(",\"PCA9685\":{\"PWM_FREQ\":%i,"),pca9685_freq);
|
||||||
|
ResponseAppend_P(PSTR("\"INVERT\":%i,"), pca9685_inverted?1:0);
|
||||||
for (uint32_t pin=0;pin<16;pin++) {
|
for (uint32_t pin=0;pin<16;pin++) {
|
||||||
ResponseAppend_P(PSTR("\"PWM%i\":%i,"),pin,pca9685_pin_pwm_value[pin]);
|
uint16_t pwm_val = PCA9685_GetPWMvalue(pca9685_pin_pwm_value[pin], pca9685_inverted); // return logical (possibly inverted) pwm value
|
||||||
|
ResponseAppend_P(PSTR("\"PWM%i\":%i,"),pin,pwm_val);
|
||||||
}
|
}
|
||||||
ResponseAppend_P(PSTR("\"END\":1}}"));
|
ResponseAppend_P(PSTR("\"END\":1}}"));
|
||||||
if (telemetry) {
|
if (telemetry) {
|
||||||
|
|
Loading…
Reference in New Issue