spi/hardware.hpp

140 lines
2.3 KiB
C++
Raw Permalink Normal View History

2020-02-21 17:10:49 +01:00
#pragma once
2022-05-29 16:14:42 +02:00
#include <cstdint>
2020-02-21 17:26:14 +01:00
#include "../io/io.hpp"
2020-02-21 17:10:49 +01:00
namespace spi {
#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-29 16:14:42 +02:00
using word_t = std::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 = SPCR | (1 << SPE);
2020-02-21 17:26:14 +01:00
}
static word_t transfer(word_t data)
{
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()
{
2022-05-29 16:14:42 +02:00
std::uint8_t ui8ClockDiv = static_cast<std::uint8_t>(Cfg::FREQ);
2020-02-21 17:26:14 +01:00
if (ui8ClockDiv & 1) {
SPCR = SPCR | (1 << SPR0);
2020-02-21 17:26:14 +01:00
} else {
SPCR = SPCR & ~(1 << SPR0);
2020-02-21 17:26:14 +01:00
}
if (ui8ClockDiv & (1 << 1)) {
SPCR = SPCR | (1 << SPR1);
2020-02-21 17:26:14 +01:00
} else {
SPCR = SPCR & ~(1 << SPR1);
2020-02-21 17:26:14 +01:00
}
if (ui8ClockDiv & (1 << 2)) {
SPSR = SPSR | (1 << SPI2X);
2020-02-21 17:26:14 +01:00
} else {
SPSR = SPSR & ~(1 << SPI2X);
2020-02-21 17:26:14 +01:00
}
}
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 = SPCR | (1 << MSTR);
2020-02-21 17:26:14 +01:00
} else {
SPCR = SPCR & ~(1 << MSTR);
2020-02-21 17:26:14 +01:00
}
}
static void setBitOrder()
{
if constexpr (Cfg::BIT_ORDER == BitOrder::LSB_FIRST) {
SPCR = SPCR | (1 << DORD);
2020-02-21 17:26:14 +01:00
} else {
SPCR = SPCR & ~(1 << DORD);
2020-02-21 17:26:14 +01:00
}
}
static void setCPOL(bool bCPOL)
{
if (bCPOL) {
SPCR = SPCR | (1 << CPOL);
2020-02-21 17:26:14 +01:00
} else {
SPCR = SPCR & ~(1 << CPOL);
2020-02-21 17:26:14 +01:00
}
}
static void setCPHA(bool bCPHA)
{
if (bCPHA) {
SPCR = SPCR | (1 << CPHA);
2020-02-21 17:26:14 +01:00
} else {
SPCR = SPCR & ~(1 << CPHA);
2020-02-21 17:26:14 +01:00
}
}
2020-02-21 17:10:49 +01:00
};
#else
#error "This chip is not supported"
#endif
2020-02-21 17:10:49 +01:00
} // namespace spi