diff options
author | Daniel Garcia <danielgarcia@gmail.com> | 2019-01-20 03:49:54 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-01-20 03:49:54 +0300 |
commit | 870010f3c12310ce0851de03a0bbed8225e336fc (patch) | |
tree | 3c446ff47b820fb0e8510551b073ace12f19d608 | |
parent | ad5947d73742681ae9dc38701a257b231c06c69d (diff) | |
parent | 218b24816fcda91d38610ebe9b49aca211ba2f70 (diff) |
Merge pull request #667 from jldesignseu/atmega328pb
added support for AVR atmega328pb
-rw-r--r-- | platforms/avr/fastpin_avr.h | 2 | ||||
-rw-r--r-- | platforms/avr/fastspi_avr.h | 177 |
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 |