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(); | |
}; |