diff --git a/hardware.hpp b/hardware.hpp new file mode 100644 index 0000000..4ece8ad --- /dev/null +++ b/hardware.hpp @@ -0,0 +1,93 @@ +#pragma once + +#include + +#include + +namespace i2c { + +#if defined(__AVR_ATmega1284P__) + +enum class Prescaler { + PRESCALER_1 = 0b00, + PRESCALER_4 = 0b01, + PRESCALER_16 = 0b10, + PRESCALER_64 = 0b11, +}; + +template +class Hardware { + public: + static void init() + { + TWSR = static_cast(Pres); + TWBR = calcClock(); + } + + template + static bool start(bool read) + { + TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); + while (!(TWCR & (1 << TWINT))) + ; + + uint8_t status = TW_STATUS & 0xF8; + if (status != TW_START && status != TW_REP_START) + return false; + + TWDR = (Addr << 1) | read; + TWCR = (1 << TWINT) | (1 << TWEN); + + while (!(TWCR & (1 << TWINT))) + ; + + status = TW_STATUS & 0xF8; + if (status != TW_MT_SLA_ACK && status != TW_MR_SLA_ACK) + return false; + + return true; + } + + static bool write(uint8_t data) + { + TWDR = data; + TWCR = (1 << TWINT) | (1 << TWEN); + + while (!(TWCR & (1 << TWINT))) + ; + + uint8_t status = TW_STATUS & 0xF8; + if (status != TW_MT_DATA_ACK) + return false; + + return true; + } + + template + static uint8_t read() + { + TWCR = (1 << TWINT) | (1 << TWEN) | (!LastByte << TWEA); + while (!(TWCR & (1 << TWINT))) + ; + + return TWDR; + } + + static void stop() + { + TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); + + while (TWCR & (1 << TWSTO)) + ; + } + + private: + static constexpr uint8_t calcClock() + { + return ((F_CPU / Clock) - 16) / 2; + } +}; + +#endif + +} // namespace i2c diff --git a/i2c.hpp b/i2c.hpp index 6da1c74..00ada38 100644 --- a/i2c.hpp +++ b/i2c.hpp @@ -1,4 +1,39 @@ #pragma once +#include + +#include "hardware.hpp" + +namespace i2c { + +template struct I2c { + static void init() + { + Driver::init(); + } + + template + static bool start(bool read) + { + return Driver::template start(read); + } + + static bool write(uint8_t data) + { + return Driver::write(data); + } + + template + static uint8_t read() + { + return Driver::template read(); + } + + static void stop() + { + Driver::stop(); + } }; + +} // namespace i2c