Files
ESP8266lib/io/SoftSPI.h
2020-06-11 11:25:19 +02:00

538 lines
12 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")
/*
#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 <stdint.h>
// #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 <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) {
// 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() {
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