Software SPI compatible with the default SPI class. No Interrupt support.
Based on https://github.com/MajenkoLibraries/SoftSPI/blob/master/src/SoftSPI.cpp
Software SPI compatible with the default SPI class. No Interrupt support.
Based on https://github.com/MajenkoLibraries/SoftSPI/blob/master/src/SoftSPI.cpp
| #include "SoftSPI.h" | |
| SoftSPI::SoftSPI(PinName mosi, PinName miso, PinName sck) | |
| { | |
| _mosi = mosi; | |
| _miso = miso; | |
| _sck = sck; | |
| _delay = 2; | |
| _cke = 0; | |
| _ckp = 0; | |
| _order = MSBFIRST; | |
| } | |
| void SoftSPI::wait(uint_fast8_t del) { | |
| for (uint_fast8_t i = 0; i < del; i++) { | |
| asm volatile("nop"); | |
| } | |
| } | |
| uint8_t SoftSPI::transfer(uint8_t val) | |
| { | |
| uint8_t out = 0; | |
| if (_order == MSBFIRST) | |
| { | |
| uint8_t v2 = | |
| ((val & 0x01) << 7) | | |
| ((val & 0x02) << 5) | | |
| ((val & 0x04) << 3) | | |
| ((val & 0x08) << 1) | | |
| ((val & 0x10) >> 1) | | |
| ((val & 0x20) >> 3) | | |
| ((val & 0x40) >> 5) | | |
| ((val & 0x80) >> 7); | |
| val = v2; | |
| } | |
| uint8_t del = _delay >> 1; | |
| uint8_t bval = 0; | |
| /* | |
| * CPOL := 0, CPHA := 0 => INIT = 0, PRE = Z|0, MID = 1, POST = 0 | |
| * CPOL := 1, CPHA := 0 => INIT = 1, PRE = Z|1, MID = 0, POST = 1 | |
| * CPOL := 0, CPHA := 1 => INIT = 0, PRE = 1 , MID = 0, POST = Z|0 | |
| * CPOL := 1, CPHA := 1 => INIT = 1, PRE = 0 , MID = 1, POST = Z|1 | |
| */ | |
| int sck = (_ckp) ? HIGH : LOW; | |
| for (uint8_t bit = 0u; bit < 8u; bit++) | |
| { | |
| if (_cke) | |
| { | |
| sck ^= 1; | |
| digitalWrite(_sck, sck); | |
| wait(del); | |
| } | |
| /* ... Write bit */ | |
| digitalWrite(_mosi, ((val & (1 << bit)) ? HIGH : LOW)); | |
| wait(del); | |
| sck ^= 1u; | |
| digitalWrite(_sck, sck); | |
| /* ... Read bit */ | |
| { | |
| bval = digitalRead(_miso); | |
| if (_order == MSBFIRST) | |
| { | |
| out <<= 1; | |
| out |= bval; | |
| } | |
| else | |
| { | |
| out >>= 1; | |
| out |= bval << 7; | |
| } | |
| } | |
| wait(del); | |
| if (!_cke) | |
| { | |
| sck ^= 1u; | |
| digitalWrite(_sck, sck); | |
| } | |
| } | |
| return out; | |
| } | |
| uint16_t SoftSPI::transfer16(uint16_t data) | |
| { | |
| union | |
| { | |
| uint16_t val; | |
| struct | |
| { | |
| uint8_t lsb; | |
| uint8_t msb; | |
| }; | |
| } in, out; | |
| in.val = data; | |
| if (_order == MSBFIRST) | |
| { | |
| out.msb = transfer(in.msb); | |
| out.lsb = transfer(in.lsb); | |
| } | |
| else | |
| { | |
| out.lsb = transfer(in.lsb); | |
| out.msb = transfer(in.msb); | |
| } | |
| return out.val; | |
| } | |
| void SoftSPI::transfer(void *buf, size_t count) | |
| { | |
| uint8_t *buffer = (uint8_t *)buf; | |
| for (size_t i = 0; i < count; i++) | |
| { | |
| transfer(buffer[i]); | |
| } | |
| } | |
| void SoftSPI::setDataMode(uint8_t mode) | |
| { | |
| switch (mode) | |
| { | |
| case SPI_MODE0: | |
| _ckp = 0; | |
| _cke = 0; | |
| break; | |
| case SPI_MODE1: | |
| _ckp = 0; | |
| _cke = 1; | |
| break; | |
| case SPI_MODE2: | |
| _ckp = 1; | |
| _cke = 0; | |
| break; | |
| case SPI_MODE3: | |
| _ckp = 1; | |
| _cke = 1; | |
| break; | |
| } | |
| digitalWrite(_sck, _ckp ? HIGH : LOW); | |
| } | |
| void SoftSPI::setBitOrder(uint8_t order) | |
| { | |
| _order = order & 1; | |
| } | |
| void SoftSPI::setClockDivider(uint8_t div) | |
| { | |
| _delay = div; | |
| } | |
| void SoftSPI::beginTransaction(SPISettings settings) | |
| { | |
| setDataMode(settings.getDataMode()); | |
| setBitOrder(settings.getBitOrder()); | |
| setClockDivider(133000000 / settings.getClockFreq()); | |
| } | |
| void SoftSPI::endTransaction(void) | |
| { | |
| } | |
| void SoftSPI::begin() | |
| { | |
| pinMode(_mosi, OUTPUT); | |
| pinMode(_miso, INPUT); | |
| pinMode(_sck, OUTPUT); | |
| } | |
| void SoftSPI::end() | |
| { | |
| pinMode(_mosi, INPUT); | |
| pinMode(_miso, INPUT); | |
| pinMode(_sck, INPUT); | |
| } | |
| void SoftSPI::usingInterrupt(int interruptNumber) {} | |
| void SoftSPI::notUsingInterrupt(int interruptNumber) {} | |
| // SPI Configuration methods | |
| void SoftSPI::attachInterrupt() {} | |
| void SoftSPI::detachInterrupt() {} |
| #include <stdint.h> | |
| #include <SPI.h> | |
| class SoftSPI : public SPIClass | |
| { | |
| private: | |
| void wait(uint_fast8_t del); | |
| void setDataMode(uint8_t mode); | |
| void setBitOrder(uint8_t order); | |
| void setClockDivider(uint8_t div); | |
| private: | |
| uint8_t _cke; | |
| uint8_t _ckp; | |
| uint8_t _delay; | |
| uint8_t _miso; | |
| uint8_t _mosi; | |
| uint8_t _sck; | |
| uint8_t _order; | |
| public: | |
| SoftSPI(PinName miso, PinName mosi, PinName sck); | |
| ~SoftSPI() {} | |
| uint8_t transfer(uint8_t data); | |
| uint16_t transfer16(uint16_t data); | |
| void transfer(void *buf, size_t count); | |
| // Transaction Functions | |
| void usingInterrupt(int interruptNumber); | |
| void notUsingInterrupt(int interruptNumber); | |
| void beginTransaction(SPISettings settings); | |
| void endTransaction(void); | |
| // SPI Configuration methods | |
| void attachInterrupt(); | |
| void detachInterrupt(); | |
| void begin(); | |
| void end(); | |
| }; |