#ifndef SOFTSPI_H #define SOFTSPI_H #include "GPIO.h" #include "../Platforms.h" #include "../Debug.h" #pragma GCC push_options #pragma GCC optimize ("O2") template class SoftSPI { static constexpr const char* NAME = "softSPI"; public: /** ctor */ SoftSPI() { init(); } private: void init() { debugMod3(NAME, "init() MISO:%d MOSI:%d CLK:%d", PIN_MISO, PIN_MOSI, PIN_CLK); if (PIN_MISO) {MyGPIO::setInput(PIN_MISO);} if (PIN_MOSI) {MyGPIO::setOutput(PIN_MOSI);} MyGPIO::setOutput(PIN_CLK); } private: static inline void wait() { if (!fast) { for (int i = 0; i < 8; ++i) { __asm__ __volatile__("nop"); } } } inline void clkLo() { MyGPIO::clear(PIN_CLK); } inline void clkHi() { MyGPIO::set(PIN_CLK); } /** write one bit to the bus */ inline void writeBit(const bool out) { if(out) {MyGPIO::set(PIN_MOSI);} else {MyGPIO::clear(PIN_MOSI);} wait(); clkHi(); wait(); clkLo(); wait(); } /** read one bit from the bus */ inline uint8_t readBit() { clkHi(); wait(); const bool val = MyGPIO::get(PIN_MISO); wait(); clkLo(); wait(); return (val) ? 1 : 0; } inline uint8_t readWriteBit(const bool out) { if(out) {MyGPIO::set(PIN_MOSI);} else {MyGPIO::clear(PIN_MOSI);} wait(); clkHi(); wait(); const bool inp = MyGPIO::get(PIN_MISO); wait(); clkLo(); wait(); return (inp) ? 1 : 0; } public: void IRAM_ATTR writeQuad(const uint32_t quad) { writeByte((quad>>24)&0xFF); writeByte((quad>>16)&0xFF); writeByte((quad>> 8)&0xFF); writeByte((quad>> 0)&0xFF); } void IRAM_ATTR writeWord(const uint16_t word) { 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() { MyGPIO::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