diff options
author | Daniel Garcia <danielgarcia@gmail.com> | 2015-01-30 23:14:40 +0300 |
---|---|---|
committer | Daniel Garcia <danielgarcia@gmail.com> | 2015-01-30 23:14:40 +0300 |
commit | df1fc943bd5d90438968a520282642fec7cfa45c (patch) | |
tree | 848b837c2426e58a69fb25b443f46d2bcb9483d7 | |
parent | e4f5cb2e4a6ff637409e967225e43adeaaeaa0e2 (diff) |
Fixed UART SPI on AVR chipsets.
-rw-r--r-- | fastspi.h | 14 | ||||
-rw-r--r-- | platforms/avr/fastpin_avr.h | 8 | ||||
-rw-r--r-- | platforms/avr/fastspi_avr.h | 282 | ||||
-rw-r--r-- | preview_changes.txt | 1 |
4 files changed, 263 insertions, 42 deletions
@@ -51,6 +51,20 @@ class SPIOutput<SPI_DATA, SPI_CLOCK, SPI_SPEED> : public SAMHardwareSPIOutput<SP template<uint8_t SPI_SPEED> class SPIOutput<SPI_DATA, SPI_CLOCK, SPI_SPEED> : public AVRHardwareSPIOutput<SPI_DATA, SPI_CLOCK, SPI_SPEED> {}; +#if defined(SPI_UART0_DATA) + +template<uint8_t SPI_SPEED> +class SPIOutput<SPI_UART0_DATA, SPI_UART0_CLOCK, SPI_SPEED> : public AVRUSART0SPIOutput<SPI_UART0_DATA, SPI_UART0_CLOCK, SPI_SPEED> {}; + +#endif + +#if defined(SPI_UART1_DATA) + +template<uint8_t SPI_SPEED> +class SPIOutput<SPI_UART1_DATA, SPI_UART1_CLOCK, SPI_SPEED> : public AVRUSART1SPIOutput<SPI_UART1_DATA, SPI_UART1_CLOCK, SPI_SPEED> {}; + +#endif + #endif #else diff --git a/platforms/avr/fastpin_avr.h b/platforms/avr/fastpin_avr.h index 4a7c0942..6f59d24a 100644 --- a/platforms/avr/fastpin_avr.h +++ b/platforms/avr/fastpin_avr.h @@ -83,6 +83,9 @@ _DEFPIN_AVR(16, 0x04, C); _DEFPIN_AVR(17, 0x08, C); _DEFPIN_AVR(18, 0x10, C); _D #define AVR_HARDWARE_SPI 1 #define HAS_HARDWARE_PIN_SUPPORT 1 +#define SPI_UART0_DATA 1 +#define SPI_UART0_CLOCK 4 + #elif defined(__AVR_ATmega1284P__) _IO(A); _IO(B); _IO(C); _IO(D); @@ -196,6 +199,11 @@ _DEFPIN_AVR(20, 32, F); _DEFPIN_AVR(21, 16, F); _DEFPIN_AVR(22, 2, F); _DEFPIN_A #define AVR_HARDWARE_SPI 1 #define HAS_HARDWARE_PIN_SUPPORT 1 +// PD3/PD5 +// #define SPI_UART1_DATA 1 +// #define SPI_UART1_CLOCK 4 + + #endif #endif // FASTLED_FORCE_SOFTWARE_PINS diff --git a/platforms/avr/fastspi_avr.h b/platforms/avr/fastspi_avr.h index 7f0b731b..a1042ca6 100644 --- a/platforms/avr/fastspi_avr.h +++ b/platforms/avr/fastspi_avr.h @@ -11,43 +11,73 @@ // uno/mini/duemilanove #if defined(AVR_HARDWARE_SPI) -#if defined(UBRR0) + +#if defined(UBRR1) + +#ifndef UCPHA1 +#define UCPHA1 1 +#endif + template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint8_t _SPI_CLOCK_DIVIDER> -class AVRUSARTSPIOutput { +class AVRUSART1SPIOutput { Selectable *m_pSelect; public: - AVRUSARTSPIOutput() { m_pSelect = NULL; } - AVRUSARTSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; } + AVRUSART1SPIOutput() { m_pSelect = NULL; } + AVRUSART1SPIOutput(Selectable *pSelect) { m_pSelect = pSelect; } void setSelect(Selectable *pSelect) { m_pSelect = pSelect; } void init() { - UBRR0 = 0; - UCSR0A = 1<<TXC0; + UBRR1 = 0; + + /* Set MSPI mode of operation and SPI data mode 0. */ + UCSR1C = (1<<UMSEL11)|(1<<UMSEL10)|(0<<UCPHA1)|(0<<UCPOL1); + /* Enable receiver and transmitter. */ + UCSR1B = (1<<RXEN1)|(1<<TXEN1); FastPin<_CLOCK_PIN>::setOutput(); FastPin<_DATA_PIN>::setOutput(); - UCSR0C = _BV (UMSEL00) | _BV (UMSEL01); // Master SPI mode - UCSR0B = _BV (TXEN0) | _BV (RXEN0); // transmit enable and receive enable - // must be done last, see page 206 - UBRR0 = 3; // 2 Mhz clock rate + setSPIRate(); + } + + void setSPIRate() { + if(_SPI_CLOCK_DIVIDER > 2) { + UBRR1 = (_SPI_CLOCK_DIVIDER/2)-1; + } else { + UBRR1 = 0; + } } + static void stop() { // TODO: stop the uart spi output } - static void wait() __attribute__((always_inline)) { while(!(UCSR0A & (1<<UDRE0))); } + static bool shouldWait(bool wait = false) __attribute__((always_inline)) { + static bool sWait=false; + if(sWait) { + sWait = wait; return true; + } else { + sWait = wait; return false; + } + // return true; + } + static void wait() __attribute__((always_inline)) { + if(shouldWait()) { + while(!(UCSR1A & (1<<UDRE1))); + } + } static void waitFully() __attribute__((always_inline)) { wait(); } - static void writeByteNoWait(uint8_t b) __attribute__((always_inline)) { UDR0 = b;} - static void writeBytePostWait(uint8_t b) __attribute__((always_inline)) { UDR0 = b; wait(); } - static void writeByte(uint8_t b) __attribute__((always_inline)) { wait(); UDR0 = b; } - static void writeWord(uint16_t w) __attribute__((always_inline)) { writeByte(w>>8); writeByte(w&0xFF); } + static void writeByte(uint8_t b) __attribute__((always_inline)) { wait(); UDR1=b; shouldWait(true); } + static void writeBytePostWait(uint8_t b) __attribute__((always_inline)) { UDR1=b; shouldWait(true); wait(); } + static void writeByteNoWait(uint8_t b) __attribute__((always_inline)) { UDR1=b; shouldWait(true); } + + template <uint8_t BIT> inline static void writeBit(uint8_t b) { if(b && (1 << BIT)) { FastPin<_DATA_PIN>::hi(); @@ -59,18 +89,32 @@ public: FastPin<_CLOCK_PIN>::lo(); } - void select() { if(m_pSelect != NULL) { m_pSelect->select(); } } // FastPin<_SELECT_PIN>::hi(); } + void enable_pins() { } + void disable_pins() { } + + void select() { + if(m_pSelect != NULL) { + m_pSelect->select(); + } + enable_pins(); + setSPIRate(); + } + void release() { - // wait for all transmissions to finish - while ((UCSR0A & (1 <<TXC0)) == 0) {} - if(m_pSelect != NULL) { m_pSelect->release(); } // FastPin<_SELECT_PIN>::hi(); + if(m_pSelect != NULL) { + m_pSelect->release(); + } + disable_pins(); } static void writeBytesValueRaw(uint8_t value, int len) { - while(len--) { writeByte(value); } + while(len--) { + writeByte(value); + } } void writeBytesValue(uint8_t value, int len) { + //setSPIRate(); select(); while(len--) { writeByte(value); @@ -80,13 +124,13 @@ public: // Write a block of n uint8_ts out template <class D> void writeBytes(register uint8_t *data, int len) { + //setSPIRate(); uint8_t *end = data + len; select(); while(data != end) { // a slight touch of delay here helps optimize the timing of the status register check loop (not used on ARM) writeByte(D::adjust(*data++)); delaycycles<3>(); } - D::postBlock(len); release(); } @@ -94,43 +138,181 @@ 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 and/or end of each grouping - 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) { - uint8_t *end = data + len; - PixelController<RGB_ORDER> pixels(data, scale, true, advance, skip); + template <uint8_t FLAGS, class D, EOrder RGB_ORDER> void writePixels(PixelController<RGB_ORDER> pixels) { + //setSPIRate(); + int len = pixels.mLen; + select(); - while(data != end) { + while(pixels.has(1)) { if(FLAGS & FLAG_START_BIT) { writeBit<0>(1); + writeBytePostWait(D::adjust(pixels.loadAndScale0())); + writeBytePostWait(D::adjust(pixels.loadAndScale1())); + writeBytePostWait(D::adjust(pixels.loadAndScale2())); + } else { + writeByte(D::adjust(pixels.loadAndScale0())); + writeByte(D::adjust(pixels.loadAndScale1())); + writeByte(D::adjust(pixels.loadAndScale2())); } - 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(); } +}; +#endif + +#if defined(UBRR0) +template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint8_t _SPI_CLOCK_DIVIDER> +class AVRUSART0SPIOutput { + Selectable *m_pSelect; + +public: + AVRUSART0SPIOutput() { m_pSelect = NULL; } + AVRUSART0SPIOutput(Selectable *pSelect) { m_pSelect = pSelect; } + void setSelect(Selectable *pSelect) { m_pSelect = pSelect; } + + void init() { + UBRR0 = 0; + + /* Set MSPI mode of operation and SPI data mode 0. */ + UCSR0C = (1<<UMSEL01)|(1<<UMSEL00)|(0<<UCPHA0)|(0<<UCPOL0); + /* Enable receiver and transmitter. */ + UCSR0B = (1<<RXEN0)|(1<<TXEN0); + + FastPin<_CLOCK_PIN>::setOutput(); + FastPin<_DATA_PIN>::setOutput(); + + + // must be done last, see page 206 + setSPIRate(); + } - // 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<FLAGS, DATA_NOP, RGB_ORDER>(data, len, scale, advance, skip); + void setSPIRate() { + if(_SPI_CLOCK_DIVIDER > 2) { + UBRR0 = (_SPI_CLOCK_DIVIDER/2)-1; + } else { + UBRR0 = 0; + } } - 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) { - writeBytes3<0, D, RGB_ORDER>(data, len, scale, advance, skip); + + static void stop() { + // TODO: stop the uart spi output } - template <EOrder RGB_ORDER> void writeBytes3(register uint8_t *data, int len, register uint8_t scale, bool advance=true, uint8_t skip=0) { - writeBytes3<0, DATA_NOP, RGB_ORDER>(data, len, scale, advance, skip); + + static bool shouldWait(bool wait = false) __attribute__((always_inline)) { + static bool sWait=false; + if(sWait) { + sWait = wait; return true; + } else { + sWait = wait; return false; + } + // return true; } - void writeBytes3(register uint8_t *data, int len, register uint8_t scale, bool advance=true, uint8_t skip=0) { - writeBytes3<0, DATA_NOP, RGB>(data, len, scale, advance, skip); + static void wait() __attribute__((always_inline)) { + if(shouldWait()) { + while(!(UCSR0A & (1<<UDRE0))); + } } + static void waitFully() __attribute__((always_inline)) { wait(); } + + static void writeWord(uint16_t w) __attribute__((always_inline)) { writeByte(w>>8); writeByte(w&0xFF); } + static void writeByte(uint8_t b) __attribute__((always_inline)) { wait(); UDR0=b; shouldWait(true); } + static void writeBytePostWait(uint8_t b) __attribute__((always_inline)) { UDR0=b; shouldWait(true); wait(); } + static void writeByteNoWait(uint8_t b) __attribute__((always_inline)) { UDR0=b; shouldWait(true); } + + + template <uint8_t BIT> inline static void writeBit(uint8_t b) { + if(b && (1 << BIT)) { + FastPin<_DATA_PIN>::hi(); + } else { + FastPin<_DATA_PIN>::lo(); + } + + FastPin<_CLOCK_PIN>::hi(); + FastPin<_CLOCK_PIN>::lo(); + } + + void enable_pins() { } + void disable_pins() { } + + void select() { + if(m_pSelect != NULL) { + m_pSelect->select(); + } + enable_pins(); + setSPIRate(); + } + + void release() { + if(m_pSelect != NULL) { + m_pSelect->release(); + } + disable_pins(); + } + + static void writeBytesValueRaw(uint8_t value, int len) { + while(len--) { + writeByte(value); + } + } + + void writeBytesValue(uint8_t value, int len) { + //setSPIRate(); + select(); + while(len--) { + writeByte(value); + } + release(); + } + + // Write a block of n uint8_ts out + template <class D> void writeBytes(register uint8_t *data, int len) { + //setSPIRate(); + uint8_t *end = data + len; + select(); + while(data != end) { + // a slight touch of delay here helps optimize the timing of the status register check loop (not used on ARM) + writeByte(D::adjust(*data++)); delaycycles<3>(); + } + release(); + } + + void writeBytes(register uint8_t *data, int len) { writeBytes<DATA_NOP>(data, len); } + + // 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 writePixels(PixelController<RGB_ORDER> pixels) { + //setSPIRate(); + int len = pixels.mLen; + + select(); + while(pixels.has(1)) { + if(FLAGS & FLAG_START_BIT) { + writeBit<0>(1); + writeBytePostWait(D::adjust(pixels.loadAndScale0())); + writeBytePostWait(D::adjust(pixels.loadAndScale1())); + writeBytePostWait(D::adjust(pixels.loadAndScale2())); + } else { + writeByte(D::adjust(pixels.loadAndScale0())); + writeByte(D::adjust(pixels.loadAndScale1())); + writeByte(D::adjust(pixels.loadAndScale2())); + } + + pixels.advanceData(); + pixels.stepDithering(); + } + D::postBlock(len); + release(); + } }; #endif + #if defined(SPSR) ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -181,7 +363,6 @@ public: FastPin<SPI_SELECT>::setOutput(); FastPin<SPI_SELECT>::lo(); #endif - release(); SPCR |= ((1<<SPE) | (1<<MSTR) ); // enable SPI as master SPCR &= ~ ( (1<<SPR1) | (1<<SPR0) ); // clear out the prescalar bits @@ -205,7 +386,8 @@ public: SPDR=0; shouldWait(false); - } + release(); + } static bool shouldWait(bool wait = false) __attribute__((always_inline)) { static bool sWait=false; @@ -235,8 +417,24 @@ public: shouldWait(false); } - void select() { if(m_pSelect != NULL) { m_pSelect->select(); } } // FastPin<_SELECT_PIN>::hi(); } - void release() { if(m_pSelect != NULL) { m_pSelect->release(); } } // FastPin<_SELECT_PIN>::lo(); } + void enable_pins() { + SPCR |= ((1<<SPE) | (1<<MSTR) ); // enable SPI as master + } + + void disable_pins() { + SPCR &= ~(((1<<SPE) | (1<<MSTR) )); // disable SPI + } + + void select() { + if(m_pSelect != NULL) { m_pSelect->select(); } + enable_pins(); + setSPIRate(); + } + + void release() { + if(m_pSelect != NULL) { m_pSelect->release(); } + disable_pins(); + } static void writeBytesValueRaw(uint8_t value, int len) { while(len--) { writeByte(value); } diff --git a/preview_changes.txt b/preview_changes.txt index f58f911a..4cfed4d9 100644 --- a/preview_changes.txt +++ b/preview_changes.txt @@ -1,4 +1,5 @@ FastLED 3.1 preview changes: +* UART in SPI mode support on AVR * Support for using both hardware SPI pinsets on the Teensy 3.x - 11/13 and 7/14. * Added UCS1904 support * Better AVR cycle counting |