From 8760b8f03b02640425704412087257b156b8ac58 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 14 Aug 2020 15:10:02 +0200 Subject: [PATCH] Add SM2135 support for BGR Add SM2135 support for BGR and GRB color bulbs thanks to CrudelisPL (#9073) --- tasmota/xlgt_04_sm2135.ino | 155 ++++++++++++++++++++++--------------- 1 file changed, 94 insertions(+), 61 deletions(-) diff --git a/tasmota/xlgt_04_sm2135.ino b/tasmota/xlgt_04_sm2135.ino index e262395a8..b48da2308 100644 --- a/tasmota/xlgt_04_sm2135.ino +++ b/tasmota/xlgt_04_sm2135.ino @@ -1,7 +1,7 @@ /* xlgt_04_sm2135.ino - sm2135 five channel led support for Tasmota - Copyright (C) 2020 Theo Arends + Copyright (C) 2020 Theo Arends and CrudelisPL 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 @@ -20,9 +20,12 @@ #ifdef USE_LIGHT #ifdef USE_SM2135 /*********************************************************************************************\ - * SM2135 RGBCW Led bulbs like some Action LSC SmartLed + * SM2135 RGBCW Led bulbs like some Action LSC SmartLed or Polux * + * Action LSC SmartLed (GreenRedBlue) * {"NAME":"LSC RGBCW LED","GPIO":[0,0,0,0,0,0,0,0,181,0,180,0,0],"FLAG":0,"BASE":18} + * Polux E14 (BlueGreenRed) - Notice GPIO00 = 9 (Switch1) + * {"NAME":"Polux RGBCW E14","GPIO":[9,0,0,0,0,0,0,0,181,0,180,0,0],"FLAG":0,"BASE":18} \*********************************************************************************************/ #define XLGT_04 4 @@ -50,84 +53,110 @@ #define SM2135_55MA 0x09 #define SM2135_60MA 0x0A +enum Sm2135Color { SM2135_WCGRB, SM2135_WCBGR }; + // RGB current CW current const uint8_t SM2135_CURRENT = (SM2135_20MA << 4) | SM2135_15MA; // See https://github.com/arendst/Tasmota/issues/6495#issuecomment-549121683 struct SM2135 { uint8_t clk = 0; uint8_t data = 0; + uint8_t model = SM2135_WCGRB; } Sm2135; -uint8_t Sm2135Write(uint8_t data) -{ - for (uint32_t i = 0; i < 8; i++) { - digitalWrite(Sm2135.clk, LOW); - digitalWrite(Sm2135.data, (data & 0x80)); - digitalWrite(Sm2135.clk, HIGH); - data = data << 1; - } - digitalWrite(Sm2135.clk, LOW); - digitalWrite(Sm2135.data, HIGH); - pinMode(Sm2135.data, INPUT); - digitalWrite(Sm2135.clk, HIGH); - uint8_t ack = digitalRead(Sm2135.data); - pinMode(Sm2135.data, OUTPUT); - return ack; +/*********************************************************************************************\ + * SM2135 code +\*********************************************************************************************/ + +const uint8_t SM2135_DELAY = 4; + +void Sm2135SetLow(uint8_t pin) { + noInterrupts(); + digitalWrite(pin, LOW); + pinMode(pin, OUTPUT); + interrupts(); } -void Sm2135Send(uint8_t *buffer, uint8_t size) -{ +void Sm2135SetHigh(uint8_t pin) { + noInterrupts(); + pinMode(pin, INPUT_PULLUP); + interrupts(); +} + +bool Sm2135Init(void) { digitalWrite(Sm2135.data, LOW); - for (uint32_t i = 0; i < size; i++) { - Sm2135Write(buffer[i]); - } digitalWrite(Sm2135.clk, LOW); - digitalWrite(Sm2135.clk, HIGH); - digitalWrite(Sm2135.data, HIGH); + Sm2135SetHigh(Sm2135.data); + Sm2135SetHigh(Sm2135.clk); + return (!((digitalRead(Sm2135.data) == LOW || digitalRead(Sm2135.clk) == LOW))); +} + +bool Sm2135Write(uint8_t value) { + for (uint8_t curr = 0X80; curr != 0; curr >>= 1) { + if (curr & value) { + Sm2135SetHigh(Sm2135.data); + } else { + Sm2135SetLow(Sm2135.data); + } + Sm2135SetHigh(Sm2135.clk); + delayMicroseconds(SM2135_DELAY); + Sm2135SetLow(Sm2135.clk); + } + // get Ack or Nak + Sm2135SetHigh(Sm2135.data); + Sm2135SetHigh(Sm2135.clk); + delayMicroseconds(SM2135_DELAY / 2); + uint8_t ack = digitalRead(Sm2135.data); + Sm2135SetLow(Sm2135.clk); + delayMicroseconds(SM2135_DELAY / 2); + Sm2135SetLow(Sm2135.data); + return (0 == ack); +} + +bool Sm2135Start(uint8_t addr) { + Sm2135SetLow(Sm2135.data); + delayMicroseconds(SM2135_DELAY); + Sm2135SetLow(Sm2135.clk); + return Sm2135Write(addr); +} + +void Sm2135Stop(void) { + Sm2135SetLow(Sm2135.data); + delayMicroseconds(SM2135_DELAY); + Sm2135SetHigh(Sm2135.clk); + delayMicroseconds(SM2135_DELAY); + Sm2135SetHigh(Sm2135.data); + delayMicroseconds(SM2135_DELAY); } /********************************************************************************************/ -bool Sm2135SetChannels(void) -{ +bool Sm2135SetChannels(void) { uint8_t *cur_col = (uint8_t*)XdrvMailbox.data; uint8_t data[6]; + Sm2135Start(SM2135_ADDR_MC); + Sm2135Write(SM2135_CURRENT); if ((0 == cur_col[0]) && (0 == cur_col[1]) && (0 == cur_col[2])) { - // No color so must be Cold/Warm -/* - if ((cur_col[3] + cur_col[4]) >= (1 * 256)) { - // Scale down to 255 total to fix max power usage of 9W (=40mA) - -// cur_col[3] >>= 1; // Divide by 2 -// cur_col[4] >>= 1; // Divide by 2 - } -*/ - data[0] = SM2135_ADDR_MC; - data[1] = SM2135_CURRENT; - data[2] = SM2135_CW; - Sm2135Send(data, 3); + Sm2135Write(SM2135_CW); + Sm2135Stop(); delay(1); - data[0] = SM2135_ADDR_C; - data[1] = cur_col[4]; // Warm - data[2] = cur_col[3]; // Cold - Sm2135Send(data, 3); + Sm2135Start(SM2135_ADDR_C); + Sm2135Write(cur_col[4]); // Warm + Sm2135Write(cur_col[3]); // Cold } else { - // Color -/* - if ((cur_col[0] + cur_col[1] + cur_col[2]) >= (3 * 256)) { - // Scale down to 765 total to fix max power usage of 9W - // Currently not needed with setting 3 x 15mA = 45mA = 11W = 765 + Sm2135Write(SM2135_RGB); + if (SM2135_WCBGR == Sm2135.model) { + Sm2135Write(cur_col[2]); // Blue + Sm2135Write(cur_col[1]); // Green + Sm2135Write(cur_col[0]); // Red + } else { + Sm2135Write(cur_col[1]); // Green + Sm2135Write(cur_col[0]); // Red + Sm2135Write(cur_col[2]); // Blue } -*/ - data[0] = SM2135_ADDR_MC; - data[1] = SM2135_CURRENT; - data[2] = SM2135_RGB; - data[3] = cur_col[1]; // Green - data[4] = cur_col[0]; // Red - data[5] = cur_col[2]; // Blue - Sm2135Send(data, 6); } + Sm2135Stop(); return true; } @@ -138,14 +167,18 @@ void Sm2135ModuleSelected(void) Sm2135.clk = Pin(GPIO_SM2135_CLK); Sm2135.data = Pin(GPIO_SM2135_DAT); - pinMode(Sm2135.data, OUTPUT); - digitalWrite(Sm2135.data, HIGH); - pinMode(Sm2135.clk, OUTPUT); - digitalWrite(Sm2135.clk, HIGH); + Sm2135.model = SM2135_WCGRB; + if (PinUsed(GPIO_SWT1)) { + Sm2135.model = SM2135_WCBGR; + pinMode(Pin(GPIO_SWT1), INPUT); // Discard GPIO_SWT functionality + SetPin(Pin(GPIO_SWT1), AGPIO(GPIO_NONE)); + } + + Sm2135Init(); light_type = LT_RGBWC; light_flg = XLGT_04; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DBG: SM2135 Found")); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DBG: SM2135 (%s) Found"), (SM2135_WCBGR == Sm2135.model) ? PSTR("BGR") : PSTR("GRB")); } }