167 lines
3.1 KiB
C++
167 lines
3.1 KiB
C++
#ifndef SOFTSPI_H
|
|
#define SOFTSPI_H
|
|
|
|
#include "GPIO.h"
|
|
#include "../Platforms.h"
|
|
#include "../Debug.h"
|
|
|
|
|
|
|
|
#pragma GCC push_options
|
|
#pragma GCC optimize ("O3")
|
|
|
|
|
|
template <int PIN_MISO, int PIN_MOSI, int PIN_CLK, bool fast> 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
|