#ifndef __INC_FASTSPI_NRF_H #define __INC_FASTSPI_NRF_H #ifdef NRF51 #ifndef FASTLED_FORCE_SOFTWARE_SPI #define FASTLED_ALL_PINS_HARDWARE_SPI // A nop/stub class, mostly to show the SPI methods that are needed/used by the various SPI chipset implementations. Should // be used as a definition for the set of methods that the spi implementation classes should use (since C++ doesn't support the // idea of interfaces - it's possible this could be done with virtual classes, need to decide if i want that overhead) template class NRF51SPIOutput { struct saveData { uint32_t sck; uint32_t mosi; uint32_t miso; uint32_t freq; uint32_t enable; } mSavedData; void saveSPIData() { mSavedData.sck = NRF_SPI0->PSELSCK; mSavedData.mosi = NRF_SPI0->PSELMOSI; mSavedData.miso = NRF_SPI0->PSELMISO; mSavedData.freq = NRF_SPI0->FREQUENCY; mSavedData.enable = NRF_SPI0->ENABLE; } void restoreSPIData() { NRF_SPI0->PSELSCK = mSavedData.sck; NRF_SPI0->PSELMOSI = mSavedData.mosi; NRF_SPI0->PSELMISO = mSavedData.miso; NRF_SPI0->FREQUENCY = mSavedData.freq; mSavedData.enable = NRF_SPI0->ENABLE; } public: NRF51SPIOutput() { FastPin<_DATA_PIN>::setOutput(); FastPin<_CLOCK_PIN>::setOutput(); } NRF51SPIOutput(Selectable *pSelect) { FastPin<_DATA_PIN>::setOutput(); FastPin<_CLOCK_PIN>::setOutput(); } // set the object representing the selectable void setSelect(Selectable *pSelect) { /* TODO */ } // initialize the SPI subssytem void init() { FastPin<_DATA_PIN>::setOutput(); FastPin<_CLOCK_PIN>::setOutput(); NRF_SPI0->PSELSCK = _CLOCK_PIN; NRF_SPI0->PSELMOSI = _DATA_PIN; NRF_SPI0->PSELMISO = 0xFFFFFFFF; NRF_SPI0->FREQUENCY = 0x80000000; NRF_SPI0->ENABLE = 1; NRF_SPI0->EVENTS_READY = 0; } // latch the CS select void select() { saveSPIData(); init(); } // release the CS select void release() { shouldWait(); restoreSPIData(); } static bool shouldWait(bool wait = false) __attribute__((always_inline)) __attribute__((always_inline)) { // static bool sWait=false; // bool oldWait = sWait; // sWait = wait; // never going to bother with waiting since we're always running the spi clock at max speed on the rfduino // TODO: When we set clock rate, implement/fix waiting properly, otherwise the world hangs up return false; } // wait until all queued up data has been written static void waitFully() __attribute__((always_inline)){ if(shouldWait()) { while(NRF_SPI0->EVENTS_READY==0); } NRF_SPI0->INTENCLR; } static void wait() __attribute__((always_inline)){ if(shouldWait()) { while(NRF_SPI0->EVENTS_READY==0); } NRF_SPI0->INTENCLR; } // write a byte out via SPI (returns immediately on writing register) static void writeByte(uint8_t b) __attribute__((always_inline)) { wait(); NRF_SPI0->TXD = b; NRF_SPI0->INTENCLR; shouldWait(true); } // write a word out via SPI (returns immediately on writing register) static void writeWord(uint16_t w) __attribute__((always_inline)){ writeByte(w>>8); writeByte(w & 0xFF); } // A raw set of writing byte values, assumes setup/init/waiting done elsewhere (static for use by adjustment classes) 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(); while(len--) { writeByte(value); } waitFully(); release(); } // A full cycle of writing a raw block of data out, including select, release, and waiting template void writeBytes(uint8_t *data, int len) { uint8_t *end = data + len; select(); while(data != end) { writeByte(D::adjust(*data++)); } D::postBlock(len); waitFully(); release(); } void writeBytes(uint8_t *data, int len) { writeBytes(data, len); } // write a single bit out, which bit from the passed in byte is determined by template parameter template inline static void writeBit(uint8_t b) { waitFully(); NRF_SPI0->ENABLE = 0; if(b & 1<::hi(); } else { FastPin<_DATA_PIN>::lo(); } FastPin<_CLOCK_PIN>::toggle(); FastPin<_CLOCK_PIN>::toggle(); NRF_SPI0->ENABLE = 1; } template void writePixels(PixelController pixels) { select(); int len = pixels.mLen; while(pixels.has(1)) { 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(); } D::postBlock(len); waitFully(); release(); } }; #endif #endif #endif