spi/spi.hpp

162 lines
2.6 KiB
C++

#pragma once
#include "../io/io.hpp"
#include <avr/io.h>
namespace spi {
class Spi {
public:
enum class ClockDiv {
CLKDIV_4 = 0,
CLKDIV_16 = 1,
CLKDIV_64 = 2,
CLKDIV_128 = 3,
CLKDIV_2X_2 = 4,
CLKDIV_2X_8 = 5,
CLKDIV_2X_32 = 6,
CLKDIV_2X_64 = 7,
};
enum class Mode {
MODE_0 = 0,
MODE_1 = 1,
MODE_2 = 2,
MODE_3 = 3,
};
private:
static void setCPOL(bool bCPOL)
{
if (bCPOL) {
SPCR |= (1 << CPOL);
} else {
SPCR &= ~(1 << CPOL);
}
}
static void setCPHA(bool bCPHA)
{
if (bCPHA) {
SPCR |= (1 << CPHA);
} else {
SPCR &= ~(1 << CPHA);
}
}
static io::Pin<io::P::B5> sm_cSCK;
static io::Pin<io::P::B4> sm_cMISO;
static io::Pin<io::P::B3> sm_cMOSI;
static io::Pin<io::P::B2> sm_cSS;
public:
static void init(ClockDiv enmClockDiv = ClockDiv::CLKDIV_128, Mode enmMode = Mode::MODE_0, bool bMaster = true,
bool bLSBFirst = false, bool bMISOPullup = false)
{
if (bMaster) {
sm_cSS.write(true);
sm_cSCK.dir(io::Dir::OUT);
sm_cMISO.dir(io::Dir::IN);
sm_cMISO.pullup(bMISOPullup);
sm_cMOSI.dir(io::Dir::OUT);
sm_cSS.dir(io::Dir::OUT);
} else {
sm_cSCK.dir(io::Dir::IN);
sm_cMISO.dir(io::Dir::OUT);
sm_cMOSI.dir(io::Dir::IN);
sm_cSS.dir(io::Dir::IN);
sm_cSS.pullup(true);
}
setClockDiv(enmClockDiv);
setMode(enmMode);
setMaster(bMaster);
setBitOrder(bLSBFirst);
SPCR |= (1 << SPE);
}
static void deinit()
{
SPCR = 0;
sm_cSCK.dir(io::Dir::IN);
sm_cMISO.dir(io::Dir::IN);
sm_cMOSI.dir(io::Dir::IN);
sm_cSS.dir(io::Dir::IN);
}
static void setClockDiv(ClockDiv enmClockDiv)
{
uint8_t ui8ClockDiv = static_cast<uint8_t>(enmClockDiv);
if (ui8ClockDiv & 1) {
SPCR |= (1 << SPR0);
} else {
SPCR &= ~(1 << SPR0);
}
if (ui8ClockDiv & (1 << 1)) {
SPCR |= (1 << SPR1);
} else {
SPCR &= ~(1 << SPR1);
}
if (ui8ClockDiv & (1 << 2)) {
SPSR |= (1 << SPI2X);
} else {
SPSR &= ~(1 << SPI2X);
}
}
static void setMode(Mode enmMode)
{
if (enmMode == Mode::MODE_0 || enmMode == Mode::MODE_1) {
setCPOL(false);
} else {
setCPOL(true);
}
if (enmMode == Mode::MODE_0 || enmMode == Mode::MODE_2) {
setCPHA(false);
} else {
setCPHA(true);
}
}
static void setMaster(bool bMaster)
{
if (bMaster) {
SPCR |= (1 << MSTR);
} else {
SPCR &= ~(1 << MSTR);
}
}
static void setBitOrder(bool bLSBFirst)
{
if (bLSBFirst) {
SPCR |= (1 << DORD);
} else {
SPCR &= ~(1 << DORD);
}
}
static uint8_t transfer(uint8_t ui8Data)
{
SPDR = ui8Data;
while (!(SPSR & (1 << SPIF)))
;
return SPDR;
}
static void select(bool bSelect)
{
sm_cSS.write(!bSelect);
}
};
} // namespace spi