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:
authorDaniel Garcia <danielgarcia@gmail.com>2019-01-20 03:49:54 +0300
committerGitHub <noreply@github.com>2019-01-20 03:49:54 +0300
commit870010f3c12310ce0851de03a0bbed8225e336fc (patch)
tree3c446ff47b820fb0e8510551b073ace12f19d608
parentad5947d73742681ae9dc38701a257b231c06c69d (diff)
parent218b24816fcda91d38610ebe9b49aca211ba2f70 (diff)
Merge pull request #667 from jldesignseu/atmega328pb
added support for AVR atmega328pb
-rw-r--r--platforms/avr/fastpin_avr.h2
-rw-r--r--platforms/avr/fastspi_avr.h177
2 files changed, 178 insertions, 1 deletions
diff --git a/platforms/avr/fastpin_avr.h b/platforms/avr/fastpin_avr.h
index e62a4ad8..8cfd96ea 100644
--- a/platforms/avr/fastpin_avr.h
+++ b/platforms/avr/fastpin_avr.h
@@ -158,7 +158,7 @@ _DEFPIN_AVR(16, 0x04, C); _DEFPIN_AVR(17, 0x08, C); _DEFPIN_AVR(18, 0x10, C); _D
#define SPI_UART0_CLOCK 12
#endif
-#elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega8__)
+#elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PB__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega8__)
// Accelerated port definitions for arduino avrs
_IO(D); _IO(B); _IO(C);
diff --git a/platforms/avr/fastspi_avr.h b/platforms/avr/fastspi_avr.h
index 2ed5bb15..fc14d596 100644
--- a/platforms/avr/fastspi_avr.h
+++ b/platforms/avr/fastspi_avr.h
@@ -493,6 +493,183 @@ public:
release();
}
};
+#elif defined(SPSR0)
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Hardware SPI support using SPDR0 registers and friends
+//
+// Technically speaking, this uses the AVR SPI registers. This will work on the Teensy 3.0 because Paul made a set of compatability
+// classes that map the AVR SPI registers to ARM's, however this caps the performance of output.
+//
+// TODO: implement ARMHardwareSPIOutput
+//
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint8_t _SPI_CLOCK_DIVIDER>
+class AVRHardwareSPIOutput {
+ Selectable *m_pSelect;
+ bool mWait;
+public:
+ AVRHardwareSPIOutput() { m_pSelect = NULL; mWait = false;}
+ AVRHardwareSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; }
+ void setSelect(Selectable *pSelect) { m_pSelect = pSelect; }
+
+ void setSPIRate() {
+ SPCR0 &= ~ ( (1<<SPR10) | (1<<SPR0) ); // clear out the prescalar bits
+
+ bool b2x = false;
+
+ if(_SPI_CLOCK_DIVIDER >= 128) { SPCR0 |= (1<<SPR1); SPCR0 |= (1<<SPR0); }
+ else if(_SPI_CLOCK_DIVIDER >= 64) { SPCR0 |= (1<<SPR1);}
+ else if(_SPI_CLOCK_DIVIDER >= 32) { SPCR0 |= (1<<SPR1); b2x = true; }
+ else if(_SPI_CLOCK_DIVIDER >= 16) { SPCR0 |= (1<<SPR0); }
+ else if(_SPI_CLOCK_DIVIDER >= 8) { SPCR0 |= (1<<SPR0); b2x = true; }
+ else if(_SPI_CLOCK_DIVIDER >= 4) { /* do nothing - default rate */ }
+ else { b2x = true; }
+
+ if(b2x) { SPSR0 |= (1<<SPI2X); }
+ else { SPSR0 &= ~ (1<<SPI2X); }
+ }
+
+ void init() {
+ volatile uint8_t clr;
+
+ // set the pins to output
+ FastPin<_DATA_PIN>::setOutput();
+ FastPin<_CLOCK_PIN>::setOutput();
+#ifdef SPI_SELECT
+ // Make sure the slave select line is set to output, or arduino will block us
+ FastPin<SPI_SELECT>::setOutput();
+ FastPin<SPI_SELECT>::lo();
+#endif
+
+ SPCR0 |= ((1<<SPE) | (1<<MSTR) ); // enable SPI as master
+ SPCR0 &= ~ ( (1<<SPR1) | (1<<SPR0) ); // clear out the prescalar bits
+
+ clr = SPSR0; // clear SPI status register
+ clr = SPDR0; // clear SPI data register
+ clr;
+
+ bool b2x = false;
+
+ if(_SPI_CLOCK_DIVIDER >= 128) { SPCR0 |= (1<<SPR1); SPCR0 |= (1<<SPR0); }
+ else if(_SPI_CLOCK_DIVIDER >= 64) { SPCR0 |= (1<<SPR1);}
+ else if(_SPI_CLOCK_DIVIDER >= 32) { SPCR0 |= (1<<SPR1); b2x = true; }
+ else if(_SPI_CLOCK_DIVIDER >= 16) { SPCR0 |= (1<<SPR0); }
+ else if(_SPI_CLOCK_DIVIDER >= 8) { SPCR0 |= (1<<SPR0); b2x = true; }
+ else if(_SPI_CLOCK_DIVIDER >= 4) { /* do nothing - default rate */ }
+ else { b2x = true; }
+
+ if(b2x) { SPSR0 |= (1<<SPI2X); }
+ else { SPSR0 &= ~ (1<<SPI2X); }
+
+ SPDR0=0;
+ shouldWait(false);
+ release();
+ }
+
+ 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(!(SPSR0 & (1<<SPIF))); } }
+ 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(); SPDR0=b; shouldWait(true); }
+ static void writeBytePostWait(uint8_t b) __attribute__((always_inline)) { SPDR0=b; shouldWait(true); wait(); }
+ static void writeByteNoWait(uint8_t b) __attribute__((always_inline)) { SPDR0=b; shouldWait(true); }
+
+ template <uint8_t BIT> inline static void writeBit(uint8_t b) {
+ SPCR0 &= ~(1 << SPE);
+ if(b & (1 << BIT)) {
+ FastPin<_DATA_PIN>::hi();
+ } else {
+ FastPin<_DATA_PIN>::lo();
+ }
+
+ FastPin<_CLOCK_PIN>::hi();
+ FastPin<_CLOCK_PIN>::lo();
+ SPCR0 |= 1 << SPE;
+ shouldWait(false);
+ }
+
+ void enable_pins() {
+ SPCR0 |= ((1<<SPE) | (1<<MSTR) ); // enable SPI as master
+ }
+
+ void disable_pins() {
+ SPCR0 &= ~(((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); }
+ }
+
+ 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);
+ waitFully();
+ release();
+ }
+};
#endif
#else