First commit.
This commit is contained in:
@ -0,0 +1,159 @@
|
||||
#ifndef __INC_CLOCKLESS_BLOCK_ESP8266_H
|
||||
#define __INC_CLOCKLESS_BLOCK_ESP8266_H
|
||||
|
||||
#define FASTLED_HAS_BLOCKLESS 1
|
||||
|
||||
#define FIX_BITS(bits) (((bits & 0x0fL) << 12) | (bits & 0x30))
|
||||
|
||||
#define MIN(X,Y) (((X)<(Y)) ? (X):(Y))
|
||||
#define USED_LANES (MIN(LANES, 6))
|
||||
#define PORT_MASK (((1 << USED_LANES)-1) & 0x0000FFFFL)
|
||||
#define PIN_MASK FIX_BITS(PORT_MASK)
|
||||
|
||||
FASTLED_NAMESPACE_BEGIN
|
||||
|
||||
#ifdef FASTLED_DEBUG_COUNT_FRAME_RETRIES
|
||||
extern uint32_t _frame_cnt;
|
||||
extern uint32_t _retry_cnt;
|
||||
#endif
|
||||
|
||||
template <uint8_t LANES, int FIRST_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = GRB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
|
||||
class InlineBlockClocklessController : public CPixelLEDController<RGB_ORDER, LANES, PORT_MASK> {
|
||||
typedef typename FastPin<FIRST_PIN>::port_ptr_t data_ptr_t;
|
||||
typedef typename FastPin<FIRST_PIN>::port_t data_t;
|
||||
|
||||
CMinWait<WAIT_TIME> mWait;
|
||||
public:
|
||||
virtual int size() { return CLEDController::size() * LANES; }
|
||||
|
||||
virtual void showPixels(PixelController<RGB_ORDER, LANES, PORT_MASK> & pixels) {
|
||||
// mWait.wait();
|
||||
/*uint32_t clocks = */
|
||||
int cnt=FASTLED_INTERRUPT_RETRY_COUNT;
|
||||
while(!showRGBInternal(pixels) && cnt--) {
|
||||
os_intr_unlock();
|
||||
#ifdef FASTLED_DEBUG_COUNT_FRAME_RETRIES
|
||||
_retry_cnt++;
|
||||
#endif
|
||||
delayMicroseconds(WAIT_TIME * 10);
|
||||
os_intr_lock();
|
||||
}
|
||||
// #if FASTLED_ALLOW_INTTERUPTS == 0
|
||||
// Adjust the timer
|
||||
// long microsTaken = CLKS_TO_MICROS(clocks);
|
||||
// MS_COUNTER += (1 + (microsTaken / 1000));
|
||||
// #endif
|
||||
|
||||
// mWait.mark();
|
||||
}
|
||||
|
||||
template<int PIN> static void initPin() {
|
||||
_ESPPIN<PIN, 1<<(PIN & 0xFF)>::setOutput();
|
||||
}
|
||||
|
||||
virtual void init() {
|
||||
void (* funcs[])() ={initPin<12>, initPin<13>, initPin<14>, initPin<15>, initPin<4>, initPin<5>};
|
||||
|
||||
for (uint8_t i = 0; i < USED_LANES; ++i) {
|
||||
funcs[i]();
|
||||
}
|
||||
}
|
||||
|
||||
virtual uint16_t getMaxRefreshRate() const { return 400; }
|
||||
|
||||
typedef union {
|
||||
uint8_t bytes[8];
|
||||
uint16_t shorts[4];
|
||||
uint32_t raw[2];
|
||||
} Lines;
|
||||
|
||||
#define ESP_ADJUST 0 // (2*(F_CPU/24000000))
|
||||
#define ESP_ADJUST2 0
|
||||
template<int BITS,int PX> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & last_mark, register Lines & b, PixelController<RGB_ORDER, LANES, PORT_MASK> &pixels) { // , register uint32_t & b2) {
|
||||
Lines b2 = b;
|
||||
transpose8x1_noinline(b.bytes,b2.bytes);
|
||||
|
||||
register uint8_t d = pixels.template getd<PX>(pixels);
|
||||
register uint8_t scale = pixels.template getscale<PX>(pixels);
|
||||
|
||||
for(register uint32_t i = 0; i < USED_LANES; i++) {
|
||||
while((__clock_cycles() - last_mark) < (T1+T2+T3));
|
||||
last_mark = __clock_cycles();
|
||||
*FastPin<FIRST_PIN>::sport() = PIN_MASK;
|
||||
|
||||
uint32_t nword = (uint32_t)(~b2.bytes[7-i]);
|
||||
while((__clock_cycles() - last_mark) < (T1-6));
|
||||
*FastPin<FIRST_PIN>::cport() = FIX_BITS(nword);
|
||||
|
||||
while((__clock_cycles() - last_mark) < (T1+T2));
|
||||
*FastPin<FIRST_PIN>::cport() = PIN_MASK;
|
||||
|
||||
b.bytes[i] = pixels.template loadAndScale<PX>(pixels,i,d,scale);
|
||||
}
|
||||
|
||||
for(register uint32_t i = USED_LANES; i < 8; i++) {
|
||||
while((__clock_cycles() - last_mark) < (T1+T2+T3));
|
||||
last_mark = __clock_cycles();
|
||||
*FastPin<FIRST_PIN>::sport() = PIN_MASK;
|
||||
|
||||
uint32_t nword = (uint32_t)(~b2.bytes[7-i]);
|
||||
while((__clock_cycles() - last_mark) < (T1-6));
|
||||
*FastPin<FIRST_PIN>::cport() = FIX_BITS(nword);
|
||||
|
||||
while((__clock_cycles() - last_mark) < (T1+T2));
|
||||
*FastPin<FIRST_PIN>::cport() = PIN_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
// This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
|
||||
// gcc will use register Y for the this pointer.
|
||||
static uint32_t ICACHE_RAM_ATTR showRGBInternal(PixelController<RGB_ORDER, LANES, PORT_MASK> &allpixels) {
|
||||
|
||||
// Setup the pixel controller and load/scale the first byte
|
||||
Lines b0;
|
||||
|
||||
for(int i = 0; i < USED_LANES; i++) {
|
||||
b0.bytes[i] = allpixels.loadAndScale0(i);
|
||||
}
|
||||
allpixels.preStepFirstByteDithering();
|
||||
|
||||
os_intr_lock();
|
||||
uint32_t _start = __clock_cycles();
|
||||
uint32_t last_mark = _start;
|
||||
|
||||
while(allpixels.has(1)) {
|
||||
// Write first byte, read next byte
|
||||
writeBits<8+XTRA0,1>(last_mark, b0, allpixels);
|
||||
|
||||
// Write second byte, read 3rd byte
|
||||
writeBits<8+XTRA0,2>(last_mark, b0, allpixels);
|
||||
allpixels.advanceData();
|
||||
|
||||
// Write third byte
|
||||
writeBits<8+XTRA0,0>(last_mark, b0, allpixels);
|
||||
|
||||
#if (FASTLED_ALLOW_INTERRUPTS == 1)
|
||||
os_intr_unlock();
|
||||
#endif
|
||||
|
||||
allpixels.stepDithering();
|
||||
|
||||
#if (FASTLED_ALLOW_INTERRUPTS == 1)
|
||||
os_intr_lock();
|
||||
// if interrupts took longer than 45µs, punt on the current frame
|
||||
if((int32_t)(__clock_cycles()-last_mark) > 0) {
|
||||
if((int32_t)(__clock_cycles()-last_mark) > (T1+T2+T3+((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US))) { os_intr_unlock(); return 0; }
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
os_intr_unlock();
|
||||
#ifdef FASTLED_DEBUG_COUNT_FRAME_RETRIES
|
||||
_frame_cnt++;
|
||||
#endif
|
||||
return __clock_cycles() - _start;
|
||||
}
|
||||
};
|
||||
|
||||
FASTLED_NAMESPACE_END
|
||||
#endif
|
@ -0,0 +1,117 @@
|
||||
#pragma once
|
||||
|
||||
FASTLED_NAMESPACE_BEGIN
|
||||
|
||||
#ifdef FASTLED_DEBUG_COUNT_FRAME_RETRIES
|
||||
extern uint32_t _frame_cnt;
|
||||
extern uint32_t _retry_cnt;
|
||||
#endif
|
||||
|
||||
// Info on reading cycle counter from https://github.com/kbeckmann/nodemcu-firmware/blob/ws2812-dual/app/modules/ws2812.c
|
||||
__attribute__ ((always_inline)) inline static uint32_t __clock_cycles() {
|
||||
uint32_t cyc;
|
||||
__asm__ __volatile__ ("rsr %0,ccount":"=a" (cyc));
|
||||
return cyc;
|
||||
}
|
||||
|
||||
#define FASTLED_HAS_CLOCKLESS 1
|
||||
|
||||
template <int DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
|
||||
class ClocklessController : public CPixelLEDController<RGB_ORDER> {
|
||||
typedef typename FastPin<DATA_PIN>::port_ptr_t data_ptr_t;
|
||||
typedef typename FastPin<DATA_PIN>::port_t data_t;
|
||||
|
||||
data_t mPinMask;
|
||||
data_ptr_t mPort;
|
||||
CMinWait<WAIT_TIME> mWait;
|
||||
public:
|
||||
virtual void init() {
|
||||
FastPin<DATA_PIN>::setOutput();
|
||||
mPinMask = FastPin<DATA_PIN>::mask();
|
||||
mPort = FastPin<DATA_PIN>::port();
|
||||
}
|
||||
|
||||
virtual uint16_t getMaxRefreshRate() const { return 400; }
|
||||
|
||||
protected:
|
||||
|
||||
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
|
||||
// mWait.wait();
|
||||
int cnt = FASTLED_INTERRUPT_RETRY_COUNT;
|
||||
while((showRGBInternal(pixels)==0) && cnt--) {
|
||||
#ifdef FASTLED_DEBUG_COUNT_FRAME_RETRIES
|
||||
_retry_cnt++;
|
||||
#endif
|
||||
os_intr_unlock();
|
||||
delayMicroseconds(WAIT_TIME);
|
||||
os_intr_lock();
|
||||
}
|
||||
// mWait.mark();
|
||||
}
|
||||
|
||||
#define _ESP_ADJ (0)
|
||||
#define _ESP_ADJ2 (0)
|
||||
|
||||
template<int BITS> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & last_mark, register uint32_t b) {
|
||||
b <<= 24; b = ~b;
|
||||
for(register uint32_t i = BITS; i > 0; i--) {
|
||||
while((__clock_cycles() - last_mark) < (T1+T2+T3));
|
||||
last_mark = __clock_cycles();
|
||||
FastPin<DATA_PIN>::hi();
|
||||
|
||||
while((__clock_cycles() - last_mark) < T1);
|
||||
if(b & 0x80000000L) { FastPin<DATA_PIN>::lo(); }
|
||||
b <<= 1;
|
||||
|
||||
while((__clock_cycles() - last_mark) < (T1+T2));
|
||||
FastPin<DATA_PIN>::lo();
|
||||
}
|
||||
}
|
||||
|
||||
// This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
|
||||
// gcc will use register Y for the this pointer.
|
||||
static uint32_t ICACHE_RAM_ATTR showRGBInternal(PixelController<RGB_ORDER> pixels) {
|
||||
// Setup the pixel controller and load/scale the first byte
|
||||
pixels.preStepFirstByteDithering();
|
||||
register uint32_t b = pixels.loadAndScale0();
|
||||
pixels.preStepFirstByteDithering();
|
||||
os_intr_lock();
|
||||
uint32_t start = __clock_cycles();
|
||||
uint32_t last_mark = start;
|
||||
while(pixels.has(1)) {
|
||||
// Write first byte, read next byte
|
||||
writeBits<8+XTRA0>(last_mark, b);
|
||||
b = pixels.loadAndScale1();
|
||||
|
||||
// Write second byte, read 3rd byte
|
||||
writeBits<8+XTRA0>(last_mark, b);
|
||||
b = pixels.loadAndScale2();
|
||||
|
||||
// Write third byte, read 1st byte of next pixel
|
||||
writeBits<8+XTRA0>(last_mark, b);
|
||||
b = pixels.advanceAndLoadAndScale0();
|
||||
|
||||
#if (FASTLED_ALLOW_INTERRUPTS == 1)
|
||||
os_intr_unlock();
|
||||
#endif
|
||||
|
||||
pixels.stepDithering();
|
||||
|
||||
#if (FASTLED_ALLOW_INTERRUPTS == 1)
|
||||
os_intr_lock();
|
||||
// if interrupts took longer than 45µs, punt on the current frame
|
||||
if((int32_t)(__clock_cycles()-last_mark) > 0) {
|
||||
if((int32_t)(__clock_cycles()-last_mark) > (T1+T2+T3+((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US))) { sei(); return 0; }
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
os_intr_unlock();
|
||||
#ifdef FASTLED_DEBUG_COUNT_FRAME_RETRIES
|
||||
_frame_cnt++;
|
||||
#endif
|
||||
return __clock_cycles() - start;
|
||||
}
|
||||
};
|
||||
|
||||
FASTLED_NAMESPACE_END
|
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastpin_esp8266.h"
|
||||
#include "clockless_esp8266.h"
|
||||
#include "clockless_block_esp8266.h"
|
101
.pio/libdeps/local/FastLED/platforms/esp/8266/fastpin_esp8266.h
Normal file
101
.pio/libdeps/local/FastLED/platforms/esp/8266/fastpin_esp8266.h
Normal file
@ -0,0 +1,101 @@
|
||||
#pragma once
|
||||
|
||||
FASTLED_NAMESPACE_BEGIN
|
||||
|
||||
struct FASTLED_ESP_IO {
|
||||
volatile uint32_t _GPO;
|
||||
volatile uint32_t _GPOS;
|
||||
volatile uint32_t _GPOC;
|
||||
};
|
||||
|
||||
#define _GPB (*(FASTLED_ESP_IO*)(0x60000000+(0x300)))
|
||||
|
||||
|
||||
template<uint8_t PIN, uint32_t MASK> class _ESPPIN {
|
||||
|
||||
public:
|
||||
typedef volatile uint32_t * port_ptr_t;
|
||||
typedef uint32_t port_t;
|
||||
|
||||
inline static void setOutput() { pinMode(PIN, OUTPUT); }
|
||||
inline static void setInput() { pinMode(PIN, INPUT); }
|
||||
|
||||
inline static void hi() __attribute__ ((always_inline)) { if(PIN < 16) { _GPB._GPOS = MASK; } else { GP16O |= MASK; } }
|
||||
inline static void lo() __attribute__ ((always_inline)) { if(PIN < 16) { _GPB._GPOC = MASK; } else { GP16O &= ~MASK; } }
|
||||
inline static void set(register port_t val) __attribute__ ((always_inline)) { if(PIN < 16) { _GPB._GPO = val; } else { GP16O = val; }}
|
||||
|
||||
inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
|
||||
|
||||
inline static void toggle() __attribute__ ((always_inline)) { if(PIN < 16) { _GPB._GPO ^= MASK; } else { GP16O ^= MASK; } }
|
||||
|
||||
inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); }
|
||||
inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); }
|
||||
inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; }
|
||||
|
||||
inline static port_t hival() __attribute__ ((always_inline)) { if (PIN<16) { return GPO | MASK; } else { return GP16O | MASK; } }
|
||||
inline static port_t loval() __attribute__ ((always_inline)) { if (PIN<16) { return GPO & ~MASK; } else { return GP16O & ~MASK; } }
|
||||
inline static port_ptr_t port() __attribute__ ((always_inline)) { if(PIN<16) { return &_GPB._GPO; } else { return &GP16O; } }
|
||||
inline static port_ptr_t sport() __attribute__ ((always_inline)) { return &_GPB._GPOS; } // there is no GP160 support for this
|
||||
inline static port_ptr_t cport() __attribute__ ((always_inline)) { return &_GPB._GPOC; }
|
||||
inline static port_t mask() __attribute__ ((always_inline)) { return MASK; }
|
||||
|
||||
inline static bool isset() __attribute__ ((always_inline)) { return (PIN < 16) ? (GPO & MASK) : (GP16O & MASK); }
|
||||
};
|
||||
|
||||
#define _FL_DEFPIN(PIN, REAL_PIN) template<> class FastPin<PIN> : public _ESPPIN<REAL_PIN, (1<<(REAL_PIN & 0xFF))> {};
|
||||
|
||||
|
||||
#ifdef FASTLED_ESP8266_RAW_PIN_ORDER
|
||||
#define MAX_PIN 16
|
||||
_FL_DEFPIN(0,0); _FL_DEFPIN(1,1); _FL_DEFPIN(2,2); _FL_DEFPIN(3,3);
|
||||
_FL_DEFPIN(4,4); _FL_DEFPIN(5,5);
|
||||
|
||||
// These pins should be disabled, as they always cause WDT resets
|
||||
// _FL_DEFPIN(6,6); _FL_DEFPIN(7,7);
|
||||
// _FL_DEFPIN(8,8); _FL_DEFPIN(9,9); _FL_DEFPIN(10,10); _FL_DEFPIN(11,11);
|
||||
|
||||
_FL_DEFPIN(12,12); _FL_DEFPIN(13,13); _FL_DEFPIN(14,14); _FL_DEFPIN(15,15);
|
||||
_FL_DEFPIN(16,16);
|
||||
|
||||
#define PORTA_FIRST_PIN 12
|
||||
#elif defined(FASTLED_ESP8266_D1_PIN_ORDER)
|
||||
#define MAX_PIN 15
|
||||
_FL_DEFPIN(0,3);
|
||||
_FL_DEFPIN(1,1);
|
||||
_FL_DEFPIN(2,16);
|
||||
_FL_DEFPIN(3,5);
|
||||
_FL_DEFPIN(4,4);
|
||||
_FL_DEFPIN(5,14);
|
||||
_FL_DEFPIN(6,12);
|
||||
_FL_DEFPIN(7,13);
|
||||
_FL_DEFPIN(8,0);
|
||||
_FL_DEFPIN(9,2);
|
||||
_FL_DEFPIN(10,15);
|
||||
_FL_DEFPIN(11,13);
|
||||
_FL_DEFPIN(12,12);
|
||||
_FL_DEFPIN(13,14);
|
||||
_FL_DEFPIN(14,4);
|
||||
_FL_DEFPIN(15,5);
|
||||
|
||||
#define PORTA_FIRST_PIN 12
|
||||
|
||||
#else // if defined(FASTLED_ESP8266_NODEMCU_PIN_ORDER)
|
||||
#define MAX_PIN 10
|
||||
|
||||
// This seems to be the standard Dxx pin mapping on most of the esp boards that i've found
|
||||
_FL_DEFPIN(0,16); _FL_DEFPIN(1,5); _FL_DEFPIN(2,4); _FL_DEFPIN(3,0);
|
||||
_FL_DEFPIN(4,2); _FL_DEFPIN(5,14); _FL_DEFPIN(6,12); _FL_DEFPIN(7,13);
|
||||
_FL_DEFPIN(8,15); _FL_DEFPIN(9,3); _FL_DEFPIN(10,1);
|
||||
|
||||
#define PORTA_FIRST_PIN 6
|
||||
|
||||
// The rest of the pins - these are generally not available
|
||||
// _FL_DEFPIN(11,6);
|
||||
// _FL_DEFPIN(12,7); _FL_DEFPIN(13,8); _FL_DEFPIN(14,9); _FL_DEFPIN(15,10);
|
||||
// _FL_DEFPIN(16,11);
|
||||
|
||||
#endif
|
||||
|
||||
#define HAS_HARDWARE_PIN_SUPPORT
|
||||
|
||||
#define FASTLED_NAMESPACE_END
|
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef ESP8266
|
||||
#define ESP8266
|
||||
#endif
|
||||
|
||||
#define FASTLED_ESP8266
|
||||
|
||||
// Use system millis timer
|
||||
#define FASTLED_HAS_MILLIS
|
||||
|
||||
typedef volatile uint32_t RoReg;
|
||||
typedef volatile uint32_t RwReg;
|
||||
typedef uint32_t prog_uint32_t;
|
||||
|
||||
|
||||
// Default to NOT using PROGMEM here
|
||||
#ifndef FASTLED_USE_PROGMEM
|
||||
# define FASTLED_USE_PROGMEM 0
|
||||
#endif
|
||||
|
||||
#ifndef FASTLED_ALLOW_INTERRUPTS
|
||||
# define FASTLED_ALLOW_INTERRUPTS 1
|
||||
# define INTERRUPT_THRESHOLD 0
|
||||
#endif
|
||||
|
||||
#define NEED_CXX_BITS
|
||||
|
||||
// These can be overridden
|
||||
#if !defined(FASTLED_ESP8266_RAW_PIN_ORDER) && !defined(FASTLED_ESP8266_NODEMCU_PIN_ORDER) && !defined(FASTLED_ESP8266_D1_PIN_ORDER)
|
||||
# ifdef ARDUINO_ESP8266_NODEMCU
|
||||
# define FASTLED_ESP8266_NODEMCU_PIN_ORDER
|
||||
# else
|
||||
# define FASTLED_ESP8266_RAW_PIN_ORDER
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// #define cli() os_intr_lock();
|
||||
// #define sei() os_intr_lock();
|
Reference in New Issue
Block a user