Lepsi casovani, funkcni pro PL9823 pomoci definice WSLED_PL9823

This commit is contained in:
Pavel Brychta 2023-07-22 17:44:36 +02:00
parent b607188a15
commit 6800956d92
5 changed files with 242 additions and 272 deletions

View File

@ -1,4 +1,4 @@
{ {
"name": "WSLed", "name": "WSLed",
"version": "0.0.2" "version": "0.0.3"
} }

View File

@ -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
<http://www.gnu.org/licenses/>.
-------------------------------------------------------------------------*/
#if defined(ARDUINO_ARCH_ESP8266)
#include <Arduino.h>
#include <eagle_soc.h>
#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

View File

@ -1,28 +1,22 @@
// Ovladani signalizacni chytre LED diody // Ovladani signalizacni chytre LED diody
#include "WSLed.hpp" #include "WSLed.hpp"
#if defined(ARDUINO_ARCH_ESP32) #if defined(ARDUINO_ARCH_ESP32)
//# include "esp_task.h" // # include "esp_task.h"
// https://github.com/JSchaenzle/ESP32-NeoPixel-WS2812-RMT/blob/master/ws2812_control.c // https://github.com/JSchaenzle/ESP32-NeoPixel-WS2812-RMT/blob/master/ws2812_control.c
# include <set> #include <set>
# ifndef LED_RMT_TX_CHANNEL #ifndef LED_RMT_TX_CHANNEL
# define LED_RMT_TX_CHANNEL RMT_CHANNEL_0 #define LED_RMT_TX_CHANNEL RMT_CHANNEL_0
# endif #endif
// These values are determined by measuring pulse timing with logic analyzer and adjusting to match datasheet. // These values are determined by measuring pulse timing with logic analyzer and adjusting to match datasheet.
# define T0H 16 // 0 bit high time #define T0H 16 // 0 bit high time
# define T1H 32 // 1 bit high time #define T1H 32 // 1 bit high time
# define T0L 34 // 0 bit low time #define T0L 34 // 0 bit low time
# define T1L 18 // 1 bit low time #define T1L 18 // 1 bit low time
# define INRAM IRAM_ATTR
#endif #endif
#if defined(ARDUINO_ARCH_ESP8266) #if defined(ARDUINO_ARCH_ESP8266)
// due to linker overriding the ICACHE_RAM_ATTR for cpp files, these methods are // 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 // moved into a C file so the attribute will be applied correctly
#if (ARDUINO_ESP8266_MAJOR < 3) extern "C" IRAM_ATTR void espShow(uint8_t pin, uint8_t * pixels, uint32_t numBytes, boolean is800KHz);
# 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);
#endif #endif
// TODO: Proverit ESP32 s https://github.com/adafruit/Adafruit_NeoPixel/blob/master/esp.c // 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 // ... 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])) #define countof(a) (sizeof(a) / sizeof(a[0]))
static const uint16_t LB[] PROGMEM = { 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, 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, 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, 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, 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 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(); ptr->rtLed();
@ -46,7 +39,7 @@ static void ledTrampoline(wsLED *ptr)
inline bool wsLED::canShow() const inline bool wsLED::canShow() const
{ {
return (micros() - _endtime) >= 70L; return (micros() - mEndTime) >= 70L;
} }
void wsLED::show() void wsLED::show()
@ -54,66 +47,66 @@ void wsLED::show()
uint8_t color[3]; uint8_t color[3];
for (uint8_t i = 0; i < 3; i++) { for (uint8_t i = 0; i < 3; i++) {
// https://github.com/FastLED/FastLED/wiki/FastLED-Color-Correction // https://github.com/FastLED/FastLED/wiki/FastLED-Color-Correction
uint16_t c = (uint16_t)_color[i] * (1 + (uint16_t)_scale); uint16_t c = (uint16_t) mColor[i] * (1 + (uint16_t) mScale);
color[i] = (uint8_t)(c >> 8); color[i] = (uint8_t) (c >> 8);
} }
while (!canShow()) while (!canShow())
__asm__ volatile ("nop"); __asm__ volatile("nop");
#if defined(ARDUINO_ARCH_ESP32) #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); uint32_t mask = 1 << (BITS_PER_LED_CMD - 1);
for (uint32_t bit = 0; bit < BITS_PER_LED_CMD; bit++) { for (uint32_t bit = 0; bit < BITS_PER_LED_CMD; bit++) {
uint32_t bit_is_set = bits_to_send & mask; 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; mask >>= 1;
} }
ESP_ERROR_CHECK(rmt_write_items(LED_RMT_TX_CHANNEL, led_data_buffer, LED_BUFFER_ITEMS, false)); 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 _endtime = micros() + 100; // TODO: unfortunately this time is not valid for ESP32 using RMT peripheral
#else #else
noInterrupts(); 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(); interrupts();
_endtime = micros(); mEndTime = micros();
#endif #endif
} }
wsLED::wsLED(int pin, int order) wsLED::wsLED(int pin, int order)
: _pin(pin) : mPin(pin), mOrder(order)
, _order(order) {
, _scale(0xff) }
, _ledState(LED_STOP)
{}
wsLED::wsLED() wsLED::wsLED()
: _pin(NOT_A_PIN) : mPin(NOT_A_PIN), mOrder(RGB)
, _order(RGB) {
, _scale(0xff) }
, _ledState(LED_STOP)
{}
void wsLED::begin(int pin) void wsLED::begin(int pin)
{ {
_pin = pin; mPin = pin;
begin(); begin();
} }
void wsLED::begin() void wsLED::begin()
{ {
if (NOT_A_PIN != _pin) { if (NOT_A_PIN != mPin) {
#if defined(ARDUINO_ARCH_ESP8266) #if defined(ARDUINO_ARCH_ESP8266)
pinMode(_pin, OUTPUT); pinMode(mPin, OUTPUT);
#endif #endif
#if defined(ARDUINO_ARCH_ESP32) #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; rmt_config_t config;
config.rmt_mode = RMT_MODE_TX; config.rmt_mode = RMT_MODE_TX;
config.channel = LED_RMT_TX_CHANNEL; 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.mem_block_num = 3;
config.tx_config.loop_en = false; config.tx_config.loop_en = false;
config.tx_config.carrier_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_config(&config));
ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0)); ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0));
#endif #endif
_color[0] = _color[1] = _color[2] = 0;
show(); show();
} }
} }
void wsLED::setColor(LEDRGB color) void wsLED::setColor(const LEDRGB & color)
{ {
_color[(_order >> 6) & 7] = color.r; mColor[(mOrder >> 6) & 7] = color.r;
_color[(_order >> 3) & 7] = color.g; mColor[(mOrder >> 3) & 7] = color.g;
_color[_order & 7] = color.b; mColor[mOrder & 7] = color.b;
} }
void wsLED::rtLed() void wsLED::rtLed()
{ {
uint32_t timing; uint32_t timing;
_handler.detach(); mTimer.detach();
switch (_ledState) { switch (mLedState) {
case LED_BLINK: case LED_BLINK:
if (_subState) { if (mSubState) {
setColor(_color2); setColor(mColor2);
} else { } else {
setColor(_color1); 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: { case LED_PULSE: {
++_subState; mLedState = mSavedState;
_subState %= countof(LB); mSubState = 0;
uint16_t val = pgm_read_word(&LB[_subState]); setColor(mColor1);
_scale = (uint8_t)val; timing = 5;
val >>= 8; break;
timing = 30ul * val;
if (timing < 30) {
timing = 30;
} }
break;
}
case LED_PULSE: { case LED_PULSE_START:
_ledState = _savedState; setColor(mPulseColor);
_subState = 0; mLedState = LED_PULSE;
setColor(_color1); timing = mPulseDuration;
timing = 5; break;
break;
}
case LED_PULSE_START: default:
setColor(_pulseColor); timing = 5000;
_ledState = LED_PULSE; break;
timing = _pulseDuration;
break;
default:
timing = 5000;
break;
} }
show(); 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; mColor1 = color1;
_color2 = color2; mColor2 = color2;
if (LED_BREATH == _ledState) { if (LED_BREATH == mLedState) {
setColor(_color1); setColor(mColor1);
} }
} }
void wsLED::blink(uint32_t speed) void wsLED::blink(uint32_t speed)
{ {
if (NOT_A_PIN != _pin) { if (NOT_A_PIN != mPin) {
if (LED_BLINK != _ledState) { if (LED_BLINK != mLedState) {
_handler.detach(); mTimer.detach();
_ledState = LED_BLINK; mLedState = LED_BLINK;
_scale = 0xff; mScale = 0xff;
_subState = 1; mSubState = 1;
_blinkSpeed = speed; mBlinkSpeed = speed;
_handler.attach_ms(5, ledTrampoline, this); mTimer.attach_ms(5, ledTrampoline, this);
} }
} }
} }
@ -216,13 +208,13 @@ void wsLED::blink(uint32_t speed)
void wsLED::breath() void wsLED::breath()
{ {
if (NOT_A_PIN != _pin) { if (NOT_A_PIN != mPin) {
if (LED_BREATH != _ledState) { if (LED_BREATH != mLedState) {
_handler.detach(); mTimer.detach();
_ledState = LED_BREATH; mLedState = LED_BREATH;
_subState = 0; mSubState = 0;
setColor(_color1); setColor(mColor1);
_handler.attach_ms(5, ledTrampoline, this); mTimer.attach_ms(5, ledTrampoline, this);
} }
} }
} }
@ -230,40 +222,40 @@ void wsLED::breath()
void wsLED::setOrder(int neworder) 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) { if (NOT_A_PIN != mPin) {
_handler.detach(); mTimer.detach();
_scale = 0xff; mScale = 0xff;
_pulseColor = color; mPulseColor = color;
if (LED_BREATH == _ledState || LED_BLINK == _ledState) { if (LED_BREATH == mLedState || LED_BLINK == mLedState) {
_savedState = _ledState; mSavedState = mLedState;
} else { } else {
_savedState = LED_STOP; mSavedState = LED_STOP;
} }
_pulseDuration = duration; mPulseDuration = duration;
_ledState = LED_PULSE_START; mLedState = LED_PULSE_START;
_handler.attach_ms(5, ledTrampoline, this); mTimer.attach_ms(5, ledTrampoline, this);
} }
} }
ledstate_t wsLED::getState() ledstate_t wsLED::getState()
{ {
return _ledState; return mLedState;
} }
void wsLED::stop(LEDRGB color) void wsLED::stop(const LEDRGB & color)
{ {
if (NOT_A_PIN != _pin) { if (NOT_A_PIN != mPin) {
_handler.detach(); mTimer.detach();
_ledState = LED_STOP; mLedState = LED_STOP;
_scale = 0xff; mScale = 0xff;
setColor(color); setColor(color);
show(); show();
} }

View File

@ -1,6 +1,6 @@
// Ovladani RGB WS2812 LED diody pro signalizacni ucely // Ovladani RGB WS2812 LED diody pro signalizacni ucely
/**The MIT License (MIT) /**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 Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights 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, 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 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
See more at http://www.xpablo.cz
*/ */
#pragma once #pragma once
#include <Arduino.h> #include <Arduino.h>
#include <Ticker.h> #include <Ticker.h>
#if defined(ARDUINO_ARCH_ESP32) #if defined(ARDUINO_ARCH_ESP32)
# include <driver/rmt.h> #include <driver/rmt.h>
# define BITS_PER_LED_CMD 24 #define BITS_PER_LED_CMD 24
# define LED_BUFFER_ITEMS ((1 * BITS_PER_LED_CMD)) #define LED_BUFFER_ITEMS ((1 * BITS_PER_LED_CMD))
#endif #endif
struct LEDRGB { struct LEDRGB {
@ -44,17 +43,17 @@ struct LEDRGB {
uint8_t blue; uint8_t blue;
}; };
}; };
uint8_t raw[3]; uint8_t raw[3]{};
}; };
// Array access operator to index into the crgb object // 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]; return raw[x];
} }
// Array access operator to index into the crgb object // 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]; return raw[x];
} }
@ -65,19 +64,19 @@ struct LEDRGB {
} }
// allow construction from R, G, B // 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) : r(ir), g(ig), b(ib)
{ {
} }
// allow construction from 32-bit (really 24-bit) bit 0xRRGGBB color code // 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) : r((colorcode >> 16) & 0xFF), g((colorcode >> 8) & 0xFF), b((colorcode >> 0) & 0xFF)
{ {
} }
// allow copy construction // allow copy construction
inline LEDRGB(const LEDRGB& rhs) __attribute__((always_inline)) inline LEDRGB(const LEDRGB & rhs) __attribute__((always_inline))
{ {
r = rhs.r; r = rhs.r;
g = rhs.g; g = rhs.g;
@ -85,7 +84,7 @@ struct LEDRGB {
} }
// allow assignment from one RGB struct to another // 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; r = rhs.r;
g = rhs.g; g = rhs.g;
@ -94,16 +93,16 @@ struct LEDRGB {
} }
// allow assignment from 32-bit (really 24-bit) 0xRRGGBB color code // 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; r = (colorcode >> 16) & 0xFF;
g = (colorcode >> 8) & 0xFF; g = (colorcode >> 8) & 0xFF;
b = (colorcode >> 0) & 0xFF; b = (colorcode >> 0) & 0xFF;
return *this; return *this;
} }
// allow assignment from R, G, and B // 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; r = nr;
g = ng; g = ng;
@ -124,45 +123,44 @@ typedef enum {
LED_PULSE_START, LED_PULSE_START,
LED_PULSE, LED_PULSE,
LED_PATTERN, LED_PATTERN,
}ledstate_t; } ledstate_t;
class wsLED class wsLED {
{ protected:
protected: int mPin; // pin, na kterem je LED pripojena
int _pin; // pin, na kterem je LED pripojena LEDRGB mColor1;
LEDRGB _color1; LEDRGB mColor2;
LEDRGB _color2; int mOrder; // ColorOrder
int _order; // ColorOrder uint8_t mScale = 0xff;
uint8_t _scale; uint8_t mColor[3]{};
uint8_t _color[3]; Ticker mTimer;
Ticker _handler; volatile ledstate_t mLedState = LED_STOP; // stav LEDky (blika, dycha, ...)
volatile ledstate_t _ledState; // stav LEDky (blika, dycha, ...) volatile ledstate_t mSavedState = LED_STOP; // stav pro navrat
volatile ledstate_t _savedState; // stav pro navrat volatile int mSubState = 0; // pomocny stav/index v poli dychani
volatile int _subState; // pomocny stav/index v poli dychani uint32_t mPulseDuration = 0;
uint32_t _pulseDuration; uint32_t mBlinkSpeed = 0;
uint32_t _blinkSpeed; LEDRGB mPulseColor;
LEDRGB _pulseColor;
#if defined(ARDUINO_ARCH_ESP32) #if defined(ARDUINO_ARCH_ESP32)
int _rmtChannel = 0; int _rmtChannel = 0;
rmt_item32_t led_data_buffer[LED_BUFFER_ITEMS] = {0}; rmt_item32_t led_data_buffer[LED_BUFFER_ITEMS] = {0};
#endif #endif
uint32_t _endtime; uint32_t mEndTime = 0;
void show(); void show();
void setColor(LEDRGB color); void setColor(const LEDRGB & color);
bool canShow() const; bool canShow() const;
public: public:
wsLED(int pin, int order = RGB); wsLED(int pin, int order = RGB);
wsLED(); wsLED();
void begin(); void begin();
void begin(int pin); void begin(int pin);
void rtLed(); // vykonna metoda 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 blink(uint32_t speed = 300);
void breath(); void breath();
void setOrder(int neworder); void setOrder(int neworder);
ledstate_t getState(); ledstate_t getState();
void pulse(LEDRGB color, uint32_t duration); void pulse(const LEDRGB & color, uint32_t duration);
void stop(LEDRGB color = LEDRGB(0, 0, 0)); void stop(const LEDRGB & color = LEDRGB(0, 0, 0));
}; };

82
src/esp8266.c Normal file
View File

@ -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 <Arduino.h>
#ifdef ESP8266
#include <eagle_soc.h>
#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