From 293a0997c9a7a84de37018581c1ccc6ef454c298 Mon Sep 17 00:00:00 2001
From: grauerfuchs <42082416+grauerfuchs@users.noreply.github.com>
Date: Wed, 8 Apr 2020 13:53:28 -0400
Subject: [PATCH] Fix / optimize PCA9533 LED (Mightyboard) (#17381)

---
 Marlin/Configuration.h                        |   1 -
 Marlin/src/feature/leds/leds.cpp              |   6 +-
 Marlin/src/feature/leds/pca9533.cpp           | 127 ++++++++++++++++++
 Marlin/src/feature/leds/pca9533.h             |  59 ++++++++
 .../variants/BIGTREE_SKR_PRO_1v1/variant.h    |   2 +-
 buildroot/share/tests/DUE-tests               |   2 +-
 buildroot/share/tests/rambo-tests             |   2 +-
 platformio.ini                                |  11 +-
 8 files changed, 197 insertions(+), 13 deletions(-)
 create mode 100644 Marlin/src/feature/leds/pca9533.cpp
 create mode 100644 Marlin/src/feature/leds/pca9533.h

diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h
index f02e69ee5a..175a5fbef3 100644
--- a/Marlin/Configuration.h
+++ b/Marlin/Configuration.h
@@ -2164,7 +2164,6 @@
 //#define PCA9632
 
 // Support for PCA9533 PWM LED driver
-// https://github.com/mikeshub/SailfishRGB_LED
 //#define PCA9533
 
 /**
diff --git a/Marlin/src/feature/leds/leds.cpp b/Marlin/src/feature/leds/leds.cpp
index 995693ffc5..13d60fd5b7 100644
--- a/Marlin/src/feature/leds/leds.cpp
+++ b/Marlin/src/feature/leds/leds.cpp
@@ -39,7 +39,7 @@
 #endif
 
 #if ENABLED(PCA9533)
-  #include <SailfishRGB_LED.h>
+  #include "pca9533.h"
 #endif
 
 #if ENABLED(LED_COLOR_PRESETS)
@@ -72,7 +72,7 @@ void LEDLights::setup() {
     neo.init();
   #endif
   #if ENABLED(PCA9533)
-    RGBinit();
+    PCA9533_init();
   #endif
   #if ENABLED(LED_USER_PRESET_STARTUP)
     set_default();
@@ -141,7 +141,7 @@ void LEDLights::set_color(const LEDColor &incol
   #endif
 
   #if ENABLED(PCA9533)
-    RGBsetColor(incol.r, incol.g, incol.b, true);
+    PCA9533_setColor(incol.r, incol.g, incol.b);
   #endif
 
   #if EITHER(LED_CONTROL_MENU, PRINTER_EVENT_LEDS)
diff --git a/Marlin/src/feature/leds/pca9533.cpp b/Marlin/src/feature/leds/pca9533.cpp
new file mode 100644
index 0000000000..82bdaf6665
--- /dev/null
+++ b/Marlin/src/feature/leds/pca9533.cpp
@@ -0,0 +1,127 @@
+/*
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * 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/>.
+ *
+ */
+
+/**
+ * PCA9533 LED controller driver (MightyBoard, FlashForge Creator Pro, etc.)
+ *  by @grauerfuchs - 1 Apr 2020
+ */
+#include "../../inc/MarlinConfig.h"
+
+#if ENABLED(PCA9533)
+
+#include "pca9533.h"
+#include <Wire.h>
+
+void PCA9533_init() {
+  Wire.begin();
+  PCA9533_reset();
+}
+
+static void PCA9533_writeAllRegisters(uint8_t psc0, uint8_t pwm0, uint8_t psc1, uint8_t pwm1, uint8_t ls0){
+  uint8_t data[6] = { PCA9533_REG_PSC0 | PCA9533_REGM_AI, psc0, pwm0, psc1, pwm1, ls0 };
+  Wire.beginTransmission(PCA9533_Addr >> 1);
+  Wire.write(data, 6);
+  Wire.endTransmission();
+  delayMicroseconds(1);
+}
+
+static void PCA9533_writeRegister(uint8_t reg, uint8_t val){
+  uint8_t data[2] = { reg, val };
+  Wire.beginTransmission(PCA9533_Addr >> 1);
+  Wire.write(data, 2);
+  Wire.endTransmission();
+  delayMicroseconds(1);
+}
+
+// Reset (clear) all registers
+void PCA9533_reset() {
+  PCA9533_writeAllRegisters(0, 0, 0, 0, 0);
+}
+
+// Turn all LEDs off
+void PCA9533_setOff() {
+  PCA9533_writeRegister(PCA9533_REG_SEL, 0);
+}
+
+void PCA9533_setColor(uint8_t red, uint8_t green, uint8_t blue) {
+  uint8_t r_pwm0 = 0; // Register data - PWM value
+  uint8_t r_pwm1 = 0; // Register data - PWM value
+
+  uint8_t op_g = 0, op_r = 0, op_b = 0; // Opcodes - Green, Red, Blue
+
+  // Light theory! GREEN takes priority because
+  // it's the most visible to the human eye.
+       if (green ==   0)  op_g = PCA9533_LED_OP_OFF;
+  else if (green == 255)  op_g = PCA9533_LED_OP_ON;
+  else { r_pwm0 = green;  op_g = PCA9533_LED_OP_PWM0; }
+
+  // RED
+       if (red ==   0)    op_r = PCA9533_LED_OP_OFF;
+  else if (red == 255)    op_r = PCA9533_LED_OP_ON;
+  else if (r_pwm0 == 0 || r_pwm0 == red) {
+         r_pwm0 = red;    op_r = PCA9533_LED_OP_PWM0;
+  }
+  else {
+         r_pwm1 = red;    op_r = PCA9533_LED_OP_PWM1;
+  }
+
+  // BLUE
+       if (blue ==   0)   op_b = PCA9533_LED_OP_OFF;
+  else if (blue == 255)   op_b = PCA9533_LED_OP_ON;
+  else if (r_pwm0 == 0 || r_pwm0 == blue) {
+         r_pwm0 = blue;   op_b = PCA9533_LED_OP_PWM0;
+  }
+  else if (r_pwm1 == 0 || r_pwm1 == blue) {
+         r_pwm1 = blue;   op_b = PCA9533_LED_OP_PWM1;
+  }
+  else {
+    /**
+     * Conflict. 3 values are requested but only 2 channels exist.
+     * G is on channel 0 and R is on channel 1, so work from there.
+     * Find the closest match, average the values, then use the free channel.
+     */
+    uint8_t dgb = ABS(green - blue),
+            dgr = ABS(green - red),
+            dbr = ABS(blue - red);
+    if (dgb < dgr && dgb < dbr) {         // Mix with G on channel 0.
+      op_b = PCA9533_LED_OP_PWM0;
+      r_pwm0 = uint8_t(((uint16_t)green + (uint16_t)blue) / 2);
+    }
+    else if (dbr <= dgr && dbr <= dgb) {  // Mix with R on channel 1.
+      op_b = PCA9533_LED_OP_PWM1;
+      r_pwm1 = uint8_t(((uint16_t)red + (uint16_t)blue) / 2);
+    }
+    else {                                // Mix R+G on 0 and put B on 1.
+      op_r = PCA9533_LED_OP_PWM0;
+      r_pwm0 = uint8_t(((uint16_t)green + (uint16_t)red) / 2);
+      op_b = PCA9533_LED_OP_PWM1;
+      r_pwm1 = blue;
+    }
+  }
+
+  // Write the changes to the hardware
+  PCA9533_writeAllRegisters(0, r_pwm0, 0, r_pwm1,
+    (op_g << PCA9533_LED_OFS_GRN) | (op_r << PCA9533_LED_OFS_RED) | (op_b << PCA9533_LED_OFS_BLU)
+  );
+}
+
+#endif // PCA9533
diff --git a/Marlin/src/feature/leds/pca9533.h b/Marlin/src/feature/leds/pca9533.h
new file mode 100644
index 0000000000..a134ca15fd
--- /dev/null
+++ b/Marlin/src/feature/leds/pca9533.h
@@ -0,0 +1,59 @@
+/*
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * 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/>.
+ *
+ */
+#pragma once
+
+/*
+ * Driver for the PCA9533 LED controller found on the MightyBoard
+ * used by FlashForge Creator Pro, MakerBot, etc.
+ * Written 2020 APR 01 by grauerfuchs
+ */
+#include <Arduino.h>
+
+#define ENABLE_I2C_PULLUPS
+
+// Chip address (for Wire)
+#define PCA9533_Addr        0xC4 
+
+// Control registers
+#define PCA9533_REG_READ    0x00
+#define PCA9533_REG_PSC0    0x01
+#define PCA9533_REG_PWM0    0x02
+#define PCA9533_REG_PSC1    0x03
+#define PCA9533_REG_PWM1    0x04
+#define PCA9533_REG_SEL     0x05
+#define PCA9533_REGM_AI     0x10
+
+// LED selector operation
+#define PCA9533_LED_OP_OFF  0B00
+#define PCA9533_LED_OP_ON   0B01
+#define PCA9533_LED_OP_PWM0 0B10
+#define PCA9533_LED_OP_PWM1 0B11
+
+// Select register bit offsets for LED colors
+#define PCA9533_LED_OFS_RED 0
+#define PCA9533_LED_OFS_GRN 2
+#define PCA9533_LED_OFS_BLU 4
+
+void PCA9533_init();
+void PCA9533_reset();
+void PCA9533_setColor(uint8_t red, uint8_t green, uint8_t blue);
+void PCA9533_setOff();
diff --git a/buildroot/share/PlatformIO/variants/BIGTREE_SKR_PRO_1v1/variant.h b/buildroot/share/PlatformIO/variants/BIGTREE_SKR_PRO_1v1/variant.h
index 5ff2ea5768..0eab1abe53 100644
--- a/buildroot/share/PlatformIO/variants/BIGTREE_SKR_PRO_1v1/variant.h
+++ b/buildroot/share/PlatformIO/variants/BIGTREE_SKR_PRO_1v1/variant.h
@@ -234,7 +234,7 @@ extern "C" {
 
 // On-board LED pin number
 #define LED_BUILTIN             PA7
-//#define LED_GREEN             LED_BUILTIN   should be defined here but omitted to avoid redefinition in SailfishRGB_LED
+#define LED_GREEN               LED_BUILTIN
 
 // Below SPI and I2C definitions already done in the core
 // Could be redefined here if differs from the default one
diff --git a/buildroot/share/tests/DUE-tests b/buildroot/share/tests/DUE-tests
index cfce93a92e..0d9b95e1cf 100755
--- a/buildroot/share/tests/DUE-tests
+++ b/buildroot/share/tests/DUE-tests
@@ -16,7 +16,7 @@ opt_set FANMUX0_PIN 53
 opt_enable S_CURVE_ACCELERATION EEPROM_SETTINGS GCODE_MACROS \
            PIDTEMPBED FIX_MOUNTED_PROBE Z_SAFE_HOMING CODEPENDENT_XY_HOMING \
            EEPROM_SETTINGS SDSUPPORT BINARY_FILE_TRANSFER \
-           BLINKM PCA9632 RGB_LED RGB_LED_R_PIN RGB_LED_G_PIN RGB_LED_B_PIN LED_CONTROL_MENU \
+           BLINKM PCA9533 PCA9632 RGB_LED RGB_LED_R_PIN RGB_LED_G_PIN RGB_LED_B_PIN LED_CONTROL_MENU \
            NEOPIXEL_LED CASE_LIGHT_ENABLE CASE_LIGHT_USE_NEOPIXEL CASE_LIGHT_MENU \
            NOZZLE_PARK_FEATURE ADVANCED_PAUSE_FEATURE FILAMENT_RUNOUT_DISTANCE_MM FILAMENT_RUNOUT_SENSOR \
            AUTO_BED_LEVELING_BILINEAR Z_MIN_PROBE_REPEATABILITY_TEST DEBUG_LEVELING_FEATURE \
diff --git a/buildroot/share/tests/rambo-tests b/buildroot/share/tests/rambo-tests
index 57c363c3a4..7fab4fc6ca 100644
--- a/buildroot/share/tests/rambo-tests
+++ b/buildroot/share/tests/rambo-tests
@@ -53,7 +53,7 @@ opt_enable REPRAP_DISCOUNT_SMART_CONTROLLER LCD_PROGRESS_BAR LCD_PROGRESS_BAR_TE
            FIX_MOUNTED_PROBE Z_SAFE_HOMING CODEPENDENT_XY_HOMING PIDTEMPBED PROBE_TEMP_COMPENSATION \
            PROBING_HEATERS_OFF PROBING_FANS_OFF PROBING_STEPPERS_OFF WAIT_FOR_BED_HEATER \
            EEPROM_SETTINGS SDSUPPORT SD_REPRINT_LAST_SELECTED_FILE BINARY_FILE_TRANSFER \
-           BLINKM PCA9632 RGB_LED RGB_LED_R_PIN RGB_LED_G_PIN RGB_LED_B_PIN LED_CONTROL_MENU \
+           BLINKM PCA9533 PCA9632 RGB_LED RGB_LED_R_PIN RGB_LED_G_PIN RGB_LED_B_PIN LED_CONTROL_MENU \
            NEOPIXEL_LED CASE_LIGHT_ENABLE CASE_LIGHT_USE_NEOPIXEL CASE_LIGHT_MENU \
            PID_PARAMS_PER_HOTEND PID_AUTOTUNE_MENU PID_EDIT_MENU LCD_SHOW_E_TOTAL \
            PRINTCOUNTER SERVICE_NAME_1 SERVICE_INTERVAL_1 LEVEL_BED_CORNERS \
diff --git a/platformio.ini b/platformio.ini
index f7fb31ec2e..2ba1c5c1f3 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -33,7 +33,6 @@ lib_deps =
   LiquidTWI2=https://github.com/lincomatic/LiquidTWI2/archive/master.zip
   Arduino-L6470=https://github.com/ameyer/Arduino-L6470/archive/0.8.0.zip
   SailfishLCD=https://github.com/mikeshub/SailfishLCD/archive/master.zip
-  SailfishRGB_LED=https://github.com/mikeshub/SailfishRGB_LED/archive/master.zip
   SlowSoftI2CMaster=https://github.com/mikeshub/SlowSoftI2CMaster/archive/master.zip
 
 # Globally defined properties
@@ -623,7 +622,7 @@ build_flags       = ${common.build_flags}
 build_unflags     = -std=gnu++11
 extra_scripts     = pre:buildroot/share/PlatformIO/scripts/generic_create_variant.py
   buildroot/share/PlatformIO/scripts/STEVAL__F401XX.py
-lib_ignore        = Adafruit NeoPixel, TMCStepper, SailfishLCD, SailfishRGB_LED, SlowSoftI2CMaster, SoftwareSerial
+lib_ignore        = Adafruit NeoPixel, TMCStepper, SailfishLCD, SlowSoftI2CMaster, SoftwareSerial
 src_filter        = ${common.default_src_filter} +<src/HAL/STM32>
 
 #
@@ -639,7 +638,7 @@ build_flags       = ${common.build_flags}
   -IMarlin/src/HAL/STM32
 build_unflags     = -std=gnu++11
 extra_scripts     = pre:buildroot/share/PlatformIO/scripts/generic_create_variant.py
-lib_ignore        = Adafruit NeoPixel, TMCStepper, SailfishLCD, SailfishRGB_LED, SlowSoftI2CMaster, SoftwareSerial
+lib_ignore        = Adafruit NeoPixel, TMCStepper, SailfishLCD, SlowSoftI2CMaster, SoftwareSerial
 src_filter        = ${common.default_src_filter} +<src/HAL/STM32>
 
 
@@ -679,7 +678,7 @@ build_flags       = ${common.build_flags}
   -IMarlin/src/HAL/STM32
 build_unflags     = -std=gnu++11
 extra_scripts     = pre:buildroot/share/PlatformIO/scripts/generic_create_variant.py
-lib_ignore        = Adafruit NeoPixel, TMCStepper, SailfishLCD, SailfishRGB_LED, SlowSoftI2CMaster, SoftwareSerial
+lib_ignore        = Adafruit NeoPixel, TMCStepper, SailfishLCD, SlowSoftI2CMaster, SoftwareSerial
 src_filter        = ${common.default_src_filter} +<src/HAL/STM32>
 
 #
@@ -742,7 +741,7 @@ build_flags       = ${common.build_flags}
   -DPIN_SERIAL2_TX=PD_5
 build_unflags     = -std=gnu++11
 extra_scripts     = pre:buildroot/share/PlatformIO/scripts/generic_create_variant.py
-lib_ignore        = Adafruit NeoPixel, SailfishLCD, SailfishRGB_LED, SlowSoftI2CMaster
+lib_ignore        = Adafruit NeoPixel, SailfishLCD, SlowSoftI2CMaster
 src_filter        = ${common.default_src_filter} +<src/HAL/STM32>
 
 #
@@ -780,7 +779,7 @@ lib_deps      = ${common.lib_deps}
   ESP3DLib=https://github.com/luc-github/ESP3DLib.git
   arduinoWebSockets=https://github.com/Links2004/arduinoWebSockets.git
   ESP32SSDP=https://github.com/luc-github/ESP32SSDP.git
-lib_ignore    = LiquidCrystal, LiquidTWI2, SailfishLCD, SailfishRGB_LED, ESPAsyncTCP
+lib_ignore    = LiquidCrystal, LiquidTWI2, SailfishLCD, ESPAsyncTCP
 src_filter    = ${common.default_src_filter} +<src/HAL/ESP32>
 upload_speed  = 115200
 #upload_port   = marlinesp.local
-- 
GitLab