Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/FastLED/FastLED.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'fastspi_bitbang.h')
-rw-r--r--fastspi_bitbang.h166
1 files changed, 77 insertions, 89 deletions
diff --git a/fastspi_bitbang.h b/fastspi_bitbang.h
index f9c1a218..b596f628 100644
--- a/fastspi_bitbang.h
+++ b/fastspi_bitbang.h
@@ -10,7 +10,7 @@
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <uint8_t DATA_PIN, uint8_t CLOCK_PIN, uint8_t SPI_SPEED>
-class AVRSoftwareSPIOutput {
+class AVRSoftwareSPIOutput {
// The data types for pointers to the pin port - typedef'd here from the Pin definition because on avr these
// are pointers to 8 bit values, while on arm they are 32 bit
typedef typename FastPin<DATA_PIN>::port_ptr_t data_ptr_t;
@@ -41,14 +41,14 @@ public:
// wait until the SPI subsystem is ready for more data to write. A NOP when bitbanging
static void wait() __attribute__((always_inline)) { }
static void waitFully() __attribute__((always_inline)) { wait(); }
-
+
static void writeByteNoWait(uint8_t b) __attribute__((always_inline)) { writeByte(b); }
static void writeBytePostWait(uint8_t b) __attribute__((always_inline)) { writeByte(b); wait(); }
static void writeWord(uint16_t w) __attribute__((always_inline)) { writeByte(w>>8); writeByte(w&0xFF); }
-
+
// naive writeByte implelentation, simply calls writeBit on the 8 bits in the byte.
- static void writeByte(uint8_t b) __attribute__((always_inline)) {
+ static void writeByte(uint8_t b) {
writeBit<7>(b);
writeBit<6>(b);
writeBit<5>(b);
@@ -59,9 +59,9 @@ public:
writeBit<0>(b);
}
-private:
+private:
// writeByte implementation with data/clock registers passed in.
- static void writeByte(uint8_t b, clock_ptr_t clockpin, data_ptr_t datapin) __attribute__((always_inline)) {
+ static void writeByte(uint8_t b, clock_ptr_t clockpin, data_ptr_t datapin) {
writeBit<7>(b, clockpin, datapin);
writeBit<6>(b, clockpin, datapin);
writeBit<5>(b, clockpin, datapin);
@@ -73,11 +73,11 @@ private:
}
// writeByte implementation with the data register passed in and prebaked values for data hi w/clock hi and
- // low and data lo w/clock hi and lo. This is to be used when clock and data are on the same GPIO register,
+ // low and data lo w/clock hi and lo. This is to be used when clock and data are on the same GPIO register,
// can get close to getting a bit out the door in 2 clock cycles!
- static void writeByte(uint8_t b, data_ptr_t datapin,
- data_t hival, data_t loval,
- clock_t hiclock, clock_t loclock) __attribute__((always_inline, hot)) {
+ static void writeByte(uint8_t b, data_ptr_t datapin,
+ data_t hival, data_t loval,
+ clock_t hiclock, clock_t loclock) {
writeBit<7>(b, datapin, hival, loval, hiclock, loclock);
writeBit<6>(b, datapin, hival, loval, hiclock, loclock);
writeBit<5>(b, datapin, hival, loval, hiclock, loclock);
@@ -91,9 +91,9 @@ private:
// writeByte implementation with not just registers passed in, but pre-baked values for said registers for
// data hi/lo and clock hi/lo values. Note: weird things will happen if this method is called in cases where
// the data and clock pins are on the same port! Don't do that!
- static void writeByte(uint8_t b, clock_ptr_t clockpin, data_ptr_t datapin,
- data_t hival, data_t loval,
- clock_t hiclock, clock_t loclock) __attribute__((always_inline)) {
+ static void writeByte(uint8_t b, clock_ptr_t clockpin, data_ptr_t datapin,
+ data_t hival, data_t loval,
+ clock_t hiclock, clock_t loclock) {
writeBit<7>(b, clockpin, datapin, hival, loval, hiclock, loclock);
writeBit<6>(b, clockpin, datapin, hival, loval, hiclock, loclock);
writeBit<5>(b, clockpin, datapin, hival, loval, hiclock, loclock);
@@ -105,37 +105,38 @@ private:
}
public:
- #define SPI_DELAY delaycycles< (SPI_SPEED-2) / 2>();
+ #define SPI_DELAY delaycycles<1+((SPI_SPEED-2) / 2)>();
+ #define SPI_DELAY_HALF delaycycles<1+ ((SPI_SPEED-4) / 4)>();
// write the BIT'th bit out via spi, setting the data pin then strobing the clcok
- template <uint8_t BIT> __attribute__((always_inline, hot)) inline static void writeBit(uint8_t b) {
- if(b & (1 << BIT)) {
+ template <uint8_t BIT> __attribute__((always_inline, hot)) inline static void writeBit(uint8_t b) {
+ if(b & (1 << BIT)) {
FastPin<DATA_PIN>::hi();
- if(SPI_SPEED < 3) {
+ if(SPI_SPEED < 3) {
FastPin<CLOCK_PIN>::strobe();
- } else {
+ } else {
FastPin<CLOCK_PIN>::hi(); SPI_DELAY;
FastPin<CLOCK_PIN>::lo(); SPI_DELAY;
}
- } else {
+ } else {
FastPin<DATA_PIN>::lo();
- if(SPI_SPEED < 3) {
+ if(SPI_SPEED < 3) {
FastPin<CLOCK_PIN>::strobe();
- } else {
+ } else {
FastPin<CLOCK_PIN>::hi(); SPI_DELAY;
FastPin<CLOCK_PIN>::lo(); SPI_DELAY;
}
}
}
-
+
private:
// write the BIT'th bit out via spi, setting the data pin then strobing the clock, using the passed in pin registers to accelerate access if needed
- template <uint8_t BIT> __attribute__((always_inline)) inline static void writeBit(uint8_t b, clock_ptr_t clockpin, data_ptr_t datapin) {
- if(b & (1 << BIT)) {
+ template <uint8_t BIT> __attribute__((always_inline)) inline static void writeBit(uint8_t b, clock_ptr_t clockpin, data_ptr_t datapin) {
+ if(b & (1 << BIT)) {
FastPin<DATA_PIN>::hi(datapin);
FastPin<CLOCK_PIN>::hi(clockpin); SPI_DELAY;
FastPin<CLOCK_PIN>::lo(clockpin); SPI_DELAY;
- } else {
+ } else {
FastPin<DATA_PIN>::lo(datapin);
FastPin<CLOCK_PIN>::hi(clockpin); SPI_DELAY;
FastPin<CLOCK_PIN>::lo(clockpin); SPI_DELAY;
@@ -145,14 +146,14 @@ private:
// the version of write to use when clock and data are on separate pins with precomputed values for setting
// the clock and data pins
- template <uint8_t BIT> __attribute__((always_inline)) inline static void writeBit(uint8_t b, clock_ptr_t clockpin, data_ptr_t datapin,
- data_t hival, data_t loval, clock_t hiclock, clock_t loclock) {
+ template <uint8_t BIT> __attribute__((always_inline)) inline static void writeBit(uint8_t b, clock_ptr_t clockpin, data_ptr_t datapin,
+ data_t hival, data_t loval, clock_t hiclock, clock_t loclock) {
// // only need to explicitly set clock hi if clock and data are on different ports
- if(b & (1 << BIT)) {
+ if(b & (1 << BIT)) {
FastPin<DATA_PIN>::fastset(datapin, hival);
FastPin<CLOCK_PIN>::fastset(clockpin, hiclock); SPI_DELAY;
FastPin<CLOCK_PIN>::fastset(clockpin, loclock); SPI_DELAY;
- } else {
+ } else {
// NOP;
FastPin<DATA_PIN>::fastset(datapin, loval);
FastPin<CLOCK_PIN>::fastset(clockpin, hiclock); SPI_DELAY;
@@ -162,21 +163,21 @@ private:
// the version of write to use when clock and data are on the same port with precomputed values for the various
// combinations
- template <uint8_t BIT> __attribute__((always_inline)) inline static void writeBit(uint8_t b, data_ptr_t clockdatapin,
- data_t datahiclockhi, data_t dataloclockhi,
- data_t datahiclocklo, data_t dataloclocklo) {
+ template <uint8_t BIT> __attribute__((always_inline)) inline static void writeBit(uint8_t b, data_ptr_t clockdatapin,
+ data_t datahiclockhi, data_t dataloclockhi,
+ data_t datahiclocklo, data_t dataloclocklo) {
#if 0
writeBit<BIT>(b);
#else
- if(b & (1 << BIT)) {
- FastPin<DATA_PIN>::fastset(clockdatapin, datahiclocklo); SPI_DELAY;
+ if(b & (1 << BIT)) {
+ FastPin<DATA_PIN>::fastset(clockdatapin, datahiclocklo); SPI_DELAY_HALF;
FastPin<DATA_PIN>::fastset(clockdatapin, datahiclockhi); SPI_DELAY;
- FastPin<DATA_PIN>::fastset(clockdatapin, datahiclocklo); SPI_DELAY;
- } else {
+ FastPin<DATA_PIN>::fastset(clockdatapin, datahiclocklo); SPI_DELAY_HALF;
+ } else {
// NOP;
- FastPin<DATA_PIN>::fastset(clockdatapin, dataloclocklo); SPI_DELAY;
+ FastPin<DATA_PIN>::fastset(clockdatapin, dataloclocklo); SPI_DELAY_HALF;
FastPin<DATA_PIN>::fastset(clockdatapin, dataloclockhi); SPI_DELAY;
- FastPin<DATA_PIN>::fastset(clockdatapin, dataloclocklo); SPI_DELAY;
+ FastPin<DATA_PIN>::fastset(clockdatapin, dataloclocklo); SPI_DELAY_HALF;
}
#endif
}
@@ -190,7 +191,7 @@ public:
void release() { if(m_pSelect != NULL) { m_pSelect->release(); } } // FastPin<SELECT_PIN>::lo(); }
// Write out len bytes of the given value out over SPI. Useful for quickly flushing, say, a line of 0's down the line.
- void writeBytesValue(uint8_t value, int len) {
+ void writeBytesValue(uint8_t value, int len) {
select();
writeBytesValueRaw(value, len);
release();
@@ -201,7 +202,7 @@ public:
// TODO: Weird things may happen if software bitbanging SPI output and other pins on the output reigsters are being twiddled. Need
// to allow specifying whether or not exclusive i/o access is allowed during this process, and if i/o access is not allowed fall
// back to the degenerative code below
- while(len--) {
+ while(len--) {
writeByte(value);
}
#else
@@ -215,18 +216,18 @@ public:
register data_t datalo = FastPin<DATA_PIN>::loval();
register clock_t clockhi = FastPin<CLOCK_PIN>::hival();
register clock_t clocklo = FastPin<CLOCK_PIN>::loval();
- while(len--) {
+ while(len--) {
writeByte(value, clockpin, datapin, datahi, datalo, clockhi, clocklo);
}
} else {
- // If data and clock are on the same port then we can combine setting the data and clock pins
+ // If data and clock are on the same port then we can combine setting the data and clock pins
register data_t datahi_clockhi = FastPin<DATA_PIN>::hival() | FastPin<CLOCK_PIN>::mask();
register data_t datalo_clockhi = FastPin<DATA_PIN>::loval() | FastPin<CLOCK_PIN>::mask();
register data_t datahi_clocklo = FastPin<DATA_PIN>::hival() & ~FastPin<CLOCK_PIN>::mask();
register data_t datalo_clocklo = FastPin<DATA_PIN>::loval() & ~FastPin<CLOCK_PIN>::mask();
- while(len--) {
+ while(len--) {
writeByte(value, datapin, datahi_clockhi, datalo_clockhi, datahi_clocklo, datalo_clocklo);
}
}
@@ -234,12 +235,12 @@ public:
}
// write a block of len uint8_ts out. Need to type this better so that explicit casts into the call aren't required.
- // note that this template version takes a class parameter for a per-byte modifier to the data.
- template <class D> void writeBytes(register uint8_t *data, int len) {
+ // note that this template version takes a class parameter for a per-byte modifier to the data.
+ template <class D> void writeBytes(register uint8_t *data, int len) {
select();
#ifdef FAST_SPI_INTERRUPTS_WRITE_PINS
uint8_t *end = data + len;
- while(data != end) {
+ while(data != end) {
writeByte(D::adjust(*data++));
}
#else
@@ -255,28 +256,28 @@ public:
register clock_t clocklo = FastPin<CLOCK_PIN>::loval();
uint8_t *end = data + len;
- while(data != end) {
+ while(data != end) {
writeByte(D::adjust(*data++), clockpin, datapin, datahi, datalo, clockhi, clocklo);
}
} else {
// FastPin<CLOCK_PIN>::hi();
- // If data and clock are on the same port then we can combine setting the data and clock pins
+ // If data and clock are on the same port then we can combine setting the data and clock pins
register data_t datahi_clockhi = FastPin<DATA_PIN>::hival() | FastPin<CLOCK_PIN>::mask();
register data_t datalo_clockhi = FastPin<DATA_PIN>::loval() | FastPin<CLOCK_PIN>::mask();
register data_t datahi_clocklo = FastPin<DATA_PIN>::hival() & ~FastPin<CLOCK_PIN>::mask();
register data_t datalo_clocklo = FastPin<DATA_PIN>::loval() & ~FastPin<CLOCK_PIN>::mask();
-
+
uint8_t *end = data + len;
- while(data != end) {
+ while(data != end) {
writeByte(D::adjust(*data++), datapin, datahi_clockhi, datalo_clockhi, datahi_clocklo, datalo_clocklo);
}
// FastPin<CLOCK_PIN>::lo();
}
#endif
D::postBlock(len);
- release();
+ release();
}
// default version of writing a block of data out to the SPI port, with no data modifications being made
@@ -286,21 +287,22 @@ public:
// write a block of uint8_ts out in groups of three. len is the total number of uint8_ts to write out. The template
// parameters indicate how many uint8_ts to skip at the beginning of each grouping, as well as a class specifying a per
// byte of data modification to be made. (See DATA_NOP above)
- template <uint8_t SKIP, class D, EOrder RGB_ORDER> void writeBytes3(register uint8_t *data, int len, register uint8_t scale) {
+ template <uint8_t FLAGS, class D, EOrder RGB_ORDER> __attribute__((noinline)) void writePixels(PixelController<RGB_ORDER> pixels) {
select();
+ int len = pixels.mLen;
#ifdef FAST_SPI_INTERRUPTS_WRITE_PINS
// If interrupts or other things may be generating output while we're working on things, then we need
// to use this block
- uint8_t *end = data + len;
- while(data != end) {
- if(SKIP & FLAG_START_BIT) {
+ while(pixels.has(1)) {
+ if(FLAGS & FLAG_START_BIT) {
writeBit<0>(1);
}
- writeByte(D::adjust(data[SPI_B0], scale));
- writeByte(D::adjust(data[SPI_B1], scale));
- writeByte(D::adjust(data[SPI_B2], scale));
- data += SPI_ADVANCE;
+ writeByte(D::adjust(pixels.loadAndScale0()));
+ writeByte(D::adjust(pixels.loadAndScale1()));
+ writeByte(D::adjust(pixels.loadAndScale2()));
+ pixels.advanceData();
+ pixels.stepDithering();
}
#else
// If we can guaruntee that no one else will be writing data while we are running (namely, changing the values of the PORT/PDOR pins)
@@ -315,54 +317,40 @@ public:
register data_t datalo = FastPin<DATA_PIN>::loval();
register clock_t clockhi = FastPin<CLOCK_PIN>::hival();
register clock_t clocklo = FastPin<CLOCK_PIN>::loval();
- uint8_t *end = data + len;
- while(data != end) {
- if(SKIP & FLAG_START_BIT) {
+ while(pixels.has(1)) {
+ if(FLAGS & FLAG_START_BIT) {
writeBit<0>(1, clockpin, datapin, datahi, datalo, clockhi, clocklo);
}
- writeByte(D::adjust(data[SPI_B0], scale), clockpin, datapin, datahi, datalo, clockhi, clocklo);
- writeByte(D::adjust(data[SPI_B1], scale), clockpin, datapin, datahi, datalo, clockhi, clocklo);
- writeByte(D::adjust(data[SPI_B2], scale), clockpin, datapin, datahi, datalo, clockhi, clocklo);
- data += SPI_ADVANCE;
+ writeByte(D::adjust(pixels.loadAndScale0()), clockpin, datapin, datahi, datalo, clockhi, clocklo);
+ writeByte(D::adjust(pixels.loadAndScale1()), clockpin, datapin, datahi, datalo, clockhi, clocklo);
+ writeByte(D::adjust(pixels.loadAndScale2()), clockpin, datapin, datahi, datalo, clockhi, clocklo);
+ pixels.advanceData();
+ pixels.stepDithering();
}
} else {
- // If data and clock are on the same port then we can combine setting the data and clock pins
+ // If data and clock are on the same port then we can combine setting the data and clock pins
register data_t datahi_clockhi = FastPin<DATA_PIN>::hival() | FastPin<CLOCK_PIN>::mask();
register data_t datalo_clockhi = FastPin<DATA_PIN>::loval() | FastPin<CLOCK_PIN>::mask();
register data_t datahi_clocklo = FastPin<DATA_PIN>::hival() & ~FastPin<CLOCK_PIN>::mask();
register data_t datalo_clocklo = FastPin<DATA_PIN>::loval() & ~FastPin<CLOCK_PIN>::mask();
-
- uint8_t *end = data + len;
- while(data != end) {
- if(SKIP & FLAG_START_BIT) {
+ while(pixels.has(1)) {
+ if(FLAGS & FLAG_START_BIT) {
writeBit<0>(1, datapin, datahi_clockhi, datalo_clockhi, datahi_clocklo, datalo_clocklo);
}
- writeByte(D::adjust(data[SPI_B0], scale), datapin, datahi_clockhi, datalo_clockhi, datahi_clocklo, datalo_clocklo);
- writeByte(D::adjust(data[SPI_B1], scale), datapin, datahi_clockhi, datalo_clockhi, datahi_clocklo, datalo_clocklo);
- writeByte(D::adjust(data[SPI_B2], scale), datapin, datahi_clockhi, datalo_clockhi, datahi_clocklo, datalo_clocklo);
- data += SPI_ADVANCE;
+ writeByte(D::adjust(pixels.loadAndScale0()), datapin, datahi_clockhi, datalo_clockhi, datahi_clocklo, datalo_clocklo);
+ writeByte(D::adjust(pixels.loadAndScale1()), datapin, datahi_clockhi, datalo_clockhi, datahi_clocklo, datalo_clocklo);
+ writeByte(D::adjust(pixels.loadAndScale2()), datapin, datahi_clockhi, datalo_clockhi, datahi_clocklo, datalo_clocklo);
+ pixels.advanceData();
+ pixels.stepDithering();
}
- }
+ }
#endif
D::postBlock(len);
release();
}
-
- template <uint8_t SKIP, EOrder RGB_ORDER> void writeBytes3(register uint8_t *data, int len, register uint8_t scale) {
- writeBytes3<SKIP, DATA_NOP, RGB_ORDER>(data, len, scale);
- }
- template <class D, EOrder RGB_ORDER> void writeBytes3(register uint8_t *data, int len, register uint8_t scale) {
- writeBytes3<0, D, RGB_ORDER>(data, len, scale);
- }
- template <EOrder RGB_ORDER> void writeBytes3(register uint8_t *data, int len, register uint8_t scale) {
- writeBytes3<0, DATA_NOP, RGB_ORDER>(data, len, scale);
- }
- void writeBytes3(register uint8_t *data, int len, register uint8_t scale) {
- writeBytes3<0, DATA_NOP, RGB>(data, len, scale);
- }
};
#endif