#ifndef SOFTSPI_H #define SOFTSPI_H #include "GPIO.h" #include "../Platforms.h" #include "../Debug.h" #pragma GCC push_options #pragma GCC optimize ("O3") // NOTE: the last template argument has changed from "bool fast" to "int slowdown" where 0 is now fastest! template class SoftSPI { static constexpr const char* NAME = "softSPI"; uint8_t SLOWDOWN = 128; #ifndef BIT #define BIT(x) (1<SLOWDOWN = sd; } private: void init() { Log::addInfo(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: inline void wait() { for (int i = 0; i < SLOWDOWN; ++i) { __asm__ __volatile__("nop"); } } static inline void clkLo() { MyGPIO::clear(PIN_CLK); } static 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 */ static 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 writeQuad(const uint32_t quad) { writeByte((quad>>24)&0xFF); writeByte((quad>>16)&0xFF); writeByte((quad>> 8)&0xFF); writeByte((quad>> 0)&0xFF); } void writeWord(const uint16_t word) { writeByte((word>>8)&0xFF); writeByte((word>>0)&0xFF); } inline void 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