2020-02-21 17:10:49 +01:00
|
|
|
#pragma once
|
|
|
|
|
2020-02-21 17:26:14 +01:00
|
|
|
#include "../io/io.hpp"
|
|
|
|
|
2020-02-21 17:10:49 +01:00
|
|
|
namespace spi {
|
|
|
|
|
2020-02-21 17:35:23 +01:00
|
|
|
#if defined(__AVR_ATmega328P__)
|
|
|
|
|
2020-02-21 17:10:49 +01:00
|
|
|
template <class Cfg>
|
|
|
|
class Hardware {
|
2020-02-21 17:26:14 +01:00
|
|
|
public:
|
2022-05-28 17:03:40 +02:00
|
|
|
using word_t = uint8_t;
|
|
|
|
|
2020-02-21 17:26:14 +01:00
|
|
|
static void init()
|
|
|
|
{
|
|
|
|
if constexpr (Cfg::SIDE == Side::MASTER) {
|
|
|
|
sm_ss = true;
|
|
|
|
|
|
|
|
sm_sck.dir(io::Dir::OUT);
|
|
|
|
sm_miso.dir(io::Dir::IN);
|
|
|
|
sm_miso.pullup(Cfg::PULLUP);
|
|
|
|
sm_mosi.dir(io::Dir::OUT);
|
|
|
|
sm_ss.dir(io::Dir::OUT);
|
|
|
|
} else {
|
|
|
|
sm_sck.dir(io::Dir::IN);
|
|
|
|
sm_miso.dir(io::Dir::OUT);
|
|
|
|
sm_mosi.dir(io::Dir::IN);
|
|
|
|
sm_ss.dir(io::Dir::IN);
|
|
|
|
sm_ss.pullup(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
setClockDiv();
|
|
|
|
setMode();
|
|
|
|
setMaster();
|
|
|
|
setBitOrder();
|
|
|
|
|
|
|
|
SPCR |= (1 << SPE);
|
|
|
|
}
|
|
|
|
|
2022-05-28 17:03:40 +02:00
|
|
|
static word_t transfer(word_t data)
|
2020-02-21 17:29:45 +01:00
|
|
|
{
|
|
|
|
SPDR = data;
|
|
|
|
while (!(SPSR & (1 << SPIF)))
|
|
|
|
;
|
|
|
|
return SPDR;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void select(bool selectState)
|
|
|
|
{
|
|
|
|
sm_ss = !selectState;
|
|
|
|
}
|
|
|
|
|
2020-02-21 17:26:14 +01:00
|
|
|
private:
|
|
|
|
static io::Pin<io::P::B5> sm_sck;
|
|
|
|
static io::Pin<io::P::B4> sm_miso;
|
|
|
|
static io::Pin<io::P::B3> sm_mosi;
|
2022-05-26 14:58:47 +02:00
|
|
|
static io::Pin<Cfg::SS_PIN> sm_ss;
|
2020-02-21 17:26:14 +01:00
|
|
|
|
|
|
|
static void setClockDiv()
|
|
|
|
{
|
|
|
|
uint8_t ui8ClockDiv = static_cast<uint8_t>(Cfg::FREQ);
|
|
|
|
|
|
|
|
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()
|
|
|
|
{
|
|
|
|
if (Cfg::MODE == Mode::MODE_0 || Cfg::MODE == Mode::MODE_1) {
|
|
|
|
setCPOL(false);
|
|
|
|
} else {
|
|
|
|
setCPOL(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Cfg::MODE == Mode::MODE_0 || Cfg::MODE == Mode::MODE_2) {
|
|
|
|
setCPHA(false);
|
|
|
|
} else {
|
|
|
|
setCPHA(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void setMaster()
|
|
|
|
{
|
|
|
|
if constexpr (Cfg::SIDE == Side::MASTER) {
|
|
|
|
SPCR |= (1 << MSTR);
|
|
|
|
} else {
|
|
|
|
SPCR &= ~(1 << MSTR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void setBitOrder()
|
|
|
|
{
|
2020-02-21 17:35:23 +01:00
|
|
|
if constexpr (Cfg::BIT_ORDER == BitOrder::LSB_FIRST) {
|
2020-02-21 17:26:14 +01:00
|
|
|
SPCR |= (1 << DORD);
|
|
|
|
} else {
|
|
|
|
SPCR &= ~(1 << DORD);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2020-02-21 17:10:49 +01:00
|
|
|
};
|
|
|
|
|
2020-02-21 17:35:23 +01:00
|
|
|
#else
|
|
|
|
#error "This chip is not supported"
|
|
|
|
#endif
|
|
|
|
|
2020-02-21 17:10:49 +01:00
|
|
|
} // namespace spi
|