Permalink
Browse files

Tweak 4-way parallel output to work on pins 12-15 on esp8266 - keep b…

…locked out for now, needs some more testing.
  • Loading branch information...
focalintent committed May 22, 2016
1 parent 20e5042 commit baceb63c180d0947a4d505e6458c437f7097bd6d
Showing with 110 additions and 116 deletions.
  1. +2 −0 bitswap.h
  2. +65 −74 platforms/esp/8266/clockless_block_esp8266.h
  3. +27 −35 platforms/esp/8266/clockless_esp8266.h
  4. +16 −7 platforms/esp/8266/fastpin_esp8266.h
View
@@ -168,6 +168,8 @@ __attribute__((always_inline)) inline void slowswap(unsigned char *A, unsigned c
}
}
void transpose8x1_noinline(unsigned char *A, unsigned char *B);
/// Simplified form of bits rotating function. Based on code found here - http://www.hackersdelight.org/hdcodetxt/transpose8.c.txt - rotating
/// data into LSB for a faster write (the code using this data can happily walk the array backwards)
__attribute__((always_inline)) inline void transpose8x1(unsigned char *A, unsigned char *B) {
@@ -4,14 +4,14 @@
#define FASTLED_HAS_BLOCKLESS 1
#define PORTA_FIRST_PIN 0
#define PORT_MASK (((1<<LANES)-1) & 0xFFFF)
#define PORT_MASK (((1<<LANES)-1) & 0x0000FFFFL)
#define MIN(X,Y) (((X)<(Y)) ? (X):(Y))
#define USED_LANES (MIN(LANES,16))
#define LAST_PIN (FIRST_PIN + USED_LANES - 1)
FASTLED_NAMESPACE_BEGIN
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 = 40>
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 = 5>
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;
@@ -23,15 +23,22 @@ class InlineBlockClocklessController : public CPixelLEDController<RGB_ORDER, LAN
virtual int size() { return CLEDController::size() * LANES; }
virtual void showPixels(PixelController<RGB_ORDER, LANES, PORT_MASK> & pixels) {
mWait.wait();
uint32_t clocks = showRGBInternal(pixels);
// mWait.wait();
/*uint32_t clocks = */
int cnt=2;
while(!showRGBInternal(pixels) && cnt--) {
os_intr_unlock();
delayMicroseconds(WAIT_TIME * 10);
os_intr_lock();
showRGBInternal(pixels);
}
// #if FASTLED_ALLOW_INTTERUPTS == 0
// Adjust the timer
// long microsTaken = CLKS_TO_MICROS(clocks);
// MS_COUNTER += (1 + (microsTaken / 1000));
// #endif
mWait.mark();
// mWait.mark();
}
template<int PIN> static void initPin() {
@@ -41,116 +48,89 @@ class InlineBlockClocklessController : public CPixelLEDController<RGB_ORDER, LAN
}
virtual void init() {
initPin<0>();
initPin<1>();
initPin<2>();
initPin<3>();
initPin<4>();
initPin<5>();
initPin<6>();
initPin<7>();
initPin<8>();
initPin<9>();
initPin<10>();
initPin<11>();
// initPin<0>();
// initPin<1>();
// initPin<2>();
// initPin<3>();
// initPin<4>();
// initPin<5>();
// initPin<6>();
// initPin<7>();
// initPin<8>();
// initPin<9>();
// initPin<10>();
// initPin<11>();
initPin<12>();
initPin<13>();
initPin<14>();
initPin<15>();
mPinMask = FastPin<FIRST_PIN>::mask();
mPort = FastPin<FIRST_PIN>::port();
// Serial.print("Mask is "); Serial.println(PORT_MASK);
}
virtual uint16_t getMaxRefreshRate() const { return 400; }
typedef union {
uint8_t bytes[12];
uint16_t shorts[6];
uint32_t raw[3];
uint8_t bytes[8];
uint16_t shorts[4];
uint32_t raw[2];
} Lines;
#define ESP_ADJUST (2*(F_CPU/24000000))
#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 & next_mark, register Lines & b, PixelController<RGB_ORDER, LANES, PORT_MASK> &pixels) { // , register uint32_t & b2) {
register Lines b2;
if(USED_LANES>8) {
transpose8<1,2>(b.bytes,b2.bytes);
transpose8<1,2>(b.bytes+8,b2.bytes+1);
} else {
transpose8x1(b.bytes,b2.bytes);
}
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/2); i++) {
while(__clock_cycles() < next_mark);
next_mark = __clock_cycles() + (T1+T2+T3)-3;
*FastPin<FIRST_PIN>::sport() = PORT_MASK;
for(register uint32_t i = 0; i < USED_LANES; i++) {
while((int32_t)(next_mark - __clock_cycles()) > 0);
next_mark = __clock_cycles() + (T1+T2+T3) + ESP_ADJUST;
*FastPin<FIRST_PIN>::sport() = PORT_MASK << FIRST_PIN;
while((next_mark - __clock_cycles()) > (T2+T3+ESP_ADJUST));
if(USED_LANES>8) {
*FastPin<FIRST_PIN>::cport() = ((~b2.shorts[i]) & PORT_MASK) << FIRST_PIN;
} else {
*FastPin<FIRST_PIN>::cport() = ((~b2.bytes[7-i]) & PORT_MASK) << FIRST_PIN;
}
while((int32_t)(next_mark - __clock_cycles()) > (T2+T3+ESP_ADJUST2));
*FastPin<FIRST_PIN>::cport() = ((uint32_t)(~b2.bytes[7-i]) & PORT_MASK) << FIRST_PIN;
while((next_mark - __clock_cycles()) > (T3));
*FastPin<FIRST_PIN>::cport() = PORT_MASK;
while((int32_t)(next_mark - __clock_cycles()) > (T3 + ESP_ADJUST));
*FastPin<FIRST_PIN>::cport() = PORT_MASK << FIRST_PIN;
b.bytes[i] = pixels.template loadAndScale<PX>(pixels,i,d,scale);
b.bytes[i+(USED_LANES/2)] = pixels.template loadAndScale<PX>(pixels,i+(USED_LANES/2),d,scale);
}
// if folks use an odd numnber of lanes, get the last byte's value here
if(USED_LANES & 0x01) {
b.bytes[USED_LANES-1] = pixels.template loadAndScale<PX>(pixels,USED_LANES-1,d,scale);
}
for(register uint32_t i = USED_LANES/2; i < 8; i++) {
while(__clock_cycles() < next_mark);
next_mark = __clock_cycles() + (T1+T2+T3)-3;
*FastPin<FIRST_PIN>::sport() = PORT_MASK;
while((next_mark - __clock_cycles()) > (T2+T3+ESP_ADJUST));
if(USED_LANES>8) {
*FastPin<FIRST_PIN>::cport() = ((~b2.shorts[i]) & PORT_MASK) << FIRST_PIN;
} else {
// b2.bytes[0] = 0;
*FastPin<FIRST_PIN>::cport() = ((~b2.bytes[7-i]) & PORT_MASK) << FIRST_PIN;
}
for(register uint32_t i = USED_LANES; i < 8; i++) {
while((int32_t)(next_mark - __clock_cycles()) > 0);
next_mark = __clock_cycles() + (T1+T2+T3) + ESP_ADJUST;
*FastPin<FIRST_PIN>::sport() = PORT_MASK << FIRST_PIN;
while((next_mark - __clock_cycles()) > (T3));
*FastPin<FIRST_PIN>::cport() = PORT_MASK;
while((int32_t)(next_mark - __clock_cycles()) > (T2+T3+ESP_ADJUST2));
*FastPin<FIRST_PIN>::cport() = ((uint32_t)(~b2.bytes[7-i]) & PORT_MASK) << FIRST_PIN;
while((int32_t)(next_mark - __clock_cycles()) > (T3 + ESP_ADJUST));
*FastPin<FIRST_PIN>::cport() = PORT_MASK << FIRST_PIN;
}
}
// 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 showRGBInternal(PixelController<RGB_ORDER, LANES, PORT_MASK> &allpixels) {
// Get access to the clock
uint32_t _start = __clock_cycles();
// Setup the pixel controller and load/scale the first byte
allpixels.preStepFirstByteDithering();
register Lines b0;
Lines b0;
allpixels.preStepFirstByteDithering();
for(int i = 0; i < USED_LANES; i++) {
b0.bytes[i] = allpixels.loadAndScale0(i);
}
allpixels.preStepFirstByteDithering();
os_intr_lock();
uint32_t next_mark = __clock_cycles() + (T1+T2+T3);
uint32_t _start = __clock_cycles();
uint32_t next_mark = _start;
while(allpixels.has(1)) {
#if (FASTLED_ALLOW_INTERRUPTS == 1)
os_intr_lock();
// if interrupts took longer than 45µs, punt on the current frame
if(__clock_cycles() > next_mark) {
if((__clock_cycles()-next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); return __clock_cycles(); }
}
#endif
allpixels.stepDithering();
// Write first byte, read next byte
writeBits<8+XTRA0,1>(next_mark, b0, allpixels);
@@ -160,9 +140,20 @@ class InlineBlockClocklessController : public CPixelLEDController<RGB_ORDER, LAN
// Write third byte
writeBits<8+XTRA0,0>(next_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()-next_mark) > 0) {
if((int32_t)(__clock_cycles()-next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { os_intr_unlock(); return 0; }
}
#endif
};
os_intr_unlock();
@@ -9,7 +9,7 @@ __attribute__ ((always_inline)) inline static uint32_t __clock_cycles() {
return cyc;
}
#ifndef FASTLED_INTERRUPT_RETRY_COUNT
#ifndef FASTLED_INTERRUPT_RETRY_COUNT
#define FASTLED_INTERRUPT_RETRY_COUNT 2
#endif
@@ -46,55 +46,36 @@ class ClocklessController : public CPixelLEDController<RGB_ORDER> {
// mWait.mark();
}
#define _ESP_ADJ (6)
template<int BITS> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register uint8_t b) {
for(register uint32_t i = BITS; i > 0; i--) {
while(__clock_cycles() < next_mark);
#define _ESP_ADJ (0)
#define _ESP_ADJ2 (0)
template<int BITS> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register uint32_t b) {
b = ~b; b <<= 24;
for(register uint32_t i = BITS; i > 0; i--) {
while((int32_t)(next_mark - __clock_cycles()) > 0);
next_mark = __clock_cycles() + (T1+T2+T3 + _ESP_ADJ);
FastPin<DATA_PIN>::hi();
if(b&0x80) {
while((next_mark - __clock_cycles()) > (T3 + _ESP_ADJ));
FastPin<DATA_PIN>::lo();
} else {
while((next_mark - __clock_cycles()) > (T2+T3 + 40));
FastPin<DATA_PIN>::lo();
}
b <<= 1;
}
while((int32_t)(next_mark - __clock_cycles()) > (T2+T3 + _ESP_ADJ2));
if(b & 0x80000000L) { FastPin<DATA_PIN>::lo(); }
b <<= 1;
// while(__clock_cycles() < next_mark);
// next_mark = __clock_cycles() + (T1+T2+T3);
// FastPin<DATA_PIN>::hi();
//
// if(b&0x80) {
// while((next_mark - __clock_cycles()) > (T3+(2*(F_CPU/24000000))));
// FastPin<DATA_PIN>::lo();
// } else {
// while((next_mark - __clock_cycles()) > (T2+T3+(2*(F_CPU/24000000))));
// FastPin<DATA_PIN>::lo();
// }
while((int32_t)(next_mark - __clock_cycles()) > (T3 + _ESP_ADJ));
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 uint8_t b = pixels.loadAndScale0();
register uint32_t b = pixels.loadAndScale0();
pixels.preStepFirstByteDithering();
os_intr_lock();
uint32_t start = __clock_cycles();
uint32_t next_mark = start + (T1+T2+T3 + _ESP_ADJ);
while(pixels.has(1)) {
pixels.stepDithering();
#if (FASTLED_ALLOW_INTERRUPTS == 1)
os_intr_lock();
// if interrupts took longer than 45µs, punt on the current frame
if(__clock_cycles() > next_mark) {
if((__clock_cycles()-next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); return 0; }
}
#endif
// Write first byte, read next byte
writeBits<8+XTRA0>(next_mark, b);
b = pixels.loadAndScale1();
@@ -106,9 +87,20 @@ class ClocklessController : public CPixelLEDController<RGB_ORDER> {
// Write third byte, read 1st byte of next pixel
writeBits<8+XTRA0>(next_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()-next_mark) > 0) {
if((int32_t)(__clock_cycles()-next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); return 0; }
}
#endif
};
os_intr_unlock();
@@ -2,6 +2,15 @@
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:
@@ -11,23 +20,23 @@ template<uint8_t PIN, uint32_t MASK> class _ESPPIN {
inline static void setOutput() { pinMode(PIN, OUTPUT); }
inline static void setInput() { pinMode(PIN, INPUT); }
inline static void hi() __attribute__ ((always_inline)) { if(PIN < 16) { GPOS = MASK; } else { GP16O |= MASK; } }
inline static void lo() __attribute__ ((always_inline)) { if(PIN < 16) { GPOC = MASK; } else { GP16O &= ~MASK; } }
inline static void set(register port_t val) __attribute__ ((always_inline)) { if(PIN < 16) { GPO = val; } else { GP16O = val; }}
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) { GPO ^= MASK; } else { GP16O ^= MASK; } }
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 &GPO; } else { return &GP16O; } }
inline static port_ptr_t sport() __attribute__ ((always_inline)) { return &GPOS; } // there is no GP160 support for this
inline static port_ptr_t cport() __attribute__ ((always_inline)) { return &GPOC; }
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); }

0 comments on commit baceb63

Please sign in to comment.