Skip to content

Instantly share code, notes, and snippets.

@jaecktec
Created February 27, 2022 01:14
Show Gist options
  • Save jaecktec/9258eb7bed072155244ca1f43fbcfd0a to your computer and use it in GitHub Desktop.
Save jaecktec/9258eb7bed072155244ca1f43fbcfd0a to your computer and use it in GitHub Desktop.
Arduino Software SPI (2022)
#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();
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment