#pragma once #include "../io/io.hpp" #include 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); static void setCPHA(bool bCPHA); static io::Pin sm_cSCK; static io::Pin sm_cMISO; static io::Pin sm_cMOSI; static io::Pin 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); static void deinit(); static void setClockDiv(ClockDiv enmClockDiv); static void setMode(Mode enmMode); static void setMaster(bool bMaster); static void setBitOrder(bool bLSBFirst); static uint8_t transfer(uint8_t ui8Data); static void select(bool bSelect); }; ////////////////////////////////////////////////////////////////////////// void Spi::setCPOL(bool bCPOL) { if (bCPOL) { SPCR |= (1 << CPOL); } else { SPCR &= ~(1 << CPOL); } } ////////////////////////////////////////////////////////////////////////// void Spi::setCPHA(bool bCPHA) { if (bCPHA) { SPCR |= (1 << CPHA); } else { SPCR &= ~(1 << CPHA); } } ////////////////////////////////////////////////////////////////////////// void Spi::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); } ////////////////////////////////////////////////////////////////////////// void Spi::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); } ////////////////////////////////////////////////////////////////////////// void Spi::setClockDiv(ClockDiv enmClockDiv) { uint8_t ui8ClockDiv = static_cast(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); } } ////////////////////////////////////////////////////////////////////////// void Spi::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); } } ////////////////////////////////////////////////////////////////////////// void Spi::setMaster(bool bMaster) { if (bMaster) { SPCR |= (1 << MSTR); } else { SPCR &= ~(1 << MSTR); } } ////////////////////////////////////////////////////////////////////////// void Spi::setBitOrder(bool bLSBFirst) { if (bLSBFirst) { SPCR |= (1 << DORD); } else { SPCR &= ~(1 << DORD); } } ////////////////////////////////////////////////////////////////////////// uint8_t Spi::transfer(uint8_t ui8Data) { SPDR = ui8Data; while (!(SPSR & (1 << SPIF))) ; return SPDR; } ////////////////////////////////////////////////////////////////////////// void Spi::select(bool bSelect) { sm_cSS.write(!bSelect); } } // namespace spi