diff options
-rw-r--r-- | fastpin_arm_sam.h | 3 | ||||
-rw-r--r-- | fastspi.h | 6 | ||||
-rw-r--r-- | fastspi_arm_k20.h | 3 | ||||
-rw-r--r-- | fastspi_arm_sam.h | 162 | ||||
-rw-r--r-- | fastspi_ref.h | 98 | ||||
-rw-r--r-- | preview_changes.txt | 8 |
6 files changed, 257 insertions, 23 deletions
diff --git a/fastpin_arm_sam.h b/fastpin_arm_sam.h index 9aad9425..164754c8 100644 --- a/fastpin_arm_sam.h +++ b/fastpin_arm_sam.h @@ -96,6 +96,9 @@ _DEFPIN_DUE(68, 1, A); _DEFPIN_DUE(69, 0, A); _DEFPIN_DUE(70, 17, A); _DEFPIN_DU _DEFPIN_DUE(72, 30, C); _DEFPIN_DUE(73, 21, A); _DEFPIN_DUE(74, 25, A); _DEFPIN_DUE(75, 26, A); _DEFPIN_DUE(76, 27, A); _DEFPIN_DUE(77, 28, A); _DEFPIN_DUE(78, 23, B); +#define SPI_DATA 75 +#define SPI_CLOCK 76 +#define ARM_HARDWARE_SPI #define HAS_HARDWARE_PIN_SUPPORT #endif @@ -43,6 +43,7 @@ public: // Include the various specific SPI implementations #include "fastspi_bitbang.h" #include "fastspi_arm_k20.h" +#include "fastspi_arm_sam.h" #include "fastspi_avr.h" #include "fastspi_dma.h" @@ -67,6 +68,11 @@ class SoftwareSPIOutput : public AVRSoftwareSPIOutput<_DATA_PIN, _CLOCK_PIN, _SP template<uint8_t SPI_SPEED> class SPIOutput<SPI_DATA, SPI_CLOCK, SPI_SPEED> : public ARMHardwareSPIOutput<SPI_DATA, SPI_CLOCK, SPI_SPEED> {}; +#elif defined(__SAM3X8E__) + +template<uint8_t SPI_SPEED> +class SPIOutput<SPI_DATA, SPI_CLOCK, SPI_SPEED> : public SAMHardwareSPIOutput<SPI_DATA, SPI_CLOCK, SPI_SPEED> {}; + #else template<uint8_t SPI_SPEED> diff --git a/fastspi_arm_k20.h b/fastspi_arm_k20.h index 706755d2..906e1a27 100644 --- a/fastspi_arm_k20.h +++ b/fastspi_arm_k20.h @@ -247,7 +247,7 @@ public: template <uint8_t BIT> inline static void writeBit(uint8_t b) { uint32_t ctar1_save = SPI0_CTAR1; - // Clear out the FMSZ bits, reset them for 9 bits transferd for the start bit + // Clear out the FMSZ bits, reset them for 1 bit transferd for the start bit uint32_t ctar1 = (ctar1_save & (~SPI_CTAR_FMSZ(15))) | SPI_CTAR_FMSZ(0); update_ctar1(ctar1); @@ -278,6 +278,7 @@ public: setSPIRate(); uint8_t *end = data + len; select(); + // could be optimized to write 16bit words out instead of 8bit bytes while(data != end) { writeByte(D::adjust(*data++)); } diff --git a/fastspi_arm_sam.h b/fastspi_arm_sam.h index 9b58049d..e9d822c1 100644 --- a/fastspi_arm_sam.h +++ b/fastspi_arm_sam.h @@ -1,60 +1,184 @@ #ifndef __INC_FASTSPI_ARM_SAM_H #define __INC_FASTSPI_ARM_SAM_H +#if defined(__SAM3X8E__) +#define m_SPI ((Spi*)SPI0) + template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint8_t _SPI_CLOCK_DIVIDER> class SAMHardwareSPIOutput { + Selectable *m_pSelect; + + static inline void waitForEmpty() { while ((m_SPI->SPI_SR & SPI_SR_TDRE) == 0); } + + void enableConfig() { m_SPI->SPI_WPMR &= ~SPI_WPMR_WPEN; } + void disableConfig() { m_SPI->SPI_WPMR |= SPI_WPMR_WPEN; } + + void enableSPI() { m_SPI->SPI_CR |= SPI_CR_SPIEN; } + void disableSPI() { m_SPI->SPI_CR &= ~SPI_CR_SPIEN; } + + void readyTransferBits(register byte bits) { + bits -= 8; + // don't change the number of transfer bits while data is still being transferred from TDR to the shift register + waitForEmpty(); + m_SPI->SPI_CSR[0] = (bits << SPI_CSR_BITS_Pos) | SPI_CSR_SCBR(_SPI_CLOCK_DIVIDER); + } + + template<int BITS> static inline void writeBits(uint16_t w) { + waitForEmpty(); + m_SPI->SPI_CSR[0] = (BITS << SPI_CSR_BITS_Pos) | SPI_CSR_SCBR(_SPI_CLOCK_DIVIDER); + m_SPI->SPI_TDR = w; + } public: - SAMHardwareSPIOutput() { /* TODO */ } - SAMHArdwareSPIOutput(Selectable *pSelect) { /* TODO */ } + SAMHardwareSPIOutput() { m_pSelect = NULL; } + SAMHardwareSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; } // set the object representing the selectable void setSelect(Selectable *pSelect) { /* TODO */ } // initialize the SPI subssytem - void init() { /* TODO */ } + void init() { + // m_SPI = SPI0; + + // set the output pins + FastPin<_DATA_PIN>::setOutput(); + FastPin<_CLOCK_PIN>::setOutput(); + release(); + + // Configure the SPI clock, divider between 1-255 + // SCBR = _SPI_CLOCK_DIVIDER + + // Enable writes + enableConfig(); + + // Configure SPI as master, enable + enableSPI(); + + // Only bit in MR we want on is master, everything is left to 0, see commented out psuedocode + m_SPI->SPI_MR = SPI_MR_MSTR; + // SPI_MR.MSTR = 1; set master + // SPI_MR.PS = 0 fixed peripheral select + // SPI_MR.PCSDEC = 0 direct connect CS decode + // SPI_MR.PCS = 0 device 0 + // SPI_MR.DLYBCS = 0; 0 delay between chip selects + + // set inter-transfer delay to 0 + // DLYBCT = 0; + // DLYBS = 0; + + // CSR items + // SPI_CSR0 = 0; + // SPI_CSR0.BITS = 0 (8bit), 1 (9bit), 8 (16bit) + // SPI_CSR0.SCBR = _SPI_CLOCK_DIVIDER + // SPI_CSR0.DLYBS = 0, SPI_CSR0.DLYBCT = 0 + + } // latch the CS select - void select() { /* TODO */ } + void inline select() __attribute__((always_inline)) { if(m_pSelect != NULL) { m_pSelect->select(); } } // release the CS select - void release() { /* TODO */ } + void inline release() __attribute__((always_inline)) { if(m_pSelect != NULL) { m_pSelect->release(); } } // wait until all queued up data has been written - void waitFully(); + void waitFully() { while((m_SPI->SPI_SR & SPI_SR_TXEMPTY) == 0); } // write a byte out via SPI (returns immediately on writing register) - void writeByte(uint8_t b) { /* TODO */ } + static void writeByte(uint8_t b) { + writeBits<8>(b); + } + // write a word out via SPI (returns immediately on writing register) - void writeWord(uint16_t w) { /* TODO */ } + static void writeWord(uint16_t w) { + writeBits<16>(w); + } // A raw set of writing byte values, assumes setup/init/waiting done elsewhere - void writeBytesValueRaw(uint8_t value, int len) { /* TODO */ } + static void writeBytesValueRaw(uint8_t value, int len) { + while(len--) { writeByte(value); } + } // A full cycle of writing a value for len bytes, including select, release, and waiting - void writeBytesValue(uint8_t value, int len) { /* TODO */ } + void writeBytesValue(uint8_t value, int len) { + select(); writeBytesValueRaw(value, len); release(); + } + + template <class D> void writeBytes(register uint8_t *data, int len) { + uint8_t *end = data + len; + select(); + // could be optimized to write 16bit words out instead of 8bit bytes + while(data != end) { + writeByte(D::adjust(*data++)); + } + D::postBlock(len); + waitFully(); + release(); + } - // A full cycle of writing a raw block of data out, including select, release, and waiting - void writeBytes(uint8_t *data, int len) { /* TODO */ } + void writeBytes(register uint8_t *data, int len) { writeBytes<DATA_NOP>(data, len); } // write a single bit out, which bit from the passed in byte is determined by template parameter - template <uint8_t BIT> inline static void writeBit(uint8_t b) { /* TODO */ } + // not the most efficient mechanism in the world - but should be enough for sm16716 and friends + template <uint8_t BIT> inline void writeBit(uint8_t b) { + // need to wait for all exisiting data to go out the door, first + waitFully(); + disableSPI(); + if(b & (1 << BIT)) { + FastPin<_DATA_PIN>::hi(); + } else { + FastPin<_DATA_PIN>::lo(); + } - template <uint8_t FLAGS, class D, EOrder RGB_ORDER> void writeBytes3(register uint8_t *data, int len, register uint8_t scale, bool advance=true, uint8_t skip=0) { /* TODO*/ } + FastPin<_CLOCK_PIN>::hi(); + FastPin<_CLOCK_PIN>::lo(); + enableSPI(); + } + + // 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 and/or end of each grouping + template <uint8_t FLAGS, class D, EOrder RGB_ORDER> void writeBytes3(register uint8_t *data, int len, register CRGB scale, bool advance=true, uint8_t skip=0) { + select(); + uint8_t *end = data + len; + + // Setup the pixel controller + PixelController<RGB_ORDER> pixels(data, scale, true, advance, skip); + + while(data != end) { + if(FLAGS & FLAG_START_BIT) { + writeBit<0>(1); + writeByte(D::adjust(pixels.loadAndScale0())); + writeByte(D::adjust(pixels.loadAndScale1())); + writeByte(D::adjust(pixels.loadAndScale2())); + } else { + writeByte(D::adjust(pixels.loadAndScale0())); + writeByte(D::adjust(pixels.loadAndScale1())); + writeByte(D::adjust(pixels.loadAndScale2())); + } + + pixels.advanceData(); + pixels.stepDithering(); + data += (3+skip); + } + D::postBlock(len); + release(); + } // template instantiations for writeBytes 3 - template <uint8_t FLAGS, EOrder RGB_ORDER> void writeBytes3(register uint8_t *data, int len, register uint8_t scale, bool advance=true, uint8_t skip=0) { - writeBytes3<SKIP, DATA_NOP, RGB_ORDER>(data, len, scale, advance, skip); + template <uint8_t FLAGS, EOrder RGB_ORDER> void writeBytes3(register uint8_t *data, int len, register CRGB scale, bool advance=true, uint8_t skip=0) { + writeBytes3<FLAGS, DATA_NOP, RGB_ORDER>(data, len, scale, advance, skip); } - template <class D, EOrder RGB_ORDER> void writeBytes3(register uint8_t *data, int len, register uint8_t scale, bool advance=true, uint8_t skip=0) { + template <class D, EOrder RGB_ORDER> void writeBytes3(register uint8_t *data, int len, register CRGB scale, bool advance=true, uint8_t skip=0) { writeBytes3<0, D, RGB_ORDER>(data, len, scale, advance, skip); } - template <EOrder RGB_ORDER> void writeBytes3(register uint8_t *data, int len, register uint8_t scale, bool advance=true, uint8_t skip=0) { + template <EOrder RGB_ORDER> void writeBytes3(register uint8_t *data, int len, register CRGB scale, bool advance=true, uint8_t skip=0) { writeBytes3<0, DATA_NOP, RGB_ORDER>(data, len, scale, advance, skip); } - void writeBytes3(register uint8_t *data, int len, register uint8_t scale, bool advance=true, uint8_t skip=0) { + void writeBytes3(register uint8_t *data, int len, register CRGB scale, bool advance=true, uint8_t skip=0) { writeBytes3<0, DATA_NOP, RGB>(data, len, scale, advance, skip); + } }; +#endif + #endif
\ No newline at end of file diff --git a/fastspi_ref.h b/fastspi_ref.h new file mode 100644 index 00000000..709bec34 --- /dev/null +++ b/fastspi_ref.h @@ -0,0 +1,98 @@ +#ifndef __INC_FASTSPI_ARM_SAM_H +#define __INC_FASTSPI_ARM_SAM_H + +// A skeletal implementation of hardware SPI support. Fill in the necessary code for init, waiting, and writing. The rest of +// the method implementations should provide a starting point, even if not hte most efficient to start with +template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint8_t _SPI_CLOCK_DIVIDER> +class REFHardwareSPIOutput { + Selectable *m_pSelect; +public: + SAMHardwareSPIOutput() { m_pSelect = NULL; } + SAMHArdwareSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; } + + // set the object representing the selectable + void setSelect(Selectable *pSelect) { /* TODO */ } + + // initialize the SPI subssytem + void init() { /* TODO */ } + + // latch the CS select + void inline select() __attribute__((always_inline)) { if(m_pSelect != NULL) { m_pSelect->select(); } } + + // release the CS select + void inline release() __attribute__((always_inline)) { if(m_pSelect != NULL) { m_pSelect->release(); } } + + // wait until all queued up data has been written + static void waitFully() { /* TODO */ } + + // write a byte out via SPI (returns immediately on writing register) + static void writeByte(uint8_t b) { /* TODO */ } + + // write a word out via SPI (returns immediately on writing register) + static void writeWord(uint16_t w) { /* TODO */ } + + // A raw set of writing byte values, assumes setup/init/waiting done elsewhere + static void writeBytesValueRaw(uint8_t value, int len) { + while(len--) { writeByte(value); } + } + + // A full cycle of writing a value for len bytes, including select, release, and waiting + void writeBytesValue(uint8_t value, int len) { + select(); writeBytesValueRaw(value, len); release(); + } + + // A full cycle of writing a value for len bytes, including select, release, and waiting + template <class D> void writeBytes(register uint8_t *data, int len) { + uint8_t *end = data + len; + select(); + // could be optimized to write 16bit words out instead of 8bit bytes + while(data != end) { + writeByte(D::adjust(*data++)); + } + D::postBlock(len); + waitFully(); + release(); + } + + // A full cycle of writing a value for len bytes, including select, release, and waiting + void writeBytes(register uint8_t *data, int len) { writeBytes<DATA_NOP>(data, len); } + + // write a single bit out, which bit from the passed in byte is determined by template parameter + template <uint8_t BIT> inline static void writeBit(uint8_t b) { /* TODO */ } + + // 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 and/or end of each grouping + template <uint8_t FLAGS, class D, EOrder RGB_ORDER> void writeBytes3(register uint8_t *data, int len, register CRGB scale, bool advance=true, uint8_t skip=0) { + select(); + while(data != end) { + if(FLAGS & FLAG_START_BIT) { + writeBit<0>(1); + } + writeByte(D::adjust(pixels.loadAndScale0())); + writeByte(D::adjust(pixels.loadAndScale1())); + writeByte(D::adjust(pixels.loadAndScale2())); + + pixels.advanceData(); + pixels.stepDithering(); + data += (3+skip); + } + D::postBlock(len); + release(); + } + + // template instantiations for writeBytes 3 + template <uint8_t FLAGS, EOrder RGB_ORDER> void writeBytes3(register uint8_t *data, int len, register CRGB scale, bool advance=true, uint8_t skip=0) { + writeBytes3<FLAGS, DATA_NOP, RGB_ORDER>(data, len, scale, advance, skip); + } + template <class D, EOrder RGB_ORDER> void writeBytes3(register uint8_t *data, int len, register CRGB scale, bool advance=true, uint8_t skip=0) { + writeBytes3<0, D, RGB_ORDER>(data, len, scale, advance, skip); + } + template <EOrder RGB_ORDER> void writeBytes3(register uint8_t *data, int len, register CRGB scale, bool advance=true, uint8_t skip=0) { + writeBytes3<0, DATA_NOP, RGB_ORDER>(data, len, scale, advance, skip); + } + void writeBytes3(register uint8_t *data, int len, register CRGB scale, bool advance=true, uint8_t skip=0) { + writeBytes3<0, DATA_NOP, RGB>(data, len, scale, advance, skip); + +}; + +#endif
\ No newline at end of file diff --git a/preview_changes.txt b/preview_changes.txt index 60562fef..2866abbd 100644 --- a/preview_changes.txt +++ b/preview_changes.txt @@ -1,7 +1,9 @@ * ALL UNTESTED, USE AT YOUR OWN RISK! -* Preliminary teensy 3.1 support -* Preliminary due support (no hardware SPI, yet) -* Preliminary P9813 (aka Cool Neon Total Control Lighting support) +* RGB based scaling, allow for color balancing +* (The moon) dithering support +* Teensy 3.1 support +* Due support +* P9813 (aka Cool Neon Total Control Lighting support) * Preliminary 2-way ws2812 support * Preliminary n-way clockless support on due * Preliminary TM1829 support (broken, don't use!) |