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:
authorMark Kriegsman <1334634+kriegsman@users.noreply.github.com>2021-01-04 19:23:09 +0300
committerGitHub <noreply@github.com>2021-01-04 19:23:09 +0300
commitffee7627d0c5d70303df337a285d030fca2cbe77 (patch)
treef608940615e8a9e2d070ff0127a1a3f327d3169b
parent41652f2045ec9df7d5faf5b35efac280e13837f5 (diff)
parentd544953523a79c51a1084bb6e91ee39b55c8486a (diff)
Merge pull request #1166 from tom-miller1/master
Add hardware SPI support for Arduino Nano Every
-rw-r--r--src/platforms/avr/fastpin_avr.h11
-rw-r--r--src/platforms/avr/fastspi_avr.h159
2 files changed, 163 insertions, 7 deletions
diff --git a/src/platforms/avr/fastpin_avr.h b/src/platforms/avr/fastpin_avr.h
index db2beeaf..99a78958 100644
--- a/src/platforms/avr/fastpin_avr.h
+++ b/src/platforms/avr/fastpin_avr.h
@@ -215,15 +215,12 @@ _FL_DEFPIN(16, 1, D); _FL_DEFPIN(17, 0, D); _FL_DEFPIN(18, 2, A); _FL_DEFPIN(19,
_FL_DEFPIN(20, 4, D); _FL_DEFPIN(21, 5, D); _FL_DEFPIN(22, 2, A);
// To confirm for the SPI interfaces
-//#define SPI_DATA 18
-//#define SPI_CLOCK 13
-//#define SPI_SELECT 19
-//#define AVR_HARDWARE_SPI 1
+#define SPI_DATA 11
+#define SPI_CLOCK 13
+#define SPI_SELECT 8
+#define AVR_HARDWARE_SPI 1
#define HAS_HARDWARE_PIN_SUPPORT 1
-//#define SPI_UART0_DATA 1
-//#define SPI_UART0_CLOCK 4
-
#elif defined(__AVR_ATmega4809__)
#define MAX_PIN 21
diff --git a/src/platforms/avr/fastspi_avr.h b/src/platforms/avr/fastspi_avr.h
index 245e4065..325a24b8 100644
--- a/src/platforms/avr/fastspi_avr.h
+++ b/src/platforms/avr/fastspi_avr.h
@@ -314,6 +314,165 @@ public:
#endif
+#if defined(SPI0_CTRLA)
+
+template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint32_t _SPI_CLOCK_DIVIDER>
+class AVRHardwareSPIOutput {
+ Selectable *m_pSelect;
+
+public:
+ AVRHardwareSPIOutput() { m_pSelect = NULL; }
+ AVRHardwareSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; }
+ void setSelect(Selectable *pSelect) { m_pSelect = pSelect; }
+
+ void init() {
+ FastPin<_CLOCK_PIN>::setOutput();
+ FastPin<_DATA_PIN>::setOutput();
+
+ // Arduino Nano Every documentation lists SPI pins in ALT2 portmux position
+ PORTMUX_TWISPIROUTEA = PORTMUX_SPI01_bm;
+
+ // Set SPI master mode and clock scaler.
+ SPI0_CTRLA = SPI_MASTER_bm;
+ if(_SPI_CLOCK_DIVIDER >= 128) { SPI0_CTRLA |= SPI_PRESC1_bm|SPI_PRESC0_bm; }
+ else if (_SPI_CLOCK_DIVIDER >= 64) { SPI0_CTRLA |= SPI_PRESC1_bm; }
+ else if (_SPI_CLOCK_DIVIDER >= 32) { SPI0_CTRLA |= SPI_PRESC1_bm|SPI_CLK2X_bm; }
+ else if (_SPI_CLOCK_DIVIDER >= 16) { SPI0_CTRLA |= SPI_PRESC0_bm; }
+ else if (_SPI_CLOCK_DIVIDER >= 8) { SPI0_CTRLA |= SPI_PRESC0_bm|SPI_CLK2X_bm; }
+ else if (_SPI_CLOCK_DIVIDER >= 4) { /* default rate */ }
+ else { SPI0_CTRLA |= SPI_CLK2X_bm; }
+
+ // Set mode 0 and disable slave select.
+ SPI0_CTRLB = SPI_SSD_bm;
+
+ // Enable SPI.
+ SPI0_CTRLA |= SPI_ENABLE_bm;
+ }
+
+ void setSPIRate() {
+ SPI0_CTRLA &= ~ ( (1<<SPI_PRESC1_bp)|(1<<SPI_PRESC0_bp)|(1<<SPI_CLK2X_bp) ); // clear pre-scaler and clock multiplier bits
+
+ if(_SPI_CLOCK_DIVIDER >= 128) { SPI0_CTRLA |= SPI_PRESC1_bm|SPI_PRESC0_bm; }
+ else if (_SPI_CLOCK_DIVIDER >= 64) { SPI0_CTRLA |= SPI_PRESC1_bm; }
+ else if (_SPI_CLOCK_DIVIDER >= 32) { SPI0_CTRLA |= SPI_PRESC1_bm|SPI_CLK2X_bm; }
+ else if (_SPI_CLOCK_DIVIDER >= 16) { SPI0_CTRLA |= SPI_PRESC0_bm; }
+ else if (_SPI_CLOCK_DIVIDER >= 8) { SPI0_CTRLA |= SPI_PRESC0_bm|SPI_CLK2X_bm; }
+ else if (_SPI_CLOCK_DIVIDER >= 4) { /* default rate */ }
+ else { SPI0_CTRLA |= SPI_CLK2X_bm; }
+ }
+
+ static void stop() {
+ SPI0_CTRLA &= ~(SPI_ENABLE_bm);
+ }
+
+ static bool shouldWait(bool wait = false) __attribute__((always_inline)) {
+ static bool sWait=false;
+ if(sWait) {
+ sWait = wait; return true;
+ } else {
+ sWait = wait; return false;
+ }
+ }
+ static void wait() __attribute__((always_inline)) {
+ if(shouldWait()) {
+ while(!(SPI0_INTFLAGS & SPI_IF_bm));
+ }
+ }
+ 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(); SPI0_DATA=b; shouldWait(true); }
+ static void writeBytePostWait(uint8_t b) __attribute__((always_inline)) { SPI0_DATA=b; shouldWait(true); wait(); }
+ static void writeByteNoWait(uint8_t b) __attribute__((always_inline)) { SPI0_DATA=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)