#ifndef SOFTSPI_H #define SOFTSPI_H #include "GPIO.h" #include "../Platforms.h" #include "../Debug.h" #pragma GCC push_options #pragma GCC optimize ("O3") /* #if (PLATFORM == NODE_MCU) || (PLATFORM == WEMOS_D1_MINI) #include "fastGPIO.h" #define SPI_CS_OUTPUT GPIO15_OUTPUT_SET #define SPI_MOSI_OUTPUT GPIO13_OUTPUT_SET #define SPI_MISO_INPUT GPIO12_INPUT_SET #define SPI_MISO_NO_PULLUP GPIO12_INPUT_PULLUP_UNSET #define SPI_CLK_OUTPUT GPIO14_OUTPUT_SET #define SPI_CS_LO GPIO15_L #define SPI_CS_HI GPIO15_H #define SPI_CLK_LO GPIO14_L #define SPI_CLK_HI GPIO14_H #define SPI_MOSI_LO GPIO13_L #define SPI_MOSI_HI GPIO13_H #define SPI_MISO_READ GPIO12_IN #define SPI_FAST #elif (PLATFORM == WROOM32_DEVKIT) #include "driver/gpio.h" #include // #define SPI_PIN_MISO GPIO_NUM_35 // #define SPI_PIN_MOSI GPIO_NUM_32 // #define SPI_PIN_CLK GPIO_NUM_27 // #define SPI_PIN_CS GPIO_NUM_25 #define SPI_PIN_MISO GPIO_NUM_19 #define SPI_PIN_MOSI GPIO_NUM_23 #define SPI_PIN_CLK GPIO_NUM_18 #define SPI_PIN_CS GPIO_NUM_2 #define SPI_CS_OUTPUT GPIO::setOutput(SPI_PIN_CS) #define SPI_MOSI_OUTPUT GPIO::setOutput(SPI_PIN_MOSI) #define SPI_MISO_INPUT GPIO::setInput(SPI_PIN_MISO) #define SPI_MISO_NO_PULLUP //gpio_set_pull_mode(SPI_PIN_MISO, GPIO_FLOATING) /// ?????? #define SPI_CLK_OUTPUT GPIO::setOutput(SPI_PIN_CLK) #define SPI_CS_LO GPIO::clear(SPI_PIN_CS) #define SPI_CS_HI GPIO::set(SPI_PIN_CS) #define SPI_CLK_LO GPIO::clear(SPI_PIN_CLK) #define SPI_CLK_HI GPIO::set(SPI_PIN_CLK) #define SPI_MOSI_LO GPIO::clear(SPI_PIN_MOSI) #define SPI_MOSI_HI GPIO::set(SPI_PIN_MOSI) #define SPI_MOSI_SC(v) GPIO::setOrClear(SPI_PIN_MOSI, v) #define SPI_MISO_READ GPIO::get(SPI_PIN_MISO); #define SPI_FAST #else #error "not supported" #endif namespace spi { static constexpr const char* NAME = "SoftSPI"; // SoftSPI() { // // NOT CALLED! // // CALL INIT() manually! // } // THINGS THAT SHOULD RUN FAST AND THUS BE KEPT IN RAM static inline void csLo() { SPI_CS_LO; } // D8 static inline void csHi() { SPI_CS_HI; } // D8 static inline void clkLo() { SPI_CLK_LO; } // D5 static inline void clkHi() { SPI_CLK_HI; } // D5 static inline bool getMISO() {return SPI_MISO_READ;} // D6 #ifdef SPI_FAST static inline void wait() { //__asm__ __volatile__("nop"); } static inline void waitLong() { //DELAY_US(1); __asm__ __volatile__("nop"); __asm__ __volatile__("nop"); } #else static inline void wait() { DELAY_US(2); } static inline void waitLong() { DELAY_US(50); } #endif static void chipSelect() { clkLo(); wait(); csLo(); waitLong(); } static void chipDeselect() { clkLo(); wait(); csHi(); wait(); } static inline uint8_t readWriteBit(const bool out) { if(out) {SPI_MOSI_HI;} else {SPI_MOSI_LO;} wait(); clkHi(); wait(); const bool inp = getMISO(); wait(); clkLo(); wait(); return (inp) ? 1 : 0; } // write one bit to the bus static inline void writeBit(const bool out) { if(out) {SPI_MOSI_HI;} else {SPI_MOSI_LO;} wait(); clkHi(); wait(); clkLo(); wait(); } // read one bit from the bus static inline uint8_t readBit() { clkHi(); wait(); const bool val = getMISO(); wait(); clkLo(); wait(); return (val) ? 1 : 0; } // THINGS THAT MAY RUN SLOWER FROM THE FLASH static void IN_FLASH init() { debugMod(NAME, "init()"); SPI_MISO_INPUT; SPI_MISO_NO_PULLUP; // D6: MISO SPI_MOSI_OUTPUT; // D7: MOSI SPI_CLK_OUTPUT; // D5: CLK SPI_CS_OUTPUT; // D8: CS } // read 16 bits static uint16_t IN_FLASH readWord() { return (readBit() << 15) | (readBit() << 14) | (readBit() << 13) | (readBit() << 12) | (readBit() << 11) | (readBit() << 10) | (readBit() << 9) | (readBit() << 8) | (readBit() << 7) | (readBit() << 6) | (readBit() << 5) | (readBit() << 4) | (readBit() << 3) | (readBit() << 2) | (readBit() << 1) | (readBit() << 0); } // read 8 bits static uint8_t IRAM_ATTR readByte() { return (readBit() << 7) | (readBit() << 6) | (readBit() << 5) | (readBit() << 4) | (readBit() << 3) | (readBit() << 2) | (readBit() << 1) | (readBit() << 0); } static void IRAM_ATTR writeQuad(const uint32_t quad) { writeBit(quad & BIT(31)); writeBit(quad & BIT(30)); writeBit(quad & BIT(29)); writeBit(quad & BIT(28)); writeBit(quad & BIT(27)); writeBit(quad & BIT(26)); writeBit(quad & BIT(25)); writeBit(quad & BIT(24)); writeBit(quad & BIT(23)); writeBit(quad & BIT(22)); writeBit(quad & BIT(21)); writeBit(quad & BIT(20)); writeBit(quad & BIT(19)); writeBit(quad & BIT(18)); writeBit(quad & BIT(17)); writeBit(quad & BIT(16)); writeBit(quad & BIT(15)); writeBit(quad & BIT(14)); writeBit(quad & BIT(13)); writeBit(quad & BIT(12)); writeBit(quad & BIT(11)); writeBit(quad & BIT(10)); writeBit(quad & BIT( 9)); writeBit(quad & BIT( 8)); writeBit(quad & BIT( 7)); writeBit(quad & BIT( 6)); writeBit(quad & BIT( 5)); writeBit(quad & BIT( 4)); writeBit(quad & BIT( 3)); writeBit(quad & BIT( 2)); writeBit(quad & BIT( 1)); writeBit(quad & BIT( 0)); } static void IRAM_ATTR writeWord(const uint16_t word) { writeBit(word & BIT(15)); writeBit(word & BIT(14)); writeBit(word & BIT(13)); writeBit(word & BIT(12)); writeBit(word & BIT(11)); writeBit(word & BIT(10)); writeBit(word & BIT( 9)); writeBit(word & BIT( 8)); writeBit(word & BIT( 7)); writeBit(word & BIT( 6)); writeBit(word & BIT( 5)); writeBit(word & BIT( 4)); writeBit(word & BIT( 3)); writeBit(word & BIT( 2)); writeBit(word & BIT( 1)); writeBit(word & BIT( 0)); } static void IRAM_ATTR writeByte(uint8_t byte) { writeBit(byte & BIT( 7)); writeBit(byte & BIT( 6)); writeBit(byte & BIT( 5)); writeBit(byte & BIT( 4)); writeBit(byte & BIT( 3)); writeBit(byte & BIT( 2)); writeBit(byte & BIT( 1)); writeBit(byte & BIT( 0)); } static uint16_t IN_FLASH readWriteWord(const uint16_t word) { return (readWriteBit(word & BIT(15)) << 15) | (readWriteBit(word & BIT(14)) << 14) | (readWriteBit(word & BIT(13)) << 13) | (readWriteBit(word & BIT(12)) << 12) | (readWriteBit(word & BIT(11)) << 11) | (readWriteBit(word & BIT(10)) << 10) | (readWriteBit(word & BIT( 9)) << 9) | (readWriteBit(word & BIT( 8)) << 8) | (readWriteBit(word & BIT( 7)) << 7) | (readWriteBit(word & BIT( 6)) << 6) | (readWriteBit(word & BIT( 5)) << 5) | (readWriteBit(word & BIT( 4)) << 4) | (readWriteBit(word & BIT( 3)) << 3) | (readWriteBit(word & BIT( 2)) << 2) | (readWriteBit(word & BIT( 1)) << 1) | (readWriteBit(word & BIT( 0)) << 0); } static uint8_t IN_FLASH readWriteByte(const uint8_t byte) { return (readWriteBit(byte & BIT( 7)) << 7) | (readWriteBit(byte & BIT( 6)) << 6) | (readWriteBit(byte & BIT( 5)) << 5) | (readWriteBit(byte & BIT( 4)) << 4) | (readWriteBit(byte & BIT( 3)) << 3) | (readWriteBit(byte & BIT( 2)) << 2) | (readWriteBit(byte & BIT( 1)) << 1) | (readWriteBit(byte & BIT( 0)) << 0); } } */ template class SoftSPI { static constexpr const char* NAME = "softSPI"; public: /** ctor */ SoftSPI() { init(); } private: void init() { debugMod(NAME, "init()"); GPIO::setInput(PIN_MISO); GPIO::setOutput(PIN_MOSI); GPIO::setOutput(PIN_CLK); } private: static inline void wait() { if (!fast) { for (int i = 0; i < 8; ++i) { __asm__ __volatile__("nop"); } } } inline void clkLo() { GPIO::clear(PIN_CLK); } inline void clkHi() { GPIO::set(PIN_CLK); } /** write one bit to the bus */ inline void writeBit(const bool out) { if(out) {GPIO::set(PIN_MOSI);} else {GPIO::clear(PIN_MOSI);} wait(); clkHi(); wait(); clkLo(); wait(); } /** read one bit from the bus */ inline uint8_t readBit() { clkHi(); wait(); const bool val = GPIO::get(PIN_MISO); wait(); clkLo(); wait(); return (val) ? 1 : 0; } inline uint8_t readWriteBit(const bool out) { if(out) {GPIO::set(PIN_MOSI);} else {GPIO::clear(PIN_MOSI);} wait(); clkHi(); wait(); const bool inp = GPIO::get(PIN_MISO); wait(); clkLo(); wait(); return (inp) ? 1 : 0; } public: void IRAM_ATTR writeQuad(const uint32_t quad) { // writeBit(quad & BIT(31)); // writeBit(quad & BIT(30)); // writeBit(quad & BIT(29)); // writeBit(quad & BIT(28)); // writeBit(quad & BIT(27)); // writeBit(quad & BIT(26)); // writeBit(quad & BIT(25)); // writeBit(quad & BIT(24)); // writeBit(quad & BIT(23)); // writeBit(quad & BIT(22)); // writeBit(quad & BIT(21)); // writeBit(quad & BIT(20)); // writeBit(quad & BIT(19)); // writeBit(quad & BIT(18)); // writeBit(quad & BIT(17)); // writeBit(quad & BIT(16)); // writeBit(quad & BIT(15)); // writeBit(quad & BIT(14)); // writeBit(quad & BIT(13)); // writeBit(quad & BIT(12)); // writeBit(quad & BIT(11)); // writeBit(quad & BIT(10)); // writeBit(quad & BIT( 9)); // writeBit(quad & BIT( 8)); // writeBit(quad & BIT( 7)); // writeBit(quad & BIT( 6)); // writeBit(quad & BIT( 5)); // writeBit(quad & BIT( 4)); // writeBit(quad & BIT( 3)); // writeBit(quad & BIT( 2)); // writeBit(quad & BIT( 1)); // writeBit(quad & BIT( 0)); writeByte((quad>>24)&0xFF); writeByte((quad>>16)&0xFF); writeByte((quad>> 8)&0xFF); writeByte((quad>> 0)&0xFF); } void IRAM_ATTR writeWord(const uint16_t word) { // writeBit(word & BIT(15)); // writeBit(word & BIT(14)); // writeBit(word & BIT(13)); // writeBit(word & BIT(12)); // writeBit(word & BIT(11)); // writeBit(word & BIT(10)); // writeBit(word & BIT( 9)); // writeBit(word & BIT( 8)); // writeBit(word & BIT( 7)); // writeBit(word & BIT( 6)); // writeBit(word & BIT( 5)); // writeBit(word & BIT( 4)); // writeBit(word & BIT( 3)); // writeBit(word & BIT( 2)); // writeBit(word & BIT( 1)); // writeBit(word & BIT( 0)); writeByte((word>>8)&0xFF); writeByte((word>>0)&0xFF); } void IRAM_ATTR writeByte(uint8_t byte) { writeBit(byte & BIT( 7)); writeBit(byte & BIT( 6)); writeBit(byte & BIT( 5)); writeBit(byte & BIT( 4)); writeBit(byte & BIT( 3)); writeBit(byte & BIT( 2)); writeBit(byte & BIT( 1)); writeBit(byte & BIT( 0)); } /** read 8 bits */ uint8_t readByte() { GPIO::clear(PIN_MOSI); return (readBit() << 7) | (readBit() << 6) | (readBit() << 5) | (readBit() << 4) | (readBit() << 3) | (readBit() << 2) | (readBit() << 1) | (readBit() << 0); } uint8_t readWriteByte(const uint8_t byte) { return (readWriteBit(byte & BIT( 7)) << 7) | (readWriteBit(byte & BIT( 6)) << 6) | (readWriteBit(byte & BIT( 5)) << 5) | (readWriteBit(byte & BIT( 4)) << 4) | (readWriteBit(byte & BIT( 3)) << 3) | (readWriteBit(byte & BIT( 2)) << 2) | (readWriteBit(byte & BIT( 1)) << 1) | (readWriteBit(byte & BIT( 0)) << 0); } uint32_t readWriteQuad(const uint32_t quad) { return readWriteByte((quad>>24)&0xFF) << 24 | readWriteByte((quad>>16)&0xFF) << 16 | readWriteByte((quad>> 8)&0xFF) << 8 | readWriteByte((quad>> 0)&0xFF) << 0; } void write(const uint8_t* data, size_t len) { while(len) { writeByte(*data); ++data; --len; } } void read(uint8_t* dst, size_t len) { while(len) { *dst = readByte(); ++dst; --len; } } }; #pragma GCC pop_options // create an instance ONCE //SoftSPI spi; //using spi = SoftSPI; #endif // SOFTSPI_H