#ifndef __INC_FASTSPI_NRF_H #define __INC_FASTSPI_NRF_H #ifdef NRF51 // 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() { restoreSPIData(); } static bool shouldWait(bool wait = false) __attribute__((always_inline)) __attribute__((always_inline)) { static bool sWait=false; return false; // if(sWait) { sWait = wait; return true; } else { sWait = wait; return false; } } // wait until all queued up data has been written void waitFully() __attribute__((always_inline)){ if(shouldWait()) { while(NRF_SPI0->EVENTS_READY==0); } NRF_SPI0->EVENTS_READY=0; uint8_t b = NRF_SPI0->RXD; } void wait() __attribute__((always_inline)){ if(shouldWait()) { while(NRF_SPI0->EVENTS_READY==0); } NRF_SPI0->EVENTS_READY=0; uint8_t b = NRF_SPI0->RXD; } // void waitFully() { while(NRF_SPI0->EVENTS_READY==0); NRF_SPI0->EVENTS_READY=0; uint8_t b = NRF_SPI0->RXD; } // void wait() { while(NRF_SPI0->EVENTS_READY==0); NRF_SPI0->EVENTS_READY=0; uint8_t b = NRF_SPI0->RXD; } // write a byte out via SPI (returns immediately on writing register) // void writeByte(uint8_t b) { wait(); NRF_SPI0->TXD = b; shouldWait(true); } // void writeByte(uint8_t b) __attribute__((always_inline)){ wait(); NRF_SPI0->TXD = b; shouldWait(true); } void writeByte(uint8_t b) __attribute__((always_inline)) { NRF_SPI0->EVENTS_READY=0; /*uint8_t x = NRF_SPI0->RXD;*/ NRF_SPI0->TXD = b; } // write a word out via SPI (returns immediately on writing register) 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