From 6800956d92304e71cfc0a35a40240df76f169911 Mon Sep 17 00:00:00 2001 From: pablo2048 Date: Sat, 22 Jul 2023 17:44:36 +0200 Subject: [PATCH] Lepsi casovani, funkcni pro PL9823 pomoci definice WSLED_PL9823 --- library.json | 2 +- src/NeoPixelesp8266.c | 102 ----------------- src/WSLed.cpp | 252 ++++++++++++++++++++---------------------- src/WSLed.hpp | 76 +++++++------ src/esp8266.c | 82 ++++++++++++++ 5 files changed, 242 insertions(+), 272 deletions(-) delete mode 100644 src/NeoPixelesp8266.c create mode 100644 src/esp8266.c diff --git a/library.json b/library.json index eaac257..7166f11 100644 --- a/library.json +++ b/library.json @@ -1,4 +1,4 @@ { "name": "WSLed", - "version": "0.0.2" + "version": "0.0.3" } \ No newline at end of file diff --git a/src/NeoPixelesp8266.c b/src/NeoPixelesp8266.c deleted file mode 100644 index 25c59aa..0000000 --- a/src/NeoPixelesp8266.c +++ /dev/null @@ -1,102 +0,0 @@ -/*------------------------------------------------------------------------- -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) - -#include -#include -#if (ARDUINO_ESP8266_MAJOR < 3) -# define INRAM ICACHE_RAM_ATTR -#else -# define INRAM IRAM_ATTR -#endif - -// ESP32 doesn't define ICACHE_RAM_ATTR -#ifndef INRAM -# define INRAM IRAM_ATTR -#endif - -inline uint32_t _getCycleCount() -{ - uint32_t ccount; - __asm__ __volatile__("rsr %0,ccount":"=a" (ccount)); - return ccount; -} - -#if defined(NEOPIXEL_OLD_TIMING) -# 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 -#else -# 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 -#endif - -void INRAM 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 - GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinRegister); - - // wait for the LOW - do - { - cyclesNext = _getCycleCount(); - } while ((cyclesNext - cyclesStart) < cyclesBit); - - // set low - GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinRegister); - } - } while (pixels < end); -} - -#endif \ No newline at end of file diff --git a/src/WSLed.cpp b/src/WSLed.cpp index be5b669..a4f9801 100644 --- a/src/WSLed.cpp +++ b/src/WSLed.cpp @@ -1,28 +1,22 @@ // Ovladani signalizacni chytre LED diody #include "WSLed.hpp" #if defined(ARDUINO_ARCH_ESP32) -//# include "esp_task.h" -// https://github.com/JSchaenzle/ESP32-NeoPixel-WS2812-RMT/blob/master/ws2812_control.c -# include -# ifndef LED_RMT_TX_CHANNEL -# define LED_RMT_TX_CHANNEL RMT_CHANNEL_0 -# endif -// These values are determined by measuring pulse timing with logic analyzer and adjusting to match datasheet. -# define T0H 16 // 0 bit high time -# define T1H 32 // 1 bit high time -# define T0L 34 // 0 bit low time -# define T1L 18 // 1 bit low time -# define INRAM IRAM_ATTR + // # include "esp_task.h" + // https://github.com/JSchaenzle/ESP32-NeoPixel-WS2812-RMT/blob/master/ws2812_control.c + #include + #ifndef LED_RMT_TX_CHANNEL + #define LED_RMT_TX_CHANNEL RMT_CHANNEL_0 + #endif + // These values are determined by measuring pulse timing with logic analyzer and adjusting to match datasheet. + #define T0H 16 // 0 bit high time + #define T1H 32 // 1 bit high time + #define T0L 34 // 0 bit low time + #define T1L 18 // 1 bit low time #endif #if defined(ARDUINO_ARCH_ESP8266) // 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 -#if (ARDUINO_ESP8266_MAJOR < 3) -# define INRAM ICACHE_RAM_ATTR -#else -# define INRAM IRAM_ATTR -#endif -extern "C" void INRAM send_pixels_800(uint8_t* pixel, size_t count, uint8_t pin); +extern "C" IRAM_ATTR void espShow(uint8_t pin, uint8_t * pixels, uint32_t numBytes, boolean is800KHz); #endif // TODO: Proverit ESP32 s https://github.com/adafruit/Adafruit_NeoPixel/blob/master/esp.c // ... a s https://github.com/Freenove/Freenove_WS2812_Lib_for_ESP32 @@ -30,14 +24,13 @@ extern "C" void INRAM 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 , 0x2900 -}; + 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, 0x2900}; -static void ledTrampoline(wsLED *ptr) +static void ledTrampoline(wsLED * ptr) { ptr->rtLed(); @@ -46,7 +39,7 @@ static void ledTrampoline(wsLED *ptr) inline bool wsLED::canShow() const { - return (micros() - _endtime) >= 70L; + return (micros() - mEndTime) >= 70L; } void wsLED::show() @@ -54,66 +47,66 @@ void wsLED::show() 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); + // https://github.com/FastLED/FastLED/wiki/FastLED-Color-Correction + uint16_t c = (uint16_t) mColor[i] * (1 + (uint16_t) mScale); + color[i] = (uint8_t) (c >> 8); } while (!canShow()) - __asm__ volatile ("nop"); + __asm__ volatile("nop"); #if defined(ARDUINO_ARCH_ESP32) - uint32_t bits_to_send = ((uint32_t)color[0] << 16) | ((uint32_t)color[1] << 8) | (uint32_t)color[2]; + uint32_t bits_to_send = ((uint32_t) color[0] << 16) | ((uint32_t) color[1] << 8) | (uint32_t) color[2]; uint32_t mask = 1 << (BITS_PER_LED_CMD - 1); for (uint32_t bit = 0; bit < BITS_PER_LED_CMD; bit++) { uint32_t bit_is_set = bits_to_send & mask; - led_data_buffer[bit] = bit_is_set ? (rmt_item32_t) {{{T1H, 1, T1L, 0}}} : (rmt_item32_t) {{{T0H, 1, T0L, 0}}}; + led_data_buffer[bit] = bit_is_set ? (rmt_item32_t){{{T1H, 1, T1L, 0}}} : (rmt_item32_t){{{T0H, 1, T0L, 0}}}; mask >>= 1; } ESP_ERROR_CHECK(rmt_write_items(LED_RMT_TX_CHANNEL, led_data_buffer, LED_BUFFER_ITEMS, false)); _endtime = micros() + 100; // TODO: unfortunately this time is not valid for ESP32 using RMT peripheral #else noInterrupts(); - send_pixels_800(color, 1, _pin); + #if defined(WSLED_PL9823) + espShow(_pin, color, 1 * 3, false); + #else + espShow(mPin, color, 1 * 3, true); + #endif interrupts(); - _endtime = micros(); + mEndTime = micros(); #endif } wsLED::wsLED(int pin, int order) - : _pin(pin) - , _order(order) - , _scale(0xff) - , _ledState(LED_STOP) -{} + : mPin(pin), mOrder(order) +{ +} wsLED::wsLED() - : _pin(NOT_A_PIN) - , _order(RGB) - , _scale(0xff) - , _ledState(LED_STOP) -{} + : mPin(NOT_A_PIN), mOrder(RGB) +{ +} void wsLED::begin(int pin) { - _pin = pin; + mPin = pin; begin(); } void wsLED::begin() { - if (NOT_A_PIN != _pin) { + if (NOT_A_PIN != mPin) { #if defined(ARDUINO_ARCH_ESP8266) - pinMode(_pin, OUTPUT); + pinMode(mPin, OUTPUT); #endif #if defined(ARDUINO_ARCH_ESP32) -// TODO: mozna nejak zkusit najit volny RMT kanal? + // TODO: mozna nejak zkusit najit volny RMT kanal? rmt_config_t config; config.rmt_mode = RMT_MODE_TX; config.channel = LED_RMT_TX_CHANNEL; - config.gpio_num = (gpio_num_t)_pin; + config.gpio_num = (gpio_num_t) _pin; config.mem_block_num = 3; config.tx_config.loop_en = false; config.tx_config.carrier_en = false; @@ -124,91 +117,90 @@ void wsLED::begin() ESP_ERROR_CHECK(rmt_config(&config)); ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0)); #endif - _color[0] = _color[1] = _color[2] = 0; show(); } } -void wsLED::setColor(LEDRGB color) +void wsLED::setColor(const LEDRGB & color) { - _color[(_order >> 6) & 7] = color.r; - _color[(_order >> 3) & 7] = color.g; - _color[_order & 7] = color.b; + mColor[(mOrder >> 6) & 7] = color.r; + mColor[(mOrder >> 3) & 7] = color.g; + mColor[mOrder & 7] = color.b; } void wsLED::rtLed() { uint32_t timing; - _handler.detach(); - switch (_ledState) { - case LED_BLINK: - if (_subState) { - setColor(_color2); - } else { - setColor(_color1); + mTimer.detach(); + switch (mLedState) { + case LED_BLINK: + if (mSubState) { + setColor(mColor2); + } else { + setColor(mColor1); + } + mSubState = !mSubState; + timing = mBlinkSpeed; + break; + + case LED_BREATH: { + ++mSubState; + mSubState %= countof(LB); + uint16_t val = pgm_read_word(&LB[mSubState]); + mScale = (uint8_t) val; + val >>= 8; + timing = 30ul * val; + if (timing < 30) { + timing = 30; + } + break; } - _subState = !_subState; - timing = _blinkSpeed; - break; - case LED_BREATH: { - ++_subState; - _subState %= countof(LB); - uint16_t val = pgm_read_word(&LB[_subState]); - _scale = (uint8_t)val; - val >>= 8; - timing = 30ul * val; - if (timing < 30) { - timing = 30; + case LED_PULSE: { + mLedState = mSavedState; + mSubState = 0; + setColor(mColor1); + timing = 5; + break; } - break; - } - case LED_PULSE: { - _ledState = _savedState; - _subState = 0; - setColor(_color1); - timing = 5; - break; - } + case LED_PULSE_START: + setColor(mPulseColor); + mLedState = LED_PULSE; + timing = mPulseDuration; + break; - case LED_PULSE_START: - setColor(_pulseColor); - _ledState = LED_PULSE; - timing = _pulseDuration; - break; - - default: - timing = 5000; - break; + default: + timing = 5000; + break; } show(); - _handler.attach_ms(timing, ledTrampoline, this); + mTimer.attach_ms(timing, ledTrampoline, this); } -void wsLED::setColors(LEDRGB color1, LEDRGB color2) +void wsLED::setColors(const LEDRGB & color1, const LEDRGB & color2) { - _color1 = color1; - _color2 = color2; - if (LED_BREATH == _ledState) { - setColor(_color1); + mColor1 = color1; + mColor2 = color2; + if (LED_BREATH == mLedState) { + setColor(mColor1); } } void wsLED::blink(uint32_t speed) { - if (NOT_A_PIN != _pin) { - if (LED_BLINK != _ledState) { - _handler.detach(); - _ledState = LED_BLINK; - _scale = 0xff; - _subState = 1; - _blinkSpeed = speed; - _handler.attach_ms(5, ledTrampoline, this); + if (NOT_A_PIN != mPin) { + if (LED_BLINK != mLedState) { + mTimer.detach(); + mLedState = LED_BLINK; + mScale = 0xff; + mSubState = 1; + mBlinkSpeed = speed; + mTimer.attach_ms(5, ledTrampoline, this); } } } @@ -216,13 +208,13 @@ void wsLED::blink(uint32_t speed) void wsLED::breath() { - if (NOT_A_PIN != _pin) { - if (LED_BREATH != _ledState) { - _handler.detach(); - _ledState = LED_BREATH; - _subState = 0; - setColor(_color1); - _handler.attach_ms(5, ledTrampoline, this); + if (NOT_A_PIN != mPin) { + if (LED_BREATH != mLedState) { + mTimer.detach(); + mLedState = LED_BREATH; + mSubState = 0; + setColor(mColor1); + mTimer.attach_ms(5, ledTrampoline, this); } } } @@ -230,40 +222,40 @@ void wsLED::breath() void wsLED::setOrder(int neworder) { - _order = neworder; + mOrder = neworder; } -void wsLED::pulse(LEDRGB color, uint32_t duration) +void wsLED::pulse(const LEDRGB & color, uint32_t duration) { - if (NOT_A_PIN != _pin) { - _handler.detach(); - _scale = 0xff; - _pulseColor = color; - if (LED_BREATH == _ledState || LED_BLINK == _ledState) { - _savedState = _ledState; + if (NOT_A_PIN != mPin) { + mTimer.detach(); + mScale = 0xff; + mPulseColor = color; + if (LED_BREATH == mLedState || LED_BLINK == mLedState) { + mSavedState = mLedState; } else { - _savedState = LED_STOP; + mSavedState = LED_STOP; } - _pulseDuration = duration; - _ledState = LED_PULSE_START; - _handler.attach_ms(5, ledTrampoline, this); + mPulseDuration = duration; + mLedState = LED_PULSE_START; + mTimer.attach_ms(5, ledTrampoline, this); } } ledstate_t wsLED::getState() { - return _ledState; + return mLedState; } -void wsLED::stop(LEDRGB color) +void wsLED::stop(const LEDRGB & color) { - if (NOT_A_PIN != _pin) { - _handler.detach(); - _ledState = LED_STOP; - _scale = 0xff; + if (NOT_A_PIN != mPin) { + mTimer.detach(); + mLedState = LED_STOP; + mScale = 0xff; setColor(color); show(); } diff --git a/src/WSLed.hpp b/src/WSLed.hpp index 7e8a326..5696c1e 100644 --- a/src/WSLed.hpp +++ b/src/WSLed.hpp @@ -1,6 +1,6 @@ // Ovladani RGB WS2812 LED diody pro signalizacni ucely /**The MIT License (MIT) -Copyright (c) 2017,2020 by Pavel Brychta +Copyright (c) 2017,20,23 by Pavel Brychta, http://www.xpablo.cz 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 @@ -16,16 +16,15 @@ 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 */ #pragma once #include #include #if defined(ARDUINO_ARCH_ESP32) -# include -# define BITS_PER_LED_CMD 24 -# define LED_BUFFER_ITEMS ((1 * BITS_PER_LED_CMD)) + #include + #define BITS_PER_LED_CMD 24 + #define LED_BUFFER_ITEMS ((1 * BITS_PER_LED_CMD)) #endif struct LEDRGB { @@ -44,17 +43,17 @@ struct LEDRGB { uint8_t blue; }; }; - uint8_t raw[3]; + uint8_t raw[3]{}; }; // Array access operator to index into the crgb object - inline uint8_t& operator[] (uint8_t x) __attribute__((always_inline)) + 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)) + inline const uint8_t & operator[](uint8_t x) const __attribute__((always_inline)) { return raw[x]; } @@ -65,19 +64,19 @@ struct LEDRGB { } // allow construction from R, G, B - inline LEDRGB( uint8_t ir, uint8_t ig, uint8_t ib) __attribute__((always_inline)) + 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)) + 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)) + inline LEDRGB(const LEDRGB & rhs) __attribute__((always_inline)) { r = rhs.r; g = rhs.g; @@ -85,7 +84,7 @@ struct LEDRGB { } // allow assignment from one RGB struct to another - inline LEDRGB& operator= (const LEDRGB& rhs) __attribute__((always_inline)) + inline LEDRGB & operator=(const LEDRGB & rhs) __attribute__((always_inline)) { r = rhs.r; g = rhs.g; @@ -94,16 +93,16 @@ struct LEDRGB { } // allow assignment from 32-bit (really 24-bit) 0xRRGGBB color code - inline LEDRGB& operator= (const uint32_t colorcode) __attribute__((always_inline)) + inline LEDRGB & operator=(const uint32_t colorcode) __attribute__((always_inline)) { r = (colorcode >> 16) & 0xFF; - g = (colorcode >> 8) & 0xFF; - b = (colorcode >> 0) & 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)) + inline LEDRGB & setRGB(uint8_t nr, uint8_t ng, uint8_t nb) __attribute__((always_inline)) { r = nr; g = ng; @@ -124,45 +123,44 @@ typedef enum { LED_PULSE_START, LED_PULSE, LED_PATTERN, -}ledstate_t; +} ledstate_t; -class wsLED -{ -protected: - int _pin; // pin, na kterem je LED pripojena - LEDRGB _color1; - LEDRGB _color2; - int _order; // ColorOrder - uint8_t _scale; - uint8_t _color[3]; - Ticker _handler; - volatile ledstate_t _ledState; // stav LEDky (blika, dycha, ...) - volatile ledstate_t _savedState; // stav pro navrat - volatile int _subState; // pomocny stav/index v poli dychani - uint32_t _pulseDuration; - uint32_t _blinkSpeed; - LEDRGB _pulseColor; +class wsLED { + protected: + int mPin; // pin, na kterem je LED pripojena + LEDRGB mColor1; + LEDRGB mColor2; + int mOrder; // ColorOrder + uint8_t mScale = 0xff; + uint8_t mColor[3]{}; + Ticker mTimer; + volatile ledstate_t mLedState = LED_STOP; // stav LEDky (blika, dycha, ...) + volatile ledstate_t mSavedState = LED_STOP; // stav pro navrat + volatile int mSubState = 0; // pomocny stav/index v poli dychani + uint32_t mPulseDuration = 0; + uint32_t mBlinkSpeed = 0; + LEDRGB mPulseColor; #if defined(ARDUINO_ARCH_ESP32) int _rmtChannel = 0; rmt_item32_t led_data_buffer[LED_BUFFER_ITEMS] = {0}; #endif - uint32_t _endtime; + uint32_t mEndTime = 0; void show(); - void setColor(LEDRGB color); + void setColor(const LEDRGB & color); bool canShow() const; -public: + public: wsLED(int pin, int order = RGB); wsLED(); void begin(); void begin(int pin); void rtLed(); // vykonna metoda - void setColors(LEDRGB color1, LEDRGB color2 = LEDRGB(0, 0, 0)); + void setColors(const LEDRGB & color1, const LEDRGB & color2 = LEDRGB(0, 0, 0)); void blink(uint32_t speed = 300); void breath(); void setOrder(int neworder); ledstate_t getState(); - void pulse(LEDRGB color, uint32_t duration); - void stop(LEDRGB color = LEDRGB(0, 0, 0)); + void pulse(const LEDRGB & color, uint32_t duration); + void stop(const LEDRGB & color = LEDRGB(0, 0, 0)); }; diff --git a/src/esp8266.c b/src/esp8266.c new file mode 100644 index 0000000..74a3216 --- /dev/null +++ b/src/esp8266.c @@ -0,0 +1,82 @@ +// This is a mash-up of the Due show() code + insights from Michael Miller's +// ESP8266 work for the NeoPixelBus library: github.com/Makuna/NeoPixelBus +// Needs to be a separate .c file to enforce ICACHE_RAM_ATTR execution. + +#if defined(ESP8266) + +#include +#ifdef ESP8266 +#include +#endif + +static uint32_t _getCycleCount(void) __attribute__((always_inline)); +static inline uint32_t _getCycleCount(void) { + uint32_t ccount; + __asm__ __volatile__("rsr %0,ccount":"=a" (ccount)); + return ccount; +} + +#ifdef ESP8266 +IRAM_ATTR void espShow( + uint8_t pin, uint8_t *pixels, uint32_t numBytes, boolean is800KHz) { +#else +void espShow( + uint8_t pin, uint8_t *pixels, uint32_t numBytes, boolean is800KHz) { +#endif + +#define CYCLES_800_T0H (F_CPU / 2500001) // 0.4us +#define CYCLES_800_T1H (F_CPU / 1250001) // 0.8us +#define CYCLES_800 (F_CPU / 800001) // 1.25us per bit +#define CYCLES_400_T0H (F_CPU / 2000000) // 0.5uS +#define CYCLES_400_T1H (F_CPU / 833333) // 1.2us +#define CYCLES_400 (F_CPU / 400000) // 2.5us per bit + + uint8_t *p, *end, pix, mask; + uint32_t t, time0, time1, period, c, startTime; + +#ifdef ESP8266 + uint32_t pinMask; + pinMask = _BV(pin); +#endif + + p = pixels; + end = p + numBytes; + pix = *p++; + mask = 0x80; + startTime = 0; + + if(is800KHz) { + time0 = CYCLES_800_T0H; + time1 = CYCLES_800_T1H; + period = CYCLES_800; + } else { // 400 KHz bitstream + time0 = CYCLES_400_T0H; + time1 = CYCLES_400_T1H; + period = CYCLES_400; + } + + for(t = time0;; t = time0) { + if(pix & mask) t = time1; // Bit high duration + while(((c = _getCycleCount()) - startTime) < period); // Wait for bit start +#ifdef ESP8266 + GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinMask); // Set high +#else + gpio_set_level(pin, HIGH); +#endif + startTime = c; // Save start time + while(((c = _getCycleCount()) - startTime) < t); // Wait high duration +#ifdef ESP8266 + GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinMask); // Set low +#else + gpio_set_level(pin, LOW); +#endif + if(!(mask >>= 1)) { // Next bit/byte + if(p >= end) break; + pix = *p++; + mask = 0x80; + } + } + while((_getCycleCount() - startTime) < period); // Wait for last bit +} + +#endif // ESP8266