From 757ab484ac7e0ecb6124bccbb6afcbe95f65bb4d Mon Sep 17 00:00:00 2001 From: Zachary Annand Date: Thu, 27 Aug 2020 14:18:16 -0500 Subject: [PATCH] Independent Neopixel option (#19115) --- Marlin/Configuration.h | 13 ++++- Marlin/Configuration_adv.h | 9 ++++ Marlin/src/MarlinCore.cpp | 4 ++ Marlin/src/feature/leds/leds.cpp | 51 +++++++++++++++---- Marlin/src/feature/leds/leds.h | 45 +++++++++++++++-- Marlin/src/feature/leds/neopixel.cpp | 53 ++++++++++++++++++- Marlin/src/feature/leds/neopixel.h | 70 ++++++++++++++++++++------ Marlin/src/gcode/feature/leds/M150.cpp | 28 +++++++++-- Marlin/src/inc/Conditionals_LCD.h | 5 ++ Marlin/src/inc/Conditionals_adv.h | 22 ++++++++ Marlin/src/inc/SanityCheck.h | 5 ++ 11 files changed, 269 insertions(+), 36 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 44f14a8ee3..8cd2faf7f8 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -2362,12 +2362,21 @@ #define NEOPIXEL_PIN 4 // LED driving pin //#define NEOPIXEL2_TYPE NEOPIXEL_TYPE //#define NEOPIXEL2_PIN 5 - //#define NEOPIXEL2_INSERIES // Default behavior is NeoPixel 2 in parallel - #define NEOPIXEL_PIXELS 30 // Number of LEDs in the strip, larger of 2 strips if 2 NeoPixel strips are used + #define NEOPIXEL_PIXELS 30 // Number of LEDs in the strip. (Longest strip when NEOPIXEL2_SEPARATE is disabled.) #define NEOPIXEL_IS_SEQUENTIAL // Sequential display for temperature change - LED by LED. Disable to change all LEDs at once. #define NEOPIXEL_BRIGHTNESS 127 // Initial brightness (0-255) //#define NEOPIXEL_STARTUP_TEST // Cycle through colors at startup + // Support for second Adafruit NeoPixel LED driver controlled with M150 S1 ... + //#define NEOPIXEL2_SEPARATE + #if ENABLED(NEOPIXEL2_SEPARATE) + #define NEOPIXEL2_PIXELS 15 // Number of LEDs in the second strip + #define NEOPIXEL2_BRIGHTNESS 127 // Initial brightness (0-255) + #define NEOPIXEL2_STARTUP_TEST // Cycle through colors at startup + #else + //#define NEOPIXEL2_INSERIES // Default behavior is NeoPixel 2 in parallel + #endif + // Use a single NeoPixel LED for static (background) lighting //#define NEOPIXEL_BKGD_LED_INDEX 0 // Index of the LED to use //#define NEOPIXEL_BKGD_COLOR { 255, 255, 255, 0 } // R, G, B, W diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 8df05e8a2c..e4b3fbf2ae 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -1065,6 +1065,7 @@ //#define LED_CONTROL_MENU #if ENABLED(LED_CONTROL_MENU) #define LED_COLOR_PRESETS // Enable the Preset Color menu option + //#define NEO2_COLOR_PRESETS // Enable a second NeoPixel Preset Color menu option #if ENABLED(LED_COLOR_PRESETS) #define LED_USER_PRESET_RED 255 // User defined RED value #define LED_USER_PRESET_GREEN 128 // User defined GREEN value @@ -1073,6 +1074,14 @@ #define LED_USER_PRESET_BRIGHTNESS 255 // User defined intensity //#define LED_USER_PRESET_STARTUP // Have the printer display the user preset color on startup #endif + #if ENABLED(NEO2_COLOR_PRESETS) + #define NEO2_USER_PRESET_RED 255 // User defined RED value + #define NEO2_USER_PRESET_GREEN 128 // User defined GREEN value + #define NEO2_USER_PRESET_BLUE 0 // User defined BLUE value + #define NEO2_USER_PRESET_WHITE 255 // User defined WHITE value + #define NEO2_USER_PRESET_BRIGHTNESS 255 // User defined intensity + //#define NEO2_USER_PRESET_STARTUP // Have the printer display the user preset color on startup for the second strip + #endif #endif #endif // HAS_LCD_MENU diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp index e040c3b26c..e703eaf8d9 100644 --- a/Marlin/src/MarlinCore.cpp +++ b/Marlin/src/MarlinCore.cpp @@ -995,6 +995,10 @@ void setup() { SETUP_RUN(leds.setup()); #endif + #if ENABLED(NEOPIXEL2_SEPARATE) + SETUP_RUN(leds2.setup()); + #endif + #if ENABLED(USE_CONTROLLER_FAN) // Set up fan controller to initialize also the default configurations. SETUP_RUN(controllerFan.setup()); #endif diff --git a/Marlin/src/feature/leds/leds.cpp b/Marlin/src/feature/leds/leds.cpp index d1c0bfd5e1..01bca80926 100644 --- a/Marlin/src/feature/leds/leds.cpp +++ b/Marlin/src/feature/leds/leds.cpp @@ -44,11 +44,8 @@ #if ENABLED(LED_COLOR_PRESETS) const LEDColor LEDLights::defaultLEDColor = MakeLEDColor( - LED_USER_PRESET_RED, - LED_USER_PRESET_GREEN, - LED_USER_PRESET_BLUE, - LED_USER_PRESET_WHITE, - LED_USER_PRESET_BRIGHTNESS + LED_USER_PRESET_RED, LED_USER_PRESET_GREEN, LED_USER_PRESET_BLUE, + LED_USER_PRESET_WHITE, LED_USER_PRESET_BRIGHTNESS ); #endif @@ -117,12 +114,13 @@ void LEDLights::set_color(const LEDColor &incol // This variant uses 3-4 separate pins for the RGB(W) components. // If the pins can do PWM then their intensity will be set. - #define UPDATE_RGBW(C,c) do { if (PWM_PIN(RGB_LED_##C##_PIN)) \ + #define UPDATE_RGBW(C,c) do { \ + if (PWM_PIN(RGB_LED_##C##_PIN)) \ analogWrite(pin_t(RGB_LED_##C##_PIN), incol.c); \ - else WRITE(RGB_LED_##C##_PIN, incol.c ? HIGH : LOW); }while(0) - UPDATE_RGBW(R,r); - UPDATE_RGBW(G,g); - UPDATE_RGBW(B,b); + else \ + WRITE(RGB_LED_##C##_PIN, incol.c ? HIGH : LOW); \ + }while(0) + UPDATE_RGBW(R,r); UPDATE_RGBW(G,g); UPDATE_RGBW(B,b); #if ENABLED(RGBW_LED) UPDATE_RGBW(W,w); #endif @@ -158,4 +156,35 @@ void LEDLights::set_color(const LEDColor &incol #endif -#endif // HAS_COLOR_LEDS +#if ENABLED(NEOPIXEL2_SEPARATE) + + #if ENABLED(NEO2_COLOR_PRESETS) + const LEDColor LEDLights2::defaultLEDColor = MakeLEDColor( + NEO2_USER_PRESET_RED, NEO2_USER_PRESET_GREEN, NEO2_USER_PRESET_BLUE, + NEO2_USER_PRESET_WHITE, NEO2_USER_PRESET_BRIGHTNESS + ); + #endif + + #if ENABLED(LED_CONTROL_MENU) + LEDColor LEDLights2::color; + bool LEDLights2::lights_on; + #endif + + LEDLights2 leds2; + + void LEDLights2::setup() { + neo2.init(); + TERN_(NEO2_USER_PRESET_STARTUP, set_default()); + } + + void LEDLights2::set_color(const LEDColor &incol) { + const uint32_t neocolor = LEDColorWhite() == incol + ? neo2.Color(NEO2_WHITE) + : neo2.Color(incol.r, incol.g, incol.b, incol.w); + neo2.set_brightness(incol.i); + neo2.set_color(neocolor); + } + +#endif // NEOPIXEL2_SEPARATE + +#endif // HAS_COLOR_LEDS diff --git a/Marlin/src/feature/leds/leds.h b/Marlin/src/feature/leds/leds.h index 1302f63c15..a13f960a3b 100644 --- a/Marlin/src/feature/leds/leds.h +++ b/Marlin/src/feature/leds/leds.h @@ -155,11 +155,9 @@ public: static inline void set_color(uint8_t r, uint8_t g, uint8_t b #if HAS_WHITE_LED , uint8_t w=0 - #if ENABLED(NEOPIXEL_LED) - , uint8_t i=NEOPIXEL_BRIGHTNESS - #endif #endif #if ENABLED(NEOPIXEL_LED) + , uint8_t i=NEOPIXEL_BRIGHTNESS , bool isSequence=false #endif ) { @@ -212,3 +210,44 @@ public: }; extern LEDLights leds; + +#if ENABLED(NEOPIXEL2_SEPARATE) + + class LEDLights2 { + public: + LEDLights2() {} + + static void setup(); // init() + + static void set_color(const LEDColor &color); + + inline void set_color(uint8_t r, uint8_t g, uint8_t b, uint8_t w=0, uint8_t i=NEOPIXEL2_BRIGHTNESS) { + set_color(MakeLEDColor(r, g, b, w, i)); + } + + static inline void set_off() { set_color(LEDColorOff()); } + static inline void set_green() { set_color(LEDColorGreen()); } + static inline void set_white() { set_color(LEDColorWhite()); } + + #if ENABLED(NEO2_COLOR_PRESETS) + static const LEDColor defaultLEDColor; + static inline void set_default() { set_color(defaultLEDColor); } + static inline void set_red() { set_color(LEDColorRed()); } + static inline void set_orange() { set_color(LEDColorOrange()); } + static inline void set_yellow() { set_color(LEDColorYellow()); } + static inline void set_blue() { set_color(LEDColorBlue()); } + static inline void set_indigo() { set_color(LEDColorIndigo()); } + static inline void set_violet() { set_color(LEDColorViolet()); } + #endif + + #if ENABLED(LED_CONTROL_MENU) + static LEDColor color; // last non-off color + static bool lights_on; // the last set color was "on" + static void toggle(); // swap "off" with color + static inline void update() { set_color(color); } + #endif + }; + + extern LEDLights2 leds2; + +#endif // NEOPIXEL2_SEPARATE diff --git a/Marlin/src/feature/leds/neopixel.cpp b/Marlin/src/feature/leds/neopixel.cpp index 12759302e6..27bbeb348c 100644 --- a/Marlin/src/feature/leds/neopixel.cpp +++ b/Marlin/src/feature/leds/neopixel.cpp @@ -30,7 +30,7 @@ #include "neopixel.h" -#if ENABLED(NEOPIXEL_STARTUP_TEST) +#if EITHER(NEOPIXEL_STARTUP_TEST, NEOPIXEL2_STARTUP_TEST) #include "../../core/utility.h" #endif @@ -38,7 +38,7 @@ Marlin_NeoPixel neo; int8_t Marlin_NeoPixel::neoindex; Adafruit_NeoPixel Marlin_NeoPixel::adaneo1(NEOPIXEL_PIXELS, NEOPIXEL_PIN, NEOPIXEL_TYPE + NEO_KHZ800) - #if EITHER(MULTIPLE_NEOPIXEL_TYPES, NEOPIXEL2_INSERIES) + #if CONJOINED_NEOPIXEL , Marlin_NeoPixel::adaneo2(NEOPIXEL_PIXELS, NEOPIXEL2_PIN, NEOPIXEL2_TYPE + NEO_KHZ800) #endif ; @@ -120,4 +120,53 @@ bool Marlin_NeoPixel::set_led_color(const uint8_t r, const uint8_t g, const uint } #endif +#if ENABLED(NEOPIXEL2_SEPARATE) + + Marlin_NeoPixel2 neo2; + + int8_t Marlin_NeoPixel2::neoindex; + Adafruit_NeoPixel Marlin_NeoPixel2::adaneo(NEOPIXEL2_PIXELS, NEOPIXEL2_PIN, NEOPIXEL2_TYPE); + + void Marlin_NeoPixel2::set_color(const uint32_t color) { + if (neoindex >= 0) { + set_pixel_color(neoindex, color); + neoindex = -1; + } + else { + for (uint16_t i = 0; i < pixels(); ++i) + set_pixel_color(i, color); + } + show(); + } + + void Marlin_NeoPixel2::set_color_startup(const uint32_t color) { + for (uint16_t i = 0; i < pixels(); ++i) + set_pixel_color(i, color); + show(); + } + + void Marlin_NeoPixel2::init() { + neoindex = -1; // -1 .. NEOPIXEL2_PIXELS-1 range + set_brightness(NEOPIXEL2_BRIGHTNESS); // 0 .. 255 range + begin(); + show(); // initialize to all off + + #if ENABLED(NEOPIXEL2_STARTUP_TEST) + set_color_startup(adaneo.Color(255, 0, 0, 0)); // red + safe_delay(500); + set_color_startup(adaneo.Color(0, 255, 0, 0)); // green + safe_delay(500); + set_color_startup(adaneo.Color(0, 0, 255, 0)); // blue + safe_delay(500); + #endif + + #if ENABLED(NEO2_USER_PRESET_STARTUP) + set_color(adaneo.Color(NEO2_USER_PRESET_RED, NEO2_USER_PRESET_GREEN, NEO2_USER_PRESET_BLUE, NEO2_USER_PRESET_WHITE)); + #else + set_color(adaneo.Color(0, 0, 0, 0)); + #endif + } + +#endif // NEOPIXEL2_SEPARATE + #endif // NEOPIXEL_LED diff --git a/Marlin/src/feature/leds/neopixel.h b/Marlin/src/feature/leds/neopixel.h index 0d9fdefc06..81a0a8b1c6 100644 --- a/Marlin/src/feature/leds/neopixel.h +++ b/Marlin/src/feature/leds/neopixel.h @@ -38,10 +38,14 @@ // Defines // ------------------------ -#if defined(NEOPIXEL2_TYPE) && NEOPIXEL2_TYPE != NEOPIXEL_TYPE +#if defined(NEOPIXEL2_TYPE) && NEOPIXEL2_TYPE != NEOPIXEL_TYPE && DISABLED(NEOPIXEL2_SEPARATE) #define MULTIPLE_NEOPIXEL_TYPES 1 #endif +#if EITHER(MULTIPLE_NEOPIXEL_TYPES, NEOPIXEL2_INSERIES) + #define CONJOINED_NEOPIXEL 1 +#endif + #if NEOPIXEL_TYPE == NEO_RGB || NEOPIXEL_TYPE == NEO_RBG || NEOPIXEL_TYPE == NEO_GRB || NEOPIXEL_TYPE == NEO_GBR || NEOPIXEL_TYPE == NEO_BRG || NEOPIXEL_TYPE == NEO_BGR #define NEOPIXEL_IS_RGB 1 #else @@ -61,7 +65,7 @@ class Marlin_NeoPixel { private: static Adafruit_NeoPixel adaneo1 - #if EITHER(MULTIPLE_NEOPIXEL_TYPES, NEOPIXEL2_INSERIES) + #if CONJOINED_NEOPIXEL , adaneo2 #endif ; @@ -80,11 +84,7 @@ public: static inline void begin() { adaneo1.begin(); - #if ENABLED(NEOPIXEL2_INSERIES) - adaneo2.begin(); - #else - TERN_(MULTIPLE_NEOPIXEL_TYPES, adaneo2.begin()); - #endif + TERN_(CONJOINED_NEOPIXEL, adaneo2.begin()); } static inline void set_pixel_color(const uint16_t n, const uint32_t c) { @@ -93,23 +93,21 @@ public: else adaneo1.setPixelColor(n, c); #else adaneo1.setPixelColor(n, c); - TERN_(MULTIPLE_NEOPIXEL_TYPES, adaneo2.setPixelColor(n, c)); + #if MULTIPLE_NEOPIXEL_TYPES + adaneo2.setPixelColor(n, c); + #endif #endif } static inline void set_brightness(const uint8_t b) { adaneo1.setBrightness(b); - #if ENABLED(NEOPIXEL2_INSERIES) - adaneo2.setBrightness(b); - #else - TERN_(MULTIPLE_NEOPIXEL_TYPES, adaneo2.setBrightness(b)); - #endif + TERN_(CONJOINED_NEOPIXEL, adaneo2.setBrightness(b)); } static inline void show() { adaneo1.show(); #if PIN_EXISTS(NEOPIXEL2) - #if EITHER(MULTIPLE_NEOPIXEL_TYPES, NEOPIXEL2_INSERIES) + #if CONJOINED_NEOPIXEL adaneo2.show(); #else adaneo1.setPin(NEOPIXEL2_PIN); @@ -132,3 +130,47 @@ public: }; extern Marlin_NeoPixel neo; + +// Neo pixel channel 2 +#if ENABLED(NEOPIXEL2_SEPARATE) + + #if NEOPIXEL2_TYPE == NEO_RGB || NEOPIXEL2_TYPE == NEO_RBG || NEOPIXEL2_TYPE == NEO_GRB || NEOPIXEL2_TYPE == NEO_GBR || NEOPIXEL2_TYPE == NEO_BRG || NEOPIXEL2_TYPE == NEO_BGR + #define NEOPIXEL2_IS_RGB 1 + #else + #define NEOPIXEL2_IS_RGBW 1 + #endif + + #if NEOPIXEL2_IS_RGB + #define NEO2_WHITE 255, 255, 255, 0 + #else + #define NEO2_WHITE 0, 0, 0, 255 + #endif + + class Marlin_NeoPixel2 { + private: + static Adafruit_NeoPixel adaneo; + + public: + static int8_t neoindex; + + static void init(); + static void set_color_startup(const uint32_t c); + + static void set_color(const uint32_t c); + + static inline void begin() { adaneo.begin(); } + static inline void set_pixel_color(const uint16_t n, const uint32_t c) { adaneo.setPixelColor(n, c); } + static inline void set_brightness(const uint8_t b) { adaneo.setBrightness(b); } + static inline void show() { adaneo.show(); } + + // Accessors + static inline uint16_t pixels() { return adaneo.numPixels();} + static inline uint8_t brightness() { return adaneo.getBrightness(); } + static inline uint32_t Color(uint8_t r, uint8_t g, uint8_t b, uint8_t w) { + return adaneo.Color(r, g, b, w); + } + }; + + extern Marlin_NeoPixel2 neo2; + +#endif // NEOPIXEL2_SEPARATE diff --git a/Marlin/src/gcode/feature/leds/M150.cpp b/Marlin/src/gcode/feature/leds/M150.cpp index 83bd24c41c..cf09bf14ea 100644 --- a/Marlin/src/gcode/feature/leds/M150.cpp +++ b/Marlin/src/gcode/feature/leds/M150.cpp @@ -37,6 +37,9 @@ * With NEOPIXEL_LED: * I Set the NeoPixel index to affect. Default: All * + * With NEOPIXEL2_SEPARATE: + * S The NeoPixel strip to set. Default is index 0. + * * Examples: * * M150 R255 ; Turn LED red @@ -47,18 +50,35 @@ * M150 P127 ; Set LED 50% brightness * M150 P ; Set LED full brightness * M150 I1 R ; Set NEOPIXEL index 1 to red + * M150 S1 I1 R ; Set SEPARATE index 1 to red */ + void GcodeSuite::M150() { #if ENABLED(NEOPIXEL_LED) - neo.neoindex = parser.intval('I', -1); + const uint8_t index = parser.intval('I', -1); + #if ENABLED(NEOPIXEL2_SEPARATE) + const uint8_t unit = parser.intval('S'), + brightness = unit ? neo2.brightness() : neo.brightness(); + *(unit ? &neo2.neoindex : &neo.neoindex) = index; + #else + const uint8_t brightness = neo.brightness(); + neo.neoindex = index; + #endif #endif - leds.set_color(MakeLEDColor( + + const LEDColor color = MakeLEDColor( parser.seen('R') ? (parser.has_value() ? parser.value_byte() : 255) : 0, parser.seen('U') ? (parser.has_value() ? parser.value_byte() : 255) : 0, parser.seen('B') ? (parser.has_value() ? parser.value_byte() : 255) : 0, parser.seen('W') ? (parser.has_value() ? parser.value_byte() : 255) : 0, - parser.seen('P') ? (parser.has_value() ? parser.value_byte() : 255) : neo.brightness() - )); + parser.seen('P') ? (parser.has_value() ? parser.value_byte() : 255) : brightness + ); + + #if ENABLED(NEOPIXEL2_SEPARATE) + if (unit == 1) { leds2.set_color(color); return; } + #endif + + leds.set_color(color); } #endif // HAS_COLOR_LEDS diff --git a/Marlin/src/inc/Conditionals_LCD.h b/Marlin/src/inc/Conditionals_LCD.h index 112ff93a0e..bbe89b7c50 100644 --- a/Marlin/src/inc/Conditionals_LCD.h +++ b/Marlin/src/inc/Conditionals_LCD.h @@ -780,3 +780,8 @@ #ifndef EXTRUDE_MINTEMP #define EXTRUDE_MINTEMP 170 #endif + +// This flag indicates if Neopixel pins are shared or separated +#if EITHER(MULTIPLE_NEOPIXEL_TYPES, NEOPIXEL2_INSERIES) + #define CONJOINED_NEOPIXEL 1 +#endif diff --git a/Marlin/src/inc/Conditionals_adv.h b/Marlin/src/inc/Conditionals_adv.h index fa4f0cd9b1..35542f9412 100644 --- a/Marlin/src/inc/Conditionals_adv.h +++ b/Marlin/src/inc/Conditionals_adv.h @@ -246,6 +246,28 @@ #endif #endif +#if BOTH(LED_CONTROL_MENU, NEOPIXEL2_SEPARATE) + #ifndef LED2_USER_PRESET_RED + #define LED2_USER_PRESET_RED 255 + #endif + #ifndef LED2_USER_PRESET_GREEN + #define LED2_USER_PRESET_GREEN 255 + #endif + #ifndef LED2_USER_PRESET_BLUE + #define LED2_USER_PRESET_BLUE 255 + #endif + #ifndef LED2_USER_PRESET_WHITE + #define LED2_USER_PRESET_WHITE 0 + #endif + #ifndef LED2_USER_PRESET_BRIGHTNESS + #ifdef NEOPIXEL2_BRIGHTNESS + #define LED2_USER_PRESET_BRIGHTNESS NEOPIXEL2_BRIGHTNESS + #else + #define LED2_USER_PRESET_BRIGHTNESS 255 + #endif + #endif +#endif + // If platform requires early initialization of watchdog to properly boot #if ENABLED(USE_WATCHDOG) && defined(ARDUINO_ARCH_SAM) #define EARLY_WATCHDOG 1 diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index b345147ed9..da5ddc1c2d 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -2120,7 +2120,12 @@ static_assert(hbm[Z_AXIS] >= 0, "HOMING_BUMP_MM.Z must be greater than or equal #if !(PIN_EXISTS(NEOPIXEL) && NEOPIXEL_PIXELS > 0) #error "NEOPIXEL_LED requires NEOPIXEL_PIN and NEOPIXEL_PIXELS." #endif + #elif ENABLED(NEOPIXEL2_SEPARATE) + #if !(PIN_EXISTS(NEOPIXEL2) && NEOPIXEL2_PIXELS > 0) + #error "NEOPIXEL2 requires NEOPIXEL2_PIN and NEOPIXEL2_PIXELS." + #endif #endif + #undef _RGB_TEST #if DISABLED(NO_COMPILE_TIME_PWM)