diff --git a/src/NeoPixelesp8266.c b/src/NeoPixelesp8266.c new file mode 100644 index 0000000..6ecff6e --- /dev/null +++ b/src/NeoPixelesp8266.c @@ -0,0 +1,104 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for Esp8266 and Esp32. + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) + +#include +#if defined(ARDUINO_ARCH_ESP8266) +#include +#endif + +// ESP32 doesn't define ICACHE_RAM_ATTR +#ifndef ICACHE_RAM_ATTR +#define ICACHE_RAM_ATTR IRAM_ATTR +#endif + +inline uint32_t _getCycleCount() +{ + uint32_t ccount; + __asm__ __volatile__("rsr %0,ccount":"=a" (ccount)); + return ccount; +} + +//#define CYCLES_800_T0H (F_CPU / 2500000) // 0.4us +//#define CYCLES_800_T1H (F_CPU / 1250000) // 0.8us +//#define CYCLES_800 (F_CPU / 800000) // 1.25us per bit +#define CYCLES_800_T0H (F_CPU / 2600000) // 0.4us +#define CYCLES_800_T1H (F_CPU / 1350000) // 0.8us +#define CYCLES_800 (F_CPU / 900000) // 1.25us per bit + +void ICACHE_RAM_ATTR send_pixels_800(uint8_t* pixels, size_t count, uint8_t pin) +{ + const uint32_t pinRegister = _BV(pin); + uint8_t mask; + uint8_t subpix; + uint32_t cyclesStart; + uint8_t *end = pixels + (3 * count); + + // trigger emediately + cyclesStart = _getCycleCount() - CYCLES_800; + do + { + subpix = *pixels++; + for (mask = 0x80; mask != 0; mask >>= 1) + { + // do the checks here while we are waiting on time to pass + uint32_t cyclesBit = ((subpix & mask)) ? CYCLES_800_T1H : CYCLES_800_T0H; + uint32_t cyclesNext = cyclesStart; + + // after we have done as much work as needed for this next bit + // now wait for the HIGH + do + { + // cache and use this count so we don't incur another + // instruction before we turn the bit high + cyclesStart = _getCycleCount(); + } while ((cyclesStart - cyclesNext) < CYCLES_800); + + // set high +#if defined(ARDUINO_ARCH_ESP32) + GPIO.out_w1ts = pinRegister; +#else + GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinRegister); +#endif + + // wait for the LOW + do + { + cyclesNext = _getCycleCount(); + } while ((cyclesNext - cyclesStart) < cyclesBit); + + // set low +#if defined(ARDUINO_ARCH_ESP32) + GPIO.out_w1tc = pinRegister; +#else + GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinRegister); +#endif + } + } while (pixels < end); +} + +#endif diff --git a/src/wsLED.cpp b/src/wsLED.cpp new file mode 100644 index 0000000..a824f75 --- /dev/null +++ b/src/wsLED.cpp @@ -0,0 +1,145 @@ +// Ovladani signalizacni chytre LED diody +#include "wsLED.h" +// due to linker overriding the ICACHE_RAM_ATTR for cpp files, these methods are +// moved into a C file so the attribute will be applied correctly +extern "C" void ICACHE_RAM_ATTR send_pixels_800(uint8_t* pixel, size_t count, uint8_t pin); + +#define countof(a) (sizeof(a) / sizeof(a[0])) + +static const uint16_t LB[] PROGMEM = { + 0x201 , 0x202 , 0x103 , 0x104 , 0x105 , 0x106 , 0x107 , 0x109 , 0x10a , 0x10c , 0x10e , 0x110 , 0x112 , 0x114 , 0x116 , 0x119 , 0x11c , 0x11e , 0x122 , 0x125 , 0x128 , 0x12c , 0x130 , 0x134, + 0x139 , 0x13d , 0x142 , 0x147 , 0x14d , 0x152 , 0x158 , 0x15e , 0x165 , 0x16b , 0x172 , 0x179 , 0x180 , 0x187 , 0x18e , 0x196 , 0x19d , 0x1a5 , 0x1ac , 0x1b3 , 0x1bb , 0x1c2 , 0x1c9 , 0x1cf, + 0x1d6 , 0x1dc , 0x1e2 , 0x1e7 , 0x1ec , 0x1f0 , 0x1f4 , 0x1f7 , 0x1fa , 0x1fc , 0x1fd , 0x3fe , 0x1fd , 0x1fb , 0x1f8 , 0x1f5 , 0x1f2 , 0x1ed , 0x1e9 , 0x1e4 , 0x1de , 0x1d8 , 0x1d2 , 0x1cb, + 0x1c4 , 0x1bd , 0x1b6 , 0x1af , 0x1a7 , 0x1a0 , 0x198 , 0x191 , 0x18a , 0x182 , 0x17b , 0x174 , 0x16d , 0x167 , 0x161 , 0x15a , 0x154 , 0x14f , 0x149 , 0x144 , 0x13f , 0x13a , 0x136 , 0x131, + 0x12d , 0x12a , 0x126 , 0x123 , 0x11f , 0x11c , 0x11a , 0x117 , 0x115 , 0x112 , 0x110 , 0x10e , 0x10c , 0x10b , 0x109 , 0x108 , 0x107 , 0x105 , 0x104 , 0x203 , 0x102 , 0x201 , 0x2a00 +}; + +inline bool wsLED::canShow(void) +{ + + return (micros() - _endtime) >= 50L; +} + +void wsLED::show(void) +{ + uint8_t color[3]; + + for (uint8_t i = 0; i < 3; i++) { +// https://github.com/FastLED/FastLED/wiki/FastLED-Color-Correction + uint16_t c = (uint16_t)_color[i] * (1 + (uint16_t)_scale); + color[i] = (uint8_t)(c >> 8); + } + while (!canShow()) + __asm__ volatile ("nop"); +#if defined(ARDUINO_ARCH_ESP32) + uint32_t volatile register ilevel = XTOS_DISABLE_ALL_INTERRUPTS; +#else + noInterrupts(); + //cli(); +#endif + send_pixels_800(color, 1, _pin); +#if defined(ARDUINO_ARCH_ESP32) + XTOS_RESTORE_INTLEVEL(ilevel); +#else + interrupts(); + //sei(); +#endif + _endtime = micros(); +} + + +wsLED::wsLED(int pin, int order) +{ + + _pin = pin; + _order = order; +} + +void wsLED::begin(void) +{ + + pinMode(_pin, OUTPUT); + _color[0] = _color[1] = _color[2] = 0; + show(); +} + +void wsLED::setColor(LEDRGB &color) +{ + + _color[(_order >> 6) & 7] = color.r; + _color[(_order >> 3) & 7] = color.g; + _color[_order & 7] = color.b; +} + +void ICACHE_RAM_ATTR wsLED::rtLed(void) +{ + + switch (_ledState) { + case LED_BLINK: + _scale = 0xff; + if (_subState) { + _subState = 0; + setColor(_color2); + } else { + _subState = 1; + setColor(_color1); + } + show(); + break; + + + case LED_BREATH: { + ++_subState; + _subState %= countof(LB); + uint16_t val = pgm_read_word(&LB[_subState]); + _scale = (uint8_t)val; + show(); + val >>= 8; + _handler.attach_ms(30ul * val, lh, this); + break; + } + + default: + _handler.attach_ms(300, lh, this); // jen pomale casovani + break; + } +} + +void ICACHE_RAM_ATTR wsLED::lh(wsLED *ptr) +{ + + wsLED *pled = ptr; + pled->rtLed(); +} + +void wsLED::setColors(LEDRGB color1, LEDRGB color2) +{ + + _color1 = color1; + _color2 = color2; +} + +void wsLED::blink(int speed) +{ + + _handler.detach(); + _ledState = LED_BLINK; + _subState = 1; + _handler.attach_ms(300, lh, this); +} + +void wsLED::breath(void) +{ + + _handler.detach(); + _ledState = LED_BREATH; + _subState = 0; + setColor(_color1); + _handler.attach_ms(1, lh, this); +} + +void wsLED::setOrder(int neworder) +{ + + _order = neworder; +} diff --git a/src/wsLED.h b/src/wsLED.h new file mode 100644 index 0000000..aec7773 --- /dev/null +++ b/src/wsLED.h @@ -0,0 +1,151 @@ +// Ovladani RGB WS2812 LED diody pro signalizacni ucely +/**The MIT License (MIT) +Copyright (c) 2017,2020 by Pavel Brychta +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +See more at http://www.xpablo.cz +*/ + +#ifndef __WSLED_H__ +#define __WSLED_H__ +#include +#include + +struct LEDRGB { + union { + struct { + union { + uint8_t r; + uint8_t red; + }; + union { + uint8_t g; + uint8_t green; + }; + union { + uint8_t b; + uint8_t blue; + }; + }; + uint8_t raw[3]; + }; + + // Array access operator to index into the crgb object + inline uint8_t& operator[] (uint8_t x) __attribute__((always_inline)) + { + return raw[x]; + } + + // Array access operator to index into the crgb object + inline const uint8_t& operator[] (uint8_t x) const __attribute__((always_inline)) + { + return raw[x]; + } + + // default values are UNINITIALIZED + inline LEDRGB() __attribute__((always_inline)) + { + } + + // allow construction from R, G, B + inline LEDRGB( uint8_t ir, uint8_t ig, uint8_t ib) __attribute__((always_inline)) + : r(ir), g(ig), b(ib) + { + } + + // allow construction from 32-bit (really 24-bit) bit 0xRRGGBB color code + inline LEDRGB( uint32_t colorcode) __attribute__((always_inline)) + : r((colorcode >> 16) & 0xFF), g((colorcode >> 8) & 0xFF), b((colorcode >> 0) & 0xFF) + { + } + + // allow copy construction + inline LEDRGB(const LEDRGB& rhs) __attribute__((always_inline)) + { + r = rhs.r; + g = rhs.g; + b = rhs.b; + } + + // allow assignment from one RGB struct to another + inline LEDRGB& operator= (const LEDRGB& rhs) __attribute__((always_inline)) + { + r = rhs.r; + g = rhs.g; + b = rhs.b; + return *this; + } + + // allow assignment from 32-bit (really 24-bit) 0xRRGGBB color code + inline LEDRGB& operator= (const uint32_t colorcode) __attribute__((always_inline)) + { + r = (colorcode >> 16) & 0xFF; + g = (colorcode >> 8) & 0xFF; + b = (colorcode >> 0) & 0xFF; + return *this; + } + + // allow assignment from R, G, and B + inline LEDRGB& setRGB (uint8_t nr, uint8_t ng, uint8_t nb) __attribute__((always_inline)) + { + r = nr; + g = ng; + b = nb; + return *this; + } +}; + +enum ColorOrder { + RGB = 0012, + GRB = 0102 +}; + +class wsLED +{ +protected: + int _pin; // pin, na kterem je LED pripojena + LEDRGB _color1; + LEDRGB _color2; + int _order; // ColorOrder + uint32_t _endtime; + uint8_t _scale; + uint8_t _color[3]; + Ticker _handler; + enum { + LED_STOP = 0, + LED_BLINK, + LED_BREATH, + LED_PATTERN, + } _ledState; // stav LEDky (blika, dycha, ...) + int _subState; // pomocny stav/index v poli dychani + + bool canShow(void); + void show(void); + void setColor(LEDRGB &color); + +public: + wsLED(int pin, int order = RGB); + void begin(void); + static void lh(wsLED *ptr); + void rtLed(void); // vykonna metoda + void setColors(LEDRGB color1, LEDRGB color2 = LEDRGB(0, 0, 0)); + void blink(int speed = 300); + void breath(void); + void setOrder(int neworder); +}; + +#endif +